diff --git a/.changeset/553c3037.md b/.changeset/553c3037.md deleted file mode 100644 index 10bdce07..00000000 --- a/.changeset/553c3037.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'aicodeman': patch ---- - -Fix two multi-user scoping holes in the new filesystem path picker. `GET /api/filesystem/browse` and `GET /api/filesystem/preview` accept an optional `sessionId` that contributes the session's working directory as a browse root, but they resolved it straight off the session map without an ownership check, unlike the nine other session-scoped handlers in the same route file. A non-admin could therefore pin another user's working directory as a root simply by passing their session id, then list and preview files under it. Both endpoints now run `canAccessOwned` and report 404, which also avoids confirming that a session id exists. - -Separately, `Home` and `CASES_DIR` were unconditional browse roots for every caller. Per-user spaces live at `/`, which is inside `homedir()`, so the `Home` root alone exposed every other user's workspace to any authenticated user. In multi-user mode a non-admin now gets only their own space plus anything explicitly listed in `CODEMAN_FILE_PICKER_ROOTS`; `/mnt/d` is no longer offered by default, since a broad host mount should be an explicit operator decision in a multi-user deployment. Admins keep the host-wide roots, and single-user mode is unchanged. - -Both holes are regression-guarded in `test/routes/file-routes.test.ts`, verified to fail against the previous code. Multi-user mode is opt-in and off by default, so single-user installs were never affected. diff --git a/.changeset/fix-claude-response-viewer.md b/.changeset/fix-claude-response-viewer.md deleted file mode 100644 index 53cf018b..00000000 --- a/.changeset/fix-claude-response-viewer.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'aicodeman': patch ---- - -Normalize Claude conversations in the response viewer. A Claude transcript is an append-only event log, so one logical exchange spans many JSONL rows: tool-result rows, meta/image/skill rows, compact summaries, task and team notifications, sidechains, replayed assistant snapshots, and multi-block assistant output. The viewer rendered a card per row, which produced duplicate and truncated cards that read as lost responses. Cards are now built at real human-turn boundaries, replayed assistant snapshots are deduplicated, and sidechain rows (which belong to subagents, not the main conversation) no longer leak in. An identical prompt that legitimately recurs after an assistant reply is still kept as its own turn. - -Measured over 40 real transcripts: 3108 cards became 621, duplicate cards dropped from 74 to 8 (all of them genuinely repeated turns), no assistant text was lost, and the non-`context=full` last-response text was byte-identical on every file. - -Also rebinds recovered sessions to their transcript. `reconcileSessions()` can recover a lost mux session as a `restored-` placeholder with a stale working directory, which made transcript lookup by cwd find nothing. The placeholder still carries the first eight characters of the conversation UUID, so the viewer now rebinds to the matching top-level transcript when exactly one candidate matches. diff --git a/.changeset/mobile-filesystem-path-picker.md b/.changeset/mobile-filesystem-path-picker.md deleted file mode 100644 index 9427c9ad..00000000 --- a/.changeset/mobile-filesystem-path-picker.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"aicodeman": minor ---- - -feat(mobile): browse and insert local file and folder paths - -Add a root-confined filesystem picker to Link Existing and the extended mobile -keyboard bar. Selected paths remain editable at the active prompt, supported -images/documents/text files open in a safe inline preview, and a new one-tap -action clears only the current unsent input without invoking `/clear`. diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d3f3fd3..75871392 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,30 @@ # aicodeman +## 1.9.0 + +### Minor Changes + +- 2667150: feat(mobile): browse and insert local file and folder paths + + Add a root-confined filesystem picker to Link Existing and the extended mobile + keyboard bar. Selected paths remain editable at the active prompt, supported + images/documents/text files open in a safe inline preview, and a new one-tap + action clears only the current unsent input without invoking `/clear`. + +### Patch Changes + +- 3cff98f: Fix two multi-user scoping holes in the new filesystem path picker. `GET /api/filesystem/browse` and `GET /api/filesystem/preview` accept an optional `sessionId` that contributes the session's working directory as a browse root, but they resolved it straight off the session map without an ownership check, unlike the nine other session-scoped handlers in the same route file. A non-admin could therefore pin another user's working directory as a root simply by passing their session id, then list and preview files under it. Both endpoints now run `canAccessOwned` and report 404, which also avoids confirming that a session id exists. + + Separately, `Home` and `CASES_DIR` were unconditional browse roots for every caller. Per-user spaces live at `/`, which is inside `homedir()`, so the `Home` root alone exposed every other user's workspace to any authenticated user. In multi-user mode a non-admin now gets only their own space plus anything explicitly listed in `CODEMAN_FILE_PICKER_ROOTS`; `/mnt/d` is no longer offered by default, since a broad host mount should be an explicit operator decision in a multi-user deployment. Admins keep the host-wide roots, and single-user mode is unchanged. + + Both holes are regression-guarded in `test/routes/file-routes.test.ts`, verified to fail against the previous code. Multi-user mode is opt-in and off by default, so single-user installs were never affected. + +- bca56b4: Normalize Claude conversations in the response viewer. A Claude transcript is an append-only event log, so one logical exchange spans many JSONL rows: tool-result rows, meta/image/skill rows, compact summaries, task and team notifications, sidechains, replayed assistant snapshots, and multi-block assistant output. The viewer rendered a card per row, which produced duplicate and truncated cards that read as lost responses. Cards are now built at real human-turn boundaries, replayed assistant snapshots are deduplicated, and sidechain rows (which belong to subagents, not the main conversation) no longer leak in. An identical prompt that legitimately recurs after an assistant reply is still kept as its own turn. + + Measured over 40 real transcripts: 3108 cards became 621, duplicate cards dropped from 74 to 8 (all of them genuinely repeated turns), no assistant text was lost, and the non-`context=full` last-response text was byte-identical on every file. + + Also rebinds recovered sessions to their transcript. `reconcileSessions()` can recover a lost mux session as a `restored-` placeholder with a stale working directory, which made transcript lookup by cwd find nothing. The placeholder still carries the first eight characters of the conversation UUID, so the viewer now rebinds to the matching top-level transcript when exactly one candidate matches. + ## 1.8.3 ### Patch Changes diff --git a/package-lock.json b/package-lock.json index 6f601dfe..911e8b91 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "aicodeman", - "version": "1.8.3", + "version": "1.9.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "aicodeman", - "version": "1.8.3", + "version": "1.9.0", "hasInstallScript": true, "license": "MIT", "workspaces": [ diff --git a/package.json b/package.json index 5ff11879..1552fa64 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "aicodeman", - "version": "1.8.3", + "version": "1.9.0", "description": "Mission control for AI coding agents - run 20 autonomous agents with real-time monitoring and session persistence", "type": "module", "main": "dist/index.js",