@selesai/code 0.12.0 → 0.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/dist/core/agent-session.d.ts +1 -1
- package/dist/core/agent-session.js +1 -1
- package/dist/core/sdk.d.ts +2 -2
- package/dist/core/sdk.js +1 -1
- package/dist/core/system-prompt.d.ts +1 -1
- package/dist/core/system-prompt.js +1 -1
- package/dist/core/usage-totals.d.ts +2 -0
- package/dist/core/usage-totals.js +10 -0
- package/dist/extensions/ascii.txt +9 -0
- package/dist/extensions/package.json +1 -2
- package/dist/extensions/pi-hermes-memory/CHANGELOG.md +371 -0
- package/dist/extensions/pi-hermes-memory/LICENSE +21 -0
- package/dist/extensions/pi-hermes-memory/README.md +643 -0
- package/dist/extensions/pi-hermes-memory/docs/0.1/TASKS.md +197 -0
- package/dist/extensions/pi-hermes-memory/docs/0.2/PLAN.md +290 -0
- package/dist/extensions/pi-hermes-memory/docs/0.2/TASKS.md +134 -0
- package/dist/extensions/pi-hermes-memory/docs/0.2/TEST-PLAN.md +216 -0
- package/dist/extensions/pi-hermes-memory/docs/0.3/PLAN.md +330 -0
- package/dist/extensions/pi-hermes-memory/docs/0.3/TASKS.md +125 -0
- package/dist/extensions/pi-hermes-memory/docs/0.4/PLAN.md +160 -0
- package/dist/extensions/pi-hermes-memory/docs/0.4/TASKS.md +113 -0
- package/dist/extensions/pi-hermes-memory/docs/0.6/CHANGELOG.md +57 -0
- package/dist/extensions/pi-hermes-memory/docs/0.6/PLAN.md +202 -0
- package/dist/extensions/pi-hermes-memory/docs/0.6/TASKS.md +144 -0
- package/dist/extensions/pi-hermes-memory/docs/0.7/PLAN.md +349 -0
- package/dist/extensions/pi-hermes-memory/docs/0.7/TASKS.md +110 -0
- package/dist/extensions/pi-hermes-memory/docs/PUBLISHING.md +149 -0
- package/dist/extensions/pi-hermes-memory/docs/ROADMAP.md +468 -0
- package/dist/extensions/pi-hermes-memory/docs/images/memory-architecture.svg +1 -0
- package/dist/extensions/pi-hermes-memory/docs/images/pi-logo.svg +22 -0
- package/dist/extensions/pi-hermes-memory/docs/images/pi_memory.png +0 -0
- package/dist/extensions/pi-hermes-memory/docs/images/pi_memory.svg +19 -0
- package/dist/extensions/pi-hermes-memory/docs/images/security-flow.svg +1 -0
- package/dist/extensions/pi-hermes-memory/docs/images/session-lifecycle.svg +1 -0
- package/dist/extensions/pi-hermes-memory/docs/images/source-architecture.svg +1 -0
- package/dist/extensions/pi-hermes-memory/docs/mermaid/memory-architecture.mmd +49 -0
- package/dist/extensions/pi-hermes-memory/docs/mermaid/security-flow.mmd +40 -0
- package/dist/extensions/pi-hermes-memory/docs/mermaid/session-lifecycle.mmd +56 -0
- package/dist/extensions/pi-hermes-memory/docs/mermaid/source-architecture.mmd +54 -0
- package/dist/extensions/pi-hermes-memory/package-lock.json +3799 -0
- package/dist/extensions/pi-hermes-memory/package.json +66 -0
- package/dist/extensions/pi-hermes-memory/scripts/check-min-sdk.mjs +99 -0
- package/dist/extensions/pi-hermes-memory/scripts/ensure-dev.mjs +57 -0
- package/dist/extensions/pi-hermes-memory/src/auto-consolidation-warning.ts +6 -0
- package/dist/extensions/pi-hermes-memory/src/config.ts +178 -0
- package/dist/extensions/pi-hermes-memory/src/constants.ts +424 -0
- package/dist/extensions/pi-hermes-memory/src/extension-root-migration.ts +639 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/auto-consolidate.ts +401 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/background-review.ts +297 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/child-process-watchdog.mjs +90 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/correction-detector.ts +300 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/index-sessions.ts +86 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/insights.ts +78 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/interview.ts +37 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/learn-memory.ts +186 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/message-parts.ts +27 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/pi-child-process.ts +485 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/preview-context.ts +105 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/review-memory-ops.ts +506 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/session-backfill.ts +145 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/session-flush.ts +151 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/session-live-index.ts +94 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/skills-command.ts +1334 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/standing-pin.ts +111 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/switch-project.ts +75 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/sync-markdown-memories.ts +266 -0
- package/dist/extensions/pi-hermes-memory/src/index.ts +378 -0
- package/dist/extensions/pi-hermes-memory/src/lifecycle-timing.ts +54 -0
- package/dist/extensions/pi-hermes-memory/src/paths.ts +61 -0
- package/dist/extensions/pi-hermes-memory/src/project-context.ts +13 -0
- package/dist/extensions/pi-hermes-memory/src/project-memory-migration.ts +93 -0
- package/dist/extensions/pi-hermes-memory/src/project.ts +157 -0
- package/dist/extensions/pi-hermes-memory/src/prompt-context.ts +55 -0
- package/dist/extensions/pi-hermes-memory/src/store/atomic-lock-coordinator.ts +375 -0
- package/dist/extensions/pi-hermes-memory/src/store/canonical-storage-path.ts +54 -0
- package/dist/extensions/pi-hermes-memory/src/store/content-scanner.ts +101 -0
- package/dist/extensions/pi-hermes-memory/src/store/db.ts +1180 -0
- package/dist/extensions/pi-hermes-memory/src/store/fts-query.ts +101 -0
- package/dist/extensions/pi-hermes-memory/src/store/markdown-mutation-lock.ts +38 -0
- package/dist/extensions/pi-hermes-memory/src/store/memory-lookup.ts +24 -0
- package/dist/extensions/pi-hermes-memory/src/store/memory-store.ts +1191 -0
- package/dist/extensions/pi-hermes-memory/src/store/recovery-maintenance.ts +66 -0
- package/dist/extensions/pi-hermes-memory/src/store/schema.ts +118 -0
- package/dist/extensions/pi-hermes-memory/src/store/session-anchor-search.ts +472 -0
- package/dist/extensions/pi-hermes-memory/src/store/session-indexer.ts +511 -0
- package/dist/extensions/pi-hermes-memory/src/store/session-parser.ts +213 -0
- package/dist/extensions/pi-hermes-memory/src/store/session-search.ts +234 -0
- package/dist/extensions/pi-hermes-memory/src/store/skill-store.ts +950 -0
- package/dist/extensions/pi-hermes-memory/src/store/skill-utils.ts +133 -0
- package/dist/extensions/pi-hermes-memory/src/store/sqlite-memory-store.ts +1002 -0
- package/dist/extensions/pi-hermes-memory/src/store/sqlite-native.ts +241 -0
- package/dist/extensions/pi-hermes-memory/src/store/standing-instructions.ts +247 -0
- package/dist/extensions/pi-hermes-memory/src/tools/memory-search-tool.ts +95 -0
- package/dist/extensions/pi-hermes-memory/src/tools/memory-tool.ts +469 -0
- package/dist/extensions/pi-hermes-memory/src/tools/session-search-tool.ts +246 -0
- package/dist/extensions/pi-hermes-memory/src/tools/shared-output-view.ts +170 -0
- package/dist/extensions/pi-hermes-memory/src/tools/skill-tool.ts +333 -0
- package/dist/extensions/pi-hermes-memory/src/tools/tool-result-views.ts +105 -0
- package/dist/extensions/pi-hermes-memory/src/types.ts +214 -0
- package/dist/extensions/pi-hermes-memory/tests/config.test.ts +434 -0
- package/dist/extensions/pi-hermes-memory/tests/extension-root-migration.test.ts +368 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/auto-consolidate.test.ts +984 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/background-review.test.ts +950 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/correction-detector.test.ts +671 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/insights.test.ts +157 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/interview.test.ts +127 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/pi-child-process.test.ts +905 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/preview-context.test.ts +152 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/prompt-context.test.ts +166 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/resources-discover.test.ts +71 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/review-memory-ops.test.ts +614 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/session-backfill.test.ts +192 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/session-flush.test.ts +677 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/session-live-index.test.ts +225 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/skills-command.test.ts +827 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/standing-pin.test.ts +134 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/sync-markdown-memories.test.ts +491 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/system-prompt.test.ts +199 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/thinking-max.test.ts +64 -0
- package/dist/extensions/pi-hermes-memory/tests/index.test.ts +30 -0
- package/dist/extensions/pi-hermes-memory/tests/integration/flow.test.ts +126 -0
- package/dist/extensions/pi-hermes-memory/tests/lifecycle-timing.test.ts +76 -0
- package/dist/extensions/pi-hermes-memory/tests/paths.test.ts +23 -0
- package/dist/extensions/pi-hermes-memory/tests/project-memory-migration.test.ts +80 -0
- package/dist/extensions/pi-hermes-memory/tests/project-rebinding.test.ts +115 -0
- package/dist/extensions/pi-hermes-memory/tests/project.test.ts +120 -0
- package/dist/extensions/pi-hermes-memory/tests/run-all-timeout.test.ts +107 -0
- package/dist/extensions/pi-hermes-memory/tests/run-all.sh +45 -0
- package/dist/extensions/pi-hermes-memory/tests/store/atomic-lock-coordinator.test.ts +381 -0
- package/dist/extensions/pi-hermes-memory/tests/store/content-scanner.test.ts +388 -0
- package/dist/extensions/pi-hermes-memory/tests/store/db.test.ts +1046 -0
- package/dist/extensions/pi-hermes-memory/tests/store/markdown-mutation-lock.test.ts +34 -0
- package/dist/extensions/pi-hermes-memory/tests/store/memory-store.test.ts +2150 -0
- package/dist/extensions/pi-hermes-memory/tests/store/recovery-maintenance.test.ts +170 -0
- package/dist/extensions/pi-hermes-memory/tests/store/session-anchor-search.test.ts +210 -0
- package/dist/extensions/pi-hermes-memory/tests/store/session-indexer.test.ts +643 -0
- package/dist/extensions/pi-hermes-memory/tests/store/session-parser.test.ts +282 -0
- package/dist/extensions/pi-hermes-memory/tests/store/session-search.test.ts +287 -0
- package/dist/extensions/pi-hermes-memory/tests/store/skill-store.test.ts +678 -0
- package/dist/extensions/pi-hermes-memory/tests/store/skill-utils.test.ts +21 -0
- package/dist/extensions/pi-hermes-memory/tests/store/sqlite-lazy-load.test.ts +78 -0
- package/dist/extensions/pi-hermes-memory/tests/store/sqlite-memory-store.test.ts +543 -0
- package/dist/extensions/pi-hermes-memory/tests/store/sqlite-native.test.ts +164 -0
- package/dist/extensions/pi-hermes-memory/tests/store/standing-instructions.test.ts +171 -0
- package/dist/extensions/pi-hermes-memory/tests/tools/memory-search-tool.test.ts +84 -0
- package/dist/extensions/pi-hermes-memory/tests/tools/memory-tool.test.ts +709 -0
- package/dist/extensions/pi-hermes-memory/tests/tools/session-search-tool.test.ts +345 -0
- package/dist/extensions/pi-hermes-memory/tests/tools/shared-output-view.test.ts +362 -0
- package/dist/extensions/pi-hermes-memory/tests/tools/skill-tool.test.ts +478 -0
- package/dist/extensions/pi-hermes-memory/tests/tools/tool-result-renderer-wiring.test.ts +40 -0
- package/dist/extensions/pi-hermes-memory/tsconfig.json +19 -0
- package/dist/extensions/pi-subagents/.oxlintrc.json +43 -0
- package/dist/extensions/pi-subagents/AGENTS.md +5 -0
- package/dist/extensions/pi-subagents/CHANGELOG.md +157 -0
- package/dist/extensions/pi-subagents/README.md +12 -6
- package/dist/extensions/pi-subagents/VISION.md +81 -0
- package/dist/extensions/pi-subagents/agents/claude-code-writer.md +15 -0
- package/dist/extensions/pi-subagents/agents/claude-code.md +15 -0
- package/dist/extensions/pi-subagents/agents/codex-exec-writer.md +15 -0
- package/dist/extensions/pi-subagents/agents/codex-exec.md +15 -0
- package/dist/extensions/pi-subagents/agents/cursor-agent-writer.md +14 -0
- package/dist/extensions/pi-subagents/agents/cursor-agent.md +14 -0
- package/dist/extensions/pi-subagents/agents/reviewer.md +1 -3
- package/dist/extensions/pi-subagents/docs/agents.md +488 -0
- package/dist/extensions/pi-subagents/docs/configuration.md +46 -9
- package/dist/extensions/pi-subagents/docs/extension-api.md +42 -3
- package/dist/extensions/pi-subagents/docs/models.md +27 -4
- package/dist/extensions/pi-subagents/docs/observability.md +10 -9
- package/dist/extensions/pi-subagents/docs/tool-reference.md +102 -6
- package/dist/extensions/pi-subagents/docs/workflows.md +135 -0
- package/dist/extensions/pi-subagents/package-lock.json +389 -2
- package/dist/extensions/pi-subagents/package.json +3 -1
- package/dist/extensions/pi-subagents/prompts/review-loop.md +2 -2
- package/dist/extensions/pi-subagents/skills/council-mode/SKILL.md +1 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +3 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +7 -3
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +2 -2
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +26 -5
- package/dist/extensions/pi-subagents/src/agents/agent-management.ts +41 -22
- package/dist/extensions/pi-subagents/src/agents/agent-refinements.ts +4 -4
- package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +9 -2
- package/dist/extensions/pi-subagents/src/agents/agents.ts +322 -75
- package/dist/extensions/pi-subagents/src/agents/builtin-names.ts +6 -0
- package/dist/extensions/pi-subagents/src/agents/runtime-agent-events.ts +70 -0
- package/dist/extensions/pi-subagents/src/agents/runtime-agent-registry.ts +27 -20
- package/dist/extensions/pi-subagents/src/api/agents.ts +10 -5
- package/dist/extensions/pi-subagents/src/api/background-work.ts +5 -1
- package/dist/extensions/pi-subagents/src/api/delegation.ts +0 -7
- package/dist/extensions/pi-subagents/src/api/preflight.ts +34 -12
- package/dist/extensions/pi-subagents/src/extension/config.ts +70 -0
- package/dist/extensions/pi-subagents/src/extension/doctor.ts +3 -3
- package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +5 -3
- package/dist/extensions/pi-subagents/src/extension/index.ts +83 -30
- package/dist/extensions/pi-subagents/src/extension/public-execution.ts +44 -15
- package/dist/extensions/pi-subagents/src/extension/rpc.ts +55 -19
- package/dist/extensions/pi-subagents/src/extension/schemas.ts +41 -15
- package/dist/extensions/pi-subagents/src/extension/tool-description.ts +28 -31
- package/dist/extensions/pi-subagents/src/inspectors/herdr/actions.ts +2 -1
- package/dist/extensions/pi-subagents/src/inspectors/herdr/inspector-runner.ts +2 -10
- package/dist/extensions/pi-subagents/src/inspectors/herdr/session-roots-codec.ts +42 -0
- package/dist/extensions/pi-subagents/src/integrations/herdr-status.ts +51 -3
- package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +2 -0
- package/dist/extensions/pi-subagents/src/profiles/profiles.ts +5 -6
- package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +77 -10
- package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +176 -53
- package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +19 -12
- package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +29 -27
- package/dist/extensions/pi-subagents/src/runs/background/async-retention.ts +20 -3
- package/dist/extensions/pi-subagents/src/runs/background/async-status-snapshot.ts +23 -261
- package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +73 -7
- package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +8 -3
- package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +74 -8
- package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +37 -21
- package/dist/extensions/pi-subagents/src/runs/background/inspect-rpc.ts +8 -8
- package/dist/extensions/pi-subagents/src/runs/background/notify.ts +184 -9
- package/dist/extensions/pi-subagents/src/runs/background/result-delivery-ownership.ts +45 -0
- package/dist/extensions/pi-subagents/src/runs/background/result-files.ts +28 -14
- package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +38 -15
- package/dist/extensions/pi-subagents/src/runs/background/resume-guidance.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/background/retained-children.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +50 -13
- package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +93 -8
- package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +10 -4
- package/dist/extensions/pi-subagents/src/runs/background/steering.ts +4 -14
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +549 -377
- package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +58 -10
- package/dist/extensions/pi-subagents/src/runs/background/terminal-run-index.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +26 -1
- package/dist/extensions/pi-subagents/src/runs/background/wait-config.ts +23 -9
- package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +9 -2
- package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +2 -2
- package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +204 -129
- package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +9 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/foreground-history.ts +23 -1
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +773 -311
- package/dist/extensions/pi-subagents/src/runs/foreground/workflow-detach-reconcile.ts +140 -115
- package/dist/extensions/pi-subagents/src/runs/shared/abort-recovery.ts +119 -0
- package/dist/extensions/pi-subagents/src/runs/shared/async-status-projection.ts +463 -0
- package/dist/extensions/pi-subagents/src/runs/shared/child-identity.ts +19 -4
- package/dist/extensions/pi-subagents/src/runs/shared/child-launch-plan.ts +151 -0
- package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +21 -7
- package/dist/extensions/pi-subagents/src/runs/shared/claude-code-adapter.ts +129 -0
- package/dist/extensions/pi-subagents/src/runs/shared/codex-exec-adapter.ts +129 -0
- package/dist/extensions/pi-subagents/src/runs/shared/completion-evidence.ts +89 -0
- package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +5 -4
- package/dist/extensions/pi-subagents/src/runs/shared/cursor-agent-adapter.ts +114 -0
- package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +3 -3
- package/dist/extensions/pi-subagents/src/runs/shared/external-cli-contract.ts +167 -0
- package/dist/extensions/pi-subagents/src/runs/shared/external-cli-preflight.ts +122 -0
- package/dist/extensions/pi-subagents/src/runs/shared/external-cli-runner.ts +348 -55
- package/dist/extensions/pi-subagents/src/runs/shared/fast-mode-extension.ts +5 -5
- package/dist/extensions/pi-subagents/src/runs/shared/host-step-status.ts +230 -0
- package/dist/extensions/pi-subagents/src/runs/shared/lane-metadata.ts +105 -0
- package/dist/extensions/pi-subagents/src/runs/shared/launch-cwd.ts +16 -0
- package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +2 -1
- package/dist/extensions/pi-subagents/src/runs/shared/mcp-config-sources.ts +422 -0
- package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +221 -158
- package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-grant.ts +197 -0
- package/dist/extensions/pi-subagents/src/runs/shared/model-exclusions.ts +69 -7
- package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +47 -6
- package/dist/extensions/pi-subagents/src/runs/shared/mutation-evidence.ts +7 -2
- package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +9 -3
- package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +9 -5
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +419 -7
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +15 -1
- package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +81 -8
- package/dist/extensions/pi-subagents/src/runs/shared/process-signal.ts +13 -0
- package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +21 -1
- package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +44 -4
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +98 -13
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/shared/worktree-cleanup-plan.ts +847 -0
- package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +18 -0
- package/dist/extensions/pi-subagents/src/shared/child-session-name.ts +46 -0
- package/dist/extensions/pi-subagents/src/shared/extension-context.ts +24 -0
- package/dist/extensions/pi-subagents/src/shared/fork-context.ts +21 -0
- package/dist/extensions/pi-subagents/src/shared/formatters.ts +18 -3
- package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +5 -1
- package/dist/extensions/pi-subagents/src/shared/pruned-fork.ts +450 -0
- package/dist/extensions/pi-subagents/src/shared/session-file-trust.ts +19 -0
- package/dist/extensions/pi-subagents/src/shared/session-tokens.ts +14 -3
- package/dist/extensions/pi-subagents/src/shared/settings.ts +19 -105
- package/dist/extensions/pi-subagents/src/shared/shortcuts.ts +17 -0
- package/dist/extensions/pi-subagents/src/shared/types.ts +359 -40
- package/dist/extensions/pi-subagents/src/shared/utils.ts +41 -84
- package/dist/extensions/pi-subagents/src/shared/workflow-child-permit.ts +116 -0
- package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +1 -9
- package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +0 -4
- package/dist/extensions/pi-subagents/src/slash/slash-bridge.ts +1 -2
- package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +378 -88
- package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +22 -11
- package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +3 -0
- package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +147 -79
- package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +11 -5
- package/dist/extensions/pi-subagents/src/tui/fleet.ts +39 -18
- package/dist/extensions/pi-subagents/src/tui/render.ts +369 -46
- package/dist/extensions/pi-subagents/src/watchdog/turn-delta.ts +1 -1
- package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +6 -3
- package/dist/extensions/pi-subagents/src/workflows/host-command.ts +230 -0
- package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +740 -58
- package/dist/extensions/pi-subagents/src/workflows/workflow-child-summary.ts +121 -0
- package/dist/extensions/pi-subagents/src/workflows/workflow-preflight.ts +270 -0
- package/dist/extensions/pi-subagents/src/workflows/workflow-receipt.ts +195 -6
- package/dist/extensions/pi-subagents/src/workflows/workflow-settlement.ts +246 -0
- package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +1114 -260
- package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +34 -0
- package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +150 -3
- package/dist/extensions/pi-subagents/test/integration/claude-code-smoke.test.ts +52 -0
- package/dist/extensions/pi-subagents/test/integration/claude-code-writer-smoke.test.ts +55 -0
- package/dist/extensions/pi-subagents/test/integration/codex-exec-smoke.test.ts +53 -0
- package/dist/extensions/pi-subagents/test/integration/codex-exec-writer-smoke.test.ts +57 -0
- package/dist/extensions/pi-subagents/test/integration/cursor-agent-smoke.test.ts +59 -0
- package/dist/extensions/pi-subagents/test/integration/cursor-agent-writer-smoke.test.ts +62 -0
- package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +57 -1
- package/dist/extensions/pi-subagents/test/integration/external-cli-runner.test.ts +1 -0
- package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +20 -0
- package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +4 -3
- package/dist/extensions/pi-subagents/test/integration/orca-progress-tabs.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +54 -4
- package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +482 -4
- package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +157 -9
- package/dist/extensions/pi-subagents/test/integration/session-tokens.test.ts +5 -5
- package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +1508 -291
- package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +423 -1
- package/dist/extensions/pi-subagents/test/integration/template-resolution.test.ts +8 -0
- package/dist/extensions/pi-subagents/test/support/cursor-smoke-inputs.ts +51 -0
- package/dist/extensions/pi-subagents/test/support/helpers.ts +2 -0
- package/dist/extensions/pi-subagents/test/support/mock-pi.ts +5 -5
- package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +6 -6
- package/dist/extensions/pi-subagents/test/unit/abort-recovery.test.ts +152 -0
- package/dist/extensions/pi-subagents/test/unit/active-async-capacity.test.ts +48 -0
- package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +184 -6
- package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +66 -6
- package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +77 -0
- package/dist/extensions/pi-subagents/test/unit/agent-refinements.test.ts +18 -0
- package/dist/extensions/pi-subagents/test/unit/anti-slop-oxlint.test.ts +86 -0
- package/dist/extensions/pi-subagents/test/unit/artifacts.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +101 -1
- package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +121 -0
- package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +28 -0
- package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +14 -7
- package/dist/extensions/pi-subagents/test/unit/async-retention.test.ts +53 -0
- package/dist/extensions/pi-subagents/test/unit/async-status-projection.test.ts +190 -0
- package/dist/extensions/pi-subagents/test/unit/async-status-snapshot.test.ts +42 -0
- package/dist/extensions/pi-subagents/test/unit/auto-drain.test.ts +8 -4
- package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +23 -0
- package/dist/extensions/pi-subagents/test/unit/chain-root-attachment.test.ts +78 -1
- package/dist/extensions/pi-subagents/test/unit/child-launch-plan.test.ts +94 -0
- package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +21 -0
- package/dist/extensions/pi-subagents/test/unit/child-session-name.test.ts +50 -0
- package/dist/extensions/pi-subagents/test/unit/claude-code-adapter.test.ts +245 -0
- package/dist/extensions/pi-subagents/test/unit/codex-exec-adapter.test.ts +192 -0
- package/dist/extensions/pi-subagents/test/unit/compaction-resume.test.ts +27 -0
- package/dist/extensions/pi-subagents/test/unit/completion-evidence.test.ts +150 -0
- package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +21 -0
- package/dist/extensions/pi-subagents/test/unit/cursor-agent-adapter.test.ts +259 -0
- package/dist/extensions/pi-subagents/test/unit/cursor-smoke-inputs.test.ts +77 -0
- package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +1 -4
- package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/extension-context.test.ts +27 -0
- package/dist/extensions/pi-subagents/test/unit/external-cli-runner.test.ts +223 -0
- package/dist/extensions/pi-subagents/test/unit/fast-mode-extension.test.ts +27 -0
- package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +208 -2
- package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +29 -1
- package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +110 -1
- package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +10 -0
- package/dist/extensions/pi-subagents/test/unit/formatters.test.ts +14 -0
- package/dist/extensions/pi-subagents/test/unit/herdr-inspector.test.ts +18 -9
- package/dist/extensions/pi-subagents/test/unit/herdr-session-roots-codec.test.ts +63 -0
- package/dist/extensions/pi-subagents/test/unit/herdr-shell-command.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/herdr-status-bridge.test.ts +132 -0
- package/dist/extensions/pi-subagents/test/unit/host-command.test.ts +156 -0
- package/dist/extensions/pi-subagents/test/unit/host-step-status.test.ts +98 -0
- package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +178 -26
- package/dist/extensions/pi-subagents/test/unit/index-segment.test.ts +2 -1
- package/dist/extensions/pi-subagents/test/unit/inspect-rpc.test.ts +21 -0
- package/dist/extensions/pi-subagents/test/unit/mcp-direct-tool-grant.test.ts +138 -0
- package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/model-exclusions.test.ts +91 -0
- package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +72 -7
- package/dist/extensions/pi-subagents/test/unit/mutation-evidence.test.ts +21 -0
- package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +1 -0
- package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +20 -2
- package/dist/extensions/pi-subagents/test/unit/notify.test.ts +129 -1
- package/dist/extensions/pi-subagents/test/unit/orca-progress-tabs.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +4 -0
- package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +358 -0
- package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +574 -21
- package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +109 -1
- package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +71 -1
- package/dist/extensions/pi-subagents/test/unit/profiles.test.ts +7 -7
- package/dist/extensions/pi-subagents/test/unit/pruned-fork.test.ts +214 -0
- package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +29 -8
- package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +53 -0
- package/dist/extensions/pi-subagents/test/unit/result-delivery-ownership.test.ts +34 -0
- package/dist/extensions/pi-subagents/test/unit/result-files.test.ts +101 -3
- package/dist/extensions/pi-subagents/test/unit/retained-children.test.ts +1 -0
- package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +10 -8
- package/dist/extensions/pi-subagents/test/unit/run-fanout-budget.test.ts +71 -1
- package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +41 -7
- package/dist/extensions/pi-subagents/test/unit/runtime-agent-registration.test.ts +136 -2
- package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +137 -0
- package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +33 -12
- package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +504 -1
- package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +8 -0
- package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +12 -1
- package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +3 -5
- package/dist/extensions/pi-subagents/test/unit/steering.test.ts +5 -6
- package/dist/extensions/pi-subagents/test/unit/subagent-action-recovery.test.ts +0 -8
- package/dist/extensions/pi-subagents/test/unit/subagent-guide.test.ts +5 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +157 -2
- package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +63 -4
- package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +27 -23
- package/dist/extensions/pi-subagents/test/unit/wait-completions.test.ts +44 -0
- package/dist/extensions/pi-subagents/test/unit/wait-subscriptions.test.ts +1 -0
- package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +7 -5
- package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +106 -0
- package/dist/extensions/pi-subagents/test/unit/workflow-detach-reconcile.test.ts +484 -9
- package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +38 -4
- package/dist/extensions/pi-subagents/test/unit/workflow-preflight.test.ts +155 -0
- package/dist/extensions/pi-subagents/test/unit/workflow-receipt.test.ts +318 -0
- package/dist/extensions/pi-subagents/test/unit/workflow-resume-hint.test.ts +365 -0
- package/dist/extensions/pi-subagents/test/unit/worktree-cleanup-plan.test.ts +349 -0
- package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +21 -0
- package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +2 -7
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/effect/index.ts +13 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/effect/rules/no-service-constructor-imports.ts +52 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/index.ts +41 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-chained-type-assertions.ts +77 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-conditional-empty-object-spread.ts +49 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-known-value-widening.ts +247 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-module-mocking.ts +91 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-object-parameters.ts +126 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-reflect-apply.ts +28 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-reflect-get.ts +28 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-runtime-typeof.ts +67 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-shape-in-symbol-names.ts +39 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unknown-parameters.ts +83 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unknown-returns.ts +115 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unknown-type-aliases.ts +72 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unsafe-dictionary-type.ts +134 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-widen-then-assert.ts +366 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/require-safety-comment-for-type-assertion.ts +62 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/shared/dictionary-types.ts +502 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/shared/lexical-type-parameters.ts +60 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/shared/reflect-method.ts +35 -0
- package/dist/extensions/pi-tool-display/tests/capabilities.test.ts +1 -1
- package/dist/extensions/pi-tool-display/tests/settings-inspector.test.ts +2 -2
- package/dist/extensions/pi-tool-display/tests/tool-overrides-mcp.test.ts +1 -1
- package/dist/extensions/pi-zentui/extensions/zentui/format.ts +2 -1
- package/dist/extensions/pi-zentui/test/format.test.ts +15 -1
- package/dist/modes/interactive/components/footer.js +2 -2
- package/dist/modes/interactive/interactive-mode.js +11 -11
- package/dist/skills/workflow/SKILL.md +65 -50
- package/package.json +112 -110
- package/dist/extensions/enable-readonly-tools.test.ts +0 -63
- package/dist/extensions/enable-readonly-tools.ts +0 -24
- package/dist/extensions/model-prompt-injector/config.json +0 -16
- package/dist/extensions/model-prompt-injector/index.test.ts +0 -102
- package/dist/extensions/model-prompt-injector/index.ts +0 -148
- package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +0 -98
- package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +0 -250
|
@@ -0,0 +1,709 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for memory tool registration and execute function.
|
|
3
|
+
*/
|
|
4
|
+
import { describe, it, beforeEach, afterEach } from "node:test";
|
|
5
|
+
import * as assert from "node:assert/strict";
|
|
6
|
+
import fs from "node:fs";
|
|
7
|
+
import os from "node:os";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import { registerMemoryTool } from "../../src/tools/memory-tool.js";
|
|
10
|
+
import { MemoryStore } from "../../src/store/memory-store.js";
|
|
11
|
+
import { DatabaseManager } from "../../src/store/db.js";
|
|
12
|
+
import { getMemories, syncMemoryEntry } from "../../src/store/sqlite-memory-store.js";
|
|
13
|
+
import { ENTRY_DELIMITER, MEMORY_FILE } from "../../src/constants.js";
|
|
14
|
+
import { Value } from "typebox/value";
|
|
15
|
+
|
|
16
|
+
describe("registerMemoryTool", () => {
|
|
17
|
+
let tmpDir: string;
|
|
18
|
+
let dbManager: DatabaseManager;
|
|
19
|
+
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "memory-tool-test-"));
|
|
22
|
+
dbManager = new DatabaseManager(tmpDir);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
afterEach(() => {
|
|
26
|
+
dbManager.close();
|
|
27
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("registers action-specific memory tools with required parameters", () => {
|
|
31
|
+
const registeredTools: any[] = [];
|
|
32
|
+
|
|
33
|
+
const mockPi = {
|
|
34
|
+
registerTool: (def: any) => {
|
|
35
|
+
registeredTools.push(def);
|
|
36
|
+
},
|
|
37
|
+
} as unknown as ExtensionAPI;
|
|
38
|
+
|
|
39
|
+
registerMemoryTool(mockPi, {} as MemoryStore, null);
|
|
40
|
+
|
|
41
|
+
assert.deepStrictEqual(
|
|
42
|
+
registeredTools.map((tool) => tool.name),
|
|
43
|
+
["memory_add", "memory_replace", "memory_remove"],
|
|
44
|
+
);
|
|
45
|
+
for (const tool of registeredTools) {
|
|
46
|
+
assert.ok(tool.description.length > 0);
|
|
47
|
+
assert.ok(tool.promptSnippet.length > 0);
|
|
48
|
+
assert.ok(Array.isArray(tool.promptGuidelines));
|
|
49
|
+
assert.ok(tool.parameters);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("execute add returns JSON with usage field", async () => {
|
|
54
|
+
let capturedResult: any;
|
|
55
|
+
|
|
56
|
+
const mockPi = {
|
|
57
|
+
registerTool: (def: any) => {
|
|
58
|
+
if (!capturedResult || def.name === "memory_add") capturedResult = def;
|
|
59
|
+
},
|
|
60
|
+
} as unknown as ExtensionAPI;
|
|
61
|
+
|
|
62
|
+
const mockStore = {
|
|
63
|
+
add: () => ({
|
|
64
|
+
success: true,
|
|
65
|
+
target: "memory",
|
|
66
|
+
entries: ["Entry one"],
|
|
67
|
+
usage: "5% — 110/5000 chars",
|
|
68
|
+
entry_count: 1,
|
|
69
|
+
message: "Entry added.",
|
|
70
|
+
}),
|
|
71
|
+
} as unknown as MemoryStore;
|
|
72
|
+
|
|
73
|
+
registerMemoryTool(mockPi, mockStore, null, dbManager);
|
|
74
|
+
const result = await capturedResult.execute("tc-1", { action: "add", target: "memory", content: "Entry one" }, undefined as any, undefined as any, undefined as any);
|
|
75
|
+
|
|
76
|
+
assert.strictEqual(result.content[0].type, "text", "content should be text type");
|
|
77
|
+
const parsed = JSON.parse(result.content[0].text);
|
|
78
|
+
assert.strictEqual(parsed.success, true, "result should be success");
|
|
79
|
+
assert.ok(parsed.usage.includes("chars"), "usage should contain 'chars'");
|
|
80
|
+
assert.ok(parsed.usage.includes("5000"), "usage should show total limit");
|
|
81
|
+
assert.strictEqual(parsed.entry_count, 1, "entry_count should be 1");
|
|
82
|
+
assert.strictEqual(result.details.success, true, "details should mirror result");
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("execute add with FIFO evictions returns normal text with full rotated entries", async () => {
|
|
86
|
+
let capturedResult: any;
|
|
87
|
+
|
|
88
|
+
const mockPi = {
|
|
89
|
+
registerTool: (def: any) => {
|
|
90
|
+
if (!capturedResult || def.name === "memory_add") capturedResult = def;
|
|
91
|
+
},
|
|
92
|
+
} as unknown as ExtensionAPI;
|
|
93
|
+
|
|
94
|
+
const evictedOne = "First rotated entry with full detail.";
|
|
95
|
+
const evictedTwo = "Second rotated entry with\nmultiple lines preserved.";
|
|
96
|
+
const mockStore = {
|
|
97
|
+
add: () => ({
|
|
98
|
+
success: true,
|
|
99
|
+
target: "memory",
|
|
100
|
+
entries: ["New entry"],
|
|
101
|
+
usage: "90% — 4500/5000 chars",
|
|
102
|
+
entry_count: 1,
|
|
103
|
+
message: "Memory updated. Rotated 2 older entries to stay within the limit.",
|
|
104
|
+
evicted_entries: [evictedOne, evictedTwo],
|
|
105
|
+
evicted_count: 2,
|
|
106
|
+
}),
|
|
107
|
+
} as unknown as MemoryStore;
|
|
108
|
+
|
|
109
|
+
registerMemoryTool(mockPi, mockStore, null);
|
|
110
|
+
const result = await capturedResult.execute("tc-1", { action: "add", target: "memory", content: "New entry" }, undefined as any, undefined as any, undefined as any);
|
|
111
|
+
|
|
112
|
+
const text = result.content[0].text;
|
|
113
|
+
assert.throws(() => JSON.parse(text));
|
|
114
|
+
assert.match(text, /Memory updated\. Rotated 2 older entries/);
|
|
115
|
+
assert.match(text, /Rotated active memory entries:/);
|
|
116
|
+
assert.ok(text.includes(`1. ${evictedOne}`));
|
|
117
|
+
assert.ok(text.includes(`2. ${evictedTwo}`));
|
|
118
|
+
assert.match(text, /If one of these entries should stay active, add it again\./);
|
|
119
|
+
assert.match(text, /Usage: 90%/);
|
|
120
|
+
assert.deepStrictEqual(result.details.evicted_entries, [evictedOne, evictedTwo]);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("syncs successful adds into SQLite", async () => {
|
|
124
|
+
let capturedResult: any;
|
|
125
|
+
const mockPi = {
|
|
126
|
+
registerTool: (def: any) => {
|
|
127
|
+
if (!capturedResult || def.name === "memory_add") capturedResult = def;
|
|
128
|
+
},
|
|
129
|
+
} as unknown as ExtensionAPI;
|
|
130
|
+
|
|
131
|
+
const mockStore = {
|
|
132
|
+
add: () => ({
|
|
133
|
+
success: true,
|
|
134
|
+
target: "memory",
|
|
135
|
+
entries: ["Entry one"],
|
|
136
|
+
usage: "5% — 110/5000 chars",
|
|
137
|
+
entry_count: 1,
|
|
138
|
+
message: "Entry added.",
|
|
139
|
+
}),
|
|
140
|
+
} as unknown as MemoryStore;
|
|
141
|
+
|
|
142
|
+
registerMemoryTool(mockPi, mockStore, null, dbManager);
|
|
143
|
+
await capturedResult.execute("tc-1", { action: "add", target: "memory", content: "Entry one" }, undefined as any, undefined as any, undefined as any);
|
|
144
|
+
|
|
145
|
+
const results = getMemories(dbManager, { target: 'memory', project: null });
|
|
146
|
+
assert.strictEqual(results.length, 1);
|
|
147
|
+
assert.strictEqual(results[0].content, 'Entry one');
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("reports the matching target when replace is sent to the wrong target", async () => {
|
|
151
|
+
let removeTool: any;
|
|
152
|
+
const mockPi = {
|
|
153
|
+
registerTool: (def: any) => {
|
|
154
|
+
if (def.name === "memory_remove") removeTool = def;
|
|
155
|
+
},
|
|
156
|
+
} as unknown as ExtensionAPI;
|
|
157
|
+
const store = new MemoryStore({
|
|
158
|
+
memoryMode: "policy-only",
|
|
159
|
+
memoryCharLimit: 5000,
|
|
160
|
+
userCharLimit: 5000,
|
|
161
|
+
projectCharLimit: 5000,
|
|
162
|
+
nudgeInterval: 10,
|
|
163
|
+
reviewEnabled: false,
|
|
164
|
+
flushOnCompact: false,
|
|
165
|
+
flushOnShutdown: false,
|
|
166
|
+
flushMinTurns: 6,
|
|
167
|
+
autoConsolidate: false,
|
|
168
|
+
correctionDetection: false,
|
|
169
|
+
failureInjectionEnabled: true,
|
|
170
|
+
failureInjectionMaxAgeDays: 7,
|
|
171
|
+
failureInjectionMaxEntries: 5,
|
|
172
|
+
nudgeToolCalls: 15,
|
|
173
|
+
consolidationTimeoutMs: 60000,
|
|
174
|
+
memoryDir: tmpDir,
|
|
175
|
+
});
|
|
176
|
+
await store.loadFromDisk();
|
|
177
|
+
await store.addFailure("use pnpm for lockfiles", { category: "correction" });
|
|
178
|
+
|
|
179
|
+
registerMemoryTool(mockPi, store, null);
|
|
180
|
+
const result = await removeTool.execute(
|
|
181
|
+
"tc-1",
|
|
182
|
+
{ target: "memory", old_text: "use pnpm for lockfiles" },
|
|
183
|
+
undefined,
|
|
184
|
+
undefined,
|
|
185
|
+
undefined,
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
assert.equal(result.details.success, false);
|
|
189
|
+
assert.match(result.details.error, /No match in target "memory"/);
|
|
190
|
+
assert.match(result.details.error, /target "failure"/);
|
|
191
|
+
assert.deepEqual(result.details.matching_targets, ["failure"]);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it("prunes same-scope SQLite orphans after a Markdown mutation", async () => {
|
|
195
|
+
let capturedResult: any;
|
|
196
|
+
const mockPi = {
|
|
197
|
+
registerTool: (definition: any) => {
|
|
198
|
+
if (!capturedResult || definition.name === "memory_add") capturedResult = definition;
|
|
199
|
+
},
|
|
200
|
+
} as unknown as ExtensionAPI;
|
|
201
|
+
const store = new MemoryStore({
|
|
202
|
+
memoryMode: "policy-only",
|
|
203
|
+
memoryCharLimit: 5000,
|
|
204
|
+
userCharLimit: 5000,
|
|
205
|
+
projectCharLimit: 5000,
|
|
206
|
+
nudgeInterval: 10,
|
|
207
|
+
reviewEnabled: false,
|
|
208
|
+
flushOnCompact: false,
|
|
209
|
+
flushOnShutdown: false,
|
|
210
|
+
flushMinTurns: 6,
|
|
211
|
+
autoConsolidate: false,
|
|
212
|
+
correctionDetection: false,
|
|
213
|
+
failureInjectionEnabled: true,
|
|
214
|
+
failureInjectionMaxAgeDays: 7,
|
|
215
|
+
failureInjectionMaxEntries: 5,
|
|
216
|
+
nudgeToolCalls: 15,
|
|
217
|
+
consolidationTimeoutMs: 60000,
|
|
218
|
+
memoryDir: tmpDir,
|
|
219
|
+
});
|
|
220
|
+
await store.loadFromDisk();
|
|
221
|
+
syncMemoryEntry(dbManager, { content: "orphaned row", target: "memory", project: null });
|
|
222
|
+
|
|
223
|
+
registerMemoryTool(mockPi, store, null, dbManager);
|
|
224
|
+
await capturedResult.execute(
|
|
225
|
+
"tc-1",
|
|
226
|
+
{ action: "add", target: "memory", content: "authoritative Markdown row" },
|
|
227
|
+
undefined,
|
|
228
|
+
undefined,
|
|
229
|
+
undefined,
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
assert.deepStrictEqual(
|
|
233
|
+
getMemories(dbManager, { target: "memory", project: null }).map((entry) => entry.content),
|
|
234
|
+
["authoritative Markdown row"],
|
|
235
|
+
);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it("reconciles SQLite from fresh authoritative Markdown state", async () => {
|
|
239
|
+
let capturedResult: any;
|
|
240
|
+
const mockPi = {
|
|
241
|
+
registerTool: (definition: any) => {
|
|
242
|
+
if (!capturedResult || definition.name === "memory_add") capturedResult = definition;
|
|
243
|
+
},
|
|
244
|
+
} as unknown as ExtensionAPI;
|
|
245
|
+
const store = new MemoryStore({
|
|
246
|
+
memoryMode: "policy-only",
|
|
247
|
+
memoryCharLimit: 5000,
|
|
248
|
+
userCharLimit: 5000,
|
|
249
|
+
projectCharLimit: 5000,
|
|
250
|
+
nudgeInterval: 10,
|
|
251
|
+
reviewEnabled: false,
|
|
252
|
+
flushOnCompact: false,
|
|
253
|
+
flushOnShutdown: false,
|
|
254
|
+
flushMinTurns: 6,
|
|
255
|
+
autoConsolidate: false,
|
|
256
|
+
correctionDetection: false,
|
|
257
|
+
failureInjectionEnabled: true,
|
|
258
|
+
failureInjectionMaxAgeDays: 7,
|
|
259
|
+
failureInjectionMaxEntries: 5,
|
|
260
|
+
nudgeToolCalls: 15,
|
|
261
|
+
consolidationTimeoutMs: 60000,
|
|
262
|
+
memoryDir: tmpDir,
|
|
263
|
+
});
|
|
264
|
+
await store.loadFromDisk();
|
|
265
|
+
|
|
266
|
+
const originalSave = (store as any).saveToDisk.bind(store);
|
|
267
|
+
(store as any).saveToDisk = async (target: "memory") => {
|
|
268
|
+
await originalSave(target);
|
|
269
|
+
const markdownPath = path.join(tmpDir, MEMORY_FILE);
|
|
270
|
+
const existing = fs.readFileSync(markdownPath, "utf-8");
|
|
271
|
+
const date = new Date().toISOString().split("T")[0];
|
|
272
|
+
fs.writeFileSync(markdownPath, `${existing}${ENTRY_DELIMITER}newer writer <!-- created=${date}, last=${date} -->`);
|
|
273
|
+
syncMemoryEntry(dbManager, { content: "newer writer", target: "memory", project: null });
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
registerMemoryTool(mockPi, store, null, dbManager);
|
|
277
|
+
await capturedResult.execute(
|
|
278
|
+
"tc-1",
|
|
279
|
+
{ action: "add", target: "memory", content: "first writer" },
|
|
280
|
+
undefined,
|
|
281
|
+
undefined,
|
|
282
|
+
undefined,
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
assert.deepStrictEqual(
|
|
286
|
+
getMemories(dbManager, { target: "memory", project: null }).map((entry) => entry.content).sort(),
|
|
287
|
+
["first writer", "newer writer"],
|
|
288
|
+
);
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
it("removes FIFO-evicted entries from the SQLite mirror", async () => {
|
|
292
|
+
let capturedResult: any;
|
|
293
|
+
const mockPi = {
|
|
294
|
+
registerTool: (def: any) => {
|
|
295
|
+
if (!capturedResult || def.name === "memory_add") capturedResult = def;
|
|
296
|
+
},
|
|
297
|
+
} as unknown as ExtensionAPI;
|
|
298
|
+
|
|
299
|
+
syncMemoryEntry(dbManager, {
|
|
300
|
+
content: "Older entry",
|
|
301
|
+
target: "memory",
|
|
302
|
+
project: null,
|
|
303
|
+
});
|
|
304
|
+
syncMemoryEntry(dbManager, {
|
|
305
|
+
content: "Older entry with extra detail",
|
|
306
|
+
target: "memory",
|
|
307
|
+
project: null,
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
const mockStore = {
|
|
311
|
+
add: () => ({
|
|
312
|
+
success: true,
|
|
313
|
+
target: "memory",
|
|
314
|
+
entries: ["New entry"],
|
|
315
|
+
usage: "90% — 4500/5000 chars",
|
|
316
|
+
entry_count: 1,
|
|
317
|
+
message: "Memory updated. Rotated 1 older entry to stay within the limit.",
|
|
318
|
+
evicted_entries: ["Older entry"],
|
|
319
|
+
evicted_count: 1,
|
|
320
|
+
}),
|
|
321
|
+
} as unknown as MemoryStore;
|
|
322
|
+
|
|
323
|
+
registerMemoryTool(mockPi, mockStore, null, dbManager);
|
|
324
|
+
const result = await capturedResult.execute("tc-1", { action: "add", target: "memory", content: "New entry" }, undefined as any, undefined as any, undefined as any);
|
|
325
|
+
|
|
326
|
+
assert.match(result.content[0].text, /Rotated active memory entries:/);
|
|
327
|
+
const rows = getMemories(dbManager, { target: "memory", project: null });
|
|
328
|
+
assert.deepStrictEqual(rows.map((row) => row.content).sort(), ["New entry", "Older entry with extra detail"].sort());
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
it("uses project scope when removing FIFO-evicted SQLite entries", async () => {
|
|
332
|
+
let capturedResult: any;
|
|
333
|
+
const mockPi = {
|
|
334
|
+
registerTool: (def: any) => {
|
|
335
|
+
if (!capturedResult || def.name === "memory_add") capturedResult = def;
|
|
336
|
+
},
|
|
337
|
+
} as unknown as ExtensionAPI;
|
|
338
|
+
|
|
339
|
+
syncMemoryEntry(dbManager, {
|
|
340
|
+
content: "Shared wording",
|
|
341
|
+
target: "memory",
|
|
342
|
+
project: null,
|
|
343
|
+
});
|
|
344
|
+
syncMemoryEntry(dbManager, {
|
|
345
|
+
content: "Shared wording",
|
|
346
|
+
target: "memory",
|
|
347
|
+
project: "project-a",
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
const mockProjectStore = {
|
|
351
|
+
add: () => ({
|
|
352
|
+
success: true,
|
|
353
|
+
target: "memory",
|
|
354
|
+
entries: ["Project replacement"],
|
|
355
|
+
usage: "90% — 4500/5000 chars",
|
|
356
|
+
entry_count: 1,
|
|
357
|
+
message: "Memory updated. Rotated 1 older entry to stay within the limit.",
|
|
358
|
+
evicted_entries: ["Shared wording"],
|
|
359
|
+
evicted_count: 1,
|
|
360
|
+
}),
|
|
361
|
+
} as unknown as MemoryStore;
|
|
362
|
+
|
|
363
|
+
registerMemoryTool(mockPi, {} as MemoryStore, mockProjectStore, dbManager, "project-a");
|
|
364
|
+
await capturedResult.execute("tc-1", { action: "add", target: "project", content: "Project replacement" }, undefined as any, undefined as any, undefined as any);
|
|
365
|
+
|
|
366
|
+
const globalRows = getMemories(dbManager, { target: "memory", project: null });
|
|
367
|
+
const projectRows = getMemories(dbManager, { target: "memory", project: "project-a" });
|
|
368
|
+
assert.deepStrictEqual(globalRows.map((row) => row.content), ["Shared wording"]);
|
|
369
|
+
assert.deepStrictEqual(projectRows.map((row) => row.content), ["Project replacement"]);
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
it("maps project target to SQLite project scope", async () => {
|
|
373
|
+
let capturedResult: any;
|
|
374
|
+
const mockPi = {
|
|
375
|
+
registerTool: (def: any) => {
|
|
376
|
+
if (!capturedResult || def.name === "memory_add") capturedResult = def;
|
|
377
|
+
},
|
|
378
|
+
} as unknown as ExtensionAPI;
|
|
379
|
+
|
|
380
|
+
const addTargets: string[] = [];
|
|
381
|
+
const mockProjectStore = {
|
|
382
|
+
add: (target: string) => {
|
|
383
|
+
addTargets.push(target);
|
|
384
|
+
return {
|
|
385
|
+
success: true,
|
|
386
|
+
target,
|
|
387
|
+
entries: ["Project entry"],
|
|
388
|
+
usage: "2% — 20/5000 chars",
|
|
389
|
+
entry_count: 1,
|
|
390
|
+
message: "Entry added.",
|
|
391
|
+
};
|
|
392
|
+
},
|
|
393
|
+
} as unknown as MemoryStore;
|
|
394
|
+
|
|
395
|
+
registerMemoryTool(mockPi, {} as MemoryStore, mockProjectStore, dbManager, 'project-a');
|
|
396
|
+
const result = await capturedResult.execute("tc-1", { action: "add", target: "project", content: "Project entry" }, undefined as any, undefined as any, undefined as any);
|
|
397
|
+
|
|
398
|
+
const parsed = JSON.parse(result.content[0].text);
|
|
399
|
+
assert.strictEqual(parsed.target, 'project');
|
|
400
|
+
assert.strictEqual(result.details.target, 'project');
|
|
401
|
+
assert.deepStrictEqual(addTargets, ['memory']);
|
|
402
|
+
|
|
403
|
+
const results = getMemories(dbManager, { project: 'project-a', target: 'memory' });
|
|
404
|
+
assert.strictEqual(results.length, 1);
|
|
405
|
+
assert.strictEqual(results[0].content, 'Project entry');
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
it("resolves the active project store and name for each mutation", async () => {
|
|
409
|
+
let capturedResult: any;
|
|
410
|
+
const mockPi = {
|
|
411
|
+
registerTool: (def: any) => {
|
|
412
|
+
if (!capturedResult || def.name === "memory_add") capturedResult = def;
|
|
413
|
+
},
|
|
414
|
+
} as unknown as ExtensionAPI;
|
|
415
|
+
|
|
416
|
+
let activeProjectName = "project-a";
|
|
417
|
+
const calls: string[] = [];
|
|
418
|
+
const stores = new Map<string, MemoryStore>();
|
|
419
|
+
const makeProjectStore = (name: string) => ({
|
|
420
|
+
add: (target: string, content: string) => {
|
|
421
|
+
calls.push(`${name}:${target}:${content}`);
|
|
422
|
+
return {
|
|
423
|
+
success: true,
|
|
424
|
+
target,
|
|
425
|
+
entries: [content],
|
|
426
|
+
usage: "2% — 20/5000 chars",
|
|
427
|
+
entry_count: 1,
|
|
428
|
+
message: "Entry added.",
|
|
429
|
+
};
|
|
430
|
+
},
|
|
431
|
+
}) as unknown as MemoryStore;
|
|
432
|
+
stores.set("project-a", makeProjectStore("project-a"));
|
|
433
|
+
stores.set("project-b", makeProjectStore("project-b"));
|
|
434
|
+
|
|
435
|
+
registerMemoryTool(
|
|
436
|
+
mockPi,
|
|
437
|
+
{} as MemoryStore,
|
|
438
|
+
() => stores.get(activeProjectName) ?? null,
|
|
439
|
+
dbManager,
|
|
440
|
+
() => activeProjectName,
|
|
441
|
+
);
|
|
442
|
+
|
|
443
|
+
await capturedResult.execute("tc-1", { target: "project", content: "first" }, undefined as any, undefined as any, undefined as any);
|
|
444
|
+
activeProjectName = "project-b";
|
|
445
|
+
await capturedResult.execute("tc-2", { target: "project", content: "second" }, undefined as any, undefined as any, undefined as any);
|
|
446
|
+
|
|
447
|
+
assert.deepStrictEqual(calls, ["project-a:memory:first", "project-b:memory:second"]);
|
|
448
|
+
const projectRows = getMemories(dbManager, { project: "project-b", target: "memory" });
|
|
449
|
+
assert.deepStrictEqual(projectRows.map((row) => row.content), ["second"]);
|
|
450
|
+
});
|
|
451
|
+
it("reconciles rebound project-store mutations in the project SQLite scope", async () => {
|
|
452
|
+
let activeProjectName = "project-a";
|
|
453
|
+
type MutationObserver = (
|
|
454
|
+
target: "memory" | "user" | "failure",
|
|
455
|
+
entries: string[],
|
|
456
|
+
) => Promise<string | null | undefined>;
|
|
457
|
+
const observers = new Map<string, MutationObserver>();
|
|
458
|
+
const stores = new Map<string, MemoryStore>();
|
|
459
|
+
const makeProjectStore = (name: string) => ({
|
|
460
|
+
setMutationObserver: (observer: MutationObserver) => {
|
|
461
|
+
observers.set(name, observer);
|
|
462
|
+
},
|
|
463
|
+
}) as unknown as MemoryStore;
|
|
464
|
+
stores.set("project-a", makeProjectStore("project-a"));
|
|
465
|
+
stores.set("project-b", makeProjectStore("project-b"));
|
|
466
|
+
const mockPi = {
|
|
467
|
+
registerTool: () => {},
|
|
468
|
+
} as unknown as ExtensionAPI;
|
|
469
|
+
|
|
470
|
+
const configureProjectStore = registerMemoryTool(
|
|
471
|
+
mockPi,
|
|
472
|
+
{} as MemoryStore,
|
|
473
|
+
() => stores.get(activeProjectName) ?? null,
|
|
474
|
+
dbManager,
|
|
475
|
+
() => activeProjectName,
|
|
476
|
+
);
|
|
477
|
+
|
|
478
|
+
await observers.get("project-a")?.("memory", ["first project entry"]);
|
|
479
|
+
activeProjectName = "project-b";
|
|
480
|
+
configureProjectStore(stores.get("project-b") ?? null);
|
|
481
|
+
await observers.get("project-b")?.("memory", ["second project entry"]);
|
|
482
|
+
|
|
483
|
+
assert.deepStrictEqual(
|
|
484
|
+
getMemories(dbManager, { target: "memory", project: "project-a" }).map((row) => row.content),
|
|
485
|
+
["first project entry"],
|
|
486
|
+
);
|
|
487
|
+
assert.deepStrictEqual(
|
|
488
|
+
getMemories(dbManager, { target: "memory", project: "project-b" }).map((row) => row.content),
|
|
489
|
+
["second project entry"],
|
|
490
|
+
);
|
|
491
|
+
assert.deepStrictEqual(getMemories(dbManager, { target: "memory", project: null }), []);
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
it("returns a warning instead of failing when SQLite sync errors", async () => {
|
|
495
|
+
let capturedResult: any;
|
|
496
|
+
const mockPi = {
|
|
497
|
+
registerTool: (def: any) => {
|
|
498
|
+
if (!capturedResult || def.name === "memory_add") capturedResult = def;
|
|
499
|
+
},
|
|
500
|
+
} as unknown as ExtensionAPI;
|
|
501
|
+
|
|
502
|
+
const mockStore = {
|
|
503
|
+
add: () => ({
|
|
504
|
+
success: true,
|
|
505
|
+
target: "memory",
|
|
506
|
+
entries: ["Entry one"],
|
|
507
|
+
usage: "5% — 110/5000 chars",
|
|
508
|
+
entry_count: 1,
|
|
509
|
+
message: "Entry added.",
|
|
510
|
+
}),
|
|
511
|
+
} as unknown as MemoryStore;
|
|
512
|
+
|
|
513
|
+
const failingDbManager = {
|
|
514
|
+
getDb: () => {
|
|
515
|
+
throw new Error('sqlite unavailable');
|
|
516
|
+
},
|
|
517
|
+
} as unknown as DatabaseManager;
|
|
518
|
+
|
|
519
|
+
registerMemoryTool(mockPi, mockStore, null, failingDbManager);
|
|
520
|
+
const result = await capturedResult.execute("tc-1", { action: "add", target: "memory", content: "Entry one" }, undefined as any, undefined as any, undefined as any);
|
|
521
|
+
|
|
522
|
+
const parsed = JSON.parse(result.content[0].text);
|
|
523
|
+
assert.strictEqual(parsed.success, true);
|
|
524
|
+
assert.match(parsed.message, /SQLite search sync failed/);
|
|
525
|
+
assert.match(parsed.warning, /sqlite unavailable/);
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
it("does not sync to SQLite when core Markdown add fails", async () => {
|
|
529
|
+
let capturedResult: any;
|
|
530
|
+
const mockPi = {
|
|
531
|
+
registerTool: (def: any) => {
|
|
532
|
+
if (!capturedResult || def.name === "memory_add") capturedResult = def;
|
|
533
|
+
},
|
|
534
|
+
} as unknown as ExtensionAPI;
|
|
535
|
+
|
|
536
|
+
const mockStore = {
|
|
537
|
+
add: () => ({
|
|
538
|
+
success: false,
|
|
539
|
+
error: "Memory at 5000/5000 chars. Adding this entry would exceed the limit.",
|
|
540
|
+
}),
|
|
541
|
+
} as unknown as MemoryStore;
|
|
542
|
+
|
|
543
|
+
registerMemoryTool(mockPi, mockStore, null, dbManager);
|
|
544
|
+
const result = await capturedResult.execute(
|
|
545
|
+
"tc-1",
|
|
546
|
+
{ action: "add", target: "memory", content: "overflow entry" },
|
|
547
|
+
undefined as any,
|
|
548
|
+
undefined as any,
|
|
549
|
+
undefined as any,
|
|
550
|
+
);
|
|
551
|
+
|
|
552
|
+
const parsed = JSON.parse(result.content[0].text);
|
|
553
|
+
assert.strictEqual(parsed.success, false);
|
|
554
|
+
|
|
555
|
+
const rows = getMemories(dbManager, { target: "memory", project: null });
|
|
556
|
+
assert.strictEqual(rows.length, 0, "SQLite should stay unchanged when core add fails");
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
it("registers action-specific schemas that reject incomplete mutations", () => {
|
|
560
|
+
const registeredTools: Record<string, any> = {};
|
|
561
|
+
const mockPi = {
|
|
562
|
+
registerTool: (definition: any) => {
|
|
563
|
+
registeredTools[definition.name] = definition;
|
|
564
|
+
},
|
|
565
|
+
} as unknown as ExtensionAPI;
|
|
566
|
+
|
|
567
|
+
registerMemoryTool(mockPi, {} as MemoryStore, null);
|
|
568
|
+
|
|
569
|
+
assert.deepStrictEqual(Object.keys(registeredTools).sort(), [
|
|
570
|
+
"memory_add",
|
|
571
|
+
"memory_remove",
|
|
572
|
+
"memory_replace",
|
|
573
|
+
]);
|
|
574
|
+
assert.strictEqual(
|
|
575
|
+
Value.Check(registeredTools.memory_add.parameters, {
|
|
576
|
+
action: "add",
|
|
577
|
+
target: "failure",
|
|
578
|
+
category: "tool-quirk",
|
|
579
|
+
failure_reason: "missing content",
|
|
580
|
+
}),
|
|
581
|
+
false,
|
|
582
|
+
"add without content must fail schema validation",
|
|
583
|
+
);
|
|
584
|
+
assert.strictEqual(
|
|
585
|
+
Value.Check(registeredTools.memory_replace.parameters, {
|
|
586
|
+
target: "memory",
|
|
587
|
+
content: "new",
|
|
588
|
+
}),
|
|
589
|
+
false,
|
|
590
|
+
"replace without old_text must fail schema validation",
|
|
591
|
+
);
|
|
592
|
+
assert.strictEqual(
|
|
593
|
+
Value.Check(registeredTools.memory_remove.parameters, { target: "memory" }),
|
|
594
|
+
false,
|
|
595
|
+
"remove without old_text must fail schema validation",
|
|
596
|
+
);
|
|
597
|
+
assert.strictEqual(
|
|
598
|
+
Value.Check(registeredTools.memory_add.parameters, {
|
|
599
|
+
target: "memory",
|
|
600
|
+
content: "durable fact",
|
|
601
|
+
}),
|
|
602
|
+
true,
|
|
603
|
+
);
|
|
604
|
+
assert.strictEqual(
|
|
605
|
+
Value.Check(registeredTools.memory_replace.parameters, {
|
|
606
|
+
target: "memory",
|
|
607
|
+
old_text: "old",
|
|
608
|
+
content: "new",
|
|
609
|
+
}),
|
|
610
|
+
true,
|
|
611
|
+
);
|
|
612
|
+
assert.strictEqual(
|
|
613
|
+
Value.Check(registeredTools.memory_remove.parameters, {
|
|
614
|
+
target: "memory",
|
|
615
|
+
old_text: "old",
|
|
616
|
+
}),
|
|
617
|
+
true,
|
|
618
|
+
);
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
it("execute delegates remove to store.remove", async () => {
|
|
622
|
+
let capturedResult: any;
|
|
623
|
+
let removeArgs: any;
|
|
624
|
+
|
|
625
|
+
const mockPi = {
|
|
626
|
+
registerTool: (def: any) => {
|
|
627
|
+
if (def.name === "memory_remove") capturedResult = def;
|
|
628
|
+
},
|
|
629
|
+
} as unknown as ExtensionAPI;
|
|
630
|
+
|
|
631
|
+
const mockStore = {
|
|
632
|
+
remove: (...args: any[]) => {
|
|
633
|
+
removeArgs = args;
|
|
634
|
+
return { success: true, target: "memory", entries: [], usage: "0% — 0/5000 chars", entry_count: 0 };
|
|
635
|
+
},
|
|
636
|
+
} as unknown as MemoryStore;
|
|
637
|
+
|
|
638
|
+
registerMemoryTool(mockPi, mockStore, null);
|
|
639
|
+
await capturedResult.execute("tc-1", { target: "memory", old_text: "old entry" }, undefined as any, undefined as any, undefined as any);
|
|
640
|
+
|
|
641
|
+
assert.deepStrictEqual(removeArgs, ["memory", "old entry"], "should pass target, old_text to store.remove");
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
it("execute delegates replace to store.replace", async () => {
|
|
645
|
+
let capturedResult: any;
|
|
646
|
+
let replaceArgs: any;
|
|
647
|
+
|
|
648
|
+
const mockPi = {
|
|
649
|
+
registerTool: (def: any) => {
|
|
650
|
+
if (def.name === "memory_replace") capturedResult = def;
|
|
651
|
+
},
|
|
652
|
+
} as unknown as ExtensionAPI;
|
|
653
|
+
|
|
654
|
+
const mockStore = {
|
|
655
|
+
replace: (...args: any[]) => {
|
|
656
|
+
replaceArgs = args;
|
|
657
|
+
return { success: true, target: "memory", entries: ["new"], usage: "5% — 110/5000 chars", entry_count: 1 };
|
|
658
|
+
},
|
|
659
|
+
} as unknown as MemoryStore;
|
|
660
|
+
|
|
661
|
+
registerMemoryTool(mockPi, mockStore, null);
|
|
662
|
+
await capturedResult.execute("tc-1", { action: "replace", target: "memory", content: "new", old_text: "old" }, undefined as any, undefined as any, undefined as any);
|
|
663
|
+
|
|
664
|
+
assert.deepStrictEqual(replaceArgs, ["memory", "old", "new"], "should pass target, old_text, content to store.replace");
|
|
665
|
+
});
|
|
666
|
+
|
|
667
|
+
it("binds project identity from execute ctx.cwd instead of a factory snapshot", async () => {
|
|
668
|
+
let capturedResult: any;
|
|
669
|
+
const boundCwds: string[] = [];
|
|
670
|
+
const mockPi = {
|
|
671
|
+
registerTool: (def: any) => {
|
|
672
|
+
if (!capturedResult || def.name === "memory_add") capturedResult = def;
|
|
673
|
+
},
|
|
674
|
+
} as unknown as ExtensionAPI;
|
|
675
|
+
|
|
676
|
+
const mockProjectStore = {
|
|
677
|
+
add: () => ({
|
|
678
|
+
success: true,
|
|
679
|
+
target: "memory",
|
|
680
|
+
entries: ["from session cwd"],
|
|
681
|
+
usage: "2% — 20/5000 chars",
|
|
682
|
+
entry_count: 1,
|
|
683
|
+
message: "Entry added.",
|
|
684
|
+
}),
|
|
685
|
+
} as unknown as MemoryStore;
|
|
686
|
+
|
|
687
|
+
registerMemoryTool(
|
|
688
|
+
mockPi,
|
|
689
|
+
{} as MemoryStore,
|
|
690
|
+
mockProjectStore,
|
|
691
|
+
dbManager,
|
|
692
|
+
"factory-project",
|
|
693
|
+
(cwd) => {
|
|
694
|
+
if (cwd) boundCwds.push(cwd);
|
|
695
|
+
},
|
|
696
|
+
);
|
|
697
|
+
|
|
698
|
+
await capturedResult.execute(
|
|
699
|
+
"tc-1",
|
|
700
|
+
{ target: "project", content: "from session cwd" },
|
|
701
|
+
undefined,
|
|
702
|
+
undefined,
|
|
703
|
+
{ cwd: "/tmp/opened-session-project" },
|
|
704
|
+
);
|
|
705
|
+
|
|
706
|
+
assert.deepStrictEqual(boundCwds, ["/tmp/opened-session-project"]);
|
|
707
|
+
});
|
|
708
|
+
|
|
709
|
+
});
|