one-code-extension 0.4.0 → 0.5.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 +219 -219
- 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 +32 -23
- package/docs/guide/doctor.md +20 -13
- package/docs/guide/hooks.md +18 -3
- package/docs/guide/installation.md +27 -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 +66 -34
- 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 +123 -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 +515 -0
- package/extensions/background/index.ts +514 -236
- package/extensions/background/loop-fire.ts +136 -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 +52 -0
- package/extensions/background/wakeup.ts +159 -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 +88 -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 +229 -71
- package/extensions/btw/panel.ts +228 -100
- package/extensions/btw/prompt.ts +41 -4
- package/extensions/claude-compat/index.ts +7 -11
- package/extensions/claude-context/index.ts +446 -58
- package/extensions/compaction/cut.ts +157 -0
- package/extensions/compaction/index.ts +216 -75
- package/extensions/compaction/kept-thinking.ts +62 -0
- package/extensions/compaction/prompt.ts +15 -12
- package/extensions/context-budget/index.ts +24 -5
- package/extensions/context-management/index.ts +25 -0
- 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 +72 -19
- 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 +337 -26
- package/extensions/file-tracker/replay.ts +96 -10
- package/extensions/file-tracker/restore.ts +63 -0
- package/extensions/file-tracker/results.ts +66 -0
- package/extensions/file-tracker/shell-reads.ts +211 -0
- package/extensions/file-tracker/tracker.ts +32 -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 +198 -31
- package/extensions/hooks/matcher.ts +3 -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 +13 -5
- 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/lib/agent-cron.ts +130 -0
- package/extensions/lib/agent-loader.ts +15 -1
- package/extensions/lib/agent-view.ts +85 -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 +42 -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 +78 -0
- package/extensions/lib/context-stack.ts +81 -0
- package/extensions/lib/deferred.ts +219 -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/local-command.ts +47 -13
- 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 +174 -0
- package/extensions/lib/model-catalog/models-dev.json +18297 -0
- package/extensions/lib/model-catalog/openrouter.json +5252 -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 +308 -64
- 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 +21 -2
- package/extensions/lib/plan-mode-channels.ts +20 -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/process-tree.ts +131 -8
- package/extensions/lib/prompt-options.ts +82 -0
- package/extensions/lib/queued-delivery.ts +44 -0
- package/extensions/lib/reminders.ts +364 -58
- package/extensions/lib/replaced-builtins.mjs +199 -0
- package/extensions/lib/replay-call.ts +70 -0
- package/extensions/lib/request-replay.ts +439 -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 +13 -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 +113 -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 +149 -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 +143 -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 +70 -4
- 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 +87 -5
- 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 +209 -71
- 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 +151 -67
- 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/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 +1300 -381
- package/extensions/permissions/matcher.ts +425 -74
- package/extensions/permissions/modes.ts +6 -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 +156 -69
- package/extensions/plan-mode/reminder.ts +89 -21
- 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 +61 -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 +12 -7
- package/extensions/recap/index.ts +65 -60
- 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/code-review.ts +97 -0
- package/extensions/skill/index.ts +421 -101
- package/extensions/skill/invoke.ts +128 -18
- 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 +116 -23
- package/extensions/subagents/announce.ts +69 -0
- package/extensions/subagents/default-model.ts +2 -3
- package/extensions/subagents/delegation-steer.ts +4 -4
- package/extensions/subagents/fork-cache.ts +76 -0
- package/extensions/subagents/guide-agent.ts +189 -0
- package/extensions/subagents/hand-back-review.ts +3 -0
- package/extensions/subagents/index.ts +1493 -824
- package/extensions/subagents/live-runs.ts +26 -6
- package/extensions/subagents/model-select.ts +38 -25
- package/extensions/subagents/outcome.ts +2 -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/runner.ts +108 -80
- package/extensions/subagents/runs.ts +39 -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 +131 -47
- package/extensions/system-prompt/template.ts +24 -50
- 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 +175 -13
- 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/announce.ts +16 -0
- package/extensions/tool-search/index.ts +189 -41
- 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 +105 -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 +145 -162
- package/extensions/workflow/records.ts +1 -0
- package/extensions/workflow/run-manager.ts +29 -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 +121 -39
- package/extensions/worktree/powershell-guards.ts +167 -0
- package/extensions/worktree/rewrite.ts +14 -16
- package/package.json +19 -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
|
@@ -22,32 +22,41 @@
|
|
|
22
22
|
|
|
23
23
|
import { mkdirSync, readFileSync } from "node:fs";
|
|
24
24
|
import os from "node:os";
|
|
25
|
-
import {
|
|
25
|
+
import { join } from "node:path";
|
|
26
26
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
27
|
+
import { claudeMdLimitWarning, combinedLimitWarning, projectMemoryDir } from "../lib/memory.ts";
|
|
27
28
|
import {
|
|
28
|
-
claudeMdLimitWarning,
|
|
29
|
-
combinedLimitWarning,
|
|
30
29
|
INDEX_NEAR_LIMIT_REMINDER,
|
|
31
30
|
INDEX_OVER_LIMIT_ERROR,
|
|
32
31
|
indexLimitStatus,
|
|
33
|
-
projectMemoryDir,
|
|
34
32
|
stampFrontmatter,
|
|
35
|
-
} from "../lib/memory.ts";
|
|
36
|
-
import {
|
|
33
|
+
} from "../lib/memory-content.ts";
|
|
34
|
+
import { type ConfigMode, CONFIG_MODE_KEY, claudeSourcesOn, configMode, configModeFromEnv, savedConfigMode } from "../lib/config-mode.ts";
|
|
35
|
+
import { isClaudeLocation } from "../lib/claude-context.ts";
|
|
36
|
+
import { oneCodeSettingsPath, readSettingsForWrite, writeSettings } from "../lib/one-code-settings.ts";
|
|
37
|
+
import { claudeConfigDir, comparablePath, isPathAtOrUnder, oneCodeStateDir, tildify, tryRealpath } from "../lib/paths.ts";
|
|
38
|
+
import { resolveThroughLinks } from "../auto-mode/paths.ts";
|
|
39
|
+
import { resolveToolPath } from "../lib/tool-path.ts";
|
|
37
40
|
import { tryReadFile } from "../lib/plugins.ts";
|
|
38
41
|
import { REMINDER_CHANNEL } from "../lib/reminders.ts";
|
|
39
42
|
import { boundedDockHeight, safeThemeBold, safeThemePaint, truncateLine } from "../lib/tui-render.ts";
|
|
40
43
|
import { buildMemoryEntries, entryName, type MemoryEntry } from "./entries.ts";
|
|
41
|
-
import { openPath } from "./open-external.ts";
|
|
42
|
-
import { applyMemoryKey, decodeMemoryKey, initialMemoryState, renderMemoryPanel } from "./panel.ts";
|
|
44
|
+
import { editorHint, memoryDisplayPath, openPath } from "./open-external.ts";
|
|
45
|
+
import { applyMemoryKey, type AutoMemoryView, decodeMemoryKey, initialMemoryState, type ModeView, renderMemoryPanel, settingChanges } from "./panel.ts";
|
|
46
|
+
import { AUTO_MEMORY_KEY, autoMemoryEnabled, autoMemoryFromEnv, savedAutoMemory, savedAutoMemorySource } from "../lib/auto-memory.ts";
|
|
43
47
|
import { registerLocalCommand } from "../lib/local-command.ts";
|
|
48
|
+
import { canShowCustomUi } from "../lib/headless-output.ts";
|
|
49
|
+
import { panelUi } from "../lib/panel-focus.ts";
|
|
44
50
|
|
|
45
51
|
const MEMORY_PANEL_MAX_HEIGHT = 20;
|
|
46
52
|
|
|
47
|
-
|
|
53
|
+
/** `root` is the memory directory's real path, resolved once per session. */
|
|
54
|
+
function inputPath(input: unknown, cwd: string, root: string): string | undefined {
|
|
48
55
|
const raw = (input as { path?: unknown })?.path;
|
|
49
56
|
if (typeof raw !== "string" || !raw.trim()) return undefined;
|
|
50
|
-
|
|
57
|
+
// Match the file pi touches, including aliases and not-yet-created leaves.
|
|
58
|
+
const path = resolveThroughLinks(resolveToolPath(raw, cwd));
|
|
59
|
+
return path && isPathAtOrUnder(path, root) && comparablePath(path) !== comparablePath(root) ? path : undefined;
|
|
51
60
|
}
|
|
52
61
|
|
|
53
62
|
/** All the panel/warning entries for `cwd`, from One Code's real state dirs. */
|
|
@@ -57,15 +66,20 @@ function memoryEntriesFor(cwd: string): MemoryEntry[] {
|
|
|
57
66
|
home: os.homedir(),
|
|
58
67
|
homeClaudeDir: claudeConfigDir(),
|
|
59
68
|
homeOneCodeDir: oneCodeStateDir(),
|
|
60
|
-
memoryDir: projectMemoryDir(cwd),
|
|
69
|
+
memoryDir: autoMemoryEnabled(cwd) ? projectMemoryDir(cwd) : undefined,
|
|
61
70
|
});
|
|
62
71
|
}
|
|
63
72
|
|
|
64
73
|
export default function memoryExtension(pi: ExtensionAPI) {
|
|
65
74
|
let dir: string | undefined;
|
|
75
|
+
let dirReal = "";
|
|
66
76
|
|
|
67
77
|
pi.on("session_start", (_event, ctx) => {
|
|
78
|
+
dir = undefined;
|
|
68
79
|
const candidate = projectMemoryDir(ctx.cwd);
|
|
80
|
+
// An independent state directory can contain links into Claude's tree.
|
|
81
|
+
// Resolve missing leaves through their parents before creating anything.
|
|
82
|
+
if (!claudeSourcesOn() && isClaudeLocation(resolveThroughLinks(candidate) ?? candidate, claudeConfigDir())) return;
|
|
69
83
|
|
|
70
84
|
// Claude Code's startup warning: an instruction file over the char limit
|
|
71
85
|
// bloats every turn's context. Warn once, pointing at /memory to trim it.
|
|
@@ -92,6 +106,9 @@ export default function memoryExtension(pi: ExtensionAPI) {
|
|
|
92
106
|
}
|
|
93
107
|
}
|
|
94
108
|
|
|
109
|
+
// Auto-memory off (lib/auto-memory.ts): no folder, no stamping.
|
|
110
|
+
if (!autoMemoryEnabled(ctx.cwd)) return;
|
|
111
|
+
|
|
95
112
|
// Like Claude Code: one memory dir per git repo (shared by worktrees and
|
|
96
113
|
// subdirectories); outside a repo, per cwd.
|
|
97
114
|
try {
|
|
@@ -102,6 +119,7 @@ export default function memoryExtension(pi: ExtensionAPI) {
|
|
|
102
119
|
return;
|
|
103
120
|
}
|
|
104
121
|
dir = candidate;
|
|
122
|
+
dirReal = tryRealpath(candidate) ?? candidate;
|
|
105
123
|
|
|
106
124
|
// The MEMORY.md index is injected by the claude-context extension, folded
|
|
107
125
|
// into the `# claudeMd` block exactly as Claude Code does — not as a
|
|
@@ -111,8 +129,8 @@ export default function memoryExtension(pi: ExtensionAPI) {
|
|
|
111
129
|
|
|
112
130
|
pi.on("tool_call", (event, ctx) => {
|
|
113
131
|
if (event.toolName !== "write" || !dir) return undefined;
|
|
114
|
-
const path = inputPath(event.input, ctx.cwd);
|
|
115
|
-
if (!path
|
|
132
|
+
const path = inputPath(event.input, ctx.cwd, dirReal);
|
|
133
|
+
if (!path) return undefined;
|
|
116
134
|
const input = event.input as { content?: unknown };
|
|
117
135
|
if (typeof input.content !== "string") return undefined;
|
|
118
136
|
input.content = stampFrontmatter(input.content, ctx.sessionManager.getSessionId(), new Date().toISOString());
|
|
@@ -122,7 +140,9 @@ export default function memoryExtension(pi: ExtensionAPI) {
|
|
|
122
140
|
pi.on("tool_result", (event, ctx) => {
|
|
123
141
|
if (event.isError || !dir) return undefined;
|
|
124
142
|
if (event.toolName !== "write" && event.toolName !== "edit") return undefined;
|
|
125
|
-
|
|
143
|
+
const path = inputPath(event.input, ctx.cwd, dirReal);
|
|
144
|
+
const indexPath = join(dir, "MEMORY.md");
|
|
145
|
+
if (!path || comparablePath(path) !== comparablePath(tryRealpath(indexPath) ?? indexPath)) return undefined;
|
|
126
146
|
|
|
127
147
|
let index: string;
|
|
128
148
|
try {
|
|
@@ -144,30 +164,69 @@ export default function memoryExtension(pi: ExtensionAPI) {
|
|
|
144
164
|
|
|
145
165
|
// ---- /memory: Claude Code's Memory picker --------------------------------
|
|
146
166
|
// Pick a memory-related file (or the auto-memory folder) and open it in the
|
|
147
|
-
// external editor, matching CC. Pure panel logic lives in ./panel.ts.
|
|
167
|
+
// external editor, matching CC. Pure panel logic lives in ./panel.ts. The
|
|
168
|
+
// returned text is the model's `<local-command-stdout>`, worded as CC's.
|
|
148
169
|
registerLocalCommand(pi, "memory", {
|
|
149
170
|
description: "View or edit CLAUDE.md and memory files",
|
|
150
|
-
|
|
171
|
+
reportsResult: true,
|
|
172
|
+
handler: async (_args, ctx): Promise<string | undefined> => {
|
|
151
173
|
const entries = memoryEntriesFor(ctx.cwd);
|
|
152
|
-
if (!ctx
|
|
174
|
+
if (!canShowCustomUi(ctx)) {
|
|
175
|
+
const limitation = ctx.mode === "rpc" ? "/memory editing is unavailable in RPC; use the TUI or open a listed path in your editor.\n\n" : "";
|
|
153
176
|
const lines = entries.map(
|
|
154
177
|
(e, i) => `${i + 1}. ${e.title}${e.description ? ` — ${e.description}` : ""} [${e.path}]`,
|
|
155
178
|
);
|
|
156
|
-
|
|
157
|
-
|
|
179
|
+
const stdout = `${limitation}Memory / CLAUDE.md files:\n${lines.join("\n")}`;
|
|
180
|
+
ctx.ui.notify(stdout, "info");
|
|
181
|
+
return ctx.mode === "rpc" ? limitation.trim() : undefined;
|
|
182
|
+
}
|
|
183
|
+
const mode: ModeView = { running: configMode(), saved: savedConfigMode(), fromEnv: configModeFromEnv() !== undefined };
|
|
184
|
+
const autoMemory: AutoMemoryView = {
|
|
185
|
+
running: autoMemoryEnabled(ctx.cwd),
|
|
186
|
+
saved: savedAutoMemory(ctx.cwd),
|
|
187
|
+
fromEnv: autoMemoryFromEnv() !== undefined,
|
|
188
|
+
};
|
|
189
|
+
const before = { mode: mode.saved, autoMemory: autoMemory.saved };
|
|
190
|
+
const chosen = await openMemoryPanel(pi.events, ctx, entries, mode, autoMemory);
|
|
191
|
+
// A toggle's line leads CC's result when it changed something.
|
|
192
|
+
const changes = settingChanges(before, mode, autoMemory);
|
|
193
|
+
const modeLine = changes ? `${changes}\n\n` : "";
|
|
194
|
+
if (!chosen) {
|
|
195
|
+
// Closing after a change reports the change, not a cancel.
|
|
196
|
+
ctx.ui.notify(changes || CANCELLED, "info");
|
|
197
|
+
return changes || CANCELLED;
|
|
158
198
|
}
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
const
|
|
162
|
-
ctx.ui.notify(
|
|
163
|
-
|
|
199
|
+
const shown = memoryDisplayPath(chosen.path, ctx.cwd, os.homedir());
|
|
200
|
+
const result = await openPath(chosen.path, "file");
|
|
201
|
+
const stdout = result.ok ? `Opened ${shown}\n${editorHint()}` : `Couldn't open ${shown}: ${result.error}`;
|
|
202
|
+
ctx.ui.notify(stdout, result.ok ? "info" : "error");
|
|
203
|
+
return `${modeLine}${stdout}`;
|
|
164
204
|
},
|
|
165
205
|
});
|
|
166
206
|
}
|
|
167
207
|
|
|
168
|
-
/**
|
|
169
|
-
|
|
170
|
-
|
|
208
|
+
/** Claude Code's `/memory` result when the panel closes without a pick. */
|
|
209
|
+
const CANCELLED = "Cancelled memory editing";
|
|
210
|
+
|
|
211
|
+
/** Save one key to One Code's user settings; the running process keeps its value. */
|
|
212
|
+
function saveUserSetting(key: string, value: unknown): void {
|
|
213
|
+
const path = oneCodeSettingsPath(os.homedir());
|
|
214
|
+
writeSettings(path, { ...readSettingsForWrite(path), [key]: value });
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Show the Memory panel as a focused overlay; resolve to the chosen entry or
|
|
219
|
+
* null. The toggle rows save into `autoMemory.saved` and `mode.saved` (the
|
|
220
|
+
* config-sources row after a confirming second Enter) and keep the panel up.
|
|
221
|
+
*/
|
|
222
|
+
function openMemoryPanel(
|
|
223
|
+
events: ExtensionAPI["events"],
|
|
224
|
+
ctx: ExtensionContext,
|
|
225
|
+
entries: MemoryEntry[],
|
|
226
|
+
mode: ModeView,
|
|
227
|
+
autoMemory: AutoMemoryView,
|
|
228
|
+
): Promise<MemoryEntry | null> {
|
|
229
|
+
return panelUi(events, ctx.ui).custom<MemoryEntry | null>((tui, theme, _keybindings, done) => {
|
|
171
230
|
const paint = { fg: safeThemePaint(theme), bold: safeThemeBold(theme) };
|
|
172
231
|
const state = initialMemoryState();
|
|
173
232
|
let cache: { width: number; lines: string[] } | undefined;
|
|
@@ -180,7 +239,7 @@ function openMemoryPanel(ctx: ExtensionContext, entries: MemoryEntry[]): Promise
|
|
|
180
239
|
if (cache?.width === width) return cache.lines;
|
|
181
240
|
const termRows = (tui as { terminal: { rows: number } }).terminal.rows;
|
|
182
241
|
const height = boundedDockHeight(termRows, MEMORY_PANEL_MAX_HEIGHT);
|
|
183
|
-
const lines = renderMemoryPanel({ state, entries, width, height }, paint).map((line) =>
|
|
242
|
+
const lines = renderMemoryPanel({ state, entries, width, height, mode, autoMemory }, paint).map((line) =>
|
|
184
243
|
truncateLine(line, width),
|
|
185
244
|
);
|
|
186
245
|
cache = { width, lines };
|
|
@@ -190,10 +249,57 @@ function openMemoryPanel(ctx: ExtensionContext, entries: MemoryEntry[]): Promise
|
|
|
190
249
|
const key = decodeMemoryKey(data);
|
|
191
250
|
if (!key) return;
|
|
192
251
|
const effect = applyMemoryKey(state, key, entries);
|
|
252
|
+
if (effect?.kind === "confirm-mode" && mode.fromEnv) {
|
|
253
|
+
// The variable outranks the saved setting, so a write here would never apply.
|
|
254
|
+
state.confirmingMode = false;
|
|
255
|
+
ctx.ui.notify("Config sources are set by ONECODE_CONFIG_MODE. Unset it to switch here.", "info");
|
|
256
|
+
repaint();
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
if (effect?.kind === "toggle-auto-memory") {
|
|
260
|
+
if (autoMemory.fromEnv) {
|
|
261
|
+
ctx.ui.notify("Auto-memory is set by CLAUDE_CODE_DISABLE_AUTO_MEMORY. Unset it to switch here.", "info");
|
|
262
|
+
repaint();
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
try {
|
|
266
|
+
const wanted = !autoMemory.saved;
|
|
267
|
+
saveUserSetting(AUTO_MEMORY_KEY, wanted);
|
|
268
|
+
// Re-read the ladder: a project or managed file can still outrank the user file.
|
|
269
|
+
const decided = savedAutoMemorySource(ctx.cwd);
|
|
270
|
+
autoMemory.saved = decided.enabled;
|
|
271
|
+
if (decided.enabled !== wanted && decided.path) {
|
|
272
|
+
ctx.ui.notify(`${tildify(decided.path, os.homedir())} sets ${AUTO_MEMORY_KEY}: ${decided.enabled}, which outranks your user setting. Change it there.`, "info");
|
|
273
|
+
}
|
|
274
|
+
} catch (error) {
|
|
275
|
+
ctx.ui.notify(`Couldn't save the auto-memory setting: ${error instanceof Error ? error.message : error}`, "error");
|
|
276
|
+
}
|
|
277
|
+
repaint();
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
if (effect?.kind === "toggle-mode") {
|
|
281
|
+
const next: ConfigMode = mode.saved === "independent" ? "claude-compatible" : "independent";
|
|
282
|
+
try {
|
|
283
|
+
saveUserSetting(CONFIG_MODE_KEY, next);
|
|
284
|
+
mode.saved = next;
|
|
285
|
+
} catch (error) {
|
|
286
|
+
ctx.ui.notify(`Couldn't save the config sources setting: ${error instanceof Error ? error.message : error}`, "error");
|
|
287
|
+
}
|
|
288
|
+
repaint();
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
193
291
|
if (effect?.kind === "close") {
|
|
194
292
|
done(null);
|
|
195
293
|
return;
|
|
196
294
|
}
|
|
295
|
+
if (effect?.kind === "open" && effect.entry.kind === "folder") {
|
|
296
|
+
// CC opens the folder and keeps the picker up; only a file or Esc ends it.
|
|
297
|
+
const { path } = effect.entry;
|
|
298
|
+
void openPath(path, "folder").then((result) => {
|
|
299
|
+
if (!result.ok) ctx.ui.notify(`Couldn't open ${memoryDisplayPath(path, ctx.cwd, os.homedir())}: ${result.error}`, "error");
|
|
300
|
+
});
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
197
303
|
if (effect?.kind === "open") {
|
|
198
304
|
done(effect.entry);
|
|
199
305
|
return;
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Open a memory file or folder in the user's editor / OS opener, matching Claude
|
|
3
3
|
* Code's `/memory`: a file goes to `$VISUAL`/`$EDITOR` (or the OS default), a
|
|
4
4
|
* folder to the OS file manager. The child is detached and unref'd so the TUI is
|
|
5
|
-
* never blocked (as the MCP OAuth browser open does).
|
|
6
|
-
*
|
|
5
|
+
* never blocked (as the MCP OAuth browser open does). The caller words the
|
|
6
|
+
* result (`memoryDisplayPath`, `editorHint`), matching CC's `/memory`.
|
|
7
7
|
*
|
|
8
8
|
* Limitation: a terminal editor (vim/nano) needs the controlling tty, which the
|
|
9
9
|
* pi TUI owns, so it cannot run detached — this suits GUI editors (code, subl)
|
|
@@ -14,7 +14,10 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { spawn } from "node:child_process";
|
|
17
|
+
import { relative } from "node:path";
|
|
18
|
+
import { childProcessEnv } from "../lib/app-launch.mjs";
|
|
17
19
|
import { commandLaunch } from "../lib/command-launch.ts";
|
|
20
|
+
import { forwardSlashes, isRelativeInside, tildify } from "../lib/paths.ts";
|
|
18
21
|
|
|
19
22
|
export interface OpenPlan {
|
|
20
23
|
command: string;
|
|
@@ -52,14 +55,28 @@ export function resolveOpen(
|
|
|
52
55
|
return { command: "xdg-open", args: [path] };
|
|
53
56
|
}
|
|
54
57
|
|
|
55
|
-
export
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
export type OpenResult = { ok: true } | { ok: false; error: string };
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* CC's display path for `/memory`'s result: `~/…` under the home directory,
|
|
62
|
+
* `./…` under the working directory, the shorter when both apply, else as is.
|
|
63
|
+
*/
|
|
64
|
+
export function memoryDisplayPath(path: string, cwd: string, home: string): string {
|
|
65
|
+
const tilde = tildify(path, home);
|
|
66
|
+
const underHome = tilde !== path;
|
|
67
|
+
const rel = relative(cwd, path);
|
|
68
|
+
const dot = isRelativeInside(rel) ? `./${forwardSlashes(rel)}` : undefined;
|
|
69
|
+
if (underHome && dot) return tilde.length <= dot.length ? tilde : dot;
|
|
70
|
+
return underHome ? tilde : (dot ?? path);
|
|
59
71
|
}
|
|
60
72
|
|
|
61
|
-
/**
|
|
62
|
-
export
|
|
73
|
+
/** CC's editor hint under an opened file, naming the variable it used. */
|
|
74
|
+
export function editorHint(env: Record<string, string | undefined> = process.env): string {
|
|
75
|
+
const used = env.VISUAL ? `Using $VISUAL="${env.VISUAL}".` : env.EDITOR ? `Using $EDITOR="${env.EDITOR}".` : "";
|
|
76
|
+
return used
|
|
77
|
+
? `> ${used} To change editor, set $EDITOR or $VISUAL environment variable.`
|
|
78
|
+
: "> To use a different editor, set the $EDITOR or $VISUAL environment variable.";
|
|
79
|
+
}
|
|
63
80
|
|
|
64
81
|
/**
|
|
65
82
|
* Spawn the opener/editor detached, resolving once the child either spawns
|
|
@@ -80,21 +97,19 @@ export function openPath(path: string, kind: "file" | "folder"): Promise<OpenRes
|
|
|
80
97
|
let child: ReturnType<typeof spawn>;
|
|
81
98
|
try {
|
|
82
99
|
// `$EDITOR=code` is VS Code's `code.cmd` shim on Windows, which a bare spawn cannot start.
|
|
83
|
-
|
|
84
|
-
|
|
100
|
+
// The user's own environment under the bundled app (lib/app-launch.mjs): an
|
|
101
|
+
// editor with a terminal must not hand the app's pi state to a `pi` run there.
|
|
102
|
+
const env = childProcessEnv(process.env);
|
|
103
|
+
const launch = commandLaunch(command, args, env);
|
|
104
|
+
child = spawn(launch.command, launch.args, { env, stdio: "ignore", detached: true, windowsVerbatimArguments: launch.windowsVerbatimArguments });
|
|
85
105
|
} catch (error) {
|
|
86
|
-
finish({
|
|
106
|
+
finish({ ok: false, error: error instanceof Error ? error.message : String(error) });
|
|
87
107
|
return;
|
|
88
108
|
}
|
|
89
|
-
child.on("error", (error) => finish({
|
|
109
|
+
child.on("error", (error) => finish({ ok: false, error: error.message }));
|
|
90
110
|
child.on("spawn", () => {
|
|
91
111
|
child.unref();
|
|
92
|
-
finish({
|
|
93
|
-
message: `Opened ${path}`,
|
|
94
|
-
// CC shows the hint on file opens (even when $EDITOR handled it); folders don't.
|
|
95
|
-
hint: kind === "file" ? EDITOR_HINT : undefined,
|
|
96
|
-
ok: true,
|
|
97
|
-
});
|
|
112
|
+
finish({ ok: true });
|
|
98
113
|
});
|
|
99
114
|
});
|
|
100
115
|
}
|
|
@@ -3,66 +3,114 @@
|
|
|
3
3
|
* Memory picker: a titled list of the CLAUDE.md-family / AGENTS.md / ONECODE.md
|
|
4
4
|
* files plus "Open auto-memory folder", with an Auto-memory status line and a
|
|
5
5
|
* learn-more link. Enter opens the selected entry (in `$EDITOR`); Esc closes.
|
|
6
|
+
* Above the list, where CC keeps its toggle rows (↑ from the first file
|
|
7
|
+
* reaches them): CC's "Auto-memory" toggle (lib/auto-memory.ts), then One
|
|
8
|
+
* Code's "Config sources" row, which switches between the Claude-compatible
|
|
9
|
+
* and independent modes (lib/config-mode.ts) after a confirmation, since it
|
|
10
|
+
* changes every place configuration is read from.
|
|
6
11
|
*
|
|
7
12
|
* Kept free of pi imports so the layout and navigation are unit-tested; the
|
|
8
13
|
* extension owns repaint, the overlay, and the actual open.
|
|
9
14
|
*/
|
|
10
15
|
|
|
11
16
|
import type { MemoryEntry } from "./entries.ts";
|
|
17
|
+
import { type ConfigMode, MODE_LABELS } from "../lib/config-mode.ts";
|
|
18
|
+
import { keyId } from "../lib/key-input.ts";
|
|
19
|
+
import { wrapHints, wrapProse } from "../lib/tui-render.ts";
|
|
12
20
|
|
|
13
21
|
export const MEMORY_DOCS_URL = "https://github.com/IsuruMaduranga/one-code";
|
|
14
22
|
|
|
23
|
+
/** Cursor rows above the list. */
|
|
24
|
+
export const AUTO_MEMORY_ROW = -2;
|
|
25
|
+
export const CONFIG_SOURCES_ROW = -1;
|
|
26
|
+
|
|
15
27
|
export interface MemoryPanelState {
|
|
28
|
+
/** The selected entry's index; the two toggle rows above the list are negative. */
|
|
16
29
|
cursor: number;
|
|
30
|
+
/** Set while the config-sources switch waits for a second Enter. */
|
|
31
|
+
confirmingMode?: boolean;
|
|
17
32
|
}
|
|
18
33
|
|
|
19
34
|
export function initialMemoryState(): MemoryPanelState {
|
|
20
35
|
return { cursor: 0 };
|
|
21
36
|
}
|
|
22
37
|
|
|
38
|
+
/** A setting's value in this process, the value saved for the next start, and whether an env variable sets it. */
|
|
39
|
+
export interface SettingView<T> {
|
|
40
|
+
running: T;
|
|
41
|
+
saved: T;
|
|
42
|
+
fromEnv?: boolean;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Auto-memory; `CLAUDE_CODE_DISABLE_AUTO_MEMORY` can set it. */
|
|
46
|
+
export type AutoMemoryView = SettingView<boolean>;
|
|
47
|
+
|
|
48
|
+
/** The config-sources mode; `ONECODE_CONFIG_MODE` can set it. */
|
|
49
|
+
export type ModeView = SettingView<ConfigMode>;
|
|
50
|
+
|
|
51
|
+
/** "; applies from the next start" while the saved value differs from the running one. */
|
|
52
|
+
const pendingSuffix = (view: SettingView<unknown>): string => (view.saved === view.running ? "" : "; applies from the next start");
|
|
53
|
+
|
|
54
|
+
const MODE_DESCRIPTIONS: Record<ConfigMode, string> = {
|
|
55
|
+
"claude-compatible": "~/.claude, CLAUDE.md, .agents and pi's dirs",
|
|
56
|
+
independent: "~/.onecode, ONECODE.md, .agents and pi's dirs",
|
|
57
|
+
};
|
|
58
|
+
|
|
23
59
|
export type MemoryKey = { kind: "up" | "down" | "enter" | "close" };
|
|
24
60
|
|
|
25
61
|
export function decodeMemoryKey(data: string): MemoryKey | undefined {
|
|
26
|
-
switch (data) {
|
|
27
|
-
case "
|
|
28
|
-
case "
|
|
29
|
-
case "\x10": // ctrl+p
|
|
62
|
+
switch (keyId(data)) {
|
|
63
|
+
case "up":
|
|
64
|
+
case "ctrl+p":
|
|
30
65
|
return { kind: "up" };
|
|
31
|
-
case "
|
|
32
|
-
case "
|
|
33
|
-
case "\x0e": // ctrl+n
|
|
66
|
+
case "down":
|
|
67
|
+
case "ctrl+n":
|
|
34
68
|
return { kind: "down" };
|
|
35
|
-
case "
|
|
36
|
-
case "\n":
|
|
69
|
+
case "enter":
|
|
37
70
|
return { kind: "enter" };
|
|
38
|
-
case "
|
|
39
|
-
case "
|
|
71
|
+
case "escape":
|
|
72
|
+
case "ctrl+c":
|
|
40
73
|
return { kind: "close" };
|
|
41
74
|
default:
|
|
42
75
|
return undefined;
|
|
43
76
|
}
|
|
44
77
|
}
|
|
45
78
|
|
|
46
|
-
export type MemoryEffect =
|
|
79
|
+
export type MemoryEffect =
|
|
80
|
+
| { kind: "open"; entry: MemoryEntry }
|
|
81
|
+
| { kind: "confirm-mode" }
|
|
82
|
+
| { kind: "toggle-mode" }
|
|
83
|
+
| { kind: "toggle-auto-memory" }
|
|
84
|
+
| { kind: "close" };
|
|
47
85
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
86
|
+
/**
|
|
87
|
+
* Enter on "Config sources" asks first (`confirm-mode`); a second Enter
|
|
88
|
+
* switches (`toggle-mode`), and Esc or a move keeps the mode and the panel.
|
|
89
|
+
* "Auto-memory" toggles at once, as in Claude Code.
|
|
90
|
+
*/
|
|
91
|
+
export function applyMemoryKey(state: MemoryPanelState, key: MemoryKey, entries: readonly MemoryEntry[]): MemoryEffect | undefined {
|
|
92
|
+
const confirming = state.confirmingMode === true;
|
|
93
|
+
state.confirmingMode = false;
|
|
53
94
|
switch (key.kind) {
|
|
54
95
|
case "up":
|
|
55
|
-
state.cursor = Math.max(
|
|
96
|
+
state.cursor = Math.max(AUTO_MEMORY_ROW, state.cursor - 1);
|
|
56
97
|
return undefined;
|
|
57
98
|
case "down":
|
|
58
99
|
state.cursor = Math.min(entries.length - 1, state.cursor + 1);
|
|
59
100
|
return undefined;
|
|
60
101
|
case "enter": {
|
|
102
|
+
if (state.cursor === AUTO_MEMORY_ROW) return { kind: "toggle-auto-memory" };
|
|
103
|
+
if (state.cursor === CONFIG_SOURCES_ROW) {
|
|
104
|
+
if (confirming) return { kind: "toggle-mode" };
|
|
105
|
+
state.confirmingMode = true;
|
|
106
|
+
return { kind: "confirm-mode" };
|
|
107
|
+
}
|
|
61
108
|
const entry = entries[state.cursor];
|
|
62
109
|
return entry ? { kind: "open", entry } : undefined;
|
|
63
110
|
}
|
|
64
111
|
case "close":
|
|
65
|
-
|
|
112
|
+
// Esc on the confirmation keeps the mode and the panel.
|
|
113
|
+
return confirming ? undefined : { kind: "close" };
|
|
66
114
|
}
|
|
67
115
|
}
|
|
68
116
|
|
|
@@ -80,21 +128,36 @@ const DESC_COL = 34;
|
|
|
80
128
|
* the cursor stays visible.
|
|
81
129
|
*/
|
|
82
130
|
export function renderMemoryPanel(
|
|
83
|
-
input: {
|
|
131
|
+
input: {
|
|
132
|
+
state: MemoryPanelState;
|
|
133
|
+
entries: readonly MemoryEntry[];
|
|
134
|
+
width: number;
|
|
135
|
+
height: number;
|
|
136
|
+
mode: ModeView;
|
|
137
|
+
autoMemory?: AutoMemoryView;
|
|
138
|
+
},
|
|
84
139
|
paint: PanelPaint,
|
|
85
140
|
): string[] {
|
|
86
|
-
const { state, entries, height } = input;
|
|
141
|
+
const { state, entries, height, mode, width } = input;
|
|
142
|
+
const autoMemory = input.autoMemory ?? { running: true, saved: true };
|
|
87
143
|
|
|
88
|
-
const header = [
|
|
89
|
-
|
|
144
|
+
const header = [
|
|
145
|
+
paint.bold("Memory"),
|
|
90
146
|
"",
|
|
91
|
-
|
|
147
|
+
renderAutoMemoryRow(autoMemory, state.cursor === AUTO_MEMORY_ROW, paint),
|
|
148
|
+
renderModeRow(mode, state.cursor === CONFIG_SOURCES_ROW, paint),
|
|
92
149
|
"",
|
|
93
|
-
paint.fg("muted", "Enter to open · Esc to close"),
|
|
94
150
|
];
|
|
151
|
+
const hints = state.confirmingMode
|
|
152
|
+
? [
|
|
153
|
+
...wrapProse(modeConfirmQuestion(mode), Math.max(20, width)).map((line) => paint.fg("warning", line)),
|
|
154
|
+
...wrapHints(`Enter to switch · Esc to keep ${MODE_LABELS[mode.saved]}`, width).map((line) => paint.fg("muted", line)),
|
|
155
|
+
]
|
|
156
|
+
: wrapHints("Enter to open or toggle · ↑ for auto-memory and config sources · Esc to close", width).map((line) => paint.fg("muted", line));
|
|
157
|
+
const footer = ["", paint.fg("muted", `Learn more: ${MEMORY_DOCS_URL}`), "", ...hints];
|
|
95
158
|
|
|
96
159
|
const listCapacity = Math.max(1, height - header.length - footer.length);
|
|
97
|
-
const start = scrollStart(state.cursor, entries.length, listCapacity);
|
|
160
|
+
const start = scrollStart(Math.max(0, state.cursor), entries.length, listCapacity);
|
|
98
161
|
const rows: string[] = [];
|
|
99
162
|
for (let i = start; i < Math.min(entries.length, start + listCapacity); i++) {
|
|
100
163
|
rows.push(renderRow(entries[i], i, i === state.cursor, paint));
|
|
@@ -103,6 +166,52 @@ export function renderMemoryPanel(
|
|
|
103
166
|
return [...header, ...rows, ...footer];
|
|
104
167
|
}
|
|
105
168
|
|
|
169
|
+
/**
|
|
170
|
+
* One line per toggle the panel changed (the result `/memory` reports), empty
|
|
171
|
+
* when nothing changed.
|
|
172
|
+
*/
|
|
173
|
+
export function settingChanges(before: { mode: ConfigMode; autoMemory: boolean }, mode: ModeView, autoMemory: AutoMemoryView): string {
|
|
174
|
+
const lines: string[] = [];
|
|
175
|
+
if (autoMemory.saved !== before.autoMemory) {
|
|
176
|
+
lines.push(`Turned auto-memory ${autoMemory.saved ? "on" : "off"}${pendingSuffix(autoMemory)}`);
|
|
177
|
+
}
|
|
178
|
+
if (mode.saved !== before.mode) {
|
|
179
|
+
lines.push(`Set config sources to ${MODE_LABELS[mode.saved]}${pendingSuffix(mode)}`);
|
|
180
|
+
}
|
|
181
|
+
return lines.join("\n");
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** The question the config-sources confirmation asks. */
|
|
185
|
+
export function modeConfirmQuestion(mode: ModeView): string {
|
|
186
|
+
const next: ConfigMode = mode.saved === "independent" ? "claude-compatible" : "independent";
|
|
187
|
+
return `Switch config sources to ${MODE_LABELS[next]}? One Code will read ${MODE_DESCRIPTIONS[next]} instead, from the next start.`;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* A toggle row's plain text, "<label>: <saved>", with "(from next start)" while
|
|
192
|
+
* the saved value differs from the running one; when `envName` sets it, the
|
|
193
|
+
* running value and that it is set there. Also returns the value shown.
|
|
194
|
+
*/
|
|
195
|
+
function settingRow<T>(label: string, view: SettingView<T>, valueText: (value: T) => string, envName: string, selected: boolean): { left: string; shown: T } {
|
|
196
|
+
const shown = view.fromEnv ? view.running : view.saved;
|
|
197
|
+
const note = view.fromEnv ? ` (set by ${envName})` : view.saved !== view.running ? " (from next start)" : "";
|
|
198
|
+
return { left: `${selected ? "❯ " : " "}${label}: ${valueText(shown)}${note}`, shown };
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/** "Auto-memory: on|off". */
|
|
202
|
+
function renderAutoMemoryRow(view: AutoMemoryView, selected: boolean, paint: PanelPaint): string {
|
|
203
|
+
const { left } = settingRow("Auto-memory", view, (on) => (on ? "on" : "off"), "CLAUDE_CODE_DISABLE_AUTO_MEMORY", selected);
|
|
204
|
+
return selected ? paint.fg("accent", left) : left;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** "Config sources: <mode>" and the mode's description. */
|
|
208
|
+
function renderModeRow(mode: ModeView, selected: boolean, paint: PanelPaint): string {
|
|
209
|
+
const { left, shown } = settingRow("Config sources", mode, (value) => MODE_LABELS[value], "ONECODE_CONFIG_MODE", selected);
|
|
210
|
+
const pad = " ".repeat(Math.max(2, DESC_COL + 12 - left.length));
|
|
211
|
+
const description = MODE_DESCRIPTIONS[shown];
|
|
212
|
+
return selected ? `${paint.fg("accent", left)}${pad}${paint.fg("accent", description)}` : `${left}${pad}${paint.fg("muted", description)}`;
|
|
213
|
+
}
|
|
214
|
+
|
|
106
215
|
/** First index to show so `cursor` is within a `capacity`-tall window. */
|
|
107
216
|
function scrollStart(cursor: number, total: number, capacity: number): number {
|
|
108
217
|
if (total <= capacity) return 0;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** User-only model-upgrade advice. No reminders, transcript entries, or request hooks. */
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
4
|
+
import { modelSpec } from "../lib/model-policy.ts";
|
|
5
|
+
import { MODEL_UNUSABLE_CHANNEL, type ModelUnusableEvent, withoutUnusable } from "../lib/model-unusable.ts";
|
|
6
|
+
import { newerModelSuggestion } from "../lib/newer-model.ts";
|
|
7
|
+
import { queueNotice } from "../lib/notices.ts";
|
|
8
|
+
import { sessionOutlivesTurn } from "../lib/notifications.ts";
|
|
9
|
+
import { readSuggestNewerModels } from "../lib/one-code-settings.ts";
|
|
10
|
+
|
|
11
|
+
export default function newerModelExtension(pi: ExtensionAPI) {
|
|
12
|
+
const shown = new Set<string>();
|
|
13
|
+
const unusable = new Set<string>();
|
|
14
|
+
pi.events.on(MODEL_UNUSABLE_CHANNEL, (data) => unusable.add((data as ModelUnusableEvent).model));
|
|
15
|
+
|
|
16
|
+
const suggest = (ctx: ExtensionContext, model = ctx.model) => {
|
|
17
|
+
if (!sessionOutlivesTurn(ctx.mode) || !ctx.hasUI || !model || !readSuggestNewerModels(homedir())) return;
|
|
18
|
+
const key = JSON.stringify([ctx.sessionManager.getSessionId(), modelSpec(model)]);
|
|
19
|
+
if (shown.has(key)) return;
|
|
20
|
+
const suggestion = newerModelSuggestion(withoutUnusable(ctx.modelRegistry.getAvailable(), unusable), model);
|
|
21
|
+
if (!suggestion) return;
|
|
22
|
+
// Joined with the other extensions' startup and model-switch notices (lib/notices.ts).
|
|
23
|
+
queueNotice(pi.events, ctx, "info", `${suggestion.text} ${suggestion.fix}`);
|
|
24
|
+
shown.add(key);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// Local catalog/cache reads only. Never await a network refresh at startup.
|
|
28
|
+
// Session ids also handle RPC's duplicate session_start for a new session.
|
|
29
|
+
pi.on("session_start", (_event, ctx) => suggest(ctx));
|
|
30
|
+
pi.on("model_select", (event, ctx) => suggest(ctx, event.model));
|
|
31
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* notebook_edit's model-facing description: Claude Code's NotebookEdit text
|
|
3
|
+
* with One Code's extras (pure).
|
|
4
|
+
*
|
|
5
|
+
* Claude Code addresses a cell by the id its Read tool prints; pi's read
|
|
6
|
+
* returns the notebook's JSON, so a cell is named by its own `id` or by its
|
|
7
|
+
* position (`cell-0`). The path may be relative and is `path` or
|
|
8
|
+
* `notebook_path`; `append` and the cleared outputs are One Code's.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export const NOTEBOOK_EDIT_DESCRIPTION = `Replaces, inserts, or deletes a single cell in a Jupyter notebook (.ipynb file).
|
|
12
|
+
|
|
13
|
+
Usage:
|
|
14
|
+
- You must use the read tool on the notebook in this conversation before editing — this tool will fail otherwise.
|
|
15
|
+
- \`path\` (or \`notebook_path\`) is the notebook, absolute or relative to the working directory.
|
|
16
|
+
- \`cell_id\` is the cell's own \`id\` or, for a notebook whose cells have none, its position: \`cell-0\` is the first cell. It is required for \`replace\` and \`delete\`.
|
|
17
|
+
- \`edit_mode\` defaults to \`replace\`. Use \`insert\` to add a new cell after the cell with the given \`cell_id\` (or at the beginning of the notebook if \`cell_id\` is omitted) — \`cell_type\` is required when inserting. Use \`delete\` to remove the cell. Use \`append\` to add a cell at the end without naming one.
|
|
18
|
+
- Editing a code cell clears its outputs.`;
|