Skip to content

Release v0.1.16 - #324

Merged
NishanthNixx merged 49 commits into
mainfrom
release-v0.1.16
Aug 25, 2026
Merged

Release v0.1.16#324
NishanthNixx merged 49 commits into
mainfrom
release-v0.1.16

Conversation

@itsmeakhil

Copy link
Copy Markdown
Collaborator

No description provided.

itsmeakhil and others added 30 commits July 21, 2026 22:46
Open a folder as a collection: requests stored as YAML files
(NNN- prefix = order, dirs = folders, collection.yaml manifest),
so collections can be committed, diffed and PR-reviewed. Filesystem
is the store — mutations diff the serialized tree and write only
changed files; window focus re-reads external edits. Secrets stay
out of files ({{vault.*}} tokens pass through; environments never
serialized). Desktop only: tauri fs/dialog/persisted-scope plugins
plus a recursive fs-scope grant command for picked dirs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… loss

- Serve Monaco from the app bundle (scripts/copy-monaco.mjs → public/monaco/vs,
  loader.config in lib/monaco-loader.ts) instead of jsdelivr; every editor was
  stuck on "Loading editor..." offline. Bump monaco-editor to 0.55.1 — the
  0.53 AMD build throws in language/css/monaco.contribution.js.
- Drop the stale Firebase-key gate from build-tauri.mjs (auth was removed).
- Script runner: 5 s hard timeout with worker terminate + respawn; a top-level
  infinite loop no longer hangs the tab forever.
- Tabs persistence: strip refetchable graphqlSchema always; on quota overflow
  retry with example bodies + file bytes stripped instead of wiping all tabs.
- History: strip uploaded file bytes before POST; SQL ORDER BY/LIMIT instead of
  loading every row; clear/delete hard-delete rows (sync is gone, tombstones
  only accumulated).
- Rust proxy: pooled reqwest clients (TLS/keep-alive reuse) and a 50 MB
  response body cap with an error envelope instead of unbounded buffering.
- generate-code.ts: replace raw NUL byte in Go escaper regex with \0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H3GuKxASDXLwFCLA7o3GGH
…ed kit

Phase 4 of the tool-consistency pass. Every Media & Design tool now renders
through ToolShell + IOPanel / kit-surface panels instead of hand-rolled Cards,
sharing one visual language with the rest of the app.

Migrated (logic + visuals preserved):
- color-picker, contrast-checker, css-gradient-builder, svg-optimizer,
  image-compressor, code-screenshot, exif-viewer, favicon-generator,
  keycode-inspector
- css-generators hub + box-shadow / border-radius / clamp sub-tabs

Verified intact: color swatches/pickers/eyedropper, WCAG contrast badges,
gradient live preview + PNG export, image-compressor canvas + before/after,
EXIF preview + metadata, favicon canvas render + ICO/ZIP export, code-screenshot
export node, keycode live capture + history, and all CSS live previews.

Also: IOPanel now omits its header row when a panel has neither label nor
actions (kept from the Converters phase).

0 type errors; all 10 pages render.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ors mounted

- RequestTabs + ResponsePanel are React.memo; the nine inline
  `(v) => updateActiveTab({...})` setters become one memoized setter map,
  onSaveExample/onMount/onChange handlers are stable.
- handleSend/handleCopyCurl go through latest-value refs so RequestPanel's memo
  holds and the keydown listener stops re-registering on every edit;
  handleLoadRequest/handleCancel/handleCurlPaste/example handlers memoized.
- Response JSON parsed once (useMemo) instead of three times per render for
  the tree/table/geo views; those views cap at 200 children / 500 rows.
- Desktop layout keeps the request panel in one ResizablePanelGroup and adds
  the response panel conditionally (id/order) — Send no longer remounts Monaco.
  Body / pre-request / tests editor tabs are forceMount + hidden when inactive.
- History list row renderer memoized so VirtualHistoryList's memo holds;
  TabBar's layout effect keys on tab id/kind/method/name, not the tabs array.
