@astralyn/pi 0.82.6 → 0.83.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +61 -5099
- package/README.md +12 -111
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +9 -2
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/credential-print.d.ts +23 -0
- package/dist/cli/credential-print.d.ts.map +1 -0
- package/dist/cli/credential-print.js +116 -0
- package/dist/cli/credential-print.js.map +1 -0
- package/dist/cli/session-picker.d.ts.map +1 -1
- package/dist/cli/session-picker.js +11 -13
- package/dist/cli/session-picker.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +3 -0
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session.d.ts +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +13 -6
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +1 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +7 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +11 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +10 -0
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +1 -1
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/model-runtime.d.ts +2 -0
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +13 -6
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/resource-loader.d.ts +15 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +70 -9
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +2 -2
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/tools/bash.d.ts +1 -5
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +16 -41
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +42 -11
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +40 -11
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +17 -8
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +3 -3
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +4 -4
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts +7 -0
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js +11 -0
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +2 -3
- package/dist/core/tools/write.js.map +1 -1
- package/dist/core/trust-manager.d.ts.map +1 -1
- package/dist/core/trust-manager.js +48 -9
- package/dist/core/trust-manager.js.map +1 -1
- package/dist/extensions/deepwiki/render.d.ts.map +1 -1
- package/dist/extensions/deepwiki/render.js +34 -22
- package/dist/extensions/deepwiki/render.js.map +1 -1
- package/dist/extensions/index.d.ts.map +1 -1
- package/dist/extensions/index.js +0 -2
- package/dist/extensions/index.js.map +1 -1
- package/dist/extensions/llama/provider.d.ts.map +1 -1
- package/dist/extensions/llama/provider.js +1 -1
- package/dist/extensions/llama/provider.js.map +1 -1
- package/dist/extensions/question/dialog.d.ts.map +1 -1
- package/dist/extensions/question/dialog.js +29 -10
- package/dist/extensions/question/dialog.js.map +1 -1
- package/dist/extensions/question/index.d.ts.map +1 -1
- package/dist/extensions/question/index.js +7 -2
- package/dist/extensions/question/index.js.map +1 -1
- package/dist/extensions/question/render.d.ts +4 -8
- package/dist/extensions/question/render.d.ts.map +1 -1
- package/dist/extensions/question/render.js +202 -29
- package/dist/extensions/question/render.js.map +1 -1
- package/dist/extensions/question/results.d.ts.map +1 -1
- package/dist/extensions/question/results.js +1 -0
- package/dist/extensions/question/results.js.map +1 -1
- package/dist/extensions/question/schema.d.ts.map +1 -1
- package/dist/extensions/question/schema.js +2 -2
- package/dist/extensions/question/schema.js.map +1 -1
- package/dist/extensions/question/types.d.ts +1 -0
- package/dist/extensions/question/types.d.ts.map +1 -1
- package/dist/extensions/question/types.js +1 -1
- package/dist/extensions/question/types.js.map +1 -1
- package/dist/extensions/router/stream.d.ts +1 -0
- package/dist/extensions/router/stream.d.ts.map +1 -1
- package/dist/extensions/router/stream.js +44 -13
- package/dist/extensions/router/stream.js.map +1 -1
- package/dist/extensions/subagent/constants.d.ts +1 -0
- package/dist/extensions/subagent/constants.d.ts.map +1 -1
- package/dist/extensions/subagent/constants.js +1 -0
- package/dist/extensions/subagent/constants.js.map +1 -1
- package/dist/extensions/subagent/index.d.ts.map +1 -1
- package/dist/extensions/subagent/index.js +2 -0
- package/dist/extensions/subagent/index.js.map +1 -1
- package/dist/extensions/subagent/render.d.ts.map +1 -1
- package/dist/extensions/subagent/render.js +121 -48
- package/dist/extensions/subagent/render.js.map +1 -1
- package/dist/extensions/subagent/retry.d.ts +17 -0
- package/dist/extensions/subagent/retry.d.ts.map +1 -0
- package/dist/extensions/subagent/retry.js +41 -0
- package/dist/extensions/subagent/retry.js.map +1 -0
- package/dist/extensions/subagent/runner.d.ts.map +1 -1
- package/dist/extensions/subagent/runner.js +33 -5
- package/dist/extensions/subagent/runner.js.map +1 -1
- package/dist/extensions/subagent/sdk-runner.d.ts +6 -0
- package/dist/extensions/subagent/sdk-runner.d.ts.map +1 -1
- package/dist/extensions/subagent/sdk-runner.js +46 -24
- package/dist/extensions/subagent/sdk-runner.js.map +1 -1
- package/dist/extensions/subagent/types.d.ts +7 -0
- package/dist/extensions/subagent/types.d.ts.map +1 -1
- package/dist/extensions/subagent/types.js.map +1 -1
- package/dist/extensions/todo/index.d.ts.map +1 -1
- package/dist/extensions/todo/index.js +1 -1
- package/dist/extensions/todo/index.js.map +1 -1
- package/dist/extensions/todo/state.d.ts.map +1 -1
- package/dist/extensions/todo/state.js +10 -2
- package/dist/extensions/todo/state.js.map +1 -1
- package/dist/extensions/todo/view.d.ts +1 -1
- package/dist/extensions/todo/view.d.ts.map +1 -1
- package/dist/extensions/todo/view.js +179 -34
- package/dist/extensions/todo/view.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +43 -0
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +2 -1
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/components/armin.d.ts.map +1 -1
- package/dist/modes/interactive/components/armin.js +5 -0
- package/dist/modes/interactive/components/armin.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts +1 -0
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +4 -2
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/countdown-timer.d.ts +13 -6
- package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
- package/dist/modes/interactive/components/countdown-timer.js +54 -17
- package/dist/modes/interactive/components/countdown-timer.js.map +1 -1
- package/dist/modes/interactive/components/extension-selector.d.ts +1 -1
- package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-selector.js +10 -6
- package/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.d.ts +11 -1
- package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.js +56 -0
- package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +4 -1
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts +3 -0
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +52 -2
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +10 -0
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +133 -18
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tool-group.d.ts +1 -0
- package/dist/modes/interactive/components/tool-group.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-group.js +5 -0
- package/dist/modes/interactive/components/tool-group.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts +10 -1
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js +55 -2
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/external-editor.d.ts.map +1 -1
- package/dist/modes/interactive/external-editor.js +40 -3
- package/dist/modes/interactive/external-editor.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +5 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +92 -24
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +3 -2
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +13 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/utils/paths.d.ts +5 -0
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +7 -0
- package/dist/utils/paths.js.map +1 -1
- package/docs/bundled/README.md +13 -15
- package/docs/bundled/extensions/deepwiki.md +1 -1
- package/docs/bundled/extensions/question.md +7 -5
- package/docs/bundled/extensions/router.md +3 -4
- package/docs/bundled/extensions/statusline.md +0 -1
- package/docs/bundled/extensions/subagent.md +4 -3
- package/docs/bundled/extensions/todo.md +1 -1
- package/docs/bundled/themes.md +1 -1
- package/docs/bundled/tool-presentation.md +17 -16
- package/docs/compaction.md +25 -30
- package/docs/custom-provider.md +298 -583
- package/docs/docs.json +0 -8
- package/docs/extensions.md +132 -121
- package/docs/index.md +18 -74
- package/docs/json.md +20 -14
- package/docs/models.md +193 -151
- package/docs/providers.md +2 -1
- package/docs/quickstart.md +3 -3
- package/docs/rpc.md +166 -124
- package/docs/sdk.md +119 -178
- package/docs/security.md +1 -1
- package/docs/session-format.md +139 -119
- package/docs/skills.md +0 -1
- package/docs/themes.md +2 -2
- package/docs/tui.md +411 -549
- package/docs/usage.md +3 -11
- package/examples/README.md +6 -1
- package/examples/extensions/README.md +13 -33
- package/examples/extensions/custom-provider-anthropic/index.ts +9 -3
- package/examples/extensions/dynamic-resources/dynamic.json +1 -1
- package/examples/extensions/truncated-tool.ts +2 -2
- package/examples/sdk/12-full-control.ts +2 -0
- package/npm-shrinkwrap.json +25 -25
- package/package.json +5 -5
- package/dist/extensions/plan/constants.d.ts +0 -40
- package/dist/extensions/plan/constants.d.ts.map +0 -1
- package/dist/extensions/plan/constants.js +0 -69
- package/dist/extensions/plan/constants.js.map +0 -1
- package/dist/extensions/plan/index.d.ts +0 -3
- package/dist/extensions/plan/index.d.ts.map +0 -1
- package/dist/extensions/plan/index.js +0 -323
- package/dist/extensions/plan/index.js.map +0 -1
- package/dist/extensions/plan/schema.d.ts +0 -15
- package/dist/extensions/plan/schema.d.ts.map +0 -1
- package/dist/extensions/plan/schema.js +0 -13
- package/dist/extensions/plan/schema.js.map +0 -1
- package/dist/extensions/plan/state.d.ts +0 -29
- package/dist/extensions/plan/state.d.ts.map +0 -1
- package/dist/extensions/plan/state.js +0 -74
- package/dist/extensions/plan/state.js.map +0 -1
- package/dist/extensions/plan/storage.d.ts +0 -18
- package/dist/extensions/plan/storage.d.ts.map +0 -1
- package/dist/extensions/plan/storage.js +0 -58
- package/dist/extensions/plan/storage.js.map +0 -1
- package/dist/extensions/plan/view.d.ts +0 -36
- package/dist/extensions/plan/view.d.ts.map +0 -1
- package/dist/extensions/plan/view.js +0 -74
- package/dist/extensions/plan/view.js.map +0 -1
- package/docs/bundled/extensions/README.md +0 -19
- package/docs/bundled/extensions/plan.md +0 -33
- package/examples/extensions/plan-mode/README.md +0 -66
- package/examples/extensions/plan-mode/index.ts +0 -390
- package/examples/extensions/plan-mode/utils.ts +0 -168
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../../src/extensions/plan/storage.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAU9C,MAAM,UAAU,WAAW,CAAC,SAAiB,EAAU;IACtD,OAAO,IAAI,CAAC,WAAW,EAAE,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;AAAA,CAC/C;AAED,uEAAuE;AACvE,MAAM,UAAU,YAAY,CAAC,KAAa,EAAU;IACnD,MAAM,IAAI,GAAG,KAAK;SAChB,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;SACZ,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACrB,OAAO,IAAI,IAAI,MAAM,CAAC;AAAA,CACtB;AAED,2EAA2E;AAC3E,MAAM,UAAU,cAAc,CAAC,aAAuB,EAAU;IAC/D,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,KAAK,MAAM,IAAI,IAAI,aAAa,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,KAAK;YAAE,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,GAAG,GAAG,CAAC,CAAC;AAAA,CACf;AAED,MAAM,UAAU,iBAAiB,CAAC,OAAiD,EAAU;IAC5F,MAAM,KAAK,GAAG;QACb,KAAK;QACL,UAAU,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;QACzC,YAAY,OAAO,CAAC,UAAU,EAAE;QAChC,QAAQ,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;QACrC,YAAY,OAAO,CAAC,SAAS,EAAE;KAC/B,CAAC;IACF,IAAI,OAAO,CAAC,OAAO;QAAE,KAAK,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC/E,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;IAClD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAAA,CACxB;AAED,2DAA2D;AAC3D,MAAM,UAAU,YAAY,CAAC,OAAwB,EAAU;IAC9D,MAAM,GAAG,GAAG,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC3C,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,cAAc,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;IACxF,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IACjC,aAAa,CAAC,IAAI,EAAE,iBAAiB,CAAC,EAAE,GAAG,OAAO,EAAE,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;IACtG,OAAO,IAAI,CAAC;AAAA,CACZ","sourcesContent":["/**\n * plan/storage.ts — plan file layout and writing.\n *\n * Plans live under `<agentDir>/plans/<sessionId>/NN-<slug>.md`, append-only\n * with a monotonically increasing NN. The directory is only the initial\n * storage location — the authoritative index is the `planFiles` list in the\n * session's plan-mode entries, which follows fork/clone.\n */\nimport { mkdirSync, readdirSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { getAgentDir } from \"../../config.ts\";\n\nexport interface SavePlanOptions {\n\tsessionId: string;\n\ttitle: string;\n\tplan: string;\n\tcwd: string;\n\trevises?: string;\n}\n\nexport function getPlansDir(sessionId: string): string {\n\treturn join(getAgentDir(), \"plans\", sessionId);\n}\n\n/** File-name slug from a plan title: lowercase, ascii-ish, bounded. */\nexport function slugifyTitle(title: string): string {\n\tconst slug = title\n\t\t.toLowerCase()\n\t\t.replace(/[^a-z0-9]+/g, \"-\")\n\t\t.replace(/^-+|-+$/g, \"\")\n\t\t.slice(0, 40)\n\t\t.replace(/-+$/, \"\");\n\treturn slug || \"plan\";\n}\n\n/** Next NN based on existing `NN-*.md` names; gaps never reuse numbers. */\nexport function nextPlanNumber(existingNames: string[]): number {\n\tlet max = 0;\n\tfor (const name of existingNames) {\n\t\tconst match = /^(\\d+)-/.exec(name);\n\t\tif (match) max = Math.max(max, Number(match[1]));\n\t}\n\treturn max + 1;\n}\n\nexport function buildPlanDocument(options: SavePlanOptions & { createdIso: string }): string {\n\tconst lines = [\n\t\t\"---\",\n\t\t`title: ${JSON.stringify(options.title)}`,\n\t\t`created: ${options.createdIso}`,\n\t\t`cwd: ${JSON.stringify(options.cwd)}`,\n\t\t`session: ${options.sessionId}`,\n\t];\n\tif (options.revises) lines.push(`revises: ${JSON.stringify(options.revises)}`);\n\tlines.push(\"---\", \"\", options.plan.trimEnd(), \"\");\n\treturn lines.join(\"\\n\");\n}\n\n/** Write the plan to disk and return its absolute path. */\nexport function savePlanFile(options: SavePlanOptions): string {\n\tconst dir = getPlansDir(options.sessionId);\n\tmkdirSync(dir, { recursive: true });\n\tconst number = nextPlanNumber(readdirSync(dir));\n\tconst fileName = `${String(number).padStart(2, \"0\")}-${slugifyTitle(options.title)}.md`;\n\tconst path = join(dir, fileName);\n\twriteFileSync(path, buildPlanDocument({ ...options, createdIso: new Date().toISOString() }), \"utf-8\");\n\treturn path;\n}\n"]}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* plan/view.ts — approval-dialog context and exit_plan tool rendering.
|
|
3
|
-
*
|
|
4
|
-
* `exit_plan` carries the whole plan as a parameter, and the default renderer
|
|
5
|
-
* echoes parameters verbatim: the row would repeat, escaped onto one line, the
|
|
6
|
-
* markdown the model just printed as response text. Collapsed rows therefore
|
|
7
|
-
* carry the title only, and the plan body is available on expand.
|
|
8
|
-
*
|
|
9
|
-
* The result text is written for the model (it restates tool-state precedence
|
|
10
|
-
* rules), so the result row renders from `details` instead.
|
|
11
|
-
*/
|
|
12
|
-
import type { AgentToolResult, ExtensionContext } from "../../core/extensions/types.ts";
|
|
13
|
-
import type { Theme } from "../../modes/interactive/theme/theme.ts";
|
|
14
|
-
import type { ExitPlanDetails } from "./schema.ts";
|
|
15
|
-
/** Collapse the home prefix so a plan path stays on one line. */
|
|
16
|
-
export declare function shortenPlanPath(path: string): string;
|
|
17
|
-
/**
|
|
18
|
-
* Context pressure is the fact the compact-or-not decision turns on, so the
|
|
19
|
-
* dialog states it instead of making the user leave and check the footer.
|
|
20
|
-
*/
|
|
21
|
-
export declare function formatApprovalSubtitle(ctx: ExtensionContext): string | undefined;
|
|
22
|
-
type ExitPlanCallArgs = {
|
|
23
|
-
title?: unknown;
|
|
24
|
-
plan?: unknown;
|
|
25
|
-
revises?: unknown;
|
|
26
|
-
};
|
|
27
|
-
/** Title-only headline when collapsed; plan body and revision target on expand. */
|
|
28
|
-
export declare function formatExitPlanCall(args: ExitPlanCallArgs | undefined, theme: Theme, expanded: boolean): string;
|
|
29
|
-
/**
|
|
30
|
-
* What the user needs to know: where the plan landed and what happens next.
|
|
31
|
-
* Falls back to the model-facing text when details are missing — a thrown
|
|
32
|
-
* approval (interrupt) has no details to render from.
|
|
33
|
-
*/
|
|
34
|
-
export declare function formatExitPlanResult(result: AgentToolResult<ExitPlanDetails>, theme: Theme): string;
|
|
35
|
-
export {};
|
|
36
|
-
//# sourceMappingURL=view.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../../src/extensions/plan/view.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACxF,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wCAAwC,CAAC;AACpE,OAAO,KAAK,EAAoB,eAAe,EAAE,MAAM,aAAa,CAAC;AAErE,iEAAiE;AACjE,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOpD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,gBAAgB,GAAG,MAAM,GAAG,SAAS,CAIhF;AAKD,KAAK,gBAAgB,GAAG;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAM/E,mFAAmF;AACnF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,GAAG,MAAM,CAiB9G;AAkBD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,eAAe,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,KAAK,GAAG,MAAM,CAQnG","sourcesContent":["/**\n * plan/view.ts — approval-dialog context and exit_plan tool rendering.\n *\n * `exit_plan` carries the whole plan as a parameter, and the default renderer\n * echoes parameters verbatim: the row would repeat, escaped onto one line, the\n * markdown the model just printed as response text. Collapsed rows therefore\n * carry the title only, and the plan body is available on expand.\n *\n * The result text is written for the model (it restates tool-state precedence\n * rules), so the result row renders from `details` instead.\n */\nimport type { AgentToolResult, ExtensionContext } from \"../../core/extensions/types.ts\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport type { ExitPlanDecision, ExitPlanDetails } from \"./schema.ts\";\n\n/** Collapse the home prefix so a plan path stays on one line. */\nexport function shortenPlanPath(path: string): string {\n\tconst rawHome = process.env.USERPROFILE || process.env.HOME || \"\";\n\tconst home = rawHome.replace(/[\\\\/]+$/, \"\");\n\tif (!home) return path;\n\tconst normalize = (value: string) => value.replace(/\\\\/g, \"/\").toLowerCase();\n\tif (!normalize(path).startsWith(`${normalize(home)}/`)) return path;\n\treturn `~${path.slice(home.length).replace(/\\\\/g, \"/\")}`;\n}\n\n/**\n * Context pressure is the fact the compact-or-not decision turns on, so the\n * dialog states it instead of making the user leave and check the footer.\n */\nexport function formatApprovalSubtitle(ctx: ExtensionContext): string | undefined {\n\tconst percent = ctx.getContextUsage()?.percent;\n\tif (percent == null) return undefined;\n\treturn `Context now ${percent.toFixed(0)}% full`;\n}\n\n// ---- tool call rendering ----------------------------------------------------\n// Args arrive off the wire and stream in, so every field is read defensively.\n\ntype ExitPlanCallArgs = { title?: unknown; plan?: unknown; revises?: unknown };\n\nfunction callText(value: unknown): string {\n\treturn typeof value === \"string\" ? value.trim() : \"\";\n}\n\n/** Title-only headline when collapsed; plan body and revision target on expand. */\nexport function formatExitPlanCall(args: ExitPlanCallArgs | undefined, theme: Theme, expanded: boolean): string {\n\tconst title = callText(args?.title);\n\tconst headline = [\n\t\ttheme.fg(\"toolTitle\", theme.bold(\"exit_plan\")),\n\t\ttitle ? theme.fg(\"text\", title) : theme.fg(\"dim\", \"…\"),\n\t].join(\" \");\n\tif (!expanded) return headline;\n\n\tconst lines = [headline];\n\tconst revises = callText(args?.revises);\n\tif (revises) lines.push(theme.fg(\"dim\", `revises ${revises}`));\n\tconst plan = callText(args?.plan);\n\tif (plan) {\n\t\tlines.push(\"\");\n\t\tfor (const line of plan.split(\"\\n\")) lines.push(theme.fg(\"dim\", line));\n\t}\n\treturn lines.join(\"\\n\");\n}\n\n// ---- tool result rendering --------------------------------------------------\n\nconst DECISION_SUMMARY: Record<ExitPlanDecision, string> = {\n\texecute: \"Executing with full context\",\n\tcompactAndExecute: \"Compacting context, then executing\",\n\tkeepPlanning: \"Still planning\",\n\tcancelled: \"No approval was pending\",\n};\n\nfunction resultText(result: AgentToolResult<ExitPlanDetails>): string {\n\treturn result.content\n\t\t.filter((block): block is { type: \"text\"; text: string } => block.type === \"text\")\n\t\t.map((block) => block.text)\n\t\t.join(\"\\n\");\n}\n\n/**\n * What the user needs to know: where the plan landed and what happens next.\n * Falls back to the model-facing text when details are missing — a thrown\n * approval (interrupt) has no details to render from.\n */\nexport function formatExitPlanResult(result: AgentToolResult<ExitPlanDetails>, theme: Theme): string {\n\tconst details = result.details;\n\tif (!details) return theme.fg(\"dim\", resultText(result));\n\n\tconst lines: string[] = [];\n\tif (details.planPath) lines.push(theme.fg(\"success\", `Saved to ${shortenPlanPath(details.planPath)}`));\n\tlines.push(theme.fg(\"dim\", DECISION_SUMMARY[details.decision]));\n\treturn lines.join(\"\\n\");\n}\n"]}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/** Collapse the home prefix so a plan path stays on one line. */
|
|
2
|
-
export function shortenPlanPath(path) {
|
|
3
|
-
const rawHome = process.env.USERPROFILE || process.env.HOME || "";
|
|
4
|
-
const home = rawHome.replace(/[\\/]+$/, "");
|
|
5
|
-
if (!home)
|
|
6
|
-
return path;
|
|
7
|
-
const normalize = (value) => value.replace(/\\/g, "/").toLowerCase();
|
|
8
|
-
if (!normalize(path).startsWith(`${normalize(home)}/`))
|
|
9
|
-
return path;
|
|
10
|
-
return `~${path.slice(home.length).replace(/\\/g, "/")}`;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Context pressure is the fact the compact-or-not decision turns on, so the
|
|
14
|
-
* dialog states it instead of making the user leave and check the footer.
|
|
15
|
-
*/
|
|
16
|
-
export function formatApprovalSubtitle(ctx) {
|
|
17
|
-
const percent = ctx.getContextUsage()?.percent;
|
|
18
|
-
if (percent == null)
|
|
19
|
-
return undefined;
|
|
20
|
-
return `Context now ${percent.toFixed(0)}% full`;
|
|
21
|
-
}
|
|
22
|
-
function callText(value) {
|
|
23
|
-
return typeof value === "string" ? value.trim() : "";
|
|
24
|
-
}
|
|
25
|
-
/** Title-only headline when collapsed; plan body and revision target on expand. */
|
|
26
|
-
export function formatExitPlanCall(args, theme, expanded) {
|
|
27
|
-
const title = callText(args?.title);
|
|
28
|
-
const headline = [
|
|
29
|
-
theme.fg("toolTitle", theme.bold("exit_plan")),
|
|
30
|
-
title ? theme.fg("text", title) : theme.fg("dim", "…"),
|
|
31
|
-
].join(" ");
|
|
32
|
-
if (!expanded)
|
|
33
|
-
return headline;
|
|
34
|
-
const lines = [headline];
|
|
35
|
-
const revises = callText(args?.revises);
|
|
36
|
-
if (revises)
|
|
37
|
-
lines.push(theme.fg("dim", `revises ${revises}`));
|
|
38
|
-
const plan = callText(args?.plan);
|
|
39
|
-
if (plan) {
|
|
40
|
-
lines.push("");
|
|
41
|
-
for (const line of plan.split("\n"))
|
|
42
|
-
lines.push(theme.fg("dim", line));
|
|
43
|
-
}
|
|
44
|
-
return lines.join("\n");
|
|
45
|
-
}
|
|
46
|
-
// ---- tool result rendering --------------------------------------------------
|
|
47
|
-
const DECISION_SUMMARY = {
|
|
48
|
-
execute: "Executing with full context",
|
|
49
|
-
compactAndExecute: "Compacting context, then executing",
|
|
50
|
-
keepPlanning: "Still planning",
|
|
51
|
-
cancelled: "No approval was pending",
|
|
52
|
-
};
|
|
53
|
-
function resultText(result) {
|
|
54
|
-
return result.content
|
|
55
|
-
.filter((block) => block.type === "text")
|
|
56
|
-
.map((block) => block.text)
|
|
57
|
-
.join("\n");
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* What the user needs to know: where the plan landed and what happens next.
|
|
61
|
-
* Falls back to the model-facing text when details are missing — a thrown
|
|
62
|
-
* approval (interrupt) has no details to render from.
|
|
63
|
-
*/
|
|
64
|
-
export function formatExitPlanResult(result, theme) {
|
|
65
|
-
const details = result.details;
|
|
66
|
-
if (!details)
|
|
67
|
-
return theme.fg("dim", resultText(result));
|
|
68
|
-
const lines = [];
|
|
69
|
-
if (details.planPath)
|
|
70
|
-
lines.push(theme.fg("success", `Saved to ${shortenPlanPath(details.planPath)}`));
|
|
71
|
-
lines.push(theme.fg("dim", DECISION_SUMMARY[details.decision]));
|
|
72
|
-
return lines.join("\n");
|
|
73
|
-
}
|
|
74
|
-
//# sourceMappingURL=view.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"view.js","sourceRoot":"","sources":["../../../src/extensions/plan/view.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * plan/view.ts — approval-dialog context and exit_plan tool rendering.\n *\n * `exit_plan` carries the whole plan as a parameter, and the default renderer\n * echoes parameters verbatim: the row would repeat, escaped onto one line, the\n * markdown the model just printed as response text. Collapsed rows therefore\n * carry the title only, and the plan body is available on expand.\n *\n * The result text is written for the model (it restates tool-state precedence\n * rules), so the result row renders from `details` instead.\n */\nimport type { AgentToolResult, ExtensionContext } from \"../../core/extensions/types.ts\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport type { ExitPlanDecision, ExitPlanDetails } from \"./schema.ts\";\n\n/** Collapse the home prefix so a plan path stays on one line. */\nexport function shortenPlanPath(path: string): string {\n\tconst rawHome = process.env.USERPROFILE || process.env.HOME || \"\";\n\tconst home = rawHome.replace(/[\\\\/]+$/, \"\");\n\tif (!home) return path;\n\tconst normalize = (value: string) => value.replace(/\\\\/g, \"/\").toLowerCase();\n\tif (!normalize(path).startsWith(`${normalize(home)}/`)) return path;\n\treturn `~${path.slice(home.length).replace(/\\\\/g, \"/\")}`;\n}\n\n/**\n * Context pressure is the fact the compact-or-not decision turns on, so the\n * dialog states it instead of making the user leave and check the footer.\n */\nexport function formatApprovalSubtitle(ctx: ExtensionContext): string | undefined {\n\tconst percent = ctx.getContextUsage()?.percent;\n\tif (percent == null) return undefined;\n\treturn `Context now ${percent.toFixed(0)}% full`;\n}\n\n// ---- tool call rendering ----------------------------------------------------\n// Args arrive off the wire and stream in, so every field is read defensively.\n\ntype ExitPlanCallArgs = { title?: unknown; plan?: unknown; revises?: unknown };\n\nfunction callText(value: unknown): string {\n\treturn typeof value === \"string\" ? value.trim() : \"\";\n}\n\n/** Title-only headline when collapsed; plan body and revision target on expand. */\nexport function formatExitPlanCall(args: ExitPlanCallArgs | undefined, theme: Theme, expanded: boolean): string {\n\tconst title = callText(args?.title);\n\tconst headline = [\n\t\ttheme.fg(\"toolTitle\", theme.bold(\"exit_plan\")),\n\t\ttitle ? theme.fg(\"text\", title) : theme.fg(\"dim\", \"…\"),\n\t].join(\" \");\n\tif (!expanded) return headline;\n\n\tconst lines = [headline];\n\tconst revises = callText(args?.revises);\n\tif (revises) lines.push(theme.fg(\"dim\", `revises ${revises}`));\n\tconst plan = callText(args?.plan);\n\tif (plan) {\n\t\tlines.push(\"\");\n\t\tfor (const line of plan.split(\"\\n\")) lines.push(theme.fg(\"dim\", line));\n\t}\n\treturn lines.join(\"\\n\");\n}\n\n// ---- tool result rendering --------------------------------------------------\n\nconst DECISION_SUMMARY: Record<ExitPlanDecision, string> = {\n\texecute: \"Executing with full context\",\n\tcompactAndExecute: \"Compacting context, then executing\",\n\tkeepPlanning: \"Still planning\",\n\tcancelled: \"No approval was pending\",\n};\n\nfunction resultText(result: AgentToolResult<ExitPlanDetails>): string {\n\treturn result.content\n\t\t.filter((block): block is { type: \"text\"; text: string } => block.type === \"text\")\n\t\t.map((block) => block.text)\n\t\t.join(\"\\n\");\n}\n\n/**\n * What the user needs to know: where the plan landed and what happens next.\n * Falls back to the model-facing text when details are missing — a thrown\n * approval (interrupt) has no details to render from.\n */\nexport function formatExitPlanResult(result: AgentToolResult<ExitPlanDetails>, theme: Theme): string {\n\tconst details = result.details;\n\tif (!details) return theme.fg(\"dim\", resultText(result));\n\n\tconst lines: string[] = [];\n\tif (details.planPath) lines.push(theme.fg(\"success\", `Saved to ${shortenPlanPath(details.planPath)}`));\n\tlines.push(theme.fg(\"dim\", DECISION_SUMMARY[details.decision]));\n\treturn lines.join(\"\\n\");\n}\n"]}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# Bundled extensions
|
|
2
|
-
|
|
3
|
-
These are extensions shipped in the `@astralyn/pi` npm package. For the public API used to write external extensions, see the [Extension API documentation](../../extensions.md).
|
|
4
|
-
|
|
5
|
-
They are registered as hidden built-in extensions and use the same public Extension API available to external extensions. Their implementation details are internal to the package and are not required for installation or configuration.
|
|
6
|
-
|
|
7
|
-
| Extension | Tool or command | Documentation |
|
|
8
|
-
|---|---|---|
|
|
9
|
-
| `llama.cpp` | `/llama` | [llama.cpp](../../llama-cpp.md) |
|
|
10
|
-
| `deepwiki` | `deepwiki` | [deepwiki.md](deepwiki.md) |
|
|
11
|
-
| `plan` | `exit_plan`, `/plan` | [plan.md](plan.md) |
|
|
12
|
-
| `question` | `question` | [question.md](question.md) |
|
|
13
|
-
| `todo` | `todo`, `/todos` | [todo.md](todo.md) |
|
|
14
|
-
| `rewind` | `/rewind`, `/tree` lifecycle | [rewind.md](rewind.md) |
|
|
15
|
-
| `router` | `/router` | [router.md](router.md) |
|
|
16
|
-
| `statusline` | Footer | [statusline.md](statusline.md) |
|
|
17
|
-
| `subagent` | `subagent`, `/agents` | [subagent.md](subagent.md) |
|
|
18
|
-
|
|
19
|
-
The catalog documents installed-package behavior and configuration; it does not require access to the package's internal source.
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# plan — read-only plan mode
|
|
2
|
-
|
|
3
|
-
Adds `/plan` for a Claude-Code-style planning phase: the model explores read-only, interviews the user, and leaves the mode through a user-approved `exit_plan` tool call that saves the plan to disk and optionally compacts the context before execution starts.
|
|
4
|
-
|
|
5
|
-
## Behavior
|
|
6
|
-
|
|
7
|
-
- `/plan` (or the `--plan` CLI flag) toggles plan mode. On entry the built-in `edit`, `write`, and `bash` tools and the bundled `subagent` tool are deactivated — `subagent` because child sessions do not inherit the restricted tool set. Read-only built-ins and other extension tools (`question`, `todo`, `deepwiki`, …) stay available. A `tool_call` guard also blocks the four tools for requests already in flight when the mode toggles.
|
|
8
|
-
- While planning, the system prompt gains a plan-mode block: explore before asking, interview one decision at a time with the `question` tool (with a recommendation and trade-offs), skip the interview for small clear tasks, then present the full plan as response text before calling `exit_plan`.
|
|
9
|
-
- `exit_plan(title, plan, revises?)` opens the approval menu. Each option carries a muted description, and the dialog subtitle reports current context usage — the fact the compact-or-not decision turns on:
|
|
10
|
-
- **Start executing** *(keep full context)* — saves the plan, restores tools, and execution continues in the same run.
|
|
11
|
-
- **Compact context, then execute** *(best for long tasks)* — saves the plan, ends the run (`terminate`), compacts once the run has settled, and only then restores tools; execution restarts via a kickoff message that embeds the plan text, so continuation never depends on the compaction summary. If compaction fails, tools are restored and execution proceeds with full context.
|
|
12
|
-
- **Keep planning** *(refine before running)* — optionally collects feedback (multi-line editor in the TUI, input dialog in RPC) and returns it to the model; plan mode stays active. `Esc` and dialog timeouts map here, never to an executing option, so the dismiss hint reads "keep planning" rather than "cancel".
|
|
13
|
-
- Both executing options save the plan file. If the session has no name yet, the plan title becomes the session name.
|
|
14
|
-
- `/plan` while planning exits directly without a menu or a file — the plan text is still in context. During a pending compaction the toggle is refused until the compaction settles.
|
|
15
|
-
- Plan files live under `<agentDir>/plans/<sessionId>/NN-<slug>.md` (`~/.pi/agent/plans/…` by default, `PI_CODING_AGENT_DIR` respected) with `title`, `created`, `cwd`, `session`, and optional `revises` frontmatter. Numbering is append-only; revisions are new files that point back via `revises`.
|
|
16
|
-
- To revise a plan mid-execution, re-enter with `/plan`: the system prompt lists the branch's saved plans so the model reads the latest one, accounts for completed work, and produces a revision.
|
|
17
|
-
|
|
18
|
-
## Limits
|
|
19
|
-
|
|
20
|
-
- The kickoff message embeds at most 24 000 characters of plan markdown; longer plans are truncated with a pointer to the full file.
|
|
21
|
-
- In `json`/`print` modes `exit_plan` cannot ask, so it saves the plan and exits with context kept (write access is restored without a menu).
|
|
22
|
-
- Approving with **Compact context, then execute** and then interrupting before compaction completes (quit, resume, branch switch) degrades to the keep-context exit on the next session start.
|
|
23
|
-
- The dialog subtitle is omitted when context usage is not yet known (no assistant turn has reported usage).
|
|
24
|
-
|
|
25
|
-
## Implementation notes
|
|
26
|
-
|
|
27
|
-
- **Conversation-backed state.** Every transition appends a `plan-mode` custom entry (never sent to the LLM); lifecycle handlers replay the current branch tail → head, so `/reload`, `/tree`, resume, and fork restore the mode. Fork and clone copy entries, so the recorded plan-file paths follow the new session even though it gets a fresh session id — the `<sessionId>` directory is only the initial storage location, not the index.
|
|
28
|
-
- **State is keyed per session id** (todo pattern): resume and `/tree` can switch sessions within one process, and handlers re-point the active bucket before touching state.
|
|
29
|
-
- **Tool restore is an inverse operation, not a snapshot.** Entry records which tools were actually removed; exit re-adds exactly those, so tools other extensions activate during planning are not revoked and tools the user had disabled are not resurrected.
|
|
30
|
-
- **No write access is ever needed for the plan itself** — the plan text travels as an `exit_plan` parameter and the extension writes the file.
|
|
31
|
-
- **The compact-then-execute window is closed by construction**: plan mode (and its tool restrictions) persists until compaction completes; the run is terminated by the tool result and the compaction starts on `agent_settled`, which fires once per fully settled run.
|
|
32
|
-
- The `exit_plan` result text authoritatively announces mode changes because the per-run system prompt override is not rebuilt mid-run.
|
|
33
|
-
- **The tool row renders from the title and `details`, not from the parameters.** `exit_plan` carries the whole plan as a parameter, and its result text is written for the model, so the default renderer would echo the plan markdown escaped onto one line and then restate tool-state rules at the user. `renderCall` shows the title (plan body on expand); `renderResult` shows where the plan landed and what happens next.
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
# Plan Mode Extension
|
|
2
|
-
|
|
3
|
-
Read-only exploration mode for safe code analysis.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- **Built-in write tools disabled**: Disables edit/write while preserving other active tools
|
|
8
|
-
- **Bash allowlist**: Only read-only bash commands are allowed
|
|
9
|
-
- **Plan extraction**: Extracts numbered steps from `Plan:` sections
|
|
10
|
-
- **Progress tracking**: Widget shows completion status during execution
|
|
11
|
-
- **[DONE:n] markers**: Explicit step completion tracking
|
|
12
|
-
- **Session persistence**: State survives session resume
|
|
13
|
-
|
|
14
|
-
## Commands
|
|
15
|
-
|
|
16
|
-
- `/plan` - Toggle plan mode
|
|
17
|
-
- `/todos` - Show current plan progress
|
|
18
|
-
- `Ctrl+Alt+P` - Toggle plan mode (shortcut)
|
|
19
|
-
|
|
20
|
-
## Usage
|
|
21
|
-
|
|
22
|
-
1. Enable plan mode with `/plan` or `--plan` flag
|
|
23
|
-
2. Ask the agent to analyze code and create a plan
|
|
24
|
-
3. The agent should output a numbered plan under a `Plan:` header:
|
|
25
|
-
|
|
26
|
-
```
|
|
27
|
-
Plan:
|
|
28
|
-
1. First step description
|
|
29
|
-
2. Second step description
|
|
30
|
-
3. Third step description
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
4. Choose "Execute the plan" when prompted
|
|
34
|
-
5. During execution, the agent marks steps complete with `[DONE:n]` tags
|
|
35
|
-
6. Progress widget shows completion status
|
|
36
|
-
|
|
37
|
-
## How It Works
|
|
38
|
-
|
|
39
|
-
### Plan Mode (Read-Only)
|
|
40
|
-
- Built-in edit/write tools disabled
|
|
41
|
-
- Other active tools remain available
|
|
42
|
-
- Bash commands filtered through allowlist
|
|
43
|
-
- Agent creates a plan without making changes
|
|
44
|
-
|
|
45
|
-
### Execution Mode
|
|
46
|
-
- Full tool access restored
|
|
47
|
-
- Agent executes steps in order
|
|
48
|
-
- `[DONE:n]` markers track completion
|
|
49
|
-
- Widget shows progress
|
|
50
|
-
|
|
51
|
-
### Command Allowlist
|
|
52
|
-
|
|
53
|
-
Safe commands (allowed):
|
|
54
|
-
- File inspection: `cat`, `head`, `tail`, `less`, `more`
|
|
55
|
-
- Search: `grep`, `find`, `rg`, `fd`
|
|
56
|
-
- Directory: `ls`, `pwd`, `tree`
|
|
57
|
-
- Git read: `git status`, `git log`, `git diff`, `git branch`
|
|
58
|
-
- Package info: `npm list`, `npm outdated`, `yarn info`
|
|
59
|
-
- System info: `uname`, `whoami`, `date`, `uptime`
|
|
60
|
-
|
|
61
|
-
Blocked commands:
|
|
62
|
-
- File modification: `rm`, `mv`, `cp`, `mkdir`, `touch`
|
|
63
|
-
- Git write: `git add`, `git commit`, `git push`
|
|
64
|
-
- Package install: `npm install`, `yarn add`, `pip install`
|
|
65
|
-
- System: `sudo`, `kill`, `reboot`
|
|
66
|
-
- Editors: `vim`, `nano`, `code`
|
|
@@ -1,390 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Plan Mode Extension
|
|
3
|
-
*
|
|
4
|
-
* Read-only exploration mode for safe code analysis.
|
|
5
|
-
* When enabled, built-in write tools are disabled.
|
|
6
|
-
*
|
|
7
|
-
* Features:
|
|
8
|
-
* - /plan command or Ctrl+Alt+P to toggle
|
|
9
|
-
* - Bash restricted to allowlisted read-only commands
|
|
10
|
-
* - Extracts numbered plan steps from "Plan:" sections
|
|
11
|
-
* - [DONE:n] markers to complete steps during execution
|
|
12
|
-
* - Progress tracking widget during execution
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import type { ExtensionAPI, ExtensionContext } from "@astralyn/pi";
|
|
16
|
-
import type { AgentMessage } from "@earendil-works/pi-agent-core";
|
|
17
|
-
import type { AssistantMessage, TextContent } from "@earendil-works/pi-ai";
|
|
18
|
-
import { Key } from "@earendil-works/pi-tui";
|
|
19
|
-
import { extractTodoItems, isSafeCommand, markCompletedSteps, type TodoItem } from "./utils.ts";
|
|
20
|
-
|
|
21
|
-
// Tools
|
|
22
|
-
const PLAN_MODE_TOOLS = ["read", "bash", "grep", "find", "ls", "questionnaire"];
|
|
23
|
-
const NORMAL_MODE_TOOLS = ["read", "bash", "edit", "write"];
|
|
24
|
-
const PLAN_MODE_DISABLED_TOOLS = new Set<string>(["edit", "write"]);
|
|
25
|
-
const PLAN_MANAGED_TOOLS = new Set<string>([...PLAN_MODE_TOOLS, ...NORMAL_MODE_TOOLS]);
|
|
26
|
-
|
|
27
|
-
interface PlanModeState {
|
|
28
|
-
enabled: boolean;
|
|
29
|
-
todos?: TodoItem[];
|
|
30
|
-
executing?: boolean;
|
|
31
|
-
toolsBeforePlanMode?: string[];
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Type guard for assistant messages
|
|
35
|
-
function isAssistantMessage(m: AgentMessage): m is AssistantMessage {
|
|
36
|
-
return m.role === "assistant" && Array.isArray(m.content);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Extract text content from an assistant message
|
|
40
|
-
function getTextContent(message: AssistantMessage): string {
|
|
41
|
-
return message.content
|
|
42
|
-
.filter((block): block is TextContent => block.type === "text")
|
|
43
|
-
.map((block) => block.text)
|
|
44
|
-
.join("\n");
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export default function planModeExtension(pi: ExtensionAPI): void {
|
|
48
|
-
let planModeEnabled = false;
|
|
49
|
-
let executionMode = false;
|
|
50
|
-
let todoItems: TodoItem[] = [];
|
|
51
|
-
let toolsBeforePlanMode: string[] | undefined;
|
|
52
|
-
|
|
53
|
-
pi.registerFlag("plan", {
|
|
54
|
-
description: "Start in plan mode (read-only exploration)",
|
|
55
|
-
type: "boolean",
|
|
56
|
-
default: false,
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
function updateStatus(ctx: ExtensionContext): void {
|
|
60
|
-
// Footer status
|
|
61
|
-
if (executionMode && todoItems.length > 0) {
|
|
62
|
-
const completed = todoItems.filter((t) => t.completed).length;
|
|
63
|
-
ctx.ui.setStatus("plan-mode", ctx.ui.theme.fg("accent", `📋 ${completed}/${todoItems.length}`));
|
|
64
|
-
} else if (planModeEnabled) {
|
|
65
|
-
ctx.ui.setStatus("plan-mode", ctx.ui.theme.fg("warning", "⏸ plan"));
|
|
66
|
-
} else {
|
|
67
|
-
ctx.ui.setStatus("plan-mode", undefined);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Widget showing todo list
|
|
71
|
-
if (executionMode && todoItems.length > 0) {
|
|
72
|
-
const lines = todoItems.map((item) => {
|
|
73
|
-
if (item.completed) {
|
|
74
|
-
return (
|
|
75
|
-
ctx.ui.theme.fg("success", "☑ ") + ctx.ui.theme.fg("muted", ctx.ui.theme.strikethrough(item.text))
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
return `${ctx.ui.theme.fg("muted", "☐ ")}${item.text}`;
|
|
79
|
-
});
|
|
80
|
-
ctx.ui.setWidget("plan-todos", lines);
|
|
81
|
-
} else {
|
|
82
|
-
ctx.ui.setWidget("plan-todos", undefined);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function uniqueToolNames(toolNames: string[]): string[] {
|
|
87
|
-
return [...new Set(toolNames)];
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function getPlanModeTools(activeToolNames: string[]): string[] {
|
|
91
|
-
return uniqueToolNames([
|
|
92
|
-
...activeToolNames.filter((name) => !PLAN_MODE_DISABLED_TOOLS.has(name)),
|
|
93
|
-
...PLAN_MODE_TOOLS,
|
|
94
|
-
]);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function getNormalModeTools(activeToolNames: string[]): string[] {
|
|
98
|
-
return uniqueToolNames([
|
|
99
|
-
...NORMAL_MODE_TOOLS,
|
|
100
|
-
...activeToolNames.filter((name) => !PLAN_MANAGED_TOOLS.has(name)),
|
|
101
|
-
]);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function enablePlanModeTools(): void {
|
|
105
|
-
if (toolsBeforePlanMode === undefined) {
|
|
106
|
-
toolsBeforePlanMode = pi.getActiveTools();
|
|
107
|
-
}
|
|
108
|
-
pi.setActiveTools(getPlanModeTools(toolsBeforePlanMode));
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function restoreNormalModeTools(): void {
|
|
112
|
-
pi.setActiveTools(toolsBeforePlanMode ?? getNormalModeTools(pi.getActiveTools()));
|
|
113
|
-
toolsBeforePlanMode = undefined;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function persistState(): void {
|
|
117
|
-
pi.appendEntry("plan-mode", {
|
|
118
|
-
enabled: planModeEnabled,
|
|
119
|
-
todos: todoItems,
|
|
120
|
-
executing: executionMode,
|
|
121
|
-
toolsBeforePlanMode,
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function togglePlanMode(ctx: ExtensionContext): void {
|
|
126
|
-
planModeEnabled = !planModeEnabled;
|
|
127
|
-
executionMode = false;
|
|
128
|
-
todoItems = [];
|
|
129
|
-
|
|
130
|
-
if (planModeEnabled) {
|
|
131
|
-
enablePlanModeTools();
|
|
132
|
-
ctx.ui.notify("Plan mode enabled. Built-in write tools disabled.");
|
|
133
|
-
} else {
|
|
134
|
-
restoreNormalModeTools();
|
|
135
|
-
ctx.ui.notify("Plan mode disabled. Full access restored.");
|
|
136
|
-
}
|
|
137
|
-
updateStatus(ctx);
|
|
138
|
-
persistState();
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
pi.registerCommand("plan", {
|
|
142
|
-
description: "Toggle plan mode (read-only exploration)",
|
|
143
|
-
handler: async (_args, ctx) => togglePlanMode(ctx),
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
pi.registerCommand("todos", {
|
|
147
|
-
description: "Show current plan todo list",
|
|
148
|
-
handler: async (_args, ctx) => {
|
|
149
|
-
if (todoItems.length === 0) {
|
|
150
|
-
ctx.ui.notify("No todos. Create a plan first with /plan", "info");
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
const list = todoItems.map((item, i) => `${i + 1}. ${item.completed ? "✓" : "○"} ${item.text}`).join("\n");
|
|
154
|
-
ctx.ui.notify(`Plan Progress:\n${list}`, "info");
|
|
155
|
-
},
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
pi.registerShortcut(Key.ctrlAlt("p"), {
|
|
159
|
-
description: "Toggle plan mode",
|
|
160
|
-
handler: async (ctx) => togglePlanMode(ctx),
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
// Block destructive bash commands in plan mode
|
|
164
|
-
pi.on("tool_call", async (event) => {
|
|
165
|
-
if (!planModeEnabled || event.toolName !== "bash") return;
|
|
166
|
-
|
|
167
|
-
const command = event.input.command as string;
|
|
168
|
-
if (!isSafeCommand(command)) {
|
|
169
|
-
return {
|
|
170
|
-
block: true,
|
|
171
|
-
reason: `Plan mode: command blocked (not allowlisted). Use /plan to disable plan mode first.\nCommand: ${command}`,
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
// Filter out stale plan mode context when not in plan mode
|
|
177
|
-
pi.on("context", async (event) => {
|
|
178
|
-
if (planModeEnabled) return;
|
|
179
|
-
|
|
180
|
-
return {
|
|
181
|
-
messages: event.messages.filter((m) => {
|
|
182
|
-
const msg = m as AgentMessage & { customType?: string };
|
|
183
|
-
if (msg.customType === "plan-mode-context") return false;
|
|
184
|
-
if (msg.role !== "user") return true;
|
|
185
|
-
|
|
186
|
-
const content = msg.content;
|
|
187
|
-
if (typeof content === "string") {
|
|
188
|
-
return !content.includes("[PLAN MODE ACTIVE]");
|
|
189
|
-
}
|
|
190
|
-
if (Array.isArray(content)) {
|
|
191
|
-
return !content.some(
|
|
192
|
-
(c) => c.type === "text" && (c as TextContent).text?.includes("[PLAN MODE ACTIVE]"),
|
|
193
|
-
);
|
|
194
|
-
}
|
|
195
|
-
return true;
|
|
196
|
-
}),
|
|
197
|
-
};
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
// Inject plan/execution context before agent starts
|
|
201
|
-
pi.on("before_agent_start", async () => {
|
|
202
|
-
if (planModeEnabled) {
|
|
203
|
-
return {
|
|
204
|
-
message: {
|
|
205
|
-
customType: "plan-mode-context",
|
|
206
|
-
content: `[PLAN MODE ACTIVE]
|
|
207
|
-
You are in plan mode - a read-only exploration mode for safe code analysis.
|
|
208
|
-
|
|
209
|
-
Restrictions:
|
|
210
|
-
- Built-in edit and write tools are disabled
|
|
211
|
-
- Other currently active tools remain available
|
|
212
|
-
- Bash is restricted to an allowlist of read-only commands
|
|
213
|
-
|
|
214
|
-
Ask clarifying questions using the questionnaire tool.
|
|
215
|
-
Use brave-search skill via bash for web research.
|
|
216
|
-
|
|
217
|
-
Create a detailed numbered plan under a "Plan:" header:
|
|
218
|
-
|
|
219
|
-
Plan:
|
|
220
|
-
1. First step description
|
|
221
|
-
2. Second step description
|
|
222
|
-
...
|
|
223
|
-
|
|
224
|
-
Do NOT attempt to make changes - just describe what you would do.`,
|
|
225
|
-
display: false,
|
|
226
|
-
},
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
if (executionMode && todoItems.length > 0) {
|
|
231
|
-
const remaining = todoItems.filter((t) => !t.completed);
|
|
232
|
-
const todoList = remaining.map((t) => `${t.step}. ${t.text}`).join("\n");
|
|
233
|
-
return {
|
|
234
|
-
message: {
|
|
235
|
-
customType: "plan-execution-context",
|
|
236
|
-
content: `[EXECUTING PLAN - Full tool access enabled]
|
|
237
|
-
|
|
238
|
-
Remaining steps:
|
|
239
|
-
${todoList}
|
|
240
|
-
|
|
241
|
-
Execute each step in order.
|
|
242
|
-
After completing a step, include a [DONE:n] tag in your response.`,
|
|
243
|
-
display: false,
|
|
244
|
-
},
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
// Track progress after each turn
|
|
250
|
-
pi.on("turn_end", async (event, ctx) => {
|
|
251
|
-
if (!executionMode || todoItems.length === 0) return;
|
|
252
|
-
if (!isAssistantMessage(event.message)) return;
|
|
253
|
-
|
|
254
|
-
const text = getTextContent(event.message);
|
|
255
|
-
if (markCompletedSteps(text, todoItems) > 0) {
|
|
256
|
-
updateStatus(ctx);
|
|
257
|
-
}
|
|
258
|
-
persistState();
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
// Handle plan completion and plan mode UI
|
|
262
|
-
pi.on("agent_end", async (event, ctx) => {
|
|
263
|
-
// Check if execution is complete
|
|
264
|
-
if (executionMode && todoItems.length > 0) {
|
|
265
|
-
if (todoItems.every((t) => t.completed)) {
|
|
266
|
-
const completedList = todoItems.map((t) => `~~${t.text}~~`).join("\n");
|
|
267
|
-
pi.sendMessage(
|
|
268
|
-
{ customType: "plan-complete", content: `**Plan Complete!** ✓\n\n${completedList}`, display: true },
|
|
269
|
-
{ triggerTurn: false },
|
|
270
|
-
);
|
|
271
|
-
executionMode = false;
|
|
272
|
-
todoItems = [];
|
|
273
|
-
updateStatus(ctx);
|
|
274
|
-
persistState(); // Save cleared state so resume doesn't restore old execution mode
|
|
275
|
-
}
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
if (!planModeEnabled || !ctx.hasUI) return;
|
|
280
|
-
|
|
281
|
-
// Extract todos from last assistant message
|
|
282
|
-
const lastAssistant = [...event.messages].reverse().find(isAssistantMessage);
|
|
283
|
-
if (lastAssistant) {
|
|
284
|
-
const extracted = extractTodoItems(getTextContent(lastAssistant));
|
|
285
|
-
if (extracted.length > 0) {
|
|
286
|
-
todoItems = extracted;
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
if (todoItems.length === 0) return;
|
|
291
|
-
persistState();
|
|
292
|
-
|
|
293
|
-
// Show plan steps and prompt for next action
|
|
294
|
-
const todoListText = todoItems.map((t, i) => `${i + 1}. ☐ ${t.text}`).join("\n");
|
|
295
|
-
const planTodoListMessage = {
|
|
296
|
-
customType: "plan-todo-list",
|
|
297
|
-
content: `**Plan Steps (${todoItems.length}):**\n\n${todoListText}`,
|
|
298
|
-
display: true,
|
|
299
|
-
};
|
|
300
|
-
|
|
301
|
-
const choice = await ctx.ui.select("Plan mode - what next?", [
|
|
302
|
-
"Execute the plan (track progress)",
|
|
303
|
-
"Stay in plan mode",
|
|
304
|
-
"Refine the plan",
|
|
305
|
-
]);
|
|
306
|
-
|
|
307
|
-
if (choice?.startsWith("Execute")) {
|
|
308
|
-
const firstTodoItem = todoItems[0];
|
|
309
|
-
if (!firstTodoItem) return;
|
|
310
|
-
|
|
311
|
-
planModeEnabled = false;
|
|
312
|
-
executionMode = true;
|
|
313
|
-
restoreNormalModeTools();
|
|
314
|
-
updateStatus(ctx);
|
|
315
|
-
persistState();
|
|
316
|
-
|
|
317
|
-
const remainingList = todoItems.map((t) => `${t.step}. ${t.text}`).join("\n");
|
|
318
|
-
const execMessage = `Execute the plan.
|
|
319
|
-
|
|
320
|
-
Remaining steps:
|
|
321
|
-
${remainingList}
|
|
322
|
-
|
|
323
|
-
Start with: ${firstTodoItem.text}
|
|
324
|
-
After completing a step, include a [DONE:n] tag in your response.`;
|
|
325
|
-
pi.sendMessage(planTodoListMessage, { deliverAs: "followUp" });
|
|
326
|
-
pi.sendMessage(
|
|
327
|
-
{ customType: "plan-mode-execute", content: execMessage, display: true },
|
|
328
|
-
{ triggerTurn: true, deliverAs: "followUp" },
|
|
329
|
-
);
|
|
330
|
-
} else if (choice === "Refine the plan") {
|
|
331
|
-
const refinement = await ctx.ui.editor("Refine the plan:", "");
|
|
332
|
-
if (refinement?.trim()) {
|
|
333
|
-
pi.sendMessage(planTodoListMessage, { deliverAs: "followUp" });
|
|
334
|
-
pi.sendUserMessage(refinement.trim(), { deliverAs: "followUp" });
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
// Restore state on session start/resume
|
|
340
|
-
pi.on("session_start", async (_event, ctx) => {
|
|
341
|
-
if (pi.getFlag("plan") === true) {
|
|
342
|
-
planModeEnabled = true;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
const entries = ctx.sessionManager.getEntries();
|
|
346
|
-
|
|
347
|
-
// Restore persisted state
|
|
348
|
-
const planModeEntry = entries
|
|
349
|
-
.filter((e: { type: string; customType?: string }) => e.type === "custom" && e.customType === "plan-mode")
|
|
350
|
-
.pop() as { data?: PlanModeState } | undefined;
|
|
351
|
-
|
|
352
|
-
if (planModeEntry?.data) {
|
|
353
|
-
planModeEnabled = planModeEntry.data.enabled ?? planModeEnabled;
|
|
354
|
-
todoItems = planModeEntry.data.todos ?? todoItems;
|
|
355
|
-
executionMode = planModeEntry.data.executing ?? executionMode;
|
|
356
|
-
toolsBeforePlanMode = planModeEntry.data.toolsBeforePlanMode ?? toolsBeforePlanMode;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
// On resume: re-scan messages to rebuild completion state
|
|
360
|
-
// Only scan messages AFTER the last "plan-mode-execute" to avoid picking up [DONE:n] from previous plans
|
|
361
|
-
const isResume = planModeEntry !== undefined;
|
|
362
|
-
if (isResume && executionMode && todoItems.length > 0) {
|
|
363
|
-
// Find the index of the last plan-mode-execute entry (marks when current execution started)
|
|
364
|
-
let executeIndex = -1;
|
|
365
|
-
for (let i = entries.length - 1; i >= 0; i--) {
|
|
366
|
-
const entry = entries[i] as { type: string; customType?: string };
|
|
367
|
-
if (entry.customType === "plan-mode-execute") {
|
|
368
|
-
executeIndex = i;
|
|
369
|
-
break;
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
// Only scan messages after the execute marker
|
|
374
|
-
const messages: AssistantMessage[] = [];
|
|
375
|
-
for (let i = executeIndex + 1; i < entries.length; i++) {
|
|
376
|
-
const entry = entries[i];
|
|
377
|
-
if (entry.type === "message" && "message" in entry && isAssistantMessage(entry.message as AgentMessage)) {
|
|
378
|
-
messages.push(entry.message as AssistantMessage);
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
const allText = messages.map(getTextContent).join("\n");
|
|
382
|
-
markCompletedSteps(allText, todoItems);
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
if (planModeEnabled) {
|
|
386
|
-
enablePlanModeTools();
|
|
387
|
-
}
|
|
388
|
-
updateStatus(ctx);
|
|
389
|
-
});
|
|
390
|
-
}
|