one-code-extension 0.4.1 → 0.6.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/README.md +16 -5
- package/agents/general-purpose.md +2 -2
- package/docs/guide/README.md +2 -1
- package/docs/guide/bring-your-claude-code-setup.md +60 -9
- package/docs/guide/configuration.md +48 -14
- package/docs/guide/differences-from-claude-code.md +40 -28
- package/docs/guide/doctor.md +20 -13
- package/docs/guide/hooks.md +18 -3
- package/docs/guide/installation.md +26 -4
- package/docs/guide/permissions-modes-and-auto-mode.md +225 -49
- package/docs/guide/providers-and-models.md +137 -54
- package/docs/guide/reference.md +27 -15
- package/docs/guide/sessions-and-context.md +69 -16
- package/docs/guide/skills-plugins-and-mcp.md +57 -20
- package/docs/guide/subagents-and-workflows.md +95 -29
- package/docs/guide/tasks-and-background-work.md +101 -26
- package/docs/guide/terminal-interface.md +24 -12
- package/docs/guide/tools.md +46 -5
- package/docs/guide/troubleshooting.md +13 -9
- package/docs/guide/windows.md +58 -31
- package/extensions/artifacts/gallery.ts +227 -0
- package/extensions/artifacts/index.ts +288 -0
- package/extensions/artifacts/store.ts +570 -0
- package/extensions/artifacts/viewer.ts +199 -0
- package/extensions/ask-user/description.ts +67 -0
- package/extensions/ask-user/dialogs.ts +80 -0
- package/extensions/ask-user/index.ts +37 -33
- package/extensions/ask-user/questions.ts +32 -7
- package/extensions/ask-user/widget.ts +45 -25
- package/extensions/auto-mode/actions.ts +6 -0
- package/extensions/auto-mode/cache.ts +88 -0
- package/extensions/auto-mode/classifier-prompt.ts +5 -4
- package/extensions/auto-mode/classifier.ts +290 -65
- package/extensions/auto-mode/config.ts +72 -20
- package/extensions/auto-mode/decision-log.ts +2 -0
- package/extensions/auto-mode/defaults.ts +1 -1
- package/extensions/auto-mode/denials.ts +124 -0
- package/extensions/auto-mode/git-checkout-programs.ts +187 -0
- package/extensions/auto-mode/git-status-meta.ts +159 -0
- package/extensions/auto-mode/history.ts +189 -0
- package/extensions/auto-mode/instructions.ts +58 -52
- package/extensions/auto-mode/model-select.ts +159 -134
- package/extensions/auto-mode/paths.ts +57 -5
- package/extensions/auto-mode/pause.ts +57 -2
- package/extensions/auto-mode/prompt.ts +37 -21
- package/extensions/auto-mode/read-only-options.ts +724 -0
- package/extensions/auto-mode/resolved-paths-meta.ts +133 -0
- package/extensions/auto-mode/rules.ts +18 -1
- package/extensions/auto-mode/safety-floor.ts +361 -18
- package/extensions/auto-mode/setup-run.ts +20 -14
- package/extensions/auto-mode/shell-analysis.ts +764 -490
- package/extensions/auto-mode/shell-parse.ts +885 -0
- package/extensions/auto-mode/system-note.ts +33 -0
- package/extensions/auto-mode/transcript.ts +80 -51
- package/extensions/background/cron.ts +642 -0
- package/extensions/background/index.ts +614 -248
- package/extensions/background/loop-fire.ts +173 -0
- package/extensions/background/loop-preamble.ts +59 -0
- package/extensions/background/loop-skill.ts +163 -0
- package/extensions/background/monitor-batch.ts +53 -0
- package/extensions/background/noop-fold.ts +128 -0
- package/extensions/background/switch-guard.ts +56 -0
- package/extensions/background/wakeup.ts +178 -55
- package/extensions/bash/background.ts +53 -17
- package/extensions/bash/child.ts +7 -0
- package/extensions/bash/description.ts +188 -0
- package/extensions/bash/guards.ts +15 -67
- package/extensions/bash/index.ts +66 -35
- package/extensions/branding/compaction-keep.ts +63 -0
- package/extensions/branding/declined.ts +22 -0
- package/extensions/branding/index.ts +133 -9
- package/extensions/branding/prompt-editor.ts +53 -6
- package/extensions/branding/queued-edit.ts +31 -0
- package/extensions/branding/replaced-builtins.ts +68 -0
- package/extensions/branding/startup.ts +33 -71
- package/extensions/btw/index.ts +250 -78
- package/extensions/btw/panel.ts +228 -100
- package/extensions/btw/prompt.ts +41 -4
- package/extensions/cache-marks/index.ts +42 -0
- package/extensions/claude-compat/index.ts +7 -11
- package/extensions/claude-context/index.ts +436 -63
- package/extensions/compaction/cut.ts +157 -0
- package/extensions/compaction/index.ts +219 -75
- package/extensions/compaction/kept-thinking.ts +62 -0
- package/extensions/compaction/prompt.ts +15 -12
- package/extensions/context-budget/budget.ts +16 -2
- package/extensions/context-budget/index.ts +35 -15
- package/extensions/context-management/index.ts +36 -28
- package/extensions/doctor/build.ts +59 -8
- package/extensions/doctor/builtins.ts +84 -0
- package/extensions/doctor/cli.ts +7 -1
- package/extensions/doctor/compat.ts +88 -23
- package/extensions/doctor/dependencies.ts +41 -5
- package/extensions/doctor/fix-prompt.ts +9 -2
- package/extensions/doctor/index.ts +102 -58
- package/extensions/doctor/models.ts +102 -63
- package/extensions/doctor/presets.ts +42 -27
- package/extensions/doctor/report.ts +19 -2
- package/extensions/doctor/viewer.ts +49 -27
- package/extensions/effort/index.ts +141 -25
- package/extensions/effort/settings.ts +21 -0
- package/extensions/effort/slider.ts +24 -20
- package/extensions/exit/index.ts +32 -1
- package/extensions/file-tracker/index.ts +420 -42
- package/extensions/file-tracker/replay.ts +137 -24
- package/extensions/file-tracker/restore.ts +66 -0
- package/extensions/file-tracker/results.ts +66 -0
- package/extensions/file-tracker/shell-reads.ts +211 -0
- package/extensions/file-tracker/tracker.ts +45 -15
- package/extensions/footer/footer-line.ts +45 -24
- package/extensions/footer/index.ts +47 -2
- package/extensions/footer/pr.ts +34 -5
- package/extensions/hooks/compaction.ts +7 -0
- package/extensions/hooks/executor.ts +32 -30
- package/extensions/hooks/index.ts +209 -58
- package/extensions/hooks/matcher.ts +3 -0
- package/extensions/hooks/prompt-context.ts +59 -0
- package/extensions/hooks/protocol.ts +41 -3
- package/extensions/hooks/settings.ts +50 -19
- package/extensions/hooks/subagent-bridge.ts +2 -0
- package/extensions/hooks/trust.ts +26 -12
- package/extensions/idle-compact/index.ts +119 -0
- package/extensions/idle-compact/policy.ts +143 -0
- package/extensions/init/index.ts +11 -10
- package/extensions/init/prompt.ts +25 -32
- package/extensions/interrupted/index.ts +13 -1
- package/extensions/kept-thinking/index.ts +27 -0
- package/extensions/ledger/index.ts +46 -0
- package/extensions/ledger/wire.ts +154 -0
- package/extensions/lib/agent-cron.ts +146 -0
- package/extensions/lib/agent-loader.ts +18 -3
- package/extensions/lib/agent-view.ts +85 -0
- package/extensions/lib/anthropic-auth.ts +98 -0
- package/extensions/lib/anthropic-payload.ts +82 -1
- package/extensions/lib/anthropic-server-call.ts +230 -0
- package/extensions/lib/anthropic-server-tools.ts +485 -0
- package/extensions/lib/app-launch.mjs +94 -0
- package/extensions/lib/argument-hints.ts +190 -0
- package/extensions/lib/atomic-write.ts +6 -2
- package/extensions/lib/auto-memory.ts +75 -0
- package/extensions/lib/bash-parser.ts +84 -0
- package/extensions/lib/btw-fork.ts +93 -0
- package/extensions/lib/child-extensions.ts +52 -0
- package/extensions/lib/child-writes.ts +45 -0
- package/extensions/lib/claude-context.ts +515 -100
- package/extensions/lib/claude-external-includes.ts +68 -0
- package/extensions/lib/claude-id.ts +22 -0
- package/extensions/lib/claude-rules.ts +323 -0
- package/extensions/lib/claude-settings.ts +76 -4
- package/extensions/lib/compaction-boundary.ts +36 -0
- package/extensions/lib/compaction-keep.mjs +83 -0
- package/extensions/lib/config-mode.ts +112 -0
- package/extensions/lib/consent-dialogs.ts +63 -0
- package/extensions/lib/consent-preview.ts +5 -1
- package/extensions/lib/consent-stores.ts +48 -0
- package/extensions/lib/context-facts.ts +97 -0
- package/extensions/lib/covered-messages.ts +23 -0
- package/extensions/lib/deferred.ts +359 -25
- package/extensions/lib/dock-rows.ts +60 -0
- package/extensions/lib/empty-tool-result.ts +27 -0
- package/extensions/lib/environment-block.ts +76 -0
- package/extensions/lib/fetch-timeout.ts +24 -6
- package/extensions/{system-prompt → lib}/git-status.ts +51 -13
- package/extensions/lib/git.ts +75 -13
- package/extensions/lib/grammars/LICENSE-tree-sitter-bash +21 -0
- package/extensions/lib/grammars/README.md +2 -0
- package/extensions/lib/grammars/tree-sitter-bash.wasm +0 -0
- package/extensions/lib/guide-docs.ts +45 -0
- package/extensions/lib/headless-output.ts +46 -0
- package/extensions/lib/hook-gate.ts +7 -7
- package/extensions/lib/interrupt.ts +20 -4
- package/extensions/lib/key-input.ts +455 -0
- package/extensions/lib/keys.ts +14 -1
- package/extensions/lib/ledger/fold-memo.ts +49 -0
- package/extensions/lib/ledger/fold.ts +265 -0
- package/extensions/lib/ledger/layout.ts +72 -0
- package/extensions/lib/ledger/plan.ts +102 -0
- package/extensions/lib/ledger/records.ts +276 -0
- package/extensions/lib/ledger/state.ts +47 -0
- package/extensions/lib/ledger/validate.ts +141 -0
- package/extensions/lib/ledger/wire.ts +632 -0
- package/extensions/lib/local-command.ts +71 -19
- package/extensions/lib/mcp-overrides.ts +1 -1
- package/extensions/lib/mcp-share.ts +46 -0
- package/extensions/lib/memory-content.ts +146 -0
- package/extensions/lib/memory-index.ts +18 -0
- package/extensions/lib/memory.ts +134 -123
- package/extensions/lib/model-catalog/huggingface.json +178 -0
- package/extensions/lib/model-catalog/models-dev.json +18533 -0
- package/extensions/lib/model-catalog/openrouter.json +5050 -0
- package/extensions/lib/model-catalog-data.ts +513 -0
- package/extensions/lib/model-catalog.ts +462 -0
- package/extensions/lib/model-choice-warnings.ts +137 -0
- package/extensions/lib/model-pairings.ts +152 -0
- package/extensions/{auto-mode → lib}/model-picker.ts +26 -43
- package/extensions/lib/model-policy.ts +112 -15
- package/extensions/lib/model-tier.ts +283 -355
- package/extensions/lib/model-unusable.ts +1 -1
- package/extensions/lib/newer-model.ts +100 -0
- package/extensions/lib/notices.ts +87 -0
- package/extensions/lib/notifications.ts +357 -73
- package/extensions/lib/one-code-settings.ts +74 -8
- package/extensions/lib/open-browser.ts +63 -0
- package/extensions/lib/openrouter-generation.ts +94 -0
- package/extensions/lib/operation-deadline.ts +30 -0
- package/extensions/lib/original-command.ts +4 -4
- package/extensions/lib/package-version.ts +1 -1
- package/extensions/lib/panel-focus.ts +134 -0
- package/extensions/lib/paths.ts +17 -2
- package/extensions/lib/permission-gate.ts +72 -6
- package/extensions/lib/persisted-output.ts +60 -8
- package/extensions/lib/pi-ai-estimate.ts +19 -3
- package/extensions/lib/pi-version.ts +38 -2
- package/extensions/lib/plan-mode-channels.ts +42 -5
- package/extensions/lib/plugins.ts +26 -17
- package/extensions/lib/powershell-parse-script.ts +208 -0
- package/extensions/lib/powershell-parser.ts +344 -0
- package/extensions/lib/previous-mark.ts +101 -0
- package/extensions/lib/process-state.ts +48 -0
- package/extensions/lib/process-tree.ts +132 -8
- package/extensions/lib/prompt-options.ts +82 -0
- package/extensions/lib/queued-delivery.ts +44 -0
- package/extensions/lib/reminders.ts +370 -358
- package/extensions/lib/replaced-builtins.mjs +199 -0
- package/extensions/lib/replay-call.ts +70 -0
- package/extensions/lib/request-replay.ts +547 -0
- package/extensions/lib/scratchpad.ts +81 -14
- package/extensions/lib/send-now-channel.ts +7 -0
- package/extensions/lib/session-model-tier.ts +51 -0
- package/extensions/lib/session-work.ts +64 -0
- package/extensions/lib/settings-channels.ts +4 -4
- package/extensions/lib/shell-exit-semantics.ts +170 -0
- package/extensions/lib/shell-quote.ts +11 -0
- package/extensions/lib/shell-result.ts +70 -0
- package/extensions/lib/shell-spawn.ts +70 -6
- package/extensions/lib/shell-tool.ts +75 -25
- package/extensions/lib/side-call-cache.ts +124 -0
- package/extensions/lib/side-call-run.ts +96 -0
- package/extensions/lib/side-call-usage.ts +38 -0
- package/extensions/lib/side-call.ts +24 -1
- package/extensions/lib/single-flight.ts +18 -0
- package/extensions/lib/skill-body.ts +42 -0
- package/extensions/lib/skill-scan.ts +63 -24
- package/extensions/lib/spill-file.ts +140 -0
- package/extensions/lib/subagent-handback.ts +112 -0
- package/extensions/lib/system-role.ts +156 -0
- package/extensions/lib/terminal-text.ts +114 -0
- package/extensions/lib/text-width.ts +47 -16
- package/extensions/lib/timer-ops.ts +20 -0
- package/extensions/lib/tool-additions.ts +129 -0
- package/extensions/lib/tool-call-corruption.ts +134 -0
- package/extensions/lib/tool-path.ts +66 -0
- package/extensions/lib/tool-variants.ts +69 -0
- package/extensions/lib/tui-render.ts +255 -27
- package/extensions/lib/turn-budget-layout.ts +159 -0
- package/extensions/lib/update-check.mjs +15 -2
- package/extensions/lib/usage-bus.ts +1 -1
- package/extensions/lib/user-denial.ts +38 -0
- package/extensions/lib/workspace-channel.ts +16 -0
- package/extensions/lib/worktree-channel.ts +31 -3
- package/extensions/lib/worktree-isolation.ts +40 -10
- package/extensions/lsp/client.ts +8 -9
- package/extensions/lsp/index.ts +76 -12
- package/extensions/lsp/keep-alive.ts +1 -1
- package/extensions/lsp/trust.ts +119 -0
- package/extensions/lsp/watcher.ts +1 -1
- package/extensions/mcp/announce.ts +90 -43
- package/extensions/mcp/client.ts +161 -48
- package/extensions/mcp/config.ts +132 -8
- package/extensions/mcp/discovery.ts +19 -0
- package/extensions/mcp/index.ts +220 -121
- package/extensions/mcp/oauth/browser.ts +38 -17
- package/extensions/mcp/oauth/flow.ts +25 -17
- package/extensions/mcp/oauth/provider.ts +14 -8
- package/extensions/mcp/oauth/store.ts +34 -16
- package/extensions/mcp/panel/keys.ts +12 -11
- package/extensions/mcp/panel/render.ts +9 -6
- package/extensions/mcp/schema.ts +104 -5
- package/extensions/mcp/trust.ts +164 -73
- package/extensions/memory/entries.ts +23 -14
- package/extensions/memory/index.ts +134 -28
- package/extensions/memory/open-external.ts +33 -18
- package/extensions/memory/panel.ts +135 -26
- package/extensions/model-default/index.ts +86 -19
- package/extensions/newer-model/index.ts +31 -0
- package/extensions/notebook/description.ts +18 -0
- package/extensions/notebook/index.ts +6 -5
- package/extensions/notebook/notebook.ts +1 -1
- package/extensions/permissions/index.ts +1426 -398
- package/extensions/permissions/matcher.ts +425 -74
- package/extensions/permissions/modes.ts +11 -4
- package/extensions/permissions/panel/host.ts +130 -0
- package/extensions/permissions/panel/keys.ts +48 -0
- package/extensions/permissions/panel/render.ts +450 -0
- package/extensions/permissions/panel/state.ts +550 -0
- package/extensions/permissions/powershell-cmdlets.ts +198 -0
- package/extensions/permissions/powershell-paths.ts +197 -0
- package/extensions/permissions/powershell-rules.ts +207 -280
- package/extensions/permissions/powershell-tree.ts +557 -0
- package/extensions/permissions/project-trust.ts +27 -11
- package/extensions/permissions/protected-paths.ts +14 -2
- package/extensions/permissions/session-grant.ts +6 -0
- package/extensions/permissions/settings.ts +166 -31
- package/extensions/permissions/subagent-gate.ts +25 -0
- package/extensions/permissions/workspace.ts +78 -0
- package/extensions/plan-mode/index.ts +276 -92
- package/extensions/plan-mode/reminder.ts +89 -21
- package/extensions/plan-mode/run-state.ts +26 -0
- package/extensions/plan-mode/texts.ts +177 -0
- package/extensions/plan-mode/viewer.ts +92 -27
- package/extensions/plugins/counts.ts +3 -3
- package/extensions/plugins/index.ts +64 -46
- package/extensions/plugins/install/install.ts +16 -0
- package/extensions/plugins/marketplace/sync.ts +9 -3
- package/extensions/plugins/marketplace/types.ts +3 -1
- package/extensions/plugins/panel/keys.ts +21 -24
- package/extensions/plugins/panel/render.ts +12 -6
- package/extensions/plugins/shell-expand.ts +107 -0
- package/extensions/plugins/template.ts +32 -15
- package/extensions/powershell/child.ts +7 -0
- package/extensions/powershell/description.ts +38 -6
- package/extensions/powershell/guards.ts +1 -1
- package/extensions/powershell/index.ts +14 -7
- package/extensions/recap/index.ts +73 -71
- package/extensions/recap/prompt.ts +2 -2
- package/extensions/recap/scheduler.ts +3 -5
- package/extensions/search-tools/grep-merge.ts +39 -0
- package/extensions/search-tools/index.ts +0 -0
- package/extensions/send-now/chord.ts +62 -0
- package/extensions/send-now/index.ts +133 -0
- package/extensions/session-title/index.ts +3 -0
- package/extensions/session-title/title.ts +4 -1
- package/extensions/skill/announce.ts +30 -0
- package/extensions/skill/code-review.ts +97 -0
- package/extensions/skill/index.ts +469 -132
- package/extensions/skill/invoke.ts +118 -75
- package/extensions/skill/listing.ts +133 -9
- package/extensions/skill/panel/keys.ts +15 -16
- package/extensions/skill/panel/render.ts +5 -2
- package/extensions/skill/panel/state.ts +12 -1
- package/extensions/subagents/agent-args.ts +39 -0
- package/extensions/subagents/agent-description.ts +132 -0
- package/extensions/subagents/agents.ts +146 -31
- package/extensions/subagents/default-model.ts +2 -3
- package/extensions/subagents/delegation-steer.ts +4 -4
- package/extensions/subagents/fork-cache.ts +82 -0
- package/extensions/subagents/guide-agent.ts +189 -0
- package/extensions/subagents/hand-back-review.ts +3 -0
- package/extensions/subagents/index.ts +1594 -852
- package/extensions/subagents/live-runs.ts +26 -6
- package/extensions/subagents/model-select.ts +38 -25
- package/extensions/subagents/outcome.ts +5 -2
- package/extensions/subagents/panel-keys.ts +73 -31
- package/extensions/subagents/panel-render.ts +120 -96
- package/extensions/subagents/panel-widget.ts +60 -89
- package/extensions/subagents/parent-mode.ts +50 -0
- package/extensions/subagents/pending-claim.ts +18 -1
- package/extensions/subagents/runner.ts +135 -80
- package/extensions/subagents/runs.ts +44 -5
- package/extensions/subagents/send-to-main-tool.ts +1 -1
- package/extensions/subagents/session-turns.ts +32 -8
- package/extensions/subagents/shell-panel.ts +36 -178
- package/extensions/subagents/tasks-dialog.ts +170 -0
- package/extensions/subagents/viewport-mirror.ts +95 -0
- package/extensions/subagents/worktree.ts +57 -13
- package/extensions/system-prompt/environment.ts +19 -19
- package/extensions/system-prompt/idle-turn.ts +65 -0
- package/extensions/system-prompt/index.ts +165 -47
- package/extensions/system-prompt/template.ts +34 -51
- package/extensions/system-prompt/tiers/common.ts +23 -64
- package/extensions/system-prompt/tiers/frontier.ts +32 -11
- package/extensions/system-prompt/tiers/low.ts +67 -45
- package/extensions/system-prompt/tiers/mid.ts +96 -38
- package/extensions/system-reminder/index.ts +204 -70
- package/extensions/tasks/descriptions.ts +190 -0
- package/extensions/tasks/index.ts +120 -41
- package/extensions/tasks/store.ts +83 -16
- package/extensions/tool-call-corruption/child.ts +7 -0
- package/extensions/tool-call-corruption/index.ts +237 -0
- package/extensions/tool-search/index.ts +366 -144
- package/extensions/tool-style/index.ts +68 -10
- package/extensions/tool-style/write-description.ts +40 -0
- package/extensions/tool-style/write-render.ts +237 -0
- package/extensions/turn-duration/index.ts +7 -3
- package/extensions/turn-duration/line.ts +47 -4
- package/extensions/web/backends.ts +6 -9
- package/extensions/web/description.ts +50 -0
- package/extensions/web/index.ts +118 -53
- package/extensions/web/native-call.ts +15 -0
- package/extensions/web/native-results.ts +41 -0
- package/extensions/web-fetch/description.ts +42 -0
- package/extensions/web-fetch/extract.ts +53 -6
- package/extensions/web-fetch/index.ts +125 -76
- package/extensions/web-fetch/page-content.ts +19 -0
- package/extensions/web-fetch/response.ts +49 -0
- package/extensions/web-fetch/summarize.ts +9 -10
- package/extensions/workflow/agent-session.ts +108 -18
- package/extensions/workflow/args.ts +24 -0
- package/extensions/workflow/description.ts +67 -0
- package/extensions/workflow/globals.ts +17 -3
- package/extensions/workflow/index.ts +157 -162
- package/extensions/workflow/records.ts +1 -0
- package/extensions/workflow/run-manager.ts +33 -6
- package/extensions/workflow/saved-workflows.ts +3 -2
- package/extensions/workflow/types.ts +22 -1
- package/extensions/workflow/viewer.ts +54 -24
- package/extensions/workflow/widget.ts +20 -0
- package/extensions/worktree/descriptions.ts +91 -0
- package/extensions/worktree/guards.ts +316 -54
- package/extensions/worktree/index.ts +162 -44
- package/extensions/worktree/powershell-guards.ts +167 -0
- package/extensions/worktree/rewrite.ts +14 -16
- package/package.json +21 -7
- package/skills/artifact-design/SKILL.md +85 -0
- package/skills/code-review/SKILL.md +20 -20
- package/skills/code-review/cells/arguments-and-flags.md +19 -0
- package/skills/code-review/cells/high-3x5-recall-verify.md +137 -0
- package/skills/code-review/cells/high-8-inline.md +122 -0
- package/skills/code-review/cells/low-1-pass-max4.md +27 -0
- package/skills/code-review/cells/low-1-pass-min-files-4.md +28 -0
- package/skills/code-review/cells/max-5x5-verify-sweep.md +162 -0
- package/skills/code-review/cells/medium-3x5-verify.md +132 -0
- package/skills/code-review/cells/minimal-prompt.md +32 -0
- package/skills/code-review/cells/xhigh-10-inline-sweep.md +149 -0
- package/skills/code-review/cells/xhigh-5x5-verify-sweep.md +162 -0
- package/skills/fewer-permission-prompts/SKILL.md +1 -1
- package/skills/loop/SKILL.md +11 -0
- package/skills/security-review/SKILL.md +2 -5
- package/skills/simplify/SKILL.md +7 -5
- package/skills/workflow-authoring/SKILL.md +143 -0
- package/themes/onecode-light.json +1 -1
- package/themes/onecode.json +1 -1
- package/types/app.d.ts +58 -0
- package/types/community-packages.d.ts +26 -1
- package/extensions/auto-mode/recoverability.ts +0 -229
- package/extensions/lib/capability-index.ts +0 -466
- package/extensions/lib/model-facts.generated.json +0 -2675
- package/extensions/lib/model-facts.ts +0 -162
- package/extensions/tool-search/announce.ts +0 -42
|
@@ -1,43 +1,72 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* claude-context extension — assembles Claude Code's
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
2
|
+
* claude-context extension — assembles Claude Code's three first-message context
|
|
3
|
+
* reminders and queues them `first-prepend` (lib/claude-context.ts has the
|
|
4
|
+
* formats): the instructions block (CLAUDE.md files + MEMORY.md index) at
|
|
5
|
+
* CONTEXT_ORDER.claudeMd, the context block (userEmail + the git snapshot) at
|
|
6
|
+
* CONTEXT_ORDER.context, and the date at CONTEXT_ORDER.date, which on a model
|
|
7
|
+
* that takes a mid-conversation system message rides that message instead
|
|
8
|
+
* (system-reminder, lib/system-role.ts). They are live state: a request that
|
|
9
|
+
* opens an epoch renders them, and every later request in the epoch replays
|
|
10
|
+
* them from the ledger's record (extensions/ledger). The blocks carry ledger
|
|
11
|
+
* facts (lib/context-facts.ts), so the first request of a resumed process says
|
|
12
|
+
* once what changed in the workspace since, and a session that crosses local
|
|
13
|
+
* midnight learns the new date, both on the request's tail.
|
|
12
14
|
*
|
|
13
15
|
* When ONECODE.md files exist, this extension also emits a separate `# oneCodeMd`
|
|
14
|
-
* block at CONTEXT_ORDER.oneCodeMd — after
|
|
15
|
-
* instructions take precedence over CLAUDE.md. Keeping them out
|
|
16
|
-
*
|
|
16
|
+
* block at CONTEXT_ORDER.oneCodeMd — after the instructions block, so One
|
|
17
|
+
* Code-specific instructions take precedence over CLAUDE.md. Keeping them out
|
|
18
|
+
* of that block leaves it byte-exact with Claude Code.
|
|
17
19
|
*
|
|
18
20
|
* Paths are re-derived from home/cwd here rather than shared with the memory
|
|
19
|
-
* extension (jiti gives each extension its own module instance).
|
|
20
|
-
* longer put in the system prompt, and MEMORY.md is no longer a separate reminder
|
|
21
|
-
* — both fold into this one block, as Claude Code does.
|
|
21
|
+
* extension (jiti gives each extension its own module instance).
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
24
|
import { execFileSync } from "node:child_process";
|
|
25
25
|
import { readFileSync } from "node:fs";
|
|
26
26
|
import os from "node:os";
|
|
27
|
-
import {
|
|
28
|
-
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
29
|
-
import {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
import { dirname } from "node:path";
|
|
28
|
+
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
29
|
+
import {
|
|
30
|
+
buildClaudeMdBlock,
|
|
31
|
+
buildContextBlock,
|
|
32
|
+
buildOneCodeBlock,
|
|
33
|
+
collectImportedPaths,
|
|
34
|
+
dateBlock,
|
|
35
|
+
dateChangeReminder,
|
|
36
|
+
discoverContextFiles,
|
|
37
|
+
discoverOneCodeFiles,
|
|
38
|
+
externalInstructionIncludes,
|
|
39
|
+
localDate,
|
|
40
|
+
instructionRule,
|
|
41
|
+
nestedInstructionFiles,
|
|
42
|
+
nestedInstructionText,
|
|
43
|
+
} from "../lib/claude-context.ts";
|
|
44
|
+
import { collectGitStatus, GIT_SNAPSHOT_OWNER_CHANNEL } from "../lib/git-status.ts";
|
|
45
|
+
import { readMemoryIndex } from "../lib/memory-index.ts";
|
|
46
|
+
import { claudeConfigDir, oneCodeStateDir, tryRealpath } from "../lib/paths.ts";
|
|
47
|
+
import { CONTEXT_ORDER, REMINDER_CHANNEL, RENDER_CHANNEL, type RenderRequest, toldBlockFact } from "../lib/reminders.ts";
|
|
48
|
+
import { inContextEntries } from "../lib/compaction-boundary.ts";
|
|
49
|
+
import { compactionGitStatus, contextBlockFacts, contextFingerprints, dateFingerprint, FACT_KEYS, instructionFacts, liveFingerprints, type LiveFingerprints, resumeFactsNotice } from "../lib/context-facts.ts";
|
|
50
|
+
import { resolveToolPath } from "../lib/tool-path.ts";
|
|
51
|
+
import { sessionWorkCwd, WORKTREE_CHANNEL, type WorktreeLocation } from "../lib/worktree-channel.ts";
|
|
52
|
+
import { pathArgument } from "../auto-mode/paths.ts";
|
|
53
|
+
import { HARNESS_GIT_CONFIG } from "../lib/git.ts";
|
|
54
|
+
import { EXTERNAL_INCLUDES_NO, EXTERNAL_INCLUDES_NONE, EXTERNAL_INCLUDES_SETTING, EXTERNAL_INCLUDES_YES, externalIncludesDialog, persistExternalIncludesApproval, readExternalIncludesApproval } from "../lib/claude-external-includes.ts";
|
|
55
|
+
import { registerLocalCommand } from "../lib/local-command.ts";
|
|
56
|
+
import { consentDialog, installConsentDialogs, startupConsentReady } from "../lib/consent-dialogs.ts";
|
|
57
|
+
import type { ToldFact } from "../lib/ledger/records.ts";
|
|
58
|
+
import { foldSession } from "../lib/ledger/fold-memo.ts";
|
|
59
|
+
import { sessionIdentity } from "../lib/anthropic-auth.ts";
|
|
33
60
|
|
|
34
61
|
const REMINDER_KEY = "claude-context";
|
|
35
62
|
const ONECODE_REMINDER_KEY = "one-code-context";
|
|
63
|
+
const CONTEXT_REMINDER_KEY = "claude-context-context";
|
|
64
|
+
const DATE_REMINDER_KEY = "claude-context-date";
|
|
36
65
|
|
|
37
66
|
/** The account email Claude Code stamps as `# userEmail`. git config is our proxy. */
|
|
38
67
|
function resolveEmail(cwd: string): string | null {
|
|
39
68
|
try {
|
|
40
|
-
const email = execFileSync("git", ["config", "user.email"], { cwd, encoding: "utf8" }).trim();
|
|
69
|
+
const email = execFileSync("git", [...HARNESS_GIT_CONFIG, "config", "user.email"], { cwd, encoding: "utf8" }).trim();
|
|
41
70
|
if (email) return email;
|
|
42
71
|
} catch {
|
|
43
72
|
// no git / no config — fall through
|
|
@@ -45,64 +74,408 @@ function resolveEmail(cwd: string): string | null {
|
|
|
45
74
|
return process.env.GIT_AUTHOR_EMAIL?.trim() || process.env.EMAIL?.trim() || null;
|
|
46
75
|
}
|
|
47
76
|
|
|
48
|
-
function
|
|
49
|
-
const dir = projectMemoryDir(cwd, os.homedir());
|
|
50
|
-
const path = join(dir, "MEMORY.md");
|
|
77
|
+
function readOrEmpty(path: string): string {
|
|
51
78
|
try {
|
|
52
|
-
|
|
53
|
-
if (!raw.trim()) return null;
|
|
54
|
-
return { path, content: truncateIndex(raw) };
|
|
79
|
+
return readFileSync(path, "utf8");
|
|
55
80
|
} catch {
|
|
56
|
-
return
|
|
81
|
+
return "";
|
|
57
82
|
}
|
|
58
83
|
}
|
|
59
84
|
|
|
85
|
+
/** A tool result and the nested instruction files it carried into context (`remember`). */
|
|
86
|
+
const NESTED_SHOWN_ENTRY = "one-code:nested-instructions-shown";
|
|
87
|
+
|
|
60
88
|
export default function claudeContextExtension(pi: ExtensionAPI) {
|
|
61
|
-
pi.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
89
|
+
const resetConsentDialogs = installConsentDialogs(pi.events);
|
|
90
|
+
/** The account email stand-in, resolved at session start. */
|
|
91
|
+
let email: string | null = null;
|
|
92
|
+
/** Claude Code's git snapshot, taken once at the conversation's first turn; undefined until then. */
|
|
93
|
+
let gitStatus: string | null | undefined;
|
|
94
|
+
/**
|
|
95
|
+
* Only the main session takes the snapshot, as before it moved here: its
|
|
96
|
+
* system-prompt extension (never loaded in a child) claims it at session
|
|
97
|
+
* start. A subagent or workflow agent would otherwise run its own git
|
|
98
|
+
* commands, synchronously on the shared event loop, for every child.
|
|
99
|
+
*/
|
|
100
|
+
let takesGitSnapshot = false;
|
|
101
|
+
pi.events.on(GIT_SNAPSHOT_OWNER_CHANNEL, () => {
|
|
102
|
+
takesGitSnapshot = true;
|
|
103
|
+
});
|
|
104
|
+
/** The date the live date block carries. */
|
|
105
|
+
let blockDate = "";
|
|
106
|
+
/**
|
|
107
|
+
* Instruction files in context, by real path: the startup block's files and
|
|
108
|
+
* their imports (`startupShown`, fixed for the session), plus nested files
|
|
109
|
+
* attached, their imports, and files the model read itself.
|
|
110
|
+
*/
|
|
111
|
+
let startupShown = new Set<string>();
|
|
112
|
+
let attachedNested = new Set<string>();
|
|
113
|
+
/** Where a nested instruction actually landed: a persisted result or a pinned request tail. */
|
|
114
|
+
const shownByResult = new Map<string, Set<string>>();
|
|
115
|
+
const remember = (toolCallId: string | undefined, keys: Iterable<string>) => {
|
|
116
|
+
if (!toolCallId) return;
|
|
117
|
+
const shown = shownByResult.get(toolCallId) ?? new Set<string>();
|
|
118
|
+
const before = shown.size;
|
|
119
|
+
for (const key of keys) shown.add(key);
|
|
120
|
+
if (shown.size === before) return;
|
|
121
|
+
shownByResult.set(toolCallId, shown);
|
|
122
|
+
// Recorded on the branch, so a resume or a /tree switch knows what is already in context.
|
|
123
|
+
pi.appendEntry(NESTED_SHOWN_ENTRY, { toolCallId, keys: [...shown] });
|
|
124
|
+
};
|
|
125
|
+
/** Rebuild what the branch's own results showed (a resume, a /tree switch), then keep what is still in context. */
|
|
126
|
+
const restoreAttachments = (ctx: ExtensionContext) => {
|
|
127
|
+
shownByResult.clear();
|
|
128
|
+
for (const entry of ctx.sessionManager.getBranch() as { type: string; customType?: string; data?: unknown }[]) {
|
|
129
|
+
if (entry.type !== "custom" || entry.customType !== NESTED_SHOWN_ENTRY) continue;
|
|
130
|
+
const data = entry.data as { toolCallId?: unknown; keys?: unknown } | undefined;
|
|
131
|
+
if (typeof data?.toolCallId !== "string" || !Array.isArray(data.keys)) continue;
|
|
132
|
+
shownByResult.set(data.toolCallId, new Set(data.keys.filter((key): key is string => typeof key === "string")));
|
|
133
|
+
}
|
|
134
|
+
keepRetainedAttachments(ctx);
|
|
135
|
+
};
|
|
136
|
+
const keepRetainedAttachments = (ctx: ExtensionContext) => {
|
|
137
|
+
attachedNested = new Set(startupShown);
|
|
138
|
+
const kept = new Set(inContextEntries(ctx.sessionManager.getBranch()).flatMap((entry) =>
|
|
139
|
+
entry.type === "message" && entry.message.role === "toolResult" ? [entry.message.toolCallId] : [],
|
|
140
|
+
));
|
|
141
|
+
for (const [id, keys] of shownByResult) {
|
|
142
|
+
if (kept.has(id)) for (const key of keys) attachedNested.add(key);
|
|
143
|
+
else shownByResult.delete(id);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
/** The entered worktree: reads there resolve below its root, not the session's original directory. */
|
|
147
|
+
let entered: WorktreeLocation | undefined;
|
|
148
|
+
pi.events.on(WORKTREE_CHANNEL, (data) => {
|
|
149
|
+
const location = data as WorktreeLocation | null | undefined;
|
|
150
|
+
entered = location?.path ? location : undefined;
|
|
151
|
+
});
|
|
152
|
+
/** The instruction rule, read with the startup block (it is settings, read once a session). */
|
|
153
|
+
let rule: ReturnType<typeof instructionRule> | undefined;
|
|
154
|
+
let includeExternal = false;
|
|
155
|
+
let approvalPending: Promise<void> | undefined;
|
|
156
|
+
let approvalAbort = new AbortController();
|
|
157
|
+
let sessionGeneration = 0;
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* The instructions facts while no instructions block renders (no CLAUDE.md,
|
|
161
|
+
* no memory index): they ride the date block, so an epoch still tells the
|
|
162
|
+
* absence and a resume notices a file that appeared since.
|
|
163
|
+
*/
|
|
164
|
+
let absentInstructionFacts: ToldFact[] = [];
|
|
165
|
+
const emitDate = (date: string) => {
|
|
166
|
+
blockDate = date;
|
|
167
|
+
pi.events.emit(REMINDER_CHANNEL, {
|
|
168
|
+
text: dateBlock(date),
|
|
169
|
+
key: DATE_REMINDER_KEY,
|
|
170
|
+
placement: "first-prepend",
|
|
171
|
+
order: CONTEXT_ORDER.date,
|
|
172
|
+
facts: [toldBlockFact(FACT_KEYS.date, date), ...absentInstructionFacts],
|
|
79
173
|
});
|
|
80
|
-
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* The live workspace's fingerprints, taken at this process's first turn, for
|
|
178
|
+
* the resumed-session check, in each directory the epoch's facts may have
|
|
179
|
+
* been read in: the session's own at its start, the entered worktree at a
|
|
180
|
+
* compaction (session_compact reads there).
|
|
181
|
+
*/
|
|
182
|
+
let livePrints: { atStart: LiveFingerprints; atCompaction: () => LiveFingerprints } | undefined;
|
|
183
|
+
/** True until this process's first request inside an epoch has compared the epoch's facts with the live workspace. */
|
|
184
|
+
let resumeCheck = true;
|
|
185
|
+
const readFiles = (cwd: string) => {
|
|
186
|
+
const oneCodeFiles = discoverOneCodeFiles({ cwd, homeOneCodeDir: oneCodeStateDir(), home: os.homedir(), includeExternal });
|
|
187
|
+
return {
|
|
188
|
+
contextFiles: discoverContextFiles({ cwd, homeClaudeDir: claudeConfigDir(), rule: instructionRule(os.homedir()), home: os.homedir(), includeExternal }),
|
|
189
|
+
memoryIndex: readMemoryIndex(cwd),
|
|
190
|
+
oneCodeFiles,
|
|
191
|
+
oneCode: buildOneCodeBlock(oneCodeFiles),
|
|
192
|
+
};
|
|
193
|
+
};
|
|
194
|
+
let files: ReturnType<typeof readFiles> | undefined;
|
|
195
|
+
const adoptFiles = (current: ReturnType<typeof readFiles>) => {
|
|
196
|
+
files = current;
|
|
197
|
+
rule = instructionRule(os.homedir());
|
|
198
|
+
};
|
|
199
|
+
/**
|
|
200
|
+
* The files message 1 carries (or imports): never attached again on a read.
|
|
201
|
+
* Taken when an epoch renders the blocks; a resumed epoch's are taken from
|
|
202
|
+
* the live files at start, the closest knowledge this process has.
|
|
203
|
+
*/
|
|
204
|
+
const adoptShown = (current: ReturnType<typeof readFiles>) => {
|
|
205
|
+
startupShown = new Set([...current.contextFiles, ...current.oneCodeFiles].flatMap((file) =>
|
|
206
|
+
[file.path, ...(file.imported ?? collectImportedPaths(readOrEmpty(file.path), dirname(file.path), { home: os.homedir() }))],
|
|
207
|
+
).map((path) => tryRealpath(path) ?? path));
|
|
208
|
+
for (const path of startupShown) attachedNested.add(path);
|
|
209
|
+
};
|
|
210
|
+
const snapshotGit = (cwd: string) => {
|
|
211
|
+
const tools = pi.getActiveTools();
|
|
212
|
+
const shellTool = tools.includes("powershell") && !tools.includes("bash") ? "powershell" : "bash";
|
|
213
|
+
return takesGitSnapshot ? collectGitStatus(cwd, undefined, shellTool) : null;
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
const externalPaths = (cwd: string) => externalInstructionIncludes({ cwd, homeClaudeDir: claudeConfigDir(), rule: instructionRule(os.homedir()), home: os.homedir() });
|
|
217
|
+
const saveApproval = (ctx: ExtensionContext, approved: boolean) => {
|
|
218
|
+
includeExternal = approved;
|
|
219
|
+
try { persistExternalIncludesApproval(ctx.cwd, os.homedir(), approved); }
|
|
220
|
+
catch (error) { ctx.ui.notify(`Could not remember external CLAUDE.md include approval: ${String(error)}`, "error"); }
|
|
221
|
+
};
|
|
222
|
+
/**
|
|
223
|
+
* The instructions and ONECODE.md blocks as live state, read in `cwd`. They
|
|
224
|
+
* render when an epoch opens; inside one, message 1 is the record, so a
|
|
225
|
+
* change here (a /config approval, an edited file) shows at the next epoch.
|
|
226
|
+
*/
|
|
227
|
+
const emitInstructions = (current: ReturnType<typeof readFiles>) => {
|
|
228
|
+
const instructions = buildClaudeMdBlock(current);
|
|
229
|
+
if (instructions) {
|
|
81
230
|
pi.events.emit(REMINDER_CHANNEL, {
|
|
82
|
-
text:
|
|
83
|
-
scope: "every-turn",
|
|
231
|
+
text: instructions,
|
|
84
232
|
key: REMINDER_KEY,
|
|
85
233
|
placement: "first-prepend",
|
|
86
234
|
order: CONTEXT_ORDER.claudeMd,
|
|
87
|
-
|
|
88
|
-
suffix: "\n\n",
|
|
235
|
+
facts: instructionFacts(contextFingerprints(current)),
|
|
89
236
|
});
|
|
237
|
+
} else pi.events.emit(REMINDER_CHANNEL, { remove: true, key: REMINDER_KEY });
|
|
238
|
+
const absent = instructions ? [] : instructionFacts(contextFingerprints(current));
|
|
239
|
+
if (JSON.stringify(absent) !== JSON.stringify(absentInstructionFacts)) {
|
|
240
|
+
absentInstructionFacts = absent;
|
|
241
|
+
if (blockDate) emitDate(blockDate);
|
|
90
242
|
}
|
|
91
|
-
|
|
92
|
-
//
|
|
93
|
-
|
|
94
|
-
const oneCode = buildOneCodeBlock(
|
|
95
|
-
discoverOneCodeFiles({ cwd: ctx.cwd, homeOneCodeDir: oneCodeStateDir(), home: os.homedir() }),
|
|
96
|
-
);
|
|
97
|
-
if (oneCode) {
|
|
243
|
+
// One Code's own instructions ride in a separate block AFTER the instructions
|
|
244
|
+
// block, so they take precedence over CLAUDE.md (higher order = closer to the user text).
|
|
245
|
+
if (current.oneCode) {
|
|
98
246
|
pi.events.emit(REMINDER_CHANNEL, {
|
|
99
|
-
text: oneCode,
|
|
100
|
-
scope: "every-turn",
|
|
247
|
+
text: current.oneCode,
|
|
101
248
|
key: ONECODE_REMINDER_KEY,
|
|
102
249
|
placement: "first-prepend",
|
|
103
250
|
order: CONTEXT_ORDER.oneCodeMd,
|
|
104
|
-
suffix: "\n\n",
|
|
105
251
|
});
|
|
252
|
+
} else pi.events.emit(REMINDER_CHANNEL, { remove: true, key: ONECODE_REMINDER_KEY });
|
|
253
|
+
};
|
|
254
|
+
const emitContextBlock = (gitText: string | null, atCompaction: boolean) => {
|
|
255
|
+
const context = buildContextBlock({ email, gitStatus: gitText });
|
|
256
|
+
if (!context) {
|
|
257
|
+
pi.events.emit(REMINDER_CHANNEL, { remove: true, key: CONTEXT_REMINDER_KEY });
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
pi.events.emit(REMINDER_CHANNEL, {
|
|
261
|
+
text: context,
|
|
262
|
+
key: CONTEXT_REMINDER_KEY,
|
|
263
|
+
placement: "first-prepend",
|
|
264
|
+
order: CONTEXT_ORDER.context,
|
|
265
|
+
facts: contextBlockFacts(gitStatus ?? null, atCompaction),
|
|
266
|
+
});
|
|
267
|
+
};
|
|
268
|
+
const refreshInstructions = (cwd: string) => {
|
|
269
|
+
const current = readFiles(cwd);
|
|
270
|
+
adoptFiles(current);
|
|
271
|
+
emitInstructions(current);
|
|
272
|
+
};
|
|
273
|
+
const askApproval = async (ctx: ExtensionContext, paths: string[], afterStartup = false) => {
|
|
274
|
+
const gen = sessionGeneration;
|
|
275
|
+
const signal = approvalAbort.signal;
|
|
276
|
+
// No is first and focused, as in Claude Code. Escape is also a remembered no;
|
|
277
|
+
// a shutdown/superseded session is not an answer at all.
|
|
278
|
+
const choice = await consentDialog(pi.events, () => ctx.ui.select(externalIncludesDialog(paths, os.homedir()), [EXTERNAL_INCLUDES_NO, EXTERNAL_INCLUDES_YES], { signal }), afterStartup);
|
|
279
|
+
if (signal.aborted || gen !== sessionGeneration) return;
|
|
280
|
+
saveApproval(ctx, choice === EXTERNAL_INCLUDES_YES);
|
|
281
|
+
refreshInstructions(ctx.cwd);
|
|
282
|
+
};
|
|
283
|
+
registerLocalCommand(pi, "config", {
|
|
284
|
+
description: "Configure external CLAUDE.md includes for this project",
|
|
285
|
+
reportsResult: true,
|
|
286
|
+
handler: async (_args, ctx) => {
|
|
287
|
+
if (!ctx.hasUI) {
|
|
288
|
+
const text = "/config requires an interactive UI to change external CLAUDE.md include approval.";
|
|
289
|
+
process.stderr.write(`${text}\n`);
|
|
290
|
+
return text;
|
|
291
|
+
}
|
|
292
|
+
const gen = sessionGeneration;
|
|
293
|
+
startupConsentReady(pi.events);
|
|
294
|
+
await approvalPending;
|
|
295
|
+
if (gen !== sessionGeneration || approvalAbort.signal.aborted) return;
|
|
296
|
+
const paths = externalPaths(ctx.cwd);
|
|
297
|
+
if (!paths.length) {
|
|
298
|
+
const text = EXTERNAL_INCLUDES_NONE;
|
|
299
|
+
ctx.ui.notify(text, "info");
|
|
300
|
+
return text;
|
|
301
|
+
}
|
|
302
|
+
const row = `${EXTERNAL_INCLUDES_SETTING}: ${includeExternal ? "true" : "false"}`;
|
|
303
|
+
const picked = await consentDialog(pi.events, () => ctx.ui.select("Config", [row], { signal: approvalAbort.signal }));
|
|
304
|
+
if (picked !== row || gen !== sessionGeneration || approvalAbort.signal.aborted) return;
|
|
305
|
+
if (includeExternal) {
|
|
306
|
+
saveApproval(ctx, false);
|
|
307
|
+
refreshInstructions(ctx.cwd);
|
|
308
|
+
} else await askApproval(ctx, paths);
|
|
309
|
+
// As in Claude Code, this changes future loads, never retracts text or
|
|
310
|
+
// rewrites the frozen first-message block after a request was sent.
|
|
311
|
+
return `${EXTERNAL_INCLUDES_SETTING}: ${includeExternal ? "true" : "false"}`;
|
|
312
|
+
},
|
|
313
|
+
});
|
|
314
|
+
const drainApproval = async () => { startupConsentReady(pi.events); await approvalPending; };
|
|
315
|
+
pi.on("before_agent_start", drainApproval);
|
|
316
|
+
pi.on("session_shutdown", () => {
|
|
317
|
+
resetConsentDialogs();
|
|
318
|
+
++sessionGeneration;
|
|
319
|
+
approvalAbort.abort();
|
|
320
|
+
approvalPending = undefined;
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
pi.on("session_start", (event, ctx) => {
|
|
324
|
+
resetConsentDialogs();
|
|
325
|
+
++sessionGeneration;
|
|
326
|
+
approvalAbort.abort();
|
|
327
|
+
approvalAbort = new AbortController();
|
|
328
|
+
approvalPending = undefined;
|
|
329
|
+
const approval = readExternalIncludesApproval(ctx.cwd, os.homedir());
|
|
330
|
+
includeExternal = approval.approved;
|
|
331
|
+
if ((event.reason ?? "startup") === "startup" && ctx.hasUI && !approval.approved && !approval.warningShown) {
|
|
332
|
+
const paths = externalPaths(ctx.cwd);
|
|
333
|
+
if (paths.length) {
|
|
334
|
+
// RPC installs its input reader only AFTER session_start returns.
|
|
335
|
+
// Queue after hooks/MCP consent; gate the first turn, not startup.
|
|
336
|
+
// A dialog that fails is no answer: nothing is approved or remembered, and the turn goes on.
|
|
337
|
+
approvalPending = askApproval(ctx, paths, true).catch(() => {});
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
// The instructions block carries the instruction files the mode and Claude
|
|
341
|
+
// Code's instructionFiles pick (lib/claude-context.ts instructionRule): by
|
|
342
|
+
// default the CLAUDE.md family, or the project's AGENTS.md files when it
|
|
343
|
+
// has no CLAUDE.md, byte-exact with Claude Code either way. ONECODE.md
|
|
344
|
+
// rides its own higher-precedence block.
|
|
345
|
+
refreshInstructions(ctx.cwd);
|
|
346
|
+
email = resolveEmail(ctx.cwd);
|
|
347
|
+
attachedNested = new Set();
|
|
348
|
+
if (files) adoptShown(files);
|
|
349
|
+
restoreAttachments(ctx);
|
|
350
|
+
// /clear and a resume re-fire session_start: this process takes its own snapshot.
|
|
351
|
+
gitStatus = undefined;
|
|
352
|
+
livePrints = undefined;
|
|
353
|
+
resumeCheck = true;
|
|
354
|
+
// The user's local date. Inside an epoch the block on message 1 is the
|
|
355
|
+
// record, so a later date rides a notice (the render step below).
|
|
356
|
+
emitDate(localDate());
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
// Claude Code snapshots git "at the start of the conversation": on the first
|
|
360
|
+
// turn, typed or opened from idle, never in session_start, so the several
|
|
361
|
+
// synchronous git spawns never delay the prompt opening (findings §15). The
|
|
362
|
+
// clip note names the shell tool the model has (PowerShell only without bash).
|
|
363
|
+
pi.on("turn_start", async (_event, ctx) => {
|
|
364
|
+
const gen = sessionGeneration;
|
|
365
|
+
await drainApproval();
|
|
366
|
+
if (gen !== sessionGeneration || approvalAbort.signal.aborted) return;
|
|
367
|
+
if (gitStatus !== undefined) return;
|
|
368
|
+
// A process that starts on a compacted branch before the compaction's
|
|
369
|
+
// epoch opened (/compact, then /reload) renders that epoch's message 1:
|
|
370
|
+
// the blocks are the compaction's, not the conversation start's (R3-L11).
|
|
371
|
+
// The fold is shared with tool-search and the ledger: one fold per branch state (lib/ledger/fold-memo.ts).
|
|
372
|
+
const fold = foldSession(ctx.sessionManager, sessionIdentity(pi, ctx.model));
|
|
373
|
+
if (fold.opensEpoch && fold.cause === "compaction") {
|
|
374
|
+
refreshForCompaction(ctx);
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
gitStatus = snapshotGit(ctx.cwd);
|
|
378
|
+
if (files) {
|
|
379
|
+
const atStart = liveFingerprints(files, gitStatus, takesGitSnapshot);
|
|
380
|
+
const workCwd = sessionWorkCwd(entered, ctx.cwd);
|
|
381
|
+
// The entered worktree's, read only if the epoch's facts came from a compaction there.
|
|
382
|
+
let inWorktree: LiveFingerprints | undefined;
|
|
383
|
+
const atCompaction = () => (inWorktree ??= liveFingerprints(readFiles(workCwd), snapshotGit(workCwd), takesGitSnapshot));
|
|
384
|
+
livePrints = { atStart, atCompaction: workCwd === ctx.cwd ? () => atStart : atCompaction };
|
|
385
|
+
}
|
|
386
|
+
emitContextBlock(gitStatus, false);
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
// Inside an epoch, two facts can have moved since its message 1: the date (a
|
|
390
|
+
// session that crosses local midnight learns it, Claude Code's notice), and,
|
|
391
|
+
// on the first request of a resumed process, the workspace the instructions
|
|
392
|
+
// and git blocks describe. Each is said once, on the request's tail.
|
|
393
|
+
pi.events.on(RENDER_CHANNEL, (data) => {
|
|
394
|
+
const request = data as RenderRequest;
|
|
395
|
+
if (request.epoch) {
|
|
396
|
+
// This request renders the live blocks as message 1: with today's date,
|
|
397
|
+
// even when it opens past local midnight (a model switch, a fold).
|
|
398
|
+
resumeCheck = false;
|
|
399
|
+
if (files) adoptShown(files);
|
|
400
|
+
const today = localDate();
|
|
401
|
+
if (blockDate && blockDate !== today) emitDate(today);
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
const today = localDate();
|
|
405
|
+
const toldDate = request.toldBlocks.get(FACT_KEYS.date);
|
|
406
|
+
if (blockDate && toldDate !== undefined && toldDate !== dateFingerprint(today)) {
|
|
407
|
+
request.blocks.push({ text: dateChangeReminder(today), facts: [toldBlockFact(FACT_KEYS.date, today)] });
|
|
408
|
+
// The live block too, so a later epoch (a model switch, a fold) renders today's date on message 1.
|
|
409
|
+
emitDate(today);
|
|
410
|
+
}
|
|
411
|
+
if (!resumeCheck || !livePrints) return;
|
|
412
|
+
const atCompaction = request.modes.get(FACT_KEYS.compaction) ?? false;
|
|
413
|
+
const notice = resumeFactsNotice(request.toldBlocks, atCompaction, atCompaction ? livePrints.atCompaction() : livePrints.atStart);
|
|
414
|
+
// Checked until a request shows the notice told (its facts are the live
|
|
415
|
+
// fingerprints): a failed request revokes them, so the retry says it again.
|
|
416
|
+
if (notice) request.blocks.push(notice);
|
|
417
|
+
else resumeCheck = false;
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
// All successful compactions (manual, automatic and idle) fire this hook. The
|
|
421
|
+
// summary opens an epoch, which renders these blocks: refresh them from the
|
|
422
|
+
// workspace now, in the entered worktree if any.
|
|
423
|
+
pi.on("session_compact", (_event, ctx) => refreshForCompaction(ctx));
|
|
424
|
+
function refreshForCompaction(ctx: ExtensionContext) {
|
|
425
|
+
const cwd = sessionWorkCwd(entered, ctx.cwd);
|
|
426
|
+
const current = readFiles(cwd);
|
|
427
|
+
adoptFiles(current);
|
|
428
|
+
emitInstructions(current);
|
|
429
|
+
// Only discarded carriers need reattachment; pi can retain the recent read/tool-result tail.
|
|
430
|
+
keepRetainedAttachments(ctx);
|
|
431
|
+
email = resolveEmail(cwd);
|
|
432
|
+
gitStatus = snapshotGit(cwd);
|
|
433
|
+
emitContextBlock(compactionGitStatus(gitStatus), true);
|
|
434
|
+
emitDate(localDate());
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// A branch switch leaves the attachments of the branch left behind; the new one may lack them.
|
|
438
|
+
pi.on("session_tree", (_event, ctx) => {
|
|
439
|
+
restoreAttachments(ctx);
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
// A successful read attaches nested instruction files and matching path rules
|
|
443
|
+
// once each. These are one-shots: never replace the frozen first-prepend block.
|
|
444
|
+
// lib/claude-context.ts owns traversal, matching and source ordering.
|
|
445
|
+
pi.on("tool_result", (event, ctx) => {
|
|
446
|
+
if (event.toolName !== "read" || event.isError) return;
|
|
447
|
+
const raw = pathArgument(event.input);
|
|
448
|
+
if (!raw) return;
|
|
449
|
+
rule ??= instructionRule(os.homedir());
|
|
450
|
+
const filePath = resolveToolPath(raw, ctx.cwd);
|
|
451
|
+
// In a worktree, the directories between are below the worktree's root (its own root files
|
|
452
|
+
// are the shared checkout's, which the startup block carries).
|
|
453
|
+
const files = nestedInstructionFiles({ filePath, cwd: sessionWorkCwd(entered, ctx.cwd), rule, home: os.homedir(), includeExternal });
|
|
454
|
+
// A partial read is not evidence that the entire instruction file is shown.
|
|
455
|
+
const input = event.input as { offset?: number; limit?: number };
|
|
456
|
+
const truncated = (event.details as { truncation?: { truncated?: boolean } } | undefined)?.truncation?.truncated;
|
|
457
|
+
if ((input.offset ?? 1) <= 1 && input.limit == null && !truncated) {
|
|
458
|
+
const readKey = tryRealpath(filePath) ?? filePath;
|
|
459
|
+
attachedNested.add(readKey);
|
|
460
|
+
remember(event.toolCallId, [readKey]);
|
|
461
|
+
}
|
|
462
|
+
// Bound to this read: system-reminder's hook for it has already run, so the
|
|
463
|
+
// queue pins them to this result at the next request; unbound, the next result
|
|
464
|
+
// in a parallel batch took them, beside another file (battery round 7).
|
|
465
|
+
const shown: string[] = [];
|
|
466
|
+
for (const file of files) {
|
|
467
|
+
if (attachedNested.has(file.key)) continue;
|
|
468
|
+
attachedNested.add(file.key);
|
|
469
|
+
shown.push(file.key);
|
|
470
|
+
for (const imported of file.imported) {
|
|
471
|
+
attachedNested.add(imported);
|
|
472
|
+
shown.push(imported);
|
|
473
|
+
}
|
|
474
|
+
pi.events.emit(REMINDER_CHANNEL, { text: nestedInstructionText(file), toolCallId: event.toolCallId });
|
|
106
475
|
}
|
|
476
|
+
// Recorded with the queued text: both are on the branch now (the text as a
|
|
477
|
+
// pending one-shot bound to this result), so a quit before the request
|
|
478
|
+
// keeps them in step, and an abandoned /tree branch takes both away.
|
|
479
|
+
remember(event.toolCallId, shown);
|
|
107
480
|
});
|
|
108
481
|
}
|