- sendProxyRequest() returns the Rust envelope directly instead of
  stringify → fake Response → json(); typed ProxyEnvelope.
- Secret-variable scan covers params/headers/auth/body only, not the whole tab
  (previous response + example bodies).
- Scripts worker caches pm.response.json() per run.
- next/dynamic for GrpcPanel (protobufjs), WebSocketPanel, ImportDialog
  (js-yaml), CookieJarDialog, MetricsDialog, CollectionRunnerDialog; exporters
  are imported on click.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H3GuKxASDXLwFCLA7o3GGH
…llections

Brings the folder-of-YAML collections (file-store.ts, collection-files.ts,
move-to-vault.ts, Rust fs/dialog/persisted-scope plugins, registry commands)
onto the current main. Conflict resolution keeps main's auth removal — the
branch's deep-link plugin, auth_server command and cookie_store deps stay
deleted — and main's reqwest 0.13 / base64 0.23. The "Open folder as
collection" button moves into ToolSidebarActions, where main relocated the
sidebar header controls.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H3GuKxASDXLwFCLA7o3GGH
Postman and Insomnia comparison pages stopped conceding mock servers,
collections, scripting and the runner — all shipped. They now list REST,
GraphQL, WebSocket, native gRPC, the local mock server, runner, vault-backed
secrets and import/export formats, and concede only team/cloud workspaces,
a CLI runner and Windows/Linux builds. New /compare/mydevtools-vs-bruno and
/compare/bruno-alternative pages; api-client metadata description/keywords
and the landing capability blurb describe the real scope.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H3GuKxASDXLwFCLA7o3GGH
The Postman environment importer existed but nothing called it. The import
dialog now detects `{ name, values[] }` payloads and creates the environment;
the environment manager gets a per-environment Postman export button.
i18n key ApiClient.environmentManager.exportPostman in all 27 locales.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H3GuKxASDXLwFCLA7o3GGH
…in palette entry

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H3GuKxASDXLwFCLA7o3GGH
Two importers for the switcher path, both pure libs with tests:

- Insomnia (`lib/import/insomnia.ts`): v4 JSON resources and v5 YAML, nested
  groups, every body/auth type we support, `{{ _.VAR }}` → `{{VAR}}`,
  pre-request/after-response scripts, environments. Round-trips our own
  Insomnia v4 exporter.
- Bruno (`lib/import/bruno.ts`): the legacy `.bru` language and v4
  OpenCollection YAML. Folder trees with `folder.bru` defaults, `seq`
  ordering, `~key` disabled rows, json/text/xml/form/multipart (`@file(...)`)
  /graphql bodies, basic/bearer/apikey/oauth2 auth, scripts, and
  `environments/*` (secret var names come in with empty values).

Detection covers both, and the import dialog now creates the environments an
import brings with it instead of dropping them. 22 new tests.

Still folder-only from a paste of a single file: picking a whole Bruno
directory needs a desktop folder-read pass (readCollectionFiles is .yaml-only).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H3GuKxASDXLwFCLA7o3GGH
feat(media-design): migrate all 10 Media & Design tools onto the shar…
…nd CLI

Adds the Secure Files tool ("Files" in the UI): import files or folders and
store them as opaque `<32 random hex>.mydt` objects in a storage folder the
user picks. Original names, folder paths, types and contents are encrypted;
the app shows them only while the vault is unlocked.

Format (docs/MYDT_FORMAT.md, crates/mydt):
- Self-contained per file: Argon2id salt/params + per-file DEK wrapped by the
  key derived from the master password + XChaCha20-Poly1305 metadata and
  payload, with the header bound in as AAD. No index — listing scans the
  folder and decrypts headers, so a folder is portable and self-healing.
- Extracted into the standalone `mydt` crate: library plus a `mydt` CLI
  (encrypt/decrypt/info/ls) behind `--features cli`, so the desktop app and
  the CLI read and write identical objects. Wired into rust.yml.

