Compare commits

...
18 Commits
79 changed files with 540 additions and 38 deletions
+3 -1
View File
@@ -11,7 +11,7 @@ Personal [Pi](https://github.com/earendil-works/pi-mono) extensions, skills, glo
- the `manage-pi-links` and `nono-profiles` project-only skills under `.pi/skills/`; - the `manage-pi-links` and `nono-profiles` project-only skills under `.pi/skills/`;
- no global Pi extension symlinks. Active extensions are installed separately as pinned Gitea npm packages. - no global Pi extension symlinks. Active extensions are installed separately as pinned Gitea npm packages.
The repository contains `copy-all`, `dictate` (Linux host-service dictation), `effort-controls`, `file-search`, `interactive-subagents`, `lm-studio`, `native-hooks`, `prompt-snippets`, `subagents`, `todo-herdr`, `update`, and the private historical `workflow` extension. The link manifest does not install any extension globally. New feature work uses `develop-workflow`; the legacy extension remains unexposed as pilot evidence under [ADR 0006](docs/adr/0006-skill-led-development-workflow-04SEP2026.md). The `pptx`, `stop-slop`, `subagents`, and `xlsx` skills are intentionally excluded. Archived resources under `__archived/` are never installed. Update `config/pi-links.json` deliberately if that policy changes. The repository contains `bash-cwd`, `copy-all`, `dictate` (Linux host-service dictation), `effort-controls`, `file-search`, `interactive-subagents`, `lm-studio`, `native-hooks`, `prompt-snippets`, `subagents`, `todo-herdr`, and `update`. The link manifest does not install any extension globally. New feature work uses `develop-workflow`; both legacy workflow implementations are retained under [`__archived/extensions/`](__archived/extensions/README.md) per [ADR 0007](docs/adr/0007-archive-legacy-workflows-05SEP2026.md). The `pptx`, `stop-slop`, `subagents`, and `xlsx` skills are intentionally excluded. Archived resources under `__archived/` are never installed. Update `config/pi-links.json` deliberately if that policy changes.
## Fresh-machine setup ## Fresh-machine setup
@@ -132,6 +132,8 @@ The currently published and deployed extension set is:
- `@jbcode/pi-interactive-subagents@3.7.3`; - `@jbcode/pi-interactive-subagents@3.7.3`;
- `@jbcode/pi-todo-herdr@0.2.5`. - `@jbcode/pi-todo-herdr@0.2.5`.
[`@jbcode/pi-bash-cwd`](extensions/bash-cwd) is an unpublished compatibility package for Pi 0.84.x. It adds a validated optional `cwd` argument to the built-in `bash` tool so commands can target hidden worktrees and nested packages without an inline `cd`. Keep using explicit directory proofs for Git worktree mutations even with the override installed.
Configure the scoped Gitea npm registry and install only the packages you want. Keep the token in the user environment or user-level npm configuration; never commit it: Configure the scoped Gitea npm registry and install only the packages you want. Keep the token in the user environment or user-level npm configuration; never commit it:
```ini ```ini
+7
View File
@@ -0,0 +1,7 @@
# Archived extensions
`workflow/` and `_workflows/` are retired historical implementations, archived by explicit approval under [ADR 0007](../../docs/adr/0007-archive-legacy-workflows-05SEP2026.md). New development uses the [`develop-workflow` skill](../../skills/develop/develop-workflow/SKILL.md).
Their source and tests are retained for reference, excluded from active workspaces, typechecking, and root test commands. Historical source still contains relative imports into the former `extensions/shared` location and workspace dependency declarations; the archive is not a runnable or installable package set. To investigate the runnable historical layout, inspect commit `fee0d44e2ddd7a982e94ebf99117f69bb9bae78e` in a separate checkout rather than wiring archived files into the active runtime.
Historical plans and ADRs retain their original paths as evidence. The separate scenario and real-change pilot validation TODO remains open.
@@ -1,5 +1,5 @@
# workflow # workflow
> **Historical reference:** This private legacy extension was superseded for new development by the model-invoked [`develop-workflow` skill](../../skills/develop/develop-workflow/SKILL.md) under [ADR 0006](../../docs/adr/0006-skill-led-development-workflow-04SEP2026.md). > **Historical reference:** This private legacy extension was superseded for new development by the model-invoked [`develop-workflow` skill](../../../skills/develop/develop-workflow/SKILL.md) under [ADR 0006](../../../docs/adr/0006-skill-led-development-workflow-04SEP2026.md).
Keep this workspace private, unpublished, and unexposed during the skill pilot. It is historical implementation evidence, not the skill implementation or a prerequisite for skill development. Archive or remove it only in the separately approved post-pilot cleanup. Keep this workspace private, unpublished, and unexposed during the skill pilot. It is historical implementation evidence, not the skill implementation or a prerequisite for skill development. Archive or remove it only in the separately approved post-pilot cleanup.
+15 -15
View File
@@ -18,6 +18,19 @@
"vitest": "catalog:", "vitest": "catalog:",
}, },
}, },
"extensions/bash-cwd": {
"name": "@jbcode/pi-bash-cwd",
"version": "0.1.0",
"devDependencies": {
"@earendil-works/pi-coding-agent": "catalog:",
"typebox": "catalog:",
"typescript": "catalog:",
},
"peerDependencies": {
"@earendil-works/pi-coding-agent": "catalog:pi-peer",
"typebox": "catalog:pi-peer",
},
},
"extensions/copy-all": { "extensions/copy-all": {
"name": "@jbcode/pi-copy-all", "name": "@jbcode/pi-copy-all",
"version": "0.1.0", "version": "0.1.0",
@@ -147,19 +160,6 @@
"@earendil-works/pi-coding-agent": "catalog:pi-peer", "@earendil-works/pi-coding-agent": "catalog:pi-peer",
}, },
}, },
"extensions/workflow": {
"name": "@jbcode/pi-workflow",
"version": "0.1.0",
"dependencies": {
"@jbcode/pi-shared": "workspace:^",
},
"peerDependencies": {
"@earendil-works/pi-ai": "catalog:pi-peer",
"@earendil-works/pi-coding-agent": "catalog:pi-peer",
"@earendil-works/pi-tui": "catalog:pi-peer",
"typebox": "catalog:pi-peer",
},
},
}, },
"overrides": { "overrides": {
"@effect/platform-node-shared": "4.0.0-beta.101", "@effect/platform-node-shared": "4.0.0-beta.101",
@@ -354,6 +354,8 @@
"@ioredis/commands": ["@ioredis/commands@1.10.0", "", {}, "sha512-UmeW7z4LfctwoQ5wkhVzgq8tXkreED2xZGpX+Bg+zA+WJFZCT6c062AfCK/Dfk81xZnnwdhJCUMkitihRaoC2Q=="], "@ioredis/commands": ["@ioredis/commands@1.10.0", "", {}, "sha512-UmeW7z4LfctwoQ5wkhVzgq8tXkreED2xZGpX+Bg+zA+WJFZCT6c062AfCK/Dfk81xZnnwdhJCUMkitihRaoC2Q=="],
"@jbcode/pi-bash-cwd": ["@jbcode/pi-bash-cwd@workspace:extensions/bash-cwd"],
"@jbcode/pi-copy-all": ["@jbcode/pi-copy-all@workspace:extensions/copy-all"], "@jbcode/pi-copy-all": ["@jbcode/pi-copy-all@workspace:extensions/copy-all"],
"@jbcode/pi-dictate": ["@jbcode/pi-dictate@workspace:extensions/dictate"], "@jbcode/pi-dictate": ["@jbcode/pi-dictate@workspace:extensions/dictate"],
@@ -378,8 +380,6 @@
"@jbcode/pi-update": ["@jbcode/pi-update@workspace:extensions/update"], "@jbcode/pi-update": ["@jbcode/pi-update@workspace:extensions/update"],
"@jbcode/pi-workflow": ["@jbcode/pi-workflow@workspace:extensions/workflow"],
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.6.0", "", {}, "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw=="], "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.6.0", "", {}, "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw=="],
"@mariozechner/clipboard": ["@mariozechner/clipboard@0.3.9", "", { "optionalDependencies": { "@mariozechner/clipboard-darwin-arm64": "0.3.9", "@mariozechner/clipboard-darwin-universal": "0.3.9", "@mariozechner/clipboard-darwin-x64": "0.3.9", "@mariozechner/clipboard-linux-arm64-gnu": "0.3.9", "@mariozechner/clipboard-linux-arm64-musl": "0.3.9", "@mariozechner/clipboard-linux-riscv64-gnu": "0.3.9", "@mariozechner/clipboard-linux-x64-gnu": "0.3.9", "@mariozechner/clipboard-linux-x64-musl": "0.3.9", "@mariozechner/clipboard-win32-arm64-msvc": "0.3.9", "@mariozechner/clipboard-win32-x64-msvc": "0.3.9" } }, "sha512-ABnA53mdfkGZwOFUdZNv2S0CWGO/EIuPj8Vv9xmBFmSYg/qFc7ihO6q5FcQjvoE67kZpWkEc4AhD6B/os04yuA=="], "@mariozechner/clipboard": ["@mariozechner/clipboard@0.3.9", "", { "optionalDependencies": { "@mariozechner/clipboard-darwin-arm64": "0.3.9", "@mariozechner/clipboard-darwin-universal": "0.3.9", "@mariozechner/clipboard-darwin-x64": "0.3.9", "@mariozechner/clipboard-linux-arm64-gnu": "0.3.9", "@mariozechner/clipboard-linux-arm64-musl": "0.3.9", "@mariozechner/clipboard-linux-riscv64-gnu": "0.3.9", "@mariozechner/clipboard-linux-x64-gnu": "0.3.9", "@mariozechner/clipboard-linux-x64-musl": "0.3.9", "@mariozechner/clipboard-win32-arm64-msvc": "0.3.9", "@mariozechner/clipboard-win32-x64-msvc": "0.3.9" } }, "sha512-ABnA53mdfkGZwOFUdZNv2S0CWGO/EIuPj8Vv9xmBFmSYg/qFc7ihO6q5FcQjvoE67kZpWkEc4AhD6B/os04yuA=="],
@@ -8,6 +8,8 @@ supersedes:
# Replace the custom workflow engine with a skill-led workflow # Replace the custom workflow engine with a skill-led workflow
> The legacy-runtime retention and pilot-before-retirement prerequisite below are superseded by [ADR 0007](0007-archive-legacy-workflows-05SEP2026.md). The skill-led workflow and its outstanding validation requirements remain in force.
## Context ## Context
The custom `workflow` extension encoded useful approval, isolation, verification, and reviewer-independence policy, but coupled that policy to a large state machine, child runtime, scheduler, persistence layer, and TUI. Recorded runs failed or stalled before implementation when exact planner output, child delivery, recovery state, or liveness mechanics diverged from the engine contract. The custom `workflow` extension encoded useful approval, isolation, verification, and reviewer-independence policy, but coupled that policy to a large state machine, child runtime, scheduler, persistence layer, and TUI. Recorded runs failed or stalled before implementation when exact planner output, child delivery, recovery state, or liveness mechanics diverged from the engine contract.
@@ -0,0 +1,5 @@
# Archive the legacy workflow implementations
On 05SEP2026, JB explicitly approved archiving both legacy workflow implementations now rather than waiting for the three successful pilots required by [ADR 0006](0006-skill-led-development-workflow-04SEP2026.md). Move their source and tests to `__archived/extensions/workflow` and `__archived/extensions/_workflows`, outside active workspaces and test commands, while retaining historical documentation and the separate skill-validation TODO.
This supersedes only the retention and pilot-before-retirement prerequisite. It does not claim that scenario evaluation or pilots passed, change the `develop-workflow` skill, or authorize removal of historical run evidence. The archive preserves reference source rather than maintaining runnable legacy packages.
+3 -1
View File
@@ -42,7 +42,7 @@ bun publish
Publish `@jbcode/pi-shared` before a new version of any extension that depends on it. Gitea rejects republishing an existing name/version, so bump the changed package version first. Publish `@jbcode/pi-shared` before a new version of any extension that depends on it. Gitea rejects republishing an existing name/version, so bump the changed package version first.
`extensions/workflow` and `extensions/_workflows` are private historical evidence and must not be published. [ADR 0006](adr/0006-skill-led-development-workflow-04SEP2026.md) supersedes the proposed runtime merge; new development uses the `develop-workflow` skill. `__archived/extensions/workflow` and `__archived/extensions/_workflows` are historical reference, outside active workspaces, and must not be published. [ADR 0007](adr/0007-archive-legacy-workflows-05SEP2026.md) records their archival and supersedes ADR 0006's pilot-before-retirement prerequisite; new development uses the `develop-workflow` skill.
## Install with Pi ## Install with Pi
@@ -57,3 +57,5 @@ pi install npm:@jbcode/pi-todo-herdr@0.2.5
``` ```
Pi installs runtime dependencies from the same scoped registry. `config/pi-links.json` deliberately exposes no extension symlinks, preventing duplicate local and published copies. Pi installs runtime dependencies from the same scoped registry. `config/pi-links.json` deliberately exposes no extension symlinks, preventing duplicate local and published copies.
`@jbcode/pi-bash-cwd` is currently source-only and is not part of the deployed release set above. It can be packed and published through the same workspace process when a Pi 0.84.x installation needs the alternate-cwd compatibility override.
+3 -7
View File
@@ -1,17 +1,13 @@
# Todos # Todos
## Honor Bash tool working directories inside hidden worktrees ## Retire the Bash cwd compatibility override after a usable Pi upgrade
During the Orca polling fix on 02SEP2026, Bash tool calls configured with `cwd` beneath `/srv/data/code/jb-pi/harness-tools/.worktrees/fix-orca-polling` ran from the primary checkout instead. A `pwd` probe reproduced the mismatch, and later install and commit commands targeted the primary checkout until they were rerun with an explicit `cd` or `git -C`. The mistaken commit was reset immediately without discarding the pre-existing working changes. Reproduce this with a disposable hidden worktree and require the tool to either honor the requested directory or fail before executing the command. Cover both workspace and nested package directories; keep explicit `cd` and `git -C` as the workaround until the regression is fixed. Pi 0.85.0 corrects built-in tools that captured the process directory instead of using the live execution `ctx.cwd`, but it still does not declare or honor a per-call `cwd` argument. Its public `@earendil-works/pi-coding-agent` entry point also imports `@earendil-works/pi-server` without declaring that runtime dependency, so importing the package after a normal Bun install fails with `ERR_MODULE_NOT_FOUND`. Keep `@jbcode/pi-bash-cwd` until an upstream release exposes equivalent validated per-call cwd behavior and loads cleanly for extension consumers. Then verify the hidden-worktree root, nested-package, relative-path, and fail-before-execution cases against the built-in tool before removing the override package.
## Canonicalize symlinked Pi npm install roots ## Canonicalize symlinked Pi npm install roots
Publishing `@jbcode/pi-interactive-subagents@3.7.4` exposed a Pi package-manager failure when `~/.pi` resolves through `/home/jb/data/.home-dotdirs/.pi`. Pi 0.84.4 invoked npm 12.0.2 with `--prefix /home/jb/.pi/agent/npm` from the repository cwd. npm rewrote the lockfile root as `file:../../../data/.home-dotdirs/.pi/agent/npm`, recursively duplicated that path until the lock contained 12,576 entries and 18 MB of data, and then failed with `ENOENT` during reification. Canonicalizing the npm root, regenerating both lockfiles from that directory, and installing once restored the 124-entry lock and all configured packages. Update Pi's npm package execution to use the canonical install root as its cwd, add a symlinked-agent-directory regression test, and ensure interrupted installs terminate their package-manager children before another reconciliation begins. Publishing `@jbcode/pi-interactive-subagents@3.7.4` exposed a Pi package-manager failure when `~/.pi` resolves through `/home/jb/data/.home-dotdirs/.pi`. Pi 0.84.4 invoked npm 12.0.2 with `--prefix /home/jb/.pi/agent/npm` from the repository cwd. npm rewrote the lockfile root as `file:../../../data/.home-dotdirs/.pi/agent/npm`, recursively duplicated that path until the lock contained 12,576 entries and 18 MB of data, and then failed with `ENOENT` during reification. Canonicalizing the npm root, regenerating both lockfiles from that directory, and installing once restored the 124-entry lock and all configured packages. Update Pi's npm package execution to use the canonical install root as its cwd, add a symlinked-agent-directory regression test, and ensure interrupted installs terminate their package-manager children before another reconciliation begins.
## Archive the legacy workflow runtime after the skill pilot
[ADR 0006](adr/0006-skill-led-development-workflow-04SEP2026.md) supersedes the planned merge of `extensions/_workflows` into `extensions/workflow`. Keep both as private, unpublished, unexposed historical evidence while the `develop-workflow` skill completes scenario evaluation and three real-change pilots. After explicit retirement approval, archive or remove both implementations and their tests in a separate cleanup change; do not merge or release the legacy runtime first.
## Make `pi-links` checks work from linked worktrees ## Make `pi-links` checks work from linked worktrees
A Slice 0 `node scripts/pi-links.mjs prune --dry-run` from `.worktrees/nono-dynamic-permissions-slice-zero-direct` exited 2 and classified every active link into the primary checkout as an outside-repository conflict. The tool anchors ownership to the current worktree root, while active links correctly target the primary repository checkout. Teach check and dry-run planning to recognize canonical checkouts sharing the same Git common directory without broadening stale-link deletion to unrelated repositories. Add linked-worktree fixtures before changing prune behavior. Until fixed, run host reconciliation only from the integrated primary checkout. A Slice 0 `node scripts/pi-links.mjs prune --dry-run` from `.worktrees/nono-dynamic-permissions-slice-zero-direct` exited 2 and classified every active link into the primary checkout as an outside-repository conflict. The tool anchors ownership to the current worktree root, while active links correctly target the primary repository checkout. Teach check and dry-run planning to recognize canonical checkouts sharing the same Git common directory without broadening stale-link deletion to unrelated repositories. Add linked-worktree fixtures before changing prune behavior. Until fixed, run host reconciliation only from the integrated primary checkout.
@@ -22,7 +18,7 @@ Slice 1 found two Nono 0.74 limitations while building behavioral policy proofs.
## Replace `workflow` with a skill-based orchestrator ## Replace `workflow` with a skill-based orchestrator
The strict `workflow` extension repeatedly failed before implementation because planner output and persisted state-machine constraints were too brittle for adaptive subagent orchestration. Implement the repository-managed `develop-workflow` skill under [ADR 0006](adr/0006-skill-led-development-workflow-04SEP2026.md), where the parent owns the plan, task tree, isolated worktree, explicit approval gates, verification, and independent review while launching bounded subagents directly. Preserve file ownership, reviewer independence, and resumable repository evidence while preferring native Pi primitives. Keep this TODO open until all twelve fresh-session scenarios and three real-change pilots pass; only then request retirement approval. The strict `workflow` extension repeatedly failed before implementation because planner output and persisted state-machine constraints were too brittle for adaptive subagent orchestration. Implement the repository-managed `develop-workflow` skill under [ADR 0006](adr/0006-skill-led-development-workflow-04SEP2026.md), where the parent owns the plan, task tree, isolated worktree, explicit approval gates, verification, and independent review while launching bounded subagents directly. Preserve file ownership, reviewer independence, and resumable repository evidence while preferring native Pi primitives. Keep this TODO open until all twelve fresh-session scenarios and three real-change pilots pass. The legacy implementations were archived separately with explicit approval to waive the retirement prerequisite under [ADR 0007](adr/0007-archive-legacy-workflows-05SEP2026.md); archival does not establish validation success.
## Support finished-session resume for Claude CLI subagents ## Support finished-session resume for Claude CLI subagents
+68
View File
@@ -0,0 +1,68 @@
# Archive legacy workflows
## Status
- Status: complete
- Current phase: closure
- Next safe action: no product work remains; retain the separate skill-validation TODO.
## Request and scope
Archive both `extensions/workflow` and `extensions/_workflows` under `__archived/extensions/`. Preserve source and tests as historical reference, not supported runnable packages. Keep `develop-workflow`, historical documentation, live Pi configuration, existing worktrees, and skill validation evidence intact.
## Git identity
- Source branch: main
- Base commit: fee0d44e2ddd7a982e94ebf99117f69bb9bae78e
- Feature branch: feature/archive-workflows
- Worktree: /srv/data/code/jb-pi/harness-tools/.worktrees/archive-workflows
- Omitted source changes: none; source was clean.
## Acceptance criteria
- Both implementations and their tests are retained in the archive.
- Active workspace inventory, lockfile, and root test commands no longer reference them.
- Current docs explain the archive and explicit pilot-prerequisite override; skill validation remains open.
- Active checks pass or failures are reported with evidence; independent reviewers approve the pinned diff.
## Approved implementation plan and gates
1. Move tracked files for both implementations to `__archived/extensions/`, preserving historical code unchanged. Add an archive README explaining historical relative imports and how to recover runnable sources from Git. Fix the moved workflow README's repository documentation links.
2. Remove the obsolete workspace exclusion and legacy test globs from `package.json`; update workspace inventory assertions and only legacy workspace entries in `bun.lock`. No third-party version or dependency changes. The existing TypeScript include already excludes archives.
3. Update root README, current package documentation, retirement TODO, and ADR 0006 with an explicit pointer to a small retirement ADR. Keep separate scenario/pilot validation TODO open. Preserve historical plans and ADR content rather than mass-rewriting old paths.
4. Verify focused package/link tests, root typecheck, and full `bun run test`. There are no root lint/build scripts. Check archived file preservation and absence of active imports. No UI change, installation, publishing, host configuration, or production access.
5. Commit verified work; fetch/rebase main, reverify any changed tree, obtain separate standards and specification reviews of the exact binary diff, fast-forward local main, commit closure metadata, and safely remove only this worktree/branch. Rollback is a focused revert of the archival product commit.
- Scope approval: user selected Archive both.
- Retirement gate: user selected Archive now, explicitly overriding the deferred three-pilot prerequisite. This does not claim pilot success.
- Plan approval: user selected Approve after Orca presented the complete plan.
## Ownership
Parent agent owns all mutations listed above, including this record and new archival README/ADR. No subagent owns files. Mutating implementation deadline: 15 minutes; stop and checkpoint if exceeded. Reviewers are read-only and distinct from the parent.
## Verification matrix
Initial checks: `bun run test:packages` and `bun run test:links` exited 0; `bun run typecheck` and `bun run test` exited 1 because the new worktree lacked workspace dependencies, including `effect`. Full tests stopped at test:node; this is not a successful full run. `git diff --check` passed. All 62 archived tracked files are retained; every file except the deliberately updated README is byte-identical to the base.
Additional gate: user approved Restore locked dependencies after the missing-dependency failure. Permit `bun install --frozen-lockfile` in this isolated worktree only, with no dependency-version changes, then rerun verification. This narrows the original no-installation constraint; host Pi configuration remains untouched.
The approved `bun install --frozen-lockfile && bun run typecheck && bun run test` rerun exited 0. All stages of the root test script executed successfully. No dependency versions changed; the only lockfile changes remove the legacy workspace. Existing exact source caches for `effect@4.0.0-beta.101` and `@effect/platform-node@4.0.0-beta.101` were confirmed under `/srv/data/opensrc`. Archive preservation and whitespace checks passed. No UI changes require application validation.
## Review
First review binding: base fee0d44e2ddd7a982e94ebf99117f69bb9bae78e, product 45d6a41a39454b968392be72301884a460725366, tree e6d974aa49c34a4e46b0194b29fe3d0995ba2f9d. Commits: 5b1e771, ea05b2f, eb52030, 45d6a41. Exact diff command: `git diff --binary --full-index --find-renames fee0d44e2ddd7a982e94ebf99117f69bb9bae78e...45d6a41a39454b968392be72301884a460725366 --`. SHA-256: 6c8ede8b38d9a718886b9374f0ea572e6662ea113b1d7354e71506f5b5ecbca0. Clean status, HEAD, and tree were unchanged before/after both reviews.
Specification reviewer archive-specification (claim-verifier, session 01a0749b-2ee1-7616-ac4f-e3f46db30922) confirmed digest and approved with no findings. Standards reviewer archive-standards (claim-verifier, session not exposed) confirmed digest and rejected two low documentation issues: stale current locations in docs/npm-packages.md, and this record still describing product commit/pinning as future work. Parent accepted and corrected both. Parent is the only mutator; reviewers own no files.
Final review binding: same base, product 8d3552bc926ba70af4ec7c2b23a01c6dbd9e5eec, tree 240ce4347125de0113e4a8da0eedb0af1a5343fd. Add remediation commit 8d3552b to the first commit list. Exact command: `git diff --binary --full-index --find-renames fee0d44e2ddd7a982e94ebf99117f69bb9bae78e...8d3552bc926ba70af4ec7c2b23a01c6dbd9e5eec --`. SHA-256: b10026bce1fd5f60567c8cded5df7646af6a3ee4f971940df2f01bbb4a1cbdc6.
Standards reviewer archive-standards-final (claim-verifier, session 01a0749e-1b8d-7bd9-949c-e660b1f16c05) and specification reviewer archive-specification-final (claim-verifier, session 01a0749e-65ad-7baf-8c5d-b9a9c98ae087) both confirmed the final digest and approved with zero findings. Parent verified unchanged clean status, HEAD, tree, and digest after review. `bun run typecheck && bun run test` exited 0 again after remediation.
## Integration and rollback
Fetch of origin/main exited 0. Remote commit 7e7cfdb5cb0e1a1218b9a2c8250267d5099637fc is an ancestor of local main/base fee0d44e2ddd7a982e94ebf99117f69bb9bae78e; no new upstream tree to incorporate. Local main was still clean at the exact base and fast-forwarded successfully to reviewed product 8d3552b. This record is the only file changed by the closure commit. Rollback via focused revert of product/remediation commits. Cleanup is limited to this workflow-owned worktree and feature branch after clean-state and product/closure reachability checks; no push, publication, or host configuration changes.
## Checkpoints and blockers
None. Initial helper invocation rejected noncanonical section names before creating a record; corrected headings and retried successfully. No tool defect observed.
+89
View File
@@ -0,0 +1,89 @@
# Bash worktree cwd workflow record
## Status
- Status: complete
- Current phase: 9. Close
- Next safe action: none; the reviewed change is integrated locally and verified.
## Request and scope
- Request: address the first repository TODO so Bash execution honors the current Pi tool context inside hidden Git worktrees.
- In scope: reproduce the Pi 0.84.4 behavior; add a repository-owned, publishable `@jbcode/pi-bash-cwd` extension with an optional `cwd` tool argument resolved from the live session context; delegate command execution to Pi's built-in Bash implementation; test workspace-root, nested-package, relative-path, and missing-directory execution in a disposable hidden worktree; update package inventory and documentation; remove the resolved TODO.
- Out of scope: upgrading Pi, installing or publishing the new package, deploying, pushing, or modifying live/production data.
## Git identity
- Source branch: `main`
- Base commit: `7e7cfdb5cb0e1a1218b9a2c8250267d5099637fc`
- Feature branch: `feature/honor-bash-worktree-cwd`
- Worktree: `/srv/data/code/jb-pi/harness-tools/.worktrees/honor-bash-worktree-cwd`
- Omitted source changes: none; source checkout was clean and equal to `origin/main` after `git fetch origin main`.
## Acceptance criteria
- [x] `@jbcode/pi-bash-cwd` overrides the built-in `bash` tool with one backward-compatible optional `cwd` argument while preserving the existing command, timeout, output, truncation, cancellation, session-environment, and renderer contracts.
- [x] Absolute and relative `cwd` values resolve from the live session `ctx.cwd`; omitted `cwd` retains the session directory.
- [x] The requested directory is validated before delegating command execution.
- [x] A regression test executes `pwd` from both a disposable hidden worktree root and a nested workspace package directory and observes the requested directory.
- [x] A missing requested working directory fails before the shell command can create a sentinel side effect.
- [x] Package inventory, README guidance, and the upstream Pi 0.85.0 packaging blocker TODO are synchronized.
- [x] Existing repository typecheck and test suites pass.
- [x] The resolved Bash cwd TODO and temporary workaround language are removed or updated without changing unrelated historical evidence.
## Approved implementation plan and gates
- Plan/specification source: user request, `docs/todos.md`, and upstream Pi 0.84.4/0.85.0 source under `/srv/data/opensrc/repos/github.com/earendil-works/pi/`.
- Exact plan: (1) keep `extensions/bash-cwd` as the approved publishable package; (2) replace the built-in Bash schema with its existing `command` and `timeout` fields plus optional `cwd`; (3) resolve relative `cwd` from `ctx.cwd`, validate that the result is a directory, and only then construct and invoke Pi's built-in Bash definition for that directory; (4) preserve built-in rendering, prompt metadata, output, timeout, cancellation, truncation, and session environment by spreading and delegating to the host definition; (5) revise the regression to pass explicit absolute and relative `cwd` arguments while the session context remains the primary fixture checkout, covering hidden-worktree root, nested package, omitted cwd, and fail-before-sentinel cases; (6) retain approved package inventory/docs/full-verification work and record that Pi 0.85.0's separate `ctx.cwd` correction does not add this per-call argument.
- Plan approval: approved by the user through `ask_user` on 04SEP2026 (`approve` explicit cwd argument).
- UI classification and direction approval: non-UI; no prototype gate applies.
- Risk decisions and scope: the Pi dependency upgrade remains abandoned. The corrected tool schema adds one optional, backward-compatible field and uses the repository's existing `typebox` dependency. The package remains repository-only and will not be installed, published, or added to the active global Pi environment in this task.
## Ownership
| Assignment | Owner identity | Deadline | Exclusive paths | Before/after Git evidence | Outcome |
| --- | --- | --- | --- | --- | --- |
| Workflow setup and research | parent Pi session `01a06e08-8d07-76a7-a116-d7e3baf55b87` | 15 minutes | workflow record only | Before: clean `main` at `7e7cfdb`; after: clean feature worktree at `5f853dc` | Complete |
| Initial dependency-plan implementation | parent Pi session `01a06e08-8d07-76a7-a116-d7e3baf55b87` | 15 minutes | `package.json`, `bun.lock`, focused test, workflow record | Before: clean feature worktree at `9d68d5f`; after: Pi 0.85.0 upgrade restored; focused red test retained unstaged | Paused and replanned after upstream packaging blocker |
| Local override implementation | parent Pi session `01a06e08-8d07-76a7-a116-d7e3baf55b87` | 15 minutes | `extensions/bash-cwd/**`, `scripts/bash-cwd.test.mjs` removal, `package.json`, `scripts/package-workspaces.test.mjs`, `README.md`, `docs/npm-packages.md`, `docs/todos.md`, `docs/workflow/skill-led-development-workflow-plan.md`, workflow record | Before: feature worktree at `3d68f7c` with inspected product changes; after: clean product commit `328faa0` | Complete |
| Review remediation cycle 1 | parent Pi session `01a06e08-8d07-76a7-a116-d7e3baf55b87` | 15 minutes | `extensions/bash-cwd/index.ts`, `extensions/bash-cwd/index.test.ts`, `extensions/bash-cwd/README.md`, workflow record | Before: clean review pin `3cf354b`; after: clean remediation commit `e1c5c55` with focused and full checks passing | Complete |
## Verification matrix
| Surface | Command | Exit code | Outcome |
| --- | --- | --- | --- |
| Source/cache preflight | `git status --short --branch`; `opensrc path ...` | 0 | Clean source; Pi 0.84.4 and 0.85.0 source available locally. |
| Focused cwd reproduction | inline Node harness against Pi 0.84.4 | 0 (asserted buggy outcome) | Both hidden-worktree requests observed the primary checkout; a missing requested cwd still executed a sentinel command. |
| Focused cwd regression | `bun run --filter '@jbcode/pi-bash-cwd' test` | 0 | Four tests pass: explicit absolute hidden-worktree cwd, relative nested-package cwd, omitted cwd/session environment, configured shell path and command prefix, schema compatibility, missing cwd sentinel, and missing context. |
| Package contract | `bun run test:packages`; `bun pm pack --destination /tmp --ignore-scripts --quiet` | 0 | Workspace inventory and package contents pass; package tarball created. |
| Typecheck | `bun run typecheck` | 0 | Repository TypeScript check passes. |
| Full tests | `bun run test` | 0 | The complete post-remediation repository test chain passed in background task `bg_jdbm_mtng8zhg_2`; Node reported 306/306 in the consolidated suite and Vitest reported 22/22 file-search tests. |
| Fresh-process integration | focused test's delegated real Bash subprocesses | 0 | Commands execute through Pi 0.84.4's built-in Bash definition with session metadata preserved. |
| Post-integration tests | `bun run test` on local `main` | 0 | Background task `bg_jdbm_mtnh74gx_3` passed after fast-forward integration: 306/306 Node tests and 22/22 Vitest file-search tests. |
## Review
- Base and product HEAD: `7e7cfdb5cb0e1a1218b9a2c8250267d5099637fc` and `e1c5c55c151fc167eadf56531658482c437b1e61`
- Clean status and tree hash: clean; product tree `496022b109fd53b728dc898bf470f87c00129a11`
- Commit list: `e1c5c55`, `3cf354b`, `328faa0`, `3d68f7c`, `bda414a`, `f61f197`, `070ba3d`, `9d68d5f`, `5f853dc`
- Exact diff command: `git diff --binary --full-index --find-renames 7e7cfdb5cb0e1a1218b9a2c8250267d5099637fc...e1c5c55c151fc167eadf56531658482c437b1e61 --`
- SHA-256: `b2471221a44d2e507789fad70152059ed42e76807c6af32f1151b95bb498614c`
- Mutator identities: parent Pi session `01a06e08-8d07-76a7-a116-d7e3baf55b87`
- Standards reviewer identity, digest confirmation, and verdict: cycle 1 `bash-cwd-standards`, scout child session `01a06e2f-665e-7acc-a2cd-98f976a13b43`, digest confirmed, FAIL. Cycle 2's first identity failed with a provider WebSocket error and issued no verdict. Replacement `bash-cwd-standards-cycle-2-retry`, scout child session `01a06e48-b629-7ad2-bd65-445ad6b8d2ea`, independently regenerated the digest and returned PASS with no findings.
- Specification reviewer identity, digest confirmation, and verdict: cycle 1 `bash-cwd-specification`, scout child session `01a06e2f-b262-77f1-9aef-d5c964cb33b6`, subagent `8ae886b2`, digest confirmed, FAIL. Cycle 2 `bash-cwd-specification-cycle-2` independently confirmed the digest and returned PASS with no findings.
- Findings and remediation cycles: Pi 0.85.0 includes a separate upstream `ctx.cwd` correction but its public package imports undeclared `@earendil-works/pi-server`, causing `ERR_MODULE_NOT_FOUND`; the user selected a repository-owned override instead. During implementation, a direct live call with an extra `cwd` field still printed the primary checkout, proving Pi's schema/executor silently ignore the requested per-call directory and the first local design addressed the wrong seam. Review cycle 1 accepted three findings: preserve configured `shellPath` and `shellCommandPrefix` when recreating Pi's built-in definition; make retirement contingent on equivalent validated per-call cwd; and label npm installation as post-publication. The parent implementer loaded trusted Pi settings at execution, added a realistic custom-shell/prefix regression, and corrected package guidance.
- Before/after reviewer Git evidence: cycle 1 reviewers reported clean `feature/honor-bash-worktree-cwd` state, product HEAD `328faa0`, product tree `6b858045b91298c91f55aedd848c3a02432edafb`, and the complete changed-path set before and after their read-only reviews. Cycle 2 passing reviewers reported clean current review-pin HEAD `42dd6ef`, product HEAD `e1c5c55`, product tree `496022b109fd53b728dc898bf470f87c00129a11`, matching digest, and unchanged paths/status before and after review.
## Integration and rollback
- Synchronization and re-verification: after remediation, fetched `origin/main`; it remained at the base commit and `git rebase origin/main` was a no-op, so the verified remediated product tree did not change.
- Fast-forward result: clean local `main` advanced with `git merge --ff-only` from `7e7cfdb5cb0e1a1218b9a2c8250267d5099637fc` to approved branch tip `e5a2e53a94b8636235422b1d8f5b805e153a769e`; no push was performed.
- Product and closure commits: implementation `328faa0`, review remediation `e1c5c55`, review approval metadata `e5a2e53`, and this final record-only closure commit.
- Reachability and cleanup: approved product HEAD `e1c5c55` and review approval `e5a2e53` are ancestors of local `main`; `.worktrees/honor-bash-worktree-cwd` and local branch `feature/honor-bash-worktree-cwd` were removed after post-integration verification.
- Rollback strategy: revert implementation `328faa0` and remediation `e1c5c55` together with their supporting documentation commits; do not rewrite shared history.
## Checkpoints and blockers
- Last committed valid checkpoint: integrated review approval `e5a2e53`; this file is the final record-only closure.
- Blockers: none.
- Exact next safe action: none.
@@ -100,7 +100,7 @@ Reuse rather than wrap:
- `artifact-presenter`: plan and long-artifact review. - `artifact-presenter`: plan and long-artifact review.
- Git worktrees and normal project commands: isolation, commits, verification, rebase, and integration. - Git worktrees and normal project commands: isolation, commits, verification, rebase, and integration.
Known harness defects are workflow constraints, not footnotes. Until fixed, launch subagents directly rather than through `multi_tool_use.parallel`; never park the parent solely on an expected callback; and verify that each result was delivered. For shell work inside hidden worktrees, use explicit `cd <worktree> && ...` or `git -C <worktree> ...`, then verify `pwd` or Git's top-level path before mutation because the Bash tool has previously ignored its configured working directory. Known harness defects are workflow constraints, not footnotes. Until fixed, launch subagents directly rather than through `multi_tool_use.parallel`; never park the parent solely on an expected callback; and verify that each result was delivered. `@jbcode/pi-bash-cwd` adds validated per-call Bash working directories on Pi 0.84.x. Shell mutations inside hidden worktrees still use explicit `cd <worktree> && ...` or `git -C <worktree> ...`, followed by `pwd` or Git top-level verification, as defense-in-depth.
Before starting the full path, preflight required capabilities. Git worktree operations, a writable retained record, an explicit human interaction channel, target-interface validation when applicable, and a Git-capable independent reviewer are mandatory. Todo-herdr and artifact-presenter may degrade to the retained record and a reported artifact path, but their absence cannot bypass a gate. In print or JSON mode, or whenever a mandatory gate or validator cannot run, emit the pending decision or validation instructions and stop before product mutation. Before starting the full path, preflight required capabilities. Git worktree operations, a writable retained record, an explicit human interaction channel, target-interface validation when applicable, and a Git-capable independent reviewer are mandatory. Todo-herdr and artifact-presenter may degrade to the retained record and a reported artifact path, but their absence cannot bypass a gate. In print or JSON mode, or whenever a mandatory gate or validator cannot run, emit the pending decision or validation instructions and stop before product mutation.
@@ -144,7 +144,7 @@ When uncertain, use the full path. Record why the light path is safe when a chan
1. Read repository instructions, relevant docs, ADRs, tests, and current Git state. 1. Read repository instructions, relevant docs, ADRs, tests, and current Git state.
2. Record the source branch and exact base commit. 2. Record the source branch and exact base commit.
3. Create `./.worktrees/<feature>` on a descriptive feature branch before feature edits. 3. Create `./.worktrees/<feature>` on a descriptive feature branch before feature edits.
4. Prove every subsequent shell command's location with explicit `cd` or `git -C`; do not rely on the Bash tool's configured `cwd` until its tracked defect is fixed. 4. Prove every subsequent shell command's location with explicit `cd` or `git -C`; treat the Bash cwd override as protection against fallback execution, not a replacement for the location proof.
5. If the source checkout is dirty, explain exactly which changes the new worktree omits and ask before proceeding. 5. If the source checkout is dirty, explain exactly which changes the new worktree omits and ask before proceeding.
6. Atomically create the unique workflow record in the worktree and create a task tree in the session. 6. Atomically create the unique workflow record in the worktree and create a task tree in the session.
7. Run applicable documentation checks, then commit the initial record as a pre-mutation recovery checkpoint. 7. Run applicable documentation checks, then commit the initial record as a pre-mutation recovery checkpoint.
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 JB
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+21
View File
@@ -0,0 +1,21 @@
# @jbcode/pi-bash-cwd
Pi extension that adds an optional `cwd` argument to the built-in `bash` tool. Absolute paths are used directly, relative paths resolve from the Pi session directory, and omitted paths retain the session directory. The extension validates the directory before starting the command, preventing an ignored or invalid `cwd` from running in Pi's process directory.
The override delegates execution and rendering to Pi's built-in Bash implementation. Existing `command` and `timeout` calls remain compatible.
## Try from this checkout
```bash
pi -e ./extensions/bash-cwd/index.ts
```
Pi warns that the extension replaces the built-in `bash` tool; that warning is expected. The package is not published yet. After publication, install it with `pi install npm:@jbcode/pi-bash-cwd` and restart Pi or run `/reload`.
Use this package with Pi 0.84.x. Remove it only after moving to a Pi release that exposes equivalent validated per-call `cwd` behavior and can be imported by extensions without undeclared runtime dependencies.
## Verify
```bash
bun run --filter '@jbcode/pi-bash-cwd' test
```
+160
View File
@@ -0,0 +1,160 @@
import assert from "node:assert/strict";
import { execFileSync } from "node:child_process";
import {
access,
chmod,
mkdir,
mkdtemp,
rm,
writeFile,
} from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import test from "node:test";
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
import { createContextualBashTool } from "./index.ts";
function git(cwd: string, ...args: string[]): void {
execFileSync("git", args, { cwd, stdio: "pipe" });
}
function getOutput(
result: Awaited<ReturnType<ReturnType<typeof createContextualBashTool>["execute"]>>,
): string {
return result.content
.filter((item) => item.type === "text")
.map((item) => item.text)
.join("")
.trim();
}
async function executeIn(
sessionCwd: string,
command: string,
cwd?: string,
) {
const params = cwd === undefined ? { command } : { command, cwd };
return createContextualBashTool({}).execute(
"bash-cwd-test",
params,
undefined,
undefined,
{
cwd: sessionCwd,
sessionManager: {
getSessionId: () => "bash-cwd-test-session",
getSessionFile: () => undefined,
},
} as ExtensionContext,
);
}
test("bash honors hidden-worktree and nested-package cwd arguments", async (t) => {
const repository = await mkdtemp(join(tmpdir(), "pi-bash-cwd-"));
t.after(() => rm(repository, { recursive: true, force: true }));
await writeFile(join(repository, ".gitignore"), ".worktrees/\n");
await mkdir(join(repository, "extensions", "fixture"), { recursive: true });
await writeFile(
join(repository, "extensions", "fixture", "package.json"),
'{"private":true}\n',
);
git(repository, "init", "--initial-branch=main");
git(repository, "config", "user.name", "Bash cwd test");
git(repository, "config", "user.email", "bash-cwd@example.invalid");
git(repository, "add", ".");
git(repository, "commit", "-m", "fixture");
const worktree = join(repository, ".worktrees", "feature");
git(repository, "worktree", "add", "-b", "feature", worktree, "main");
const packageDirectory = join(worktree, "extensions", "fixture");
assert.equal(getOutput(await executeIn(repository, "pwd")), repository);
assert.equal(
getOutput(await executeIn(repository, 'printf %s "$PI_SESSION_ID"')),
"bash-cwd-test-session",
);
assert.equal(getOutput(await executeIn(repository, "pwd", worktree)), worktree);
assert.equal(
getOutput(
await executeIn(
repository,
"pwd",
".worktrees/feature/extensions/fixture",
),
),
packageDirectory,
);
const missingDirectory = join(worktree, "missing");
const sentinel = join(repository, "should-not-run");
await assert.rejects(
executeIn(repository, "touch should-not-run", missingDirectory),
/Working directory does not exist/,
);
await assert.rejects(access(sentinel));
});
test("bash preserves configured command prefixes and shell paths", async (t) => {
const directory = await mkdtemp(join(tmpdir(), "pi-bash-cwd-options-"));
t.after(() => rm(directory, { recursive: true, force: true }));
const shellMarker = join(directory, "custom-shell-used");
const shell = join(directory, "custom-shell");
await writeFile(
shell,
`#!/bin/sh\nprintf used > "${shellMarker}"\nexec /bin/bash "$@"\n`,
);
await chmod(shell, 0o755);
await mkdir(join(directory, ".pi"));
await writeFile(
join(directory, ".pi", "settings.json"),
JSON.stringify({
shellCommandPrefix: "printf prefix-",
shellPath: shell,
}),
);
const tool = createContextualBashTool();
const result = await tool.execute(
"bash-cwd-options-test",
{ command: "printf command", cwd: directory },
undefined,
undefined,
{
cwd: directory,
sessionManager: {
getSessionId: () => "bash-cwd-test-session",
getSessionFile: () => undefined,
},
isProjectTrusted: () => true,
} as ExtensionContext,
);
assert.equal(getOutput(result), "prefix-command");
await access(shellMarker);
});
test("bash exposes cwd without changing existing arguments", () => {
const schema = createContextualBashTool({}).parameters;
assert.deepEqual(Object.keys(schema.properties), ["command", "cwd", "timeout"]);
assert.deepEqual(schema.required, ["command"]);
});
test("bash fails before execution when Pi omits the tool context", async () => {
const tool = createContextualBashTool({});
await assert.rejects(
tool.execute(
"bash-cwd-test",
{ command: "pwd" },
undefined,
undefined,
undefined as unknown as ExtensionContext,
),
/Bash execution context is unavailable/,
);
});
+105
View File
@@ -0,0 +1,105 @@
import { stat } from "node:fs/promises";
import { resolve } from "node:path";
import {
createBashToolDefinition,
getAgentDir,
SettingsManager,
type BashToolOptions,
type ExtensionAPI,
type ExtensionContext,
} from "@earendil-works/pi-coding-agent";
import { type Static, Type } from "typebox";
const bashCwdParameters = Type.Object({
command: Type.String({ description: "Shell command to execute" }),
cwd: Type.Optional(
Type.String({
description:
"Working directory. Relative paths resolve from the session working directory.",
}),
),
timeout: Type.Optional(
Type.Number({ description: "Timeout in seconds (optional, no default timeout)" }),
),
});
type BashCwdInput = Static<typeof bashCwdParameters>;
type BuiltInBashDefinition = ReturnType<typeof createBashToolDefinition>;
type BuiltInBashExecute = BuiltInBashDefinition["execute"];
async function resolveWorkingDirectory(
sessionCwd: string,
requestedCwd: string | undefined,
): Promise<string> {
const cwd = resolve(sessionCwd, requestedCwd ?? ".");
let metadata;
try {
metadata = await stat(cwd);
} catch (error) {
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
throw new Error(
`Working directory does not exist: ${cwd}\nCannot execute bash commands.`,
);
}
throw error;
}
if (!metadata.isDirectory()) {
throw new Error(
`Working directory is not a directory: ${cwd}\nCannot execute bash commands.`,
);
}
return cwd;
}
function loadBashOptions(ctx: ExtensionContext): BashToolOptions {
const settings = SettingsManager.create(ctx.cwd, getAgentDir(), {
projectTrusted: ctx.isProjectTrusted(),
});
return {
commandPrefix: settings.getShellCommandPrefix(),
shellPath: settings.getShellPath(),
};
}
export function createContextualBashTool(options?: BashToolOptions) {
const baseTool = createBashToolDefinition(process.cwd(), options);
return {
...baseTool,
description:
`${baseTool.description} The optional cwd may be absolute or relative to the session working directory.`,
parameters: bashCwdParameters,
async execute(
toolCallId: Parameters<BuiltInBashExecute>[0],
params: BashCwdInput,
signal: Parameters<BuiltInBashExecute>[2],
onUpdate: Parameters<BuiltInBashExecute>[3],
ctx: ExtensionContext,
) {
if (!ctx) {
throw new Error("Bash execution context is unavailable");
}
const cwd = await resolveWorkingDirectory(ctx.cwd, params.cwd);
const contextualTool = createBashToolDefinition(
cwd,
options ?? loadBashOptions(ctx),
);
return contextualTool.execute(
toolCallId,
{ command: params.command, timeout: params.timeout },
signal,
onUpdate,
ctx,
);
},
};
}
export default function bashCwd(pi: ExtensionAPI): void {
pi.registerTool(createContextualBashTool());
}
+31
View File
@@ -0,0 +1,31 @@
{
"name": "@jbcode/pi-bash-cwd",
"version": "0.1.0",
"description": "Pi Bash override that honors the current tool execution working directory.",
"type": "module",
"license": "MIT",
"engines": { "node": ">=22.19.0" },
"keywords": ["pi-package", "pi-extension"],
"files": ["index.ts", "README.md", "LICENSE"],
"pi": { "extensions": ["./index.ts"] },
"scripts": {
"test": "node --test --experimental-strip-types index.test.ts"
},
"peerDependencies": {
"@earendil-works/pi-coding-agent": "catalog:pi-peer",
"typebox": "catalog:pi-peer"
},
"devDependencies": {
"@earendil-works/pi-coding-agent": "catalog:",
"typebox": "catalog:",
"typescript": "catalog:"
},
"publishConfig": {
"registry": "https://git.jb.codes/api/packages/jb/npm/"
},
"repository": {
"type": "git",
"url": "git+ssh://git@git.jb.codes:7722/jb/harness-tools.git",
"directory": "extensions/bash-cwd"
}
}
+2 -3
View File
@@ -11,8 +11,7 @@
}, },
"workspaces": { "workspaces": {
"packages": [ "packages": [
"extensions/*", "extensions/*"
"!extensions/_workflows"
], ],
"catalog": { "catalog": {
"@anthropic-ai/claude-agent-sdk": "0.3.218", "@anthropic-ai/claude-agent-sdk": "0.3.218",
@@ -52,7 +51,7 @@
"test:links": "node --test scripts/pi-links.test.mjs", "test:links": "node --test scripts/pi-links.test.mjs",
"test:packages": "node --test scripts/package-workspaces.test.mjs", "test:packages": "node --test scripts/package-workspaces.test.mjs",
"test:imported": "bun run --filter '@jbcode/pi-interactive-subagents' test && bun run --filter '@jbcode/pi-native-hooks' test && bun run --filter '@jbcode/pi-todo-herdr' test", "test:imported": "bun run --filter '@jbcode/pi-interactive-subagents' test && bun run --filter '@jbcode/pi-native-hooks' test && bun run --filter '@jbcode/pi-todo-herdr' test",
"test:node": "node --test --experimental-strip-types extensions/dictate/index.test.ts extensions/lm-studio/index.test.ts extensions/shared/*.test.ts extensions/subagents/by-the-way.test.ts extensions/subagents/context-usage.test.ts extensions/subagents/manager.test.ts extensions/subagents/result-delivery.test.ts extensions/subagents/takeover.test.ts extensions/_workflows/*.test.ts extensions/workflow/*.test.ts", "test:node": "node --test --experimental-strip-types extensions/bash-cwd/index.test.ts extensions/dictate/index.test.ts extensions/lm-studio/index.test.ts extensions/shared/*.test.ts extensions/subagents/by-the-way.test.ts extensions/subagents/context-usage.test.ts extensions/subagents/manager.test.ts extensions/subagents/result-delivery.test.ts extensions/subagents/takeover.test.ts",
"test:file-search": "vitest run extensions/file-search/index.spec.ts --exclude '.worktrees/**'", "test:file-search": "vitest run extensions/file-search/index.spec.ts --exclude '.worktrees/**'",
"test:live": "node --test --experimental-strip-types extensions/subagents/claude.test.ts extensions/subagents/codex.test.ts" "test:live": "node --test --experimental-strip-types extensions/subagents/claude.test.ts extensions/subagents/codex.test.ts"
}, },
+2 -8
View File
@@ -10,6 +10,7 @@ const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const extensionsRoot = path.join(root, "extensions"); const extensionsRoot = path.join(root, "extensions");
const registry = "https://git.jb.codes/api/packages/jb/npm/"; const registry = "https://git.jb.codes/api/packages/jb/npm/";
const expectedWorkspaces = [ const expectedWorkspaces = [
"bash-cwd",
"copy-all", "copy-all",
"dictate", "dictate",
"effort-controls", "effort-controls",
@@ -22,7 +23,6 @@ const expectedWorkspaces = [
"subagents", "subagents",
"todo-herdr", "todo-herdr",
"update", "update",
"workflow",
]; ];
function readJson(file) { function readJson(file) {
@@ -41,17 +41,12 @@ function dependencyText(manifest) {
}); });
} }
test("workspace inventory keeps reference workflows unpublished", () => { test("workspace inventory contains only active extensions", () => {
const rootManifest = readJson(path.join(root, "package.json")); const rootManifest = readJson(path.join(root, "package.json"));
assert.equal(rootManifest.private, true); assert.equal(rootManifest.private, true);
assert.deepEqual(rootManifest.workspaces.packages, [ assert.deepEqual(rootManifest.workspaces.packages, [
"extensions/*", "extensions/*",
"!extensions/_workflows",
]); ]);
assert.equal(
readdirSync(path.join(extensionsRoot, "_workflows")).includes("package.json"),
false,
);
const actual = readdirSync(extensionsRoot) const actual = readdirSync(extensionsRoot)
.filter((directory) => { .filter((directory) => {
@@ -64,7 +59,6 @@ test("workspace inventory keeps reference workflows unpublished", () => {
}) })
.sort(); .sort();
assert.deepEqual(actual, expectedWorkspaces); assert.deepEqual(actual, expectedWorkspaces);
assert.equal(workspaceManifest("workflow").private, true);
}); });
test("imported package snapshots retain explicit main-branch provenance", () => { test("imported package snapshots retain explicit main-branch provenance", () => {