@cjhyy/code-shell-core 0.5.0-rc.2 → 0.6.0-rc.2
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 +13 -10
- package/dist/agent/agent-definition-registry.d.ts +3 -0
- package/dist/agent/agent-definition-registry.js +3 -1
- package/dist/agent/agent-definition.d.ts +15 -0
- package/dist/agent/agent-definition.js +27 -3
- package/dist/arena/context/context-tools.js +47 -4
- package/dist/arena/ledger.js +9 -1
- package/dist/arena/strategies/utils.d.ts +1 -4
- package/dist/arena/strategies/utils.js +7 -84
- package/dist/automation/cron-expr.d.ts +10 -0
- package/dist/automation/cron-expr.js +23 -5
- package/dist/automation/runner.d.ts +21 -4
- package/dist/automation/runner.js +48 -12
- package/dist/automation/scheduler.d.ts +38 -0
- package/dist/automation/scheduler.js +89 -12
- package/dist/automation/store.js +5 -2
- package/dist/capability-control/disabled-lists.d.ts +25 -0
- package/dist/capability-control/disabled-lists.js +57 -0
- package/dist/capability-control/overlay.d.ts +15 -0
- package/dist/capability-control/overlay.js +27 -0
- package/dist/cc-orchestrator/agent-adapter.d.ts +50 -0
- package/dist/cc-orchestrator/agent-adapter.js +133 -0
- package/dist/cc-orchestrator/cc-capability.d.ts +19 -0
- package/dist/cc-orchestrator/cc-capability.js +53 -0
- package/dist/cc-orchestrator/codex-session-discovery.d.ts +24 -0
- package/dist/cc-orchestrator/codex-session-discovery.js +191 -0
- package/dist/cc-orchestrator/codex-session-history.d.ts +25 -0
- package/dist/cc-orchestrator/codex-session-history.js +187 -0
- package/dist/cc-orchestrator/external-agent-changes.d.ts +19 -0
- package/dist/cc-orchestrator/external-agent-changes.js +214 -0
- package/dist/cc-orchestrator/external-agent-driver.d.ts +18 -0
- package/dist/cc-orchestrator/external-agent-driver.js +69 -0
- package/dist/cc-orchestrator/index.d.ts +8 -0
- package/dist/cc-orchestrator/index.js +8 -0
- package/dist/cc-orchestrator/relevance-judge.d.ts +15 -0
- package/dist/cc-orchestrator/relevance-judge.js +29 -0
- package/dist/cc-orchestrator/session-discovery.d.ts +46 -0
- package/dist/cc-orchestrator/session-discovery.js +125 -0
- package/dist/cc-orchestrator/session-history.d.ts +19 -0
- package/dist/cc-orchestrator/session-history.js +67 -0
- package/dist/cli/agent-server-stdio.d.ts +15 -1
- package/dist/cli/agent-server-stdio.js +115 -17
- package/dist/cli/agent-server-tcp.js +40 -26
- package/dist/context/compaction.d.ts +56 -0
- package/dist/context/compaction.js +186 -0
- package/dist/context/manager.js +25 -4
- package/dist/cost-tracker.js +5 -61
- package/dist/credentials/cipher.d.ts +49 -0
- package/dist/credentials/cipher.js +45 -0
- package/dist/credentials/cookie-jar.d.ts +24 -0
- package/dist/credentials/cookie-jar.js +40 -0
- package/dist/credentials/index.d.ts +7 -0
- package/dist/credentials/index.js +5 -0
- package/dist/credentials/inject-credential-tool.d.ts +20 -0
- package/dist/credentials/inject-credential-tool.js +130 -0
- package/dist/credentials/store.d.ts +72 -0
- package/dist/credentials/store.js +184 -0
- package/dist/credentials/types.d.ts +56 -0
- package/dist/credentials/use-credential-tool.d.ts +29 -0
- package/dist/credentials/use-credential-tool.js +205 -0
- package/dist/credentials/use-gate.d.ts +56 -0
- package/dist/credentials/use-gate.js +52 -0
- package/dist/data/model-metadata.d.ts +77 -0
- package/dist/data/model-metadata.js +56 -0
- package/dist/data/model-metadata.json +216 -0
- package/dist/data/openrouter-models.d.ts +18 -7
- package/dist/data/openrouter-models.js +35 -8
- package/dist/engine/aux-key.d.ts +10 -0
- package/dist/engine/aux-key.js +11 -0
- package/dist/engine/dynamic-tool-defs.d.ts +19 -0
- package/dist/engine/dynamic-tool-defs.js +36 -0
- package/dist/engine/engine.d.ts +267 -138
- package/dist/engine/engine.js +957 -191
- package/dist/engine/friendly-error.d.ts +18 -0
- package/dist/engine/friendly-error.js +63 -0
- package/dist/engine/goal.d.ts +145 -0
- package/dist/engine/goal.js +144 -0
- package/dist/engine/image-policy.d.ts +13 -0
- package/dist/engine/image-policy.js +24 -0
- package/dist/engine/model-connections-pool.d.ts +17 -0
- package/dist/engine/model-connections-pool.js +66 -0
- package/dist/engine/model-facade.d.ts +10 -0
- package/dist/engine/model-facade.js +25 -0
- package/dist/engine/patch-orphaned-tools.js +3 -0
- package/dist/engine/resolve-llm-config.d.ts +16 -0
- package/dist/engine/resolve-llm-config.js +44 -0
- package/dist/engine/runtime.js +2 -1
- package/dist/engine/sandbox-cache-key.d.ts +10 -0
- package/dist/engine/sandbox-cache-key.js +9 -0
- package/dist/engine/sandbox-config.d.ts +31 -0
- package/dist/engine/sandbox-config.js +38 -0
- package/dist/engine/session-usage.d.ts +19 -0
- package/dist/engine/session-usage.js +25 -0
- package/dist/engine/steer-queue.d.ts +32 -0
- package/dist/engine/steer-queue.js +26 -0
- package/dist/engine/streaming-tool-queue.d.ts +12 -0
- package/dist/engine/streaming-tool-queue.js +50 -10
- package/dist/engine/turn-loop.d.ts +67 -3
- package/dist/engine/turn-loop.js +292 -41
- package/dist/engine/types.d.ts +175 -0
- package/dist/engine/types.js +13 -0
- package/dist/external-agents/config.d.ts +2 -0
- package/dist/external-agents/config.js +15 -0
- package/dist/external-agents/types.d.ts +31 -0
- package/dist/external-agents/types.js +1 -0
- package/dist/git/utils.js +11 -6
- package/dist/git/worktree.d.ts +48 -0
- package/dist/git/worktree.js +86 -10
- package/dist/hooks/goal-stop-hook.d.ts +28 -0
- package/dist/hooks/goal-stop-hook.js +186 -9
- package/dist/hooks/registry.d.ts +8 -0
- package/dist/hooks/registry.js +19 -0
- package/dist/hooks/shell-runner.js +10 -21
- package/dist/index.d.ts +49 -6
- package/dist/index.js +60 -4
- package/dist/llm/capabilities/param-specs.d.ts +14 -0
- package/dist/llm/capabilities/param-specs.js +62 -0
- package/dist/llm/capabilities/rules.js +4 -0
- package/dist/llm/capabilities/types.d.ts +10 -0
- package/dist/llm/client-base.d.ts +28 -1
- package/dist/llm/client-base.js +119 -13
- package/dist/llm/model-cache.js +4 -2
- package/dist/llm/model-pool.d.ts +14 -0
- package/dist/llm/model-pool.js +13 -0
- package/dist/llm/provider-auth.d.ts +41 -0
- package/dist/llm/provider-auth.js +76 -0
- package/dist/llm/provider-catalog.d.ts +4 -0
- package/dist/llm/providers/anthropic.js +64 -14
- package/dist/llm/providers/openai.d.ts +36 -0
- package/dist/llm/providers/openai.js +257 -51
- package/dist/llm/reasoning-setting.d.ts +3 -3
- package/dist/llm/reasoning-setting.js +9 -1
- package/dist/llm/stream-watchdog.js +5 -1
- package/dist/llm/token-counter.js +9 -2
- package/dist/llm/types.d.ts +4 -0
- package/dist/logging/sanitize-messages.js +22 -0
- package/dist/lsp/manager.d.ts +1 -1
- package/dist/lsp/manager.js +40 -10
- package/dist/model-catalog/builtin.d.ts +12 -0
- package/dist/model-catalog/builtin.js +407 -0
- package/dist/model-catalog/gen-connections.d.ts +20 -0
- package/dist/model-catalog/gen-connections.js +28 -0
- package/dist/model-catalog/index.d.ts +41 -0
- package/dist/model-catalog/index.js +90 -0
- package/dist/model-catalog/params.d.ts +20 -0
- package/dist/model-catalog/params.js +45 -0
- package/dist/model-catalog/resolve.d.ts +48 -0
- package/dist/model-catalog/resolve.js +33 -0
- package/dist/model-catalog/save-entry.d.ts +32 -0
- package/dist/model-catalog/save-entry.js +104 -0
- package/dist/model-catalog/types.d.ts +561 -0
- package/dist/model-catalog/types.js +93 -0
- package/dist/model-catalog/upsert.d.ts +9 -0
- package/dist/model-catalog/upsert.js +8 -0
- package/dist/onboarding.d.ts +12 -82
- package/dist/onboarding.js +61 -326
- package/dist/plugins/gitOps.d.ts +19 -0
- package/dist/plugins/gitOps.js +73 -4
- package/dist/plugins/installer/checkUpdate.d.ts +16 -0
- package/dist/plugins/installer/checkUpdate.js +32 -0
- package/dist/plugins/installer/codex/convertCommands.d.ts +19 -0
- package/dist/plugins/installer/codex/convertCommands.js +46 -0
- package/dist/plugins/installer/codex/convertMcp.d.ts +5 -2
- package/dist/plugins/installer/codex/convertMcp.js +45 -5
- package/dist/plugins/installer/install.js +25 -1
- package/dist/plugins/installer/installFromArchive.d.ts +43 -0
- package/dist/plugins/installer/installFromArchive.js +134 -0
- package/dist/plugins/installer/installFromSource.js +8 -2
- package/dist/plugins/installer/loadPluginAgents.js +6 -2
- package/dist/plugins/installer/loadPluginMcp.d.ts +9 -2
- package/dist/plugins/installer/loadPluginMcp.js +35 -2
- package/dist/plugins/installer/pruneDisabled.d.ts +24 -0
- package/dist/plugins/installer/pruneDisabled.js +73 -0
- package/dist/plugins/installer/types.d.ts +5 -2
- package/dist/plugins/installer/types.js +1 -0
- package/dist/plugins/installer/uninstall.js +4 -0
- package/dist/plugins/installer/unzip.d.ts +14 -0
- package/dist/plugins/installer/unzip.js +82 -0
- package/dist/plugins/installer/update.d.ts +14 -0
- package/dist/plugins/installer/update.js +53 -21
- package/dist/plugins/loadPluginHooks.d.ts +47 -1
- package/dist/plugins/loadPluginHooks.js +73 -1
- package/dist/plugins/marketplaceManager.d.ts +7 -0
- package/dist/plugins/marketplaceManager.js +20 -0
- package/dist/plugins/pluginCommandHook.js +4 -18
- package/dist/plugins/pluginContent.d.ts +30 -0
- package/dist/plugins/pluginContent.js +83 -0
- package/dist/plugins/pluginInstaller.d.ts +13 -0
- package/dist/plugins/pluginInstaller.js +42 -8
- package/dist/plugins/schemas.js +1 -0
- package/dist/plugins/types.d.ts +6 -0
- package/dist/preset/index.d.ts +7 -1
- package/dist/preset/index.js +96 -6
- package/dist/product/types.d.ts +1 -1
- package/dist/prompt/composer.d.ts +27 -0
- package/dist/prompt/composer.js +67 -21
- package/dist/prompt/instruction-scanner.js +5 -3
- package/dist/prompt/section-loader.js +1 -0
- package/dist/prompt/sections/base.md +1 -0
- package/dist/prompt/sections/browser.md +10 -0
- package/dist/prompt/sections/coding.md +4 -0
- package/dist/protocol/chat-session-manager.d.ts +8 -2
- package/dist/protocol/chat-session-manager.js +36 -0
- package/dist/protocol/chat-session.d.ts +65 -0
- package/dist/protocol/chat-session.js +94 -2
- package/dist/protocol/client.d.ts +27 -0
- package/dist/protocol/client.js +38 -0
- package/dist/protocol/server.d.ts +112 -0
- package/dist/protocol/server.js +586 -16
- package/dist/protocol/transport.js +3 -2
- package/dist/protocol/types.d.ts +46 -0
- package/dist/protocol/types.js +16 -0
- package/dist/quota/credentials.d.ts +3 -0
- package/dist/quota/credentials.js +80 -0
- package/dist/quota/index.d.ts +36 -0
- package/dist/quota/index.js +155 -0
- package/dist/quota/types.d.ts +48 -0
- package/dist/quota/types.js +13 -0
- package/dist/review/review-prompt.d.ts +28 -0
- package/dist/review/review-prompt.js +81 -0
- package/dist/run/FileRunStore.js +8 -3
- package/dist/run/RunApprovalBackend.js +25 -5
- package/dist/run/RunManager.d.ts +12 -0
- package/dist/run/RunManager.js +35 -0
- package/dist/run/factory.d.ts +1 -1
- package/dist/runtime/background-shell.d.ts +139 -0
- package/dist/runtime/background-shell.js +495 -0
- package/dist/runtime/output-clean.d.ts +24 -0
- package/dist/runtime/output-clean.js +41 -0
- package/dist/runtime/ring-file.d.ts +64 -0
- package/dist/runtime/ring-file.js +174 -0
- package/dist/runtime/safe-spawn.js +15 -34
- package/dist/runtime/spawn-common.d.ts +148 -0
- package/dist/runtime/spawn-common.js +303 -0
- package/dist/runtime/truncate-output.d.ts +22 -0
- package/dist/runtime/truncate-output.js +49 -0
- package/dist/runtime/utf8-cut.d.ts +11 -0
- package/dist/runtime/utf8-cut.js +23 -0
- package/dist/services/auto-dream.d.ts +4 -0
- package/dist/services/auto-dream.js +26 -26
- package/dist/services/diagnostics.d.ts +1 -2
- package/dist/services/diagnostics.js +12 -7
- package/dist/services/extract-memories.d.ts +14 -1
- package/dist/services/extract-memories.js +45 -6
- package/dist/services/memory-orchestrator.d.ts +21 -0
- package/dist/services/memory-orchestrator.js +125 -50
- package/dist/services/session-memory.js +24 -12
- package/dist/session/file-history.d.ts +124 -1
- package/dist/session/file-history.js +222 -6
- package/dist/session/memory.d.ts +116 -2
- package/dist/session/memory.js +250 -28
- package/dist/session/session-manager.d.ts +40 -0
- package/dist/session/session-manager.js +113 -3
- package/dist/session/simple-diff.d.ts +23 -0
- package/dist/session/simple-diff.js +84 -0
- package/dist/session/transcript.d.ts +25 -1
- package/dist/session/transcript.js +35 -2
- package/dist/session/undo-target.d.ts +67 -0
- package/dist/session/undo-target.js +144 -0
- package/dist/settings/disk-defaults.d.ts +9 -2
- package/dist/settings/disk-defaults.js +11 -2
- package/dist/settings/feature-flags.d.ts +64 -0
- package/dist/settings/feature-flags.js +61 -0
- package/dist/settings/manager.d.ts +68 -1
- package/dist/settings/manager.js +266 -29
- package/dist/settings/migrate-config.d.ts +45 -0
- package/dist/settings/migrate-config.js +125 -0
- package/dist/settings/schema-export.d.ts +25 -0
- package/dist/settings/schema-export.js +38 -0
- package/dist/settings/schema.d.ts +1186 -771
- package/dist/settings/schema.js +268 -97
- package/dist/skills/scanner.d.ts +9 -0
- package/dist/skills/scanner.js +30 -2
- package/dist/stt/resolve-transcribe.d.ts +31 -0
- package/dist/stt/resolve-transcribe.js +108 -0
- package/dist/stt/transcribe.d.ts +51 -0
- package/dist/stt/transcribe.js +65 -0
- package/dist/tool-system/browser-bridge.d.ts +226 -0
- package/dist/tool-system/browser-bridge.js +163 -0
- package/dist/tool-system/builtin/agent-heartbeat.d.ts +49 -0
- package/dist/tool-system/builtin/agent-heartbeat.js +89 -0
- package/dist/tool-system/builtin/agent-notifications.d.ts +12 -3
- package/dist/tool-system/builtin/agent-notifications.js +9 -3
- package/dist/tool-system/builtin/agent-output-file.d.ts +38 -0
- package/dist/tool-system/builtin/agent-output-file.js +72 -0
- package/dist/tool-system/builtin/agent-registry.d.ts +12 -0
- package/dist/tool-system/builtin/agent-registry.js +8 -0
- package/dist/tool-system/builtin/agent.d.ts +21 -1
- package/dist/tool-system/builtin/agent.js +489 -42
- package/dist/tool-system/builtin/apply-patch/applier.js +66 -8
- package/dist/tool-system/builtin/apply-patch/backup-targets.d.ts +10 -0
- package/dist/tool-system/builtin/apply-patch/backup-targets.js +30 -0
- package/dist/tool-system/builtin/apply-patch/index.js +0 -15
- package/dist/tool-system/builtin/background-jobs.d.ts +76 -0
- package/dist/tool-system/builtin/background-jobs.js +124 -0
- package/dist/tool-system/builtin/background-shell-tools.d.ts +20 -0
- package/dist/tool-system/builtin/background-shell-tools.js +108 -0
- package/dist/tool-system/builtin/background-work.d.ts +67 -0
- package/dist/tool-system/builtin/background-work.js +86 -0
- package/dist/tool-system/builtin/bash-output-style.d.ts +32 -0
- package/dist/tool-system/builtin/bash-output-style.js +40 -0
- package/dist/tool-system/builtin/bash.d.ts +5 -2
- package/dist/tool-system/builtin/bash.js +98 -62
- package/dist/tool-system/builtin/browser-tools.d.ts +33 -0
- package/dist/tool-system/builtin/browser-tools.js +312 -0
- package/dist/tool-system/builtin/cancel-goal.d.ts +31 -0
- package/dist/tool-system/builtin/cancel-goal.js +64 -0
- package/dist/tool-system/builtin/check-quota.d.ts +15 -0
- package/dist/tool-system/builtin/check-quota.js +34 -0
- package/dist/tool-system/builtin/config.js +7 -0
- package/dist/tool-system/builtin/cron.d.ts +7 -0
- package/dist/tool-system/builtin/cron.js +55 -3
- package/dist/tool-system/builtin/drive-claude-code.d.ts +30 -0
- package/dist/tool-system/builtin/drive-claude-code.js +157 -0
- package/dist/tool-system/builtin/edit-model-catalog.d.ts +3 -0
- package/dist/tool-system/builtin/edit-model-catalog.js +94 -0
- package/dist/tool-system/builtin/edit.js +20 -16
- package/dist/tool-system/builtin/eol.d.ts +29 -0
- package/dist/tool-system/builtin/eol.js +37 -0
- package/dist/tool-system/builtin/file-cache.d.ts +6 -0
- package/dist/tool-system/builtin/file-cache.js +8 -0
- package/dist/tool-system/builtin/generate-image.d.ts +35 -0
- package/dist/tool-system/builtin/generate-image.js +278 -50
- package/dist/tool-system/builtin/generate-video.d.ts +55 -0
- package/dist/tool-system/builtin/generate-video.js +361 -0
- package/dist/tool-system/builtin/glob.js +0 -7
- package/dist/tool-system/builtin/grep.js +6 -8
- package/dist/tool-system/builtin/image-providers.d.ts +86 -0
- package/dist/tool-system/builtin/image-providers.js +190 -0
- package/dist/tool-system/builtin/image-uploader.d.ts +33 -0
- package/dist/tool-system/builtin/image-uploader.js +74 -0
- package/dist/tool-system/builtin/index.d.ts +7 -1
- package/dist/tool-system/builtin/index.js +249 -25
- package/dist/tool-system/builtin/mcp-tools.js +23 -3
- package/dist/tool-system/builtin/memory.js +45 -7
- package/dist/tool-system/builtin/notebook-edit.js +0 -7
- package/dist/tool-system/builtin/powershell.js +4 -1
- package/dist/tool-system/builtin/read.js +10 -10
- package/dist/tool-system/builtin/repl.js +4 -1
- package/dist/tool-system/builtin/skill.js +9 -0
- package/dist/tool-system/builtin/sleep.js +3 -2
- package/dist/tool-system/builtin/tool-search.js +25 -7
- package/dist/tool-system/builtin/video-providers.d.ts +154 -0
- package/dist/tool-system/builtin/video-providers.js +235 -0
- package/dist/tool-system/builtin/web-fetch.js +12 -2
- package/dist/tool-system/builtin/web-search.js +21 -7
- package/dist/tool-system/builtin/worktree.d.ts +2 -1
- package/dist/tool-system/builtin/worktree.js +31 -4
- package/dist/tool-system/builtin/write.js +0 -6
- package/dist/tool-system/context.d.ts +154 -6
- package/dist/tool-system/executor.d.ts +3 -1
- package/dist/tool-system/executor.js +172 -88
- package/dist/tool-system/investigation-guard.js +1 -1
- package/dist/tool-system/mcp-manager.d.ts +42 -4
- package/dist/tool-system/mcp-manager.js +186 -20
- package/dist/tool-system/path-policy.d.ts +5 -0
- package/dist/tool-system/path-policy.js +307 -8
- package/dist/tool-system/permission.d.ts +36 -1
- package/dist/tool-system/permission.js +281 -69
- package/dist/tool-system/plan-mode-allowlist.d.ts +13 -2
- package/dist/tool-system/plan-mode-allowlist.js +24 -2
- package/dist/tool-system/registry.d.ts +1 -0
- package/dist/tool-system/registry.js +16 -2
- package/dist/tool-system/sandbox/index.d.ts +8 -0
- package/dist/tool-system/sandbox/index.js +7 -2
- package/dist/tool-system/validate-tool-metadata.d.ts +36 -0
- package/dist/tool-system/validate-tool-metadata.js +63 -0
- package/dist/types.d.ts +217 -6
- package/dist/updater.js +20 -9
- package/dist/utils/envUtils.d.ts +0 -9
- package/dist/utils/envUtils.js +3 -28
- package/dist/utils/exec.d.ts +40 -0
- package/dist/utils/exec.js +144 -0
- package/dist/utils/json.d.ts +12 -0
- package/dist/utils/json.js +92 -0
- package/dist/utils/theme.d.ts +1 -1
- package/dist/utils/theme.js +1 -1
- package/dist/utils/toolDisplay.js +0 -1
- package/package.json +13 -7
- package/dist/agent/coordinator.d.ts +0 -49
- package/dist/agent/coordinator.js +0 -77
- package/dist/settings/manager.test.js +0 -73
- package/dist/tool-system/builtin/remote-trigger.d.ts +0 -6
- package/dist/tool-system/builtin/remote-trigger.js +0 -54
- package/dist/tool-system/builtin/send-message.d.ts +0 -6
- package/dist/tool-system/builtin/send-message.js +0 -47
- /package/dist/{settings/manager.test.d.ts → credentials/types.js} +0 -0
|
@@ -23,22 +23,31 @@ ${existingList}
|
|
|
23
23
|
${conversationText.slice(0, 30000)}
|
|
24
24
|
|
|
25
25
|
## Instructions
|
|
26
|
-
Identify NEW information that should be saved as persistent memories. Categories:
|
|
26
|
+
Identify NEW information that should be saved as persistent memories. Categories (type):
|
|
27
27
|
- **user**: Information about the user's role, preferences, or expertise
|
|
28
28
|
- **feedback**: Guidance about how to approach work (corrections or confirmations)
|
|
29
29
|
- **project**: Non-obvious facts about ongoing work, goals, or decisions
|
|
30
30
|
- **reference**: Pointers to external resources or systems
|
|
31
31
|
|
|
32
|
+
Also decide each memory's storage SCOPE. **Be VERY conservative about "global" — default to "project".**
|
|
33
|
+
- **global** (RARE — strong bar): ONLY a general working principle, durable user preference, or fact about WHO THE USER IS that would be useful in literally ANY project or task. Examples that qualify: "the user prefers Chinese replies", "always grep for consumers before declaring code dead", "git subprocess args need a -- separator".
|
|
34
|
+
- A concrete task's setup or domain data is NOT global even though it isn't tied to a code repo. Counter-examples that are **project, NOT global**: a specific daily-news / morning-briefing workflow and its data sources; how to log into a specific website; a particular model's config parameters; one integration's auth choice. These are task/domain specifics → "project".
|
|
35
|
+
- **project** (DEFAULT): anything specific to this repo, this task, or this domain — including the counter-examples above.
|
|
36
|
+
- The test for global: "is this a general way-of-working or who-the-user-is that applies across EVERY project?" Only then global. When in any doubt → project.
|
|
37
|
+
|
|
32
38
|
Rules:
|
|
33
39
|
- Extract AT MOST 2 memories per session. Prefer 0 to a marginal one — most sessions are noise.
|
|
40
|
+
- AT MOST 1 of the extracted memories may be "global". The global layer is injected every session, so keep it tiny and high-value. If two candidates both seem global, keep the single most universal one global and make the other "project".
|
|
34
41
|
- Only extract information that would be useful in FUTURE conversations
|
|
35
42
|
- Do not duplicate existing memories (re-read the "Existing Memories" list above carefully)
|
|
36
43
|
- Do not extract code patterns, file structures, or git history (derivable from code)
|
|
37
44
|
- Do not extract ephemeral task details, progress snapshots, or in-flight work state — those belong in the conversation, not memory
|
|
38
45
|
- Do not extract one-off research products (news reports, AI industry summaries, slide deck content, daily progress dumps) — they're done and not "durable, reusable information"
|
|
46
|
+
- NEVER include secrets: API keys, tokens, passwords, private URLs with credentials. If the durable fact involves a credential, describe WHERE it lives (e.g. "key is in .env as FOO_KEY"), never the value itself
|
|
39
47
|
- Each memory should have a clear, specific description
|
|
40
48
|
|
|
41
|
-
Respond with a JSON array of objects with fields: type, name, description, content
|
|
49
|
+
Respond with a JSON array of objects with fields: type, scope, name, description, content
|
|
50
|
+
(scope must be "global" or "project")
|
|
42
51
|
If nothing worth remembering, respond with an empty array: []`;
|
|
43
52
|
}
|
|
44
53
|
/** Max memories to accept from a single extraction pass. Code-side cap that
|
|
@@ -47,8 +56,16 @@ If nothing worth remembering, respond with an empty array: []`;
|
|
|
47
56
|
export const MAX_MEMORIES_PER_EXTRACTION = 2;
|
|
48
57
|
/**
|
|
49
58
|
* Parse extracted memories from LLM response.
|
|
59
|
+
*
|
|
60
|
+
* `maxCount` caps how many memories are accepted from one pass (the code-side
|
|
61
|
+
* guarantee of the prompt rule). Defaults to MAX_MEMORIES_PER_EXTRACTION; a
|
|
62
|
+
* caller can pass `settings.memories.maxCount` to tune it. Non-positive or
|
|
63
|
+
* absent → the default.
|
|
50
64
|
*/
|
|
51
|
-
export function parseExtractionResponse(response) {
|
|
65
|
+
export function parseExtractionResponse(response, maxCount) {
|
|
66
|
+
const cap = typeof maxCount === "number" && maxCount > 0
|
|
67
|
+
? Math.floor(maxCount)
|
|
68
|
+
: MAX_MEMORIES_PER_EXTRACTION;
|
|
52
69
|
try {
|
|
53
70
|
// Find JSON array in response
|
|
54
71
|
const jsonMatch = response.match(/\[[\s\S]*\]/);
|
|
@@ -57,13 +74,35 @@ export function parseExtractionResponse(response) {
|
|
|
57
74
|
const parsed = JSON.parse(jsonMatch[0]);
|
|
58
75
|
if (!Array.isArray(parsed))
|
|
59
76
|
return [];
|
|
60
|
-
const valid = parsed
|
|
77
|
+
const valid = parsed
|
|
78
|
+
.filter((m) => typeof m === "object" &&
|
|
61
79
|
m !== null &&
|
|
62
80
|
typeof m.type === "string" &&
|
|
63
81
|
typeof m.name === "string" &&
|
|
64
82
|
typeof m.content === "string" &&
|
|
65
|
-
["user", "feedback", "project", "reference"].includes(m.type))
|
|
66
|
-
|
|
83
|
+
["user", "feedback", "project", "reference"].includes(m.type))
|
|
84
|
+
// Normalize scope: only "global" survives as global; everything else
|
|
85
|
+
// (absent, "project", typos) → "project" — never promote to global by accident.
|
|
86
|
+
.map((m) => ({
|
|
87
|
+
type: m.type,
|
|
88
|
+
scope: m.scope === "global" ? "global" : "project",
|
|
89
|
+
name: m.name,
|
|
90
|
+
description: m.description,
|
|
91
|
+
content: m.content,
|
|
92
|
+
}));
|
|
93
|
+
// Hard cap (用户拍板 克制): at most 1 global per extraction. The prompt asks
|
|
94
|
+
// for this, but the model may ignore it — enforce in code. Keep the first
|
|
95
|
+
// global as-is; demote any further globals to project.
|
|
96
|
+
let globalSeen = false;
|
|
97
|
+
const capped = valid.map((m) => {
|
|
98
|
+
if (m.scope !== "global")
|
|
99
|
+
return m;
|
|
100
|
+
if (globalSeen)
|
|
101
|
+
return { ...m, scope: "project" };
|
|
102
|
+
globalSeen = true;
|
|
103
|
+
return m;
|
|
104
|
+
});
|
|
105
|
+
return capped.slice(0, cap);
|
|
67
106
|
}
|
|
68
107
|
catch {
|
|
69
108
|
return [];
|
|
@@ -35,12 +35,33 @@ export interface MemoryOrchestratorOptions {
|
|
|
35
35
|
projectDir?: string;
|
|
36
36
|
/** Optional pre-constructed MemoryManager (avoids re-creating for every call). */
|
|
37
37
|
memoryManager?: MemoryManager;
|
|
38
|
+
/**
|
|
39
|
+
* Max memories to accept per extraction pass. From settings.memories.maxCount;
|
|
40
|
+
* undefined → the built-in MAX_MEMORIES_PER_EXTRACTION default.
|
|
41
|
+
*/
|
|
42
|
+
maxCount?: number;
|
|
43
|
+
/**
|
|
44
|
+
* From settings.memories.autoExtract. `false` skips step 1 (LLM memory
|
|
45
|
+
* extraction) entirely — the user-curated store stops accumulating
|
|
46
|
+
* extractor noise — while session summaries and auto-dream keep running.
|
|
47
|
+
* Absent/true = extract (default behavior).
|
|
48
|
+
*/
|
|
49
|
+
autoExtract?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Recall-based TTL in days (用户拍板 C). A `project`-type memory not read for
|
|
52
|
+
* this many days is soft-deleted (moved to memory-trash). Stable types
|
|
53
|
+
* (user/feedback/reference) and pinned entries are never pruned. From
|
|
54
|
+
* settings.memories.recallTtlDays; undefined/<=0 → no sweep.
|
|
55
|
+
*/
|
|
56
|
+
recallTtlDays?: number;
|
|
38
57
|
}
|
|
39
58
|
export interface MemoryOrchestratorResult {
|
|
40
59
|
/** Number of new memory entries extracted and saved. */
|
|
41
60
|
extracted: number;
|
|
42
61
|
/** Whether the auto-dream consolidation was triggered. */
|
|
43
62
|
dreamTriggered: boolean;
|
|
63
|
+
/** Names of memories pruned by the recall-TTL sweep. */
|
|
64
|
+
pruned: string[];
|
|
44
65
|
}
|
|
45
66
|
export declare class MemoryOrchestrator {
|
|
46
67
|
private readonly options;
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
import { MemoryManager } from "../session/memory.js";
|
|
16
16
|
import { buildExtractionPrompt, parseExtractionResponse } from "./extract-memories.js";
|
|
17
17
|
import { saveSessionMemory, buildSessionMemoryPrompt } from "./session-memory.js";
|
|
18
|
+
import { extractJSON } from "../utils/json.js";
|
|
19
|
+
import { redactSecrets } from "../logging/sanitize-messages.js";
|
|
18
20
|
import { shouldAutoDream, recordSession, recordDreamComplete, buildDreamSystemPrompt, buildDreamUserPrompt } from "./auto-dream.js";
|
|
19
21
|
import { logger } from "../logging/logger.js";
|
|
20
22
|
export class MemoryOrchestrator {
|
|
@@ -34,51 +36,83 @@ export class MemoryOrchestrator {
|
|
|
34
36
|
const mm = this.options.memoryManager ?? new MemoryManager({ projectDir: this.options.projectDir });
|
|
35
37
|
const startTime = Date.now();
|
|
36
38
|
// --------------- 1. Extract durable memories ---------------
|
|
39
|
+
// settings.memories.autoExtract=false skips the extractor entirely (the
|
|
40
|
+
// curated store stops accumulating noise); summaries + dream still run.
|
|
37
41
|
let extracted = 0;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
42
|
+
if (this.options.autoExtract === false) {
|
|
43
|
+
logger.info("memory.extraction_skipped", { sessionId, reason: "autoExtract=false" });
|
|
44
|
+
}
|
|
45
|
+
else
|
|
46
|
+
try {
|
|
47
|
+
let t = Date.now();
|
|
48
|
+
const existing = mm.loadAll();
|
|
49
|
+
const loadMs = Date.now() - t;
|
|
50
|
+
t = Date.now();
|
|
51
|
+
const extractionPrompt = buildExtractionPrompt(transcript, existing);
|
|
52
|
+
const promptMs = Date.now() - t;
|
|
53
|
+
t = Date.now();
|
|
54
|
+
const response = await this.options.callLLM("You are a memory extraction assistant. Extract only durable, reusable information worth carrying into future sessions.", extractionPrompt);
|
|
55
|
+
const llmMs = Date.now() - t;
|
|
56
|
+
t = Date.now();
|
|
57
|
+
const entries = parseExtractionResponse(response, this.options.maxCount);
|
|
58
|
+
const parseMs = Date.now() - t;
|
|
59
|
+
t = Date.now();
|
|
60
|
+
// Route by scope (用户拍板 审批门): "project" memories auto-land in the
|
|
61
|
+
// per-project store (`mm`). "global" memories do NOT auto-land global —
|
|
62
|
+
// they go to the GLOBAL pending scope and wait for the user to approve in
|
|
63
|
+
// the settings panel. Nothing auto-writes the injected global store.
|
|
64
|
+
let pendingMm = null;
|
|
65
|
+
let globalCount = 0;
|
|
66
|
+
for (const entry of entries) {
|
|
67
|
+
const isGlobal = entry.scope === "global";
|
|
68
|
+
const target = isGlobal
|
|
69
|
+
? (pendingMm ??= new MemoryManager({ scope: "pending" }))
|
|
70
|
+
: mm;
|
|
71
|
+
target.save({
|
|
72
|
+
type: entry.type,
|
|
73
|
+
name: entry.name,
|
|
74
|
+
// Defense-in-depth: the extraction prompt forbids secrets, but a prompt
|
|
75
|
+
// is not a guarantee. An auto-extracted memory is persisted with no user
|
|
76
|
+
// review, so run the model-authored strings through the same
|
|
77
|
+
// redactSecrets the logging path uses — a leaked key never lands on disk.
|
|
78
|
+
description: redactSecrets(entry.description),
|
|
79
|
+
content: redactSecrets(entry.content),
|
|
80
|
+
// Provenance mark (feedback#18 方案 C): extractor writes are "auto"
|
|
81
|
+
// so the UI can tell curated memories from extractor noise.
|
|
82
|
+
origin: "auto",
|
|
83
|
+
// 审批门: stamp the source project on pending entries so "不批准/降级"
|
|
84
|
+
// can fall them back to the project they were extracted in.
|
|
85
|
+
...(isGlobal && this.options.projectDir
|
|
86
|
+
? { originProject: this.options.projectDir }
|
|
87
|
+
: {}),
|
|
88
|
+
});
|
|
89
|
+
if (isGlobal)
|
|
90
|
+
globalCount++;
|
|
91
|
+
}
|
|
92
|
+
const saveMs = Date.now() - t;
|
|
93
|
+
extracted = entries.length;
|
|
94
|
+
logger.info("memory.extraction_done", {
|
|
95
|
+
sessionId,
|
|
96
|
+
extracted,
|
|
97
|
+
pendingGlobalCount: globalCount, // global candidates queued for approval
|
|
98
|
+
projectCount: extracted - globalCount,
|
|
99
|
+
elapsedMs: Date.now() - startTime,
|
|
100
|
+
loadMs,
|
|
101
|
+
promptMs,
|
|
102
|
+
llmMs,
|
|
103
|
+
parseMs,
|
|
104
|
+
saveMs,
|
|
105
|
+
existingCount: existing.length,
|
|
106
|
+
transcriptMessages: transcript.length,
|
|
107
|
+
responseChars: response.length,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
logger.warn("memory.extraction_failed", {
|
|
112
|
+
sessionId,
|
|
113
|
+
error: err.message,
|
|
58
114
|
});
|
|
59
115
|
}
|
|
60
|
-
const saveMs = Date.now() - t;
|
|
61
|
-
extracted = entries.length;
|
|
62
|
-
logger.info("memory.extraction_done", {
|
|
63
|
-
sessionId,
|
|
64
|
-
extracted,
|
|
65
|
-
elapsedMs: Date.now() - startTime,
|
|
66
|
-
loadMs,
|
|
67
|
-
promptMs,
|
|
68
|
-
llmMs,
|
|
69
|
-
parseMs,
|
|
70
|
-
saveMs,
|
|
71
|
-
existingCount: existing.length,
|
|
72
|
-
transcriptMessages: transcript.length,
|
|
73
|
-
responseChars: response.length,
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
catch (err) {
|
|
77
|
-
logger.warn("memory.extraction_failed", {
|
|
78
|
-
sessionId,
|
|
79
|
-
error: err.message,
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
116
|
// --------------- 2. Session summary ---------------
|
|
83
117
|
try {
|
|
84
118
|
// Only summarise sessions with enough content to be meaningful.
|
|
@@ -86,9 +120,23 @@ export class MemoryOrchestrator {
|
|
|
86
120
|
if (messageCount >= 3) {
|
|
87
121
|
const smPrompt = buildSessionMemoryPrompt(transcript);
|
|
88
122
|
const smResponse = await this.options.callLLM("You are a session summariser. Output only valid JSON.", smPrompt);
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
123
|
+
// LLM 摘要常带 markdown 围栏 / 围栏外解释文字 / 末尾逗号 → 裸 JSON.parse 易碎。
|
|
124
|
+
// 复用 utils/json 的 extractJSON(剥围栏 + 花括号配平,识别字符串/转义)拿到候选,
|
|
125
|
+
// 解析失败再修一次常见错误(末尾逗号),都不行才放弃(走 catch,该 session 无摘要)。
|
|
126
|
+
const candidate = extractJSON(smResponse);
|
|
127
|
+
let parsed = null;
|
|
128
|
+
try {
|
|
129
|
+
parsed = JSON.parse(candidate);
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
try {
|
|
133
|
+
parsed = JSON.parse(candidate.replace(/,(\s*[}\]])/g, "$1"));
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
parsed = null;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (parsed) {
|
|
92
140
|
saveSessionMemory({
|
|
93
141
|
sessionId,
|
|
94
142
|
summary: String(parsed.summary ?? "").slice(0, 1000),
|
|
@@ -117,14 +165,17 @@ export class MemoryOrchestrator {
|
|
|
117
165
|
let dreamTriggered = false;
|
|
118
166
|
try {
|
|
119
167
|
if (shouldAutoDream() && this.options.runDream) {
|
|
120
|
-
// Dream sees
|
|
121
|
-
//
|
|
168
|
+
// Dream sees project user/ (read-only context) + project dream/
|
|
169
|
+
// (workspace) + global dream/ (cross-project workspace it also cleans).
|
|
122
170
|
const userMems = mm.loadScope("user");
|
|
123
171
|
const dreamMems = mm.loadScope("dream");
|
|
124
|
-
|
|
172
|
+
const globalDreamMems = this.options.projectDir
|
|
173
|
+
? new MemoryManager({ scope: "dream" }).loadScope("dream")
|
|
174
|
+
: [];
|
|
175
|
+
if (userMems.length + dreamMems.length + globalDreamMems.length > 0) {
|
|
125
176
|
const ran = await this.options.runDream({
|
|
126
177
|
systemPrompt: buildDreamSystemPrompt(),
|
|
127
|
-
userPrompt: buildDreamUserPrompt(userMems, dreamMems),
|
|
178
|
+
userPrompt: buildDreamUserPrompt(userMems, dreamMems, globalDreamMems),
|
|
128
179
|
projectDir: this.options.projectDir,
|
|
129
180
|
});
|
|
130
181
|
if (ran) {
|
|
@@ -146,6 +197,30 @@ export class MemoryOrchestrator {
|
|
|
146
197
|
error: err.message,
|
|
147
198
|
});
|
|
148
199
|
}
|
|
149
|
-
|
|
200
|
+
// --------------- 5. Recall-based TTL sweep (用户拍板 C) ---------------
|
|
201
|
+
// Soft-delete project-type memories not read for recallTtlDays. Runs on
|
|
202
|
+
// both the project store and the global store (global also accumulates
|
|
203
|
+
// project-type events if the LLM mis-scopes). Never throws into the result.
|
|
204
|
+
const pruned = [];
|
|
205
|
+
try {
|
|
206
|
+
const ttl = this.options.recallTtlDays;
|
|
207
|
+
if (ttl && ttl > 0) {
|
|
208
|
+
pruned.push(...mm.pruneByRecall(ttl));
|
|
209
|
+
// Only sweep the global store when we're not already it (projectDir set).
|
|
210
|
+
if (this.options.projectDir) {
|
|
211
|
+
pruned.push(...new MemoryManager({ scope: "user" }).pruneByRecall(ttl));
|
|
212
|
+
}
|
|
213
|
+
if (pruned.length > 0) {
|
|
214
|
+
logger.info("memory.recall_ttl_pruned", { sessionId, pruned, ttlDays: ttl });
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
catch (err) {
|
|
219
|
+
logger.warn("memory.recall_ttl_failed", {
|
|
220
|
+
sessionId,
|
|
221
|
+
error: err.message,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
return { extracted, dreamTriggered, pruned };
|
|
150
225
|
}
|
|
151
226
|
}
|
|
@@ -6,22 +6,28 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync } from "node:fs";
|
|
8
8
|
import { join } from "node:path";
|
|
9
|
-
import {
|
|
9
|
+
import { userHome } from "../settings/manager.js";
|
|
10
10
|
import { sortSessionMemoriesByRecency } from "./session-memory-sort.js";
|
|
11
|
-
|
|
11
|
+
// Resolve per-call (NOT a module const): userHome() reads $HOME live, so a
|
|
12
|
+
// relocated/test HOME redirects writes instead of pinning the real ~/.code-shell
|
|
13
|
+
// at import time (bun freezes a module-level homedir() and never re-reads it).
|
|
14
|
+
function memoryDir() {
|
|
15
|
+
return join(userHome(), ".code-shell", "session-memories");
|
|
16
|
+
}
|
|
12
17
|
/**
|
|
13
18
|
* Save a session memory entry.
|
|
14
19
|
*/
|
|
15
20
|
export function saveSessionMemory(entry) {
|
|
16
|
-
|
|
17
|
-
|
|
21
|
+
const dir = memoryDir();
|
|
22
|
+
mkdirSync(dir, { recursive: true });
|
|
23
|
+
const file = join(dir, `${entry.sessionId}.json`);
|
|
18
24
|
writeFileSync(file, JSON.stringify(entry, null, 2), "utf-8");
|
|
19
25
|
}
|
|
20
26
|
/**
|
|
21
27
|
* Load a session memory by session ID.
|
|
22
28
|
*/
|
|
23
29
|
export function loadSessionMemory(sessionId) {
|
|
24
|
-
const file = join(
|
|
30
|
+
const file = join(memoryDir(), `${sessionId}.json`);
|
|
25
31
|
if (!existsSync(file))
|
|
26
32
|
return null;
|
|
27
33
|
try {
|
|
@@ -35,18 +41,22 @@ export function loadSessionMemory(sessionId) {
|
|
|
35
41
|
* List all session memories, most recent first.
|
|
36
42
|
*/
|
|
37
43
|
export function listSessionMemories(limit = 50) {
|
|
38
|
-
|
|
44
|
+
const dir = memoryDir();
|
|
45
|
+
if (!existsSync(dir))
|
|
39
46
|
return [];
|
|
40
47
|
// Read all entries, then order by createdAt (not by filename — the filename
|
|
41
48
|
// is the sessionId, which has no chronological meaning), then take `limit`.
|
|
42
49
|
const entries = [];
|
|
43
|
-
for (const file of readdirSync(
|
|
50
|
+
for (const file of readdirSync(dir)) {
|
|
44
51
|
if (!file.endsWith(".json"))
|
|
45
52
|
continue;
|
|
46
53
|
try {
|
|
47
|
-
entries.push(JSON.parse(readFileSync(join(
|
|
54
|
+
entries.push(JSON.parse(readFileSync(join(dir, file), "utf-8")));
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
/* intentional: skip a corrupt/torn memory file rather than failing the
|
|
58
|
+
whole listing — one bad entry must not hide all the others. */
|
|
48
59
|
}
|
|
49
|
-
catch { }
|
|
50
60
|
}
|
|
51
61
|
return sortSessionMemoriesByRecency(entries).slice(0, limit);
|
|
52
62
|
}
|
|
@@ -71,10 +81,12 @@ export function buildSessionMemoryPrompt(messages) {
|
|
|
71
81
|
|
|
72
82
|
${text.slice(0, 30000)}
|
|
73
83
|
|
|
74
|
-
Respond with JSON
|
|
84
|
+
Respond with ONLY a single JSON object — no markdown code fence, no text before
|
|
85
|
+
or after. Keep every value on one line (escape any newline as \\n) and escape
|
|
86
|
+
any double quote inside a string as \\". Shape:
|
|
75
87
|
{
|
|
76
88
|
"summary": "One paragraph summarizing what was discussed and accomplished",
|
|
77
|
-
"keyTopics": ["topic1", "topic2"
|
|
78
|
-
"decisions": ["decision1", "decision2"
|
|
89
|
+
"keyTopics": ["topic1", "topic2"],
|
|
90
|
+
"decisions": ["decision1", "decision2"]
|
|
79
91
|
}`;
|
|
80
92
|
}
|
|
@@ -10,16 +10,84 @@ export interface FileSnapshot {
|
|
|
10
10
|
backupPath: string;
|
|
11
11
|
hash: string;
|
|
12
12
|
size: number;
|
|
13
|
+
/**
|
|
14
|
+
* The conversation turn (one user message = one turn) this snapshot was taken
|
|
15
|
+
* in. Powers turn-level undo (`latestTurnUndoTargets`). Optional so snapshots
|
|
16
|
+
* written before this feature still load; absent ones share the "undefined"
|
|
17
|
+
* bucket and degrade to whole-session undo.
|
|
18
|
+
*/
|
|
19
|
+
turnSeq?: number;
|
|
20
|
+
/**
|
|
21
|
+
* Set when this turn has been undone (by `undoLatestTurn`). Undone turns are
|
|
22
|
+
* SKIPPED by undo target selection (so the next undo peels the prior turn)
|
|
23
|
+
* but kept on disk so the turn can be re-applied via `redoLatestTurn`. Cleared
|
|
24
|
+
* on redo. Replaces the earlier "delete on undo" approach so redo has material.
|
|
25
|
+
*/
|
|
26
|
+
undone?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Redo material captured when a turn is undone: the file's content AT THE TIME
|
|
30
|
+
* OF UNDO (i.e. the turn's result), so `redoLatestTurn` can re-apply it.
|
|
31
|
+
* Stored separately from `snapshots` so it never pollutes undo selection
|
|
32
|
+
* (latestUndoTarget / earliestSnapshotsPerFile / latestTurnUndoTargets).
|
|
33
|
+
*/
|
|
34
|
+
export interface RedoRecord {
|
|
35
|
+
filePath: string;
|
|
36
|
+
/** The turn this redo restores (matches the undone snapshots' turnSeq). */
|
|
37
|
+
turnSeq: number;
|
|
38
|
+
/** Backup of the post-turn content to re-apply on redo. */
|
|
39
|
+
backupPath: string;
|
|
40
|
+
/**
|
|
41
|
+
* Whether the file EXISTED before this turn (had a pre-turn snapshot). False
|
|
42
|
+
* means the turn CREATED it — undo deleted it, so redo must recreate it (and
|
|
43
|
+
* conversely undo of a created file means "remove", handled by the caller).
|
|
44
|
+
*/
|
|
45
|
+
existedBefore: boolean;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Marks that a file was CREATED in a given turn (it did not exist before the
|
|
49
|
+
* turn's first edit). Recorded by `recordCreated` from the engine hook when the
|
|
50
|
+
* pre-edit `saveSnapshot` returns null (file absent). Drives the "undo deletes a
|
|
51
|
+
* newly-created file / redo recreates it" behaviour. Like snapshots, a created
|
|
52
|
+
* marker is flipped `undone` on undo and cleared on redo rather than deleted, so
|
|
53
|
+
* the create/delete can round-trip.
|
|
54
|
+
*/
|
|
55
|
+
export interface CreatedMarker {
|
|
56
|
+
filePath: string;
|
|
57
|
+
turnSeq: number;
|
|
58
|
+
undone?: boolean;
|
|
13
59
|
}
|
|
14
60
|
export declare class FileHistory {
|
|
15
61
|
private readonly historyDir;
|
|
16
62
|
private snapshots;
|
|
63
|
+
/**
|
|
64
|
+
* Redo material for undone turns, kept SEPARATE from `snapshots` so it never
|
|
65
|
+
* pollutes undo selection (latestTurnUndoTargets / earliestSnapshotsPerFile).
|
|
66
|
+
*/
|
|
67
|
+
private redoRecords;
|
|
68
|
+
/** Per-turn "this file was created" markers (see CreatedMarker). */
|
|
69
|
+
private created;
|
|
17
70
|
constructor(sessionDir: string);
|
|
18
71
|
/**
|
|
19
72
|
* Save a snapshot of a file before it is modified.
|
|
20
73
|
* Returns the snapshot record, or null if the file doesn't exist.
|
|
74
|
+
*
|
|
75
|
+
* `turnSeq` tags the snapshot with the current conversation turn so a later
|
|
76
|
+
* `/undo` can revert exactly the files that turn changed (see
|
|
77
|
+
* latestTurnUndoTargets). Omit it for callers without turn context.
|
|
78
|
+
*/
|
|
79
|
+
saveSnapshot(filePath: string, turnSeq?: number): FileSnapshot | null;
|
|
80
|
+
/**
|
|
81
|
+
* Record that `filePath` was CREATED in `turnSeq` — called by the engine hook
|
|
82
|
+
* when the pre-edit saveSnapshot returns null (file did not exist yet). Idempotent
|
|
83
|
+
* per (path, turn): a file built then edited again in the same turn is recorded
|
|
84
|
+
* once, so undo deletes it (rather than restoring an intra-turn snapshot). A
|
|
85
|
+
* marker already flipped `undone` from a prior undo is reused as-is (not
|
|
86
|
+
* re-armed) — only fresh turns create new markers.
|
|
21
87
|
*/
|
|
22
|
-
|
|
88
|
+
recordCreated(filePath: string, turnSeq: number): void;
|
|
89
|
+
/** Redo material captured by past undos (see RedoRecord). Returns a copy. */
|
|
90
|
+
getRedoRecords(): RedoRecord[];
|
|
23
91
|
/**
|
|
24
92
|
* Get all snapshots for a specific file.
|
|
25
93
|
*/
|
|
@@ -36,6 +104,61 @@ export declare class FileHistory {
|
|
|
36
104
|
* Get all tracked files.
|
|
37
105
|
*/
|
|
38
106
|
getTrackedFiles(): string[];
|
|
107
|
+
/**
|
|
108
|
+
* Restore EVERY tracked file to its earliest snapshot — the state before the
|
|
109
|
+
* first AI edit this session. Powers `/undo all`. Targets are computed up
|
|
110
|
+
* front (restore() appends a new snapshot, so reading them lazily mid-loop
|
|
111
|
+
* would be unstable). Returns a per-file result so a partial failure doesn't
|
|
112
|
+
* hide which files reverted.
|
|
113
|
+
*/
|
|
114
|
+
restoreAllToEarliest(): Array<{
|
|
115
|
+
filePath: string;
|
|
116
|
+
ok: boolean;
|
|
117
|
+
}>;
|
|
118
|
+
/**
|
|
119
|
+
* Capture the file's CURRENT on-disk content into a fresh redo backup and
|
|
120
|
+
* append a RedoRecord. `existedBefore` distinguishes a modified file (true,
|
|
121
|
+
* redo re-applies content) from a turn-created file (false, redo recreates it).
|
|
122
|
+
* Returns false if the file can't be read (then no record is added).
|
|
123
|
+
*/
|
|
124
|
+
private captureRedoBackup;
|
|
125
|
+
/**
|
|
126
|
+
* Turn-level undo: revert every file the most recent conversation turn changed
|
|
127
|
+
* back to its pre-turn state. Unlike the earlier "delete on undo" approach this
|
|
128
|
+
* now (a) captures the turn's RESULT as redo material so `redoLatestTurn` can
|
|
129
|
+
* re-apply it, and (b) MARKS the turn's snapshots `undone` rather than deleting
|
|
130
|
+
* them — `latestTurnUndoTargets` skips undone turns, so a subsequent `/undo`
|
|
131
|
+
* still peels the previous turn ("onion"). Powers `/undo`.
|
|
132
|
+
*
|
|
133
|
+
* Files the turn CREATED (recorded via recordCreated) are DELETED on undo (with
|
|
134
|
+
* existedBefore:false redo material) instead of restored. `targets` come from
|
|
135
|
+
* latestTurnUndoTargets so preview and restore agree. Returns per-file results.
|
|
136
|
+
*/
|
|
137
|
+
undoLatestTurn(targets: FileSnapshot[]): Array<{
|
|
138
|
+
filePath: string;
|
|
139
|
+
ok: boolean;
|
|
140
|
+
}>;
|
|
141
|
+
/** Greatest turnSeq among not-yet-undone created markers, or undefined. */
|
|
142
|
+
private latestLiveCreatedTurn;
|
|
143
|
+
/**
|
|
144
|
+
* Turn-level redo: re-apply a previously undone turn. For each redo target,
|
|
145
|
+
* write the stashed post-turn content back to disk (existedBefore:false
|
|
146
|
+
* records RECREATE a turn-created file). Then clear the `undone` flags on that
|
|
147
|
+
* turn's snapshots and created markers, and drop the consumed redo records.
|
|
148
|
+
*
|
|
149
|
+
* `redoTargets` come from latestRedoTargets (which guarantees they are the
|
|
150
|
+
* latest still-undone turn). Returns per-file results.
|
|
151
|
+
*/
|
|
152
|
+
redoLatestTurn(redoTargets: RedoRecord[]): Array<{
|
|
153
|
+
filePath: string;
|
|
154
|
+
ok: boolean;
|
|
155
|
+
}>;
|
|
156
|
+
/**
|
|
157
|
+
* All snapshots in record (chronological) order. Used by undo to pick the
|
|
158
|
+
* single most-recent modification across every file (see latestUndoTarget).
|
|
159
|
+
* Returns a copy so callers can't mutate the internal list.
|
|
160
|
+
*/
|
|
161
|
+
getAllSnapshots(): FileSnapshot[];
|
|
39
162
|
private saveIndex;
|
|
40
163
|
static loadFromDir(sessionDir: string): FileHistory;
|
|
41
164
|
}
|