Desktop:
- New `/api/v1/secure-files/*` routes: settings, list, import, patch, replace,
  export, delete, folder rename/delete; raw-bytes `secure_file_read` command
  for previews.
- The webview gate hands the verified master password to Rust once per unlock
  so Argon2id can derive the Secure Files key; it lives in AppState only and
  is dropped on lock (idle auto-lock included).
- Listing keeps a decrypted-metadata cache reconciled by an id-set diff, and
  import encrypts across threads with one directory fsync per batch. 10k
  files: import 1.75s, cold list 0.30s, warm list 24ms.

UI:
- Folder tree, list and grid views (both virtualized), preview for text,
  code, images and PDF, export with a plaintext warning, rename/move/replace,
  dismissible warning for unreadable objects. Files up to 20 MB.
- Fixes a latent bug in the shared s3-drive FilePreviewDialog, which used
  Radix Tooltip without a TooltipProvider and crashed the dialog subtree.

`pnpm i18n:sync` also backfilled unrelated missing keys across the 26
non-English locales, which is why messages/ is broad.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01No7es2PjF9SNQs22RYHcdM
Grid tiles show the actual image instead of a type icon, Drive-style.

Only the tiles currently on screen are decrypted (the hook is fed the same
visible window the virtualizer computes), at most three at a time, and the
queue re-prioritizes on scroll. Each image is downscaled to 256px and
re-encoded before it is kept, so the plaintext original is dropped right away
and the blob pool stays bounded — 150 thumbnails, oldest off-screen ones
revoked, everything revoked when the tool unmounts on lock.

Cache keys include size and mtime so Replace invalidates a stale thumbnail.
SVG skips the canvas (WKWebView cannot createImageBitmap it) and anything
that fails to decode falls back to its icon without retrying.

Also moves blobMime into lib/secure-files.ts so the preview and thumbnail
paths share one implementation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01No7es2PjF9SNQs22RYHcdM
Codes were only ever issued at vault setup, so a user who burned all
eight — or set the vault up before codes existed — had no recovery path
left, even though the downloaded code file told them to regenerate from
Settings.

- New Settings card: verifies the master password, generates a fresh set
  and stores it (storing replaces the whole array, which is what
  invalidates the old codes), then shows them once with copy/download.
- GET /api/v1/auth/backup-codes returns {total, remaining} so the card
  can show how many codes are left.
- markBackupCodeUsed now throws on a non-OK response instead of failing
  silently, and the unlock gate burns the code after a successful unlock
  rather than before — a failed burn leaves a retryable code instead of
  spending one on an unlock that never happened.
- Code grid extracted so the setup gate and the settings card render
  codes identically.
- SettingsPage.backupCodes translated across all 27 locales.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018XHJKZ77EJdyDQ6gDt7WH6
Adds an Overview entry above the folder tree that swaps the main pane for
storage stats: file and folder counts, content size, true on-disk size with
the encryption overhead called out, a per-type breakdown with counts, sizes
and proportional bars, plus largest and recently added files (each row jumps
to its containing folder). Unreadable objects are surfaced here too.

On-disk size is measured, not estimated. The listing cache now stores each
object's size taken from the handle it already opens to read the header, so
the first scan after unlock gets it for free and later listings cost nothing
extra; write-through keeps it exact across import, rename and replace. Totals
cover readable objects only — unreadable ones stay in `errors` rather than
being folded into the numbers.

Everything else is derived client-side from the file list already in memory
and memoized, so the view stays instant at 100k files.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01No7es2PjF9SNQs22RYHcdM
The Files strings shipped as English placeholders because i18n-sync fills
missing keys by copying en.json — the audit passed on key presence, not on
translation. This replaces all 84 keys per locale with real translations:
navigation label, dashboard card, and the whole SecureFiles namespace.

Plural rules follow each language rather than English: ru/uk/pl/cs carry
few/many, ar carries the full zero/one/two/few/many/other set, and the
languages without a count distinction (ja/ko/zh/tr/vi/id/ms) use a single
other form. Verified by compiling all 1998 messages through
intl-messageformat per locale and formatting them with real arguments, so
every placeholder and plural branch is exercised — "3 файла", "5 plików",
"ملفان", "2 soubory".

Terminology is localised, not transliterated: vault becomes Tresor,
coffre-fort, bóveda, cassaforte, 保管庫, 保险库; storage folder, masked and
overhead follow suit. Quotation marks use each locale's convention.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01No7es2PjF9SNQs22RYHcdM
Secure Files: encrypted .mydt file vault, shared format crate and CLI
- Params/Headers: the column header was a flex row with no `gap` while the
  data rows had `gap-2`, and its trailing spacer was `w-10` against a 36px
  delete button — so KEY/VALUE never sat over their inputs. Both now share one
  grid template, and the labels use the Input's own `px-3`.
- Toolbar: `OfflineIndicator` renders null whenever you are online, but the
  divider before it rendered unconditionally, leaving a hairline and two gaps
  hanging off the end of the row. The indicator now brings its own separator.
- Group dividers were `bg-border/50` and `mx-1`: too faint to read as dividers
  on a dark ground, so they looked like unexplained holes, and the extra margin
  broke the row's 8px rhythm. Now `bg-border`, spaced by the row's own gap.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H3GuKxASDXLwFCLA7o3GGH
Drops the local Monaco bundling from c50bd6e per maintainer decision:
removes lib/monaco-loader.ts, scripts/copy-monaco.mjs, the pre{dev,build}
hooks, the build-tauri copy step and the public/monaco gitignore entry.
@monaco-editor/loader falls back to its default
cdn.jsdelivr.net/npm/monaco-editor@0.55.1/min/vs.

Keeps monaco-editor at 0.55.1: it is a types-only dependency here, and 0.55.1
is the exact version the loader pulls from the CDN, so the local typings match
what runs.

Trade-off, recorded deliberately: with no network every Monaco-backed editor
(API client body/scripts/response plus ~15 other tools) stays on
"Loading editor..." — the app is not fully offline while this stands.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H3GuKxASDXLwFCLA7o3GGH
Reported against the API client, but two of the three live in the shared
ToolSidebarLayout used by 11 tools.

- Collapsed, the 40px rail rendered a single toggle: no items, no identity,
  just an empty strip. It now shows the tool's accent icon, which peeks the
  full panel as a flyout (the existing Sheet, previously mobile-only) so the
  list stays reachable without giving up the width; the pin-open toggle sits
  below it.
- New `isOverlay` on the panel context — true for the mobile sheet and the new
  desktop flyout — so picking a row dismisses a floating panel but never the
  pinned one. All five call sites moved off `isMobile`, which would have left
  the desktop flyout covering the thing you just opened.
- API client: the tool had no title of its own (the panel header says
  "Collections"), leaving it unnamed once collapsed, and its toolbar sat flush
  against the top edge. Adds an `h1` from the existing `Navigation.apiClient`
  key — present in all 27 locales, so no new strings — and `px-4 pt-3`.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H3GuKxASDXLwFCLA7o3GGH
Two follow-ups to the collapsed-rail work, both about showing one control
where there should be one:

- The rail rendered the tool icon *and* a separate expand arrow — two buttons
  for the same action stacked in 40px. Now a single button: the tool's accent
  icon at rest (so the strip still names the tool), swapping to the toggle
  glyph on hover/focus. The desktop flyout goes with it; clicking expands, as
  the glyph promises. `isOverlay` narrows back to the mobile sheet.
- `PanelLeftClose` / `PanelLeftOpen` draw a panel outline *and* a chevron
  inside 16px, which at this size reads as two icons overlapping rather than
  one control — visible in the Notes header. Both replaced with plain
  `PanelLeft`, the same glyph shadcn uses for its sidebar trigger.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H3GuKxASDXLwFCLA7o3GGH
API Client: offline Monaco, data-loss and hang fixes, render perf, folder collections, Insomnia/Bruno import
…redicate

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H3GuKxASDXLwFCLA7o3GGH
itsmeakhil and others added 19 commits August 24, 2026 17:56
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H3GuKxASDXLwFCLA7o3GGH
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H3GuKxASDXLwFCLA7o3GGH
…abindex

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H3GuKxASDXLwFCLA7o3GGH
… the icon rail

Collapsing used to unmount the panel, which discarded the body's search text,
expanded tree groups and scroll position every time. It also made a rail
impossible: entries are published by hooks inside the body, and an unmounted
body cannot publish. Hide with display:none instead, mirroring how TabContent
keeps inactive tool tabs alive.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H3GuKxASDXLwFCLA7o3GGH
…d rail

password-manager, api-keys, to-do and environment-manager gain a populated rail
with no edits of their own — the facets are already declared as filter items.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H3GuKxASDXLwFCLA7o3GGH
…the rail

notes and snippet-manager publish pinned items, api-client its collections,
data-explorer and s3-drive their connections, bookmarks and secure-files their
root folders.

Also fixes secure-files' folder tree calling panel.close() unconditionally on
select, which collapsed the whole sidebar on every folder pick on desktop —
every other sidebar guards that with isOverlay.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H3GuKxASDXLwFCLA7o3GGH
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H3GuKxASDXLwFCLA7o3GGH
…ollapse

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H3GuKxASDXLwFCLA7o3GGH
… NUL byte

The "overview showing, nothing selected" sentinel was a literal NUL inside a
string literal in the source. Same value, but the byte made the whole file
binary to grep, ripgrep and diff, which then skip it without saying so.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H3GuKxASDXLwFCLA7o3GGH
…tives

Shipped unused. They give the next per-tool sidebar migration somewhere to land
without that migration also having to design the pieces.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H3GuKxASDXLwFCLA7o3GGH
The hero greeted off `useAuth().user.displayName`, which is a hardcoded null —
that identity object is deliberately name-free, and the editable profile name
lives in local preferences behind `useAppUser` (as top-bar and mobile-nav
already read it). So the greeting never named anyone, however the profile was
filled in.

Reads the profile name instead, via a `greetingFirstName` helper that is unit
tested. The now-unused `user` prop is dropped from DashboardHero.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H3GuKxASDXLwFCLA7o3GGH
The vault gate sat in page.tsx, which is this layout's children — so a locked
vault swapped the editor for the placeholder while the sidebar column kept
rendering a note tree, a search field and a New note button, all backed by a
vault with no key loaded.

Gate in the layout instead, above NotesProvider so the provider does not mount
and fail to load notes it cannot decrypt. password-manager, api-keys,
environment-manager, secure-files and snippet-manager already gate before the
component that owns their ToolSidebarLayout; notes differed only because its
layout is a separate route-level wrapper.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H3GuKxASDXLwFCLA7o3GGH
The settings page was one long scroll of stacked cards. Split it into four
tabs (reusing existing i18n keys — no locale churn):

- Profile      — profile card
- Appearance   — theme, accent color, language
- Security     — auto-lock, vault icons, telemetry, backup codes
- Backup & data — backup/restore, factory reset, app version

No logic changes; each section's cards moved verbatim into a TabsContent.
0 type errors; page renders.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
feat(settings): segregate settings into tabs
@vercel

vercel Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
mydevtools-tech Ready Ready Preview Aug 25, 2026 9:30am

export function importInsomniaWithMeta(text: string): InsomniaImportResult {
const t = text.trim()
// yaml.load also parses JSON, so v4 YAML exports come for free.
const doc = (t.startsWith("{") ? JSON.parse(t) : yaml.load(t)) as
@github-actions

Copy link
Copy Markdown

ThreatCrush Security Scan

1 finding(s)

MEDIUM: 1

Severity Rule Location
MEDIUM js-unsafe-yaml-load apps/desktop-ui/src/lib/import/insomnia.ts:290

Snippets are redacted; ThreatCrush never prints matched credential material.

@NishanthNixx
NishanthNixx merged commit ec1b8c4 into main Aug 25, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants