@selesai/code 0.13.15 → 0.13.18
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 +37 -0
- package/README.md +2 -14
- package/dist/bun/cli.d.ts +3 -1
- package/dist/bun/cli.js +3 -9
- package/dist/bun/{register-bedrock.js → runtime-setup.js} +5 -0
- package/dist/bun/sandbox-env-setup.d.ts +1 -0
- package/dist/bun/sandbox-env-setup.js +3 -0
- package/dist/cli/auth-command.d.ts +23 -0
- package/dist/cli/auth-command.js +102 -0
- package/dist/cli/config-selector.js +2 -1
- package/dist/cli/setup.d.ts +1 -0
- package/dist/cli/setup.js +11 -0
- package/dist/cli.js +2 -14
- package/dist/config.d.ts +3 -2
- package/dist/config.js +9 -4
- package/dist/core/agent-session-runtime.js +15 -7
- package/dist/core/agent-session.d.ts +2 -6
- package/dist/core/agent-session.js +15 -4
- package/dist/core/compaction/branch-summarization.d.ts +1 -1
- package/dist/core/compaction/branch-summarization.js +2 -1
- package/dist/core/extensions/loader.js +3 -0
- package/dist/core/extensions/types.d.ts +16 -2
- package/dist/core/http-dispatcher.js +2 -0
- package/dist/core/keybindings.d.ts +5 -0
- package/dist/core/keybindings.js +4 -0
- package/dist/core/messages.d.ts +1 -1
- package/dist/core/model-config.d.ts +15 -0
- package/dist/core/model-config.js +3 -0
- package/dist/core/model-runtime.d.ts +1 -0
- package/dist/core/model-runtime.js +5 -2
- package/dist/core/provider-composer.js +8 -2
- package/dist/core/session-export.d.ts +3 -0
- package/dist/core/session-export.js +31 -0
- package/dist/core/session-manager.d.ts +3 -2
- package/dist/core/session-manager.js +40 -13
- package/dist/core/skills.d.ts +1 -1
- package/dist/core/skills.js +4 -2
- package/dist/core/system-prompt.js +10 -10
- package/dist/core/tools/bash.js +3 -117
- package/dist/core/tools/edit.d.ts +1 -12
- package/dist/core/tools/edit.js +5 -163
- package/dist/core/tools/find.js +4 -55
- package/dist/core/tools/grep.js +4 -60
- package/dist/core/tools/ls.js +4 -49
- package/dist/core/tools/read.d.ts +4 -0
- package/dist/core/tools/read.js +10 -122
- package/dist/core/tools/renderers/bash.d.ts +11 -0
- package/dist/core/tools/renderers/bash.js +129 -0
- package/dist/core/tools/renderers/edit.d.ts +22 -0
- package/dist/core/tools/renderers/edit.js +166 -0
- package/dist/core/tools/renderers/find.d.ts +9 -0
- package/dist/core/tools/renderers/find.js +63 -0
- package/dist/core/tools/renderers/grep.d.ts +9 -0
- package/dist/core/tools/renderers/grep.js +68 -0
- package/dist/core/tools/renderers/index.d.ts +27 -0
- package/dist/core/tools/renderers/index.js +46 -0
- package/dist/core/tools/renderers/ls.d.ts +9 -0
- package/dist/core/tools/renderers/ls.js +57 -0
- package/dist/core/tools/renderers/read.d.ts +10 -0
- package/dist/core/tools/renderers/read.js +128 -0
- package/dist/core/tools/renderers/write.d.ts +9 -0
- package/dist/core/tools/renderers/write.js +152 -0
- package/dist/core/tools/write.js +5 -146
- package/dist/extensions/capability-gateway/index.ts +12 -1
- package/dist/extensions/capability-gateway/integration.test.ts +23 -0
- package/dist/extensions/pi-hermes-memory/CHANGELOG.md +18 -0
- package/dist/extensions/pi-hermes-memory/README.md +16 -12
- package/dist/extensions/pi-hermes-memory/docs/ROADMAP.md +1 -1
- package/dist/extensions/pi-hermes-memory/package-lock.json +587 -62
- package/dist/extensions/pi-hermes-memory/package.json +4 -4
- package/dist/extensions/pi-hermes-memory/src/config.ts +32 -0
- package/dist/extensions/pi-hermes-memory/src/constants.ts +12 -2
- package/dist/extensions/pi-hermes-memory/src/handlers/background-review.ts +109 -51
- package/dist/extensions/pi-hermes-memory/src/handlers/index-sessions.ts +9 -3
- package/dist/extensions/pi-hermes-memory/src/handlers/review-memory-ops.ts +257 -98
- package/dist/extensions/pi-hermes-memory/src/handlers/session-backfill.ts +9 -2
- package/dist/extensions/pi-hermes-memory/src/handlers/sync-markdown-memories.ts +5 -0
- package/dist/extensions/pi-hermes-memory/src/index.ts +22 -2
- package/dist/extensions/pi-hermes-memory/src/paths.ts +1 -1
- package/dist/extensions/pi-hermes-memory/src/store/db.ts +6 -0
- package/dist/extensions/pi-hermes-memory/src/store/fts-query.ts +58 -1
- package/dist/extensions/pi-hermes-memory/src/store/memory-store.ts +60 -8
- package/dist/extensions/pi-hermes-memory/src/store/session-indexer.ts +169 -7
- package/dist/extensions/pi-hermes-memory/src/store/session-search.ts +7 -21
- package/dist/extensions/pi-hermes-memory/src/store/sqlite-memory-store.ts +134 -15
- package/dist/extensions/pi-hermes-memory/src/tools/memory-search-tool.ts +4 -2
- package/dist/extensions/pi-hermes-memory/src/tools/memory-tool.ts +24 -9
- package/dist/extensions/pi-hermes-memory/src/types.ts +11 -0
- package/dist/extensions/pi-hermes-memory/tests/config.test.ts +42 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/background-review.test.ts +159 -3
- package/dist/extensions/pi-hermes-memory/tests/handlers/review-memory-ops.test.ts +452 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/session-backfill.test.ts +39 -0
- package/dist/extensions/pi-hermes-memory/tests/integration/corruption-recovery-integration.test.ts +91 -0
- package/dist/extensions/pi-hermes-memory/tests/store/db.test.ts +29 -0
- package/dist/extensions/pi-hermes-memory/tests/store/fts-query.test.ts +116 -0
- package/dist/extensions/pi-hermes-memory/tests/store/memory-store.test.ts +163 -0
- package/dist/extensions/pi-hermes-memory/tests/store/session-indexer.test.ts +233 -0
- package/dist/extensions/pi-hermes-memory/tests/store/session-search.test.ts +12 -0
- package/dist/extensions/pi-hermes-memory/tests/store/sqlite-memory-store.test.ts +175 -0
- package/dist/extensions/pi-hermes-memory/tests/store/sqlite-native.test.ts +2 -2
- package/dist/extensions/pi-hermes-memory/tests/tools/memory-search-tool.test.ts +22 -0
- package/dist/extensions/pi-hermes-memory/tests/tools/memory-tool.test.ts +37 -1
- package/dist/extensions/pi-intercom/CHANGELOG.md +13 -0
- package/dist/extensions/pi-intercom/README.md +16 -2
- package/dist/extensions/pi-intercom/broker/spawn.test.ts +19 -2
- package/dist/extensions/pi-intercom/broker/spawn.ts +4 -4
- package/dist/extensions/pi-intercom/index.ts +1 -1
- package/dist/extensions/pi-intercom/intercom.integration.test.ts +121 -2
- package/dist/extensions/pi-intercom/package.json +1 -1
- package/dist/extensions/pi-intercom/project-agent.test.ts +1 -1
- package/dist/extensions/pi-intercom/project-agent.ts +1 -6
- package/dist/extensions/pi-intercom/skills/pi-intercom/SKILL.md +7 -6
- package/dist/extensions/pi-rewind-hook/index.test.ts +7 -0
- package/dist/extensions/pi-subagents/.github/workflows/test.yml +36 -4
- package/dist/extensions/pi-subagents/CHANGELOG.md +120 -0
- package/dist/extensions/pi-subagents/README.md +3 -3
- package/dist/extensions/pi-subagents/agents/researcher.md +23 -13
- package/dist/extensions/pi-subagents/agents/reviewer.md +1 -1
- package/dist/extensions/pi-subagents/agents/scout.md +1 -1
- package/dist/extensions/pi-subagents/docs/agents.md +32 -16
- package/dist/extensions/pi-subagents/docs/configuration.md +41 -15
- package/dist/extensions/pi-subagents/docs/extension-api.md +109 -6
- package/dist/extensions/pi-subagents/docs/missions.md +2 -0
- package/dist/extensions/pi-subagents/docs/models.md +58 -1
- package/dist/extensions/pi-subagents/docs/observability.md +50 -12
- package/dist/extensions/pi-subagents/docs/tool-reference.md +17 -10
- package/dist/extensions/pi-subagents/docs/watchdog.md +1 -1
- package/dist/extensions/pi-subagents/docs/workflows.md +26 -9
- package/dist/extensions/pi-subagents/package-lock.json +747 -177
- package/dist/extensions/pi-subagents/package.json +6 -4
- package/dist/extensions/pi-subagents/runner-server-preload.mjs +13 -0
- package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +2 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +1 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +21 -4
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +2 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/multi-lane-orchestration.md +2 -0
- package/dist/extensions/pi-subagents/src/agents/advertised-agent-prompt.ts +63 -0
- package/dist/extensions/pi-subagents/src/agents/agent-management.ts +61 -16
- package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +2 -0
- package/dist/extensions/pi-subagents/src/agents/agents.ts +8 -0
- package/dist/extensions/pi-subagents/src/api/capability-ceiling.ts +0 -1
- package/dist/extensions/pi-subagents/src/api/{pi-args.ts → child-tool-plan.ts} +1 -1
- package/dist/extensions/pi-subagents/src/api/preflight.ts +7 -4
- package/dist/extensions/pi-subagents/src/api/shared-types.ts +2 -2
- package/dist/extensions/pi-subagents/src/api/workflow-resources.ts +6 -0
- package/dist/extensions/pi-subagents/src/extension/config.ts +4 -2
- package/dist/extensions/pi-subagents/src/extension/doctor.ts +2 -10
- package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +9 -11
- package/dist/extensions/pi-subagents/src/extension/index.ts +99 -10
- package/dist/extensions/pi-subagents/src/extension/public-execution.ts +13 -0
- package/dist/extensions/pi-subagents/src/extension/rpc.ts +7 -23
- package/dist/extensions/pi-subagents/src/extension/schemas.ts +11 -8
- package/dist/extensions/pi-subagents/src/extension/tool-description.ts +25 -7
- package/dist/extensions/pi-subagents/src/integrations/pi-web-session-liveness.ts +73 -0
- package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +228 -136
- package/dist/extensions/pi-subagents/src/intercom/supervisor-ui.ts +244 -0
- package/dist/extensions/pi-subagents/src/missions/workflow-state.ts +37 -16
- package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +18 -18
- package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +51 -25
- package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +46 -3
- package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +14 -3
- package/dist/extensions/pi-subagents/src/runs/background/async-retention.ts +9 -0
- package/dist/extensions/pi-subagents/src/runs/background/async-status-snapshot.ts +10 -12
- package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +18 -15
- package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +40 -29
- package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +8 -0
- package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +79 -247
- package/dist/extensions/pi-subagents/src/runs/background/notify.ts +88 -12
- package/dist/extensions/pi-subagents/src/runs/background/owned-process-tree.ts +6 -6
- package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +24 -24
- package/dist/extensions/pi-subagents/src/runs/background/retained-nested-route-tracker.ts +96 -0
- package/dist/extensions/pi-subagents/src/runs/background/run-child-session.ts +642 -0
- package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +75 -6
- package/dist/extensions/pi-subagents/src/runs/background/runner-aliases.ts +163 -0
- package/dist/extensions/pi-subagents/src/runs/background/runner-child-launch.ts +86 -0
- package/dist/extensions/pi-subagents/src/runs/background/runner-child-sessions.ts +31 -0
- package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +18 -4
- package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +3 -1
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +597 -1092
- package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +3 -0
- package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +4 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +20 -17
- package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +296 -394
- package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +4 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/foreground-history.ts +3 -1
- package/dist/extensions/pi-subagents/src/runs/foreground/prompt-audit.ts +9 -5
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +630 -283
- package/dist/extensions/pi-subagents/src/runs/foreground/workflow-detach-reconcile.ts +8 -5
- package/dist/extensions/pi-subagents/src/runs/foreground/workflow-foreground-steering.ts +78 -98
- package/dist/extensions/pi-subagents/src/runs/shared/abort-recovery.ts +3 -3
- package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +16 -3
- package/dist/extensions/pi-subagents/src/runs/shared/agent-contract.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/shared/async-status-projection.ts +47 -47
- package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +1 -2
- package/dist/extensions/pi-subagents/src/runs/shared/child-hooks.ts +174 -0
- package/dist/extensions/pi-subagents/src/runs/shared/child-identity.ts +14 -3
- package/dist/extensions/pi-subagents/src/runs/shared/child-launch.ts +319 -0
- package/dist/extensions/pi-subagents/src/runs/shared/child-lifecycle.ts +25 -0
- package/dist/extensions/pi-subagents/src/runs/shared/child-runtime-config.ts +126 -0
- package/dist/extensions/pi-subagents/src/runs/shared/child-session.ts +373 -0
- package/dist/extensions/pi-subagents/src/runs/shared/child-tool-plan.ts +530 -0
- package/dist/extensions/pi-subagents/src/runs/shared/completion-evidence.ts +2 -2
- package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +2 -1
- package/dist/extensions/pi-subagents/src/runs/shared/external-cli-preflight.ts +16 -0
- package/dist/extensions/pi-subagents/src/runs/shared/host-step-status.ts +11 -11
- package/dist/extensions/pi-subagents/src/runs/shared/llm-intent-arbiter.ts +30 -20
- package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +5 -4
- package/dist/extensions/pi-subagents/src/runs/shared/model-exclusions.ts +84 -15
- package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +88 -12
- package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +37 -53
- package/dist/extensions/pi-subagents/src/runs/shared/nested-path.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/shared/orca-progress-tabs.ts +18 -7
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +57 -12
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +3 -4
- package/dist/extensions/pi-subagents/src/runs/shared/permissions.ts +0 -11
- package/dist/extensions/pi-subagents/src/runs/shared/process-signal.ts +4 -1
- package/dist/extensions/pi-subagents/src/runs/shared/readonly-drain-observation.ts +42 -0
- package/dist/extensions/pi-subagents/src/runs/shared/readonly-model-continuation.ts +69 -0
- package/dist/extensions/pi-subagents/src/runs/shared/readonly-session-evidence.ts +307 -0
- package/dist/extensions/pi-subagents/src/runs/shared/run-fanout-budget.ts +8 -21
- package/dist/extensions/pi-subagents/src/runs/shared/runtime-acknowledged-extensions.ts +3 -30
- package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +17 -4
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +2 -0
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +99 -386
- package/dist/extensions/pi-subagents/src/runs/shared/tool-availability.ts +18 -62
- package/dist/extensions/pi-subagents/src/runs/shared/tool-budget.ts +0 -14
- package/dist/extensions/pi-subagents/src/runs/shared/worktree-cleanup-plan.ts +31 -9
- package/dist/extensions/pi-subagents/src/runs/shared/worktree-setup-command.ts +190 -0
- package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +506 -226
- package/dist/extensions/pi-subagents/src/shared/child-session-name.ts +1 -1
- package/dist/extensions/pi-subagents/src/shared/jsonl-writer.ts +11 -0
- package/dist/extensions/pi-subagents/src/shared/model-response-aliases.ts +13 -0
- package/dist/extensions/pi-subagents/src/shared/thinking-ceiling.ts +0 -6
- package/dist/extensions/pi-subagents/src/shared/types.ts +145 -89
- package/dist/extensions/pi-subagents/src/shared/utils.ts +13 -6
- package/dist/extensions/pi-subagents/src/shared/watch-strategy.ts +2 -0
- package/dist/extensions/pi-subagents/src/shared/workflow-child-permit.ts +18 -13
- package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +0 -6
- package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +1 -1
- package/dist/extensions/pi-subagents/src/tui/fleet.ts +11 -6
- package/dist/extensions/pi-subagents/src/tui/render.ts +277 -46
- package/dist/extensions/pi-subagents/src/watchdog/child-status.ts +0 -1
- package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +12 -12
- package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +3 -3
- package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +116 -15
- package/dist/extensions/pi-subagents/src/workflows/workflow-checklist.ts +15 -18
- package/dist/extensions/pi-subagents/src/workflows/workflow-child-summary.ts +57 -8
- package/dist/extensions/pi-subagents/src/workflows/workflow-preflight.ts +19 -19
- package/dist/extensions/pi-subagents/src/workflows/workflow-receipt.ts +3 -3
- package/dist/extensions/pi-subagents/src/workflows/workflow-resources.ts +97 -22
- package/dist/extensions/pi-subagents/src/workflows/workflow-settlement.ts +3 -0
- package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +336 -21
- package/dist/extensions/pi-subagents/test/integration/async-execution.part-1.test.ts +1181 -0
- package/dist/extensions/pi-subagents/test/integration/async-execution.part-2.test.ts +2240 -0
- package/dist/extensions/pi-subagents/test/integration/async-execution.part-3.test.ts +2268 -0
- package/dist/extensions/pi-subagents/test/integration/async-execution.part-4.test.ts +1512 -0
- package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +231 -16
- package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +4 -18
- package/dist/extensions/pi-subagents/test/integration/foreign-workflow-steering.test.ts +95 -0
- package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +9 -15
- package/dist/extensions/pi-subagents/test/integration/in-process-child.test.ts +374 -0
- package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +20 -10
- package/dist/extensions/pi-subagents/test/integration/orca-progress-tabs.test.ts +18 -6
- package/dist/extensions/pi-subagents/test/integration/recovered-assistant-error.test.ts +151 -0
- package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +42 -1
- package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +150 -25
- package/dist/extensions/pi-subagents/test/integration/result-publication.test.ts +354 -0
- package/dist/extensions/pi-subagents/test/integration/shared-cwd-terminal-evidence.test.ts +117 -0
- package/dist/extensions/pi-subagents/test/integration/single-execution.part-1.test.ts +3678 -0
- package/dist/extensions/pi-subagents/test/integration/{single-execution.test.ts → single-execution.part-2.test.ts} +500 -4207
- package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +1 -2
- package/dist/extensions/pi-subagents/test/integration/workflow-result-publication.test.ts +127 -0
- package/dist/extensions/pi-subagents/test/integration/workflow-steer-inbox.test.ts +365 -0
- package/dist/extensions/pi-subagents/test/smoke/pi085-child.ts +31 -0
- package/dist/extensions/pi-subagents/test/smoke/pi085-clean-install.mjs +74 -0
- package/dist/extensions/pi-subagents/test/smoke/pi085-extension.ts +16 -0
- package/dist/extensions/pi-subagents/test/support/async-execution-fixture.ts +699 -0
- package/dist/extensions/pi-subagents/test/support/fake-child-session.ts +418 -0
- package/dist/extensions/pi-subagents/test/support/foreign-workflow-steer-host.mjs +13 -0
- package/dist/extensions/pi-subagents/test/support/mock-pi.ts +30 -76
- package/dist/extensions/pi-subagents/test/support/notify-diagnostics-fixture.ts +84 -0
- package/dist/extensions/pi-subagents/test/support/result-publication-capacity-preload.mjs +70 -0
- package/dist/extensions/pi-subagents/test/support/runner-child-session-factory.ts +17 -0
- package/dist/extensions/pi-subagents/test/support/single-execution-fixture.ts +390 -0
- package/dist/extensions/pi-subagents/test/unit/acceptance-compaction.test.ts +120 -0
- package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +24 -3
- package/dist/extensions/pi-subagents/test/unit/advertised-agent-prompt.test.ts +87 -0
- package/dist/extensions/pi-subagents/test/unit/advertised-agent-refresh.test.ts +163 -0
- package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +70 -31
- package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +78 -3
- package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +2 -8
- package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +73 -66
- package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +51 -1
- package/dist/extensions/pi-subagents/test/unit/async-retention.test.ts +49 -1
- package/dist/extensions/pi-subagents/test/unit/async-spawn-preload.test.ts +103 -0
- package/dist/extensions/pi-subagents/test/unit/async-status-projection.test.ts +3 -3
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling-agent-allowlist.test.ts +9 -8
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +10 -7
- package/dist/extensions/pi-subagents/test/unit/chain-root-attachment.test.ts +48 -6
- package/dist/extensions/pi-subagents/test/unit/child-runtime-config.test.ts +90 -0
- package/dist/extensions/pi-subagents/test/unit/{pi-args-permission-system.test.ts → child-tool-plan-permission-system.test.ts} +48 -86
- package/dist/extensions/pi-subagents/test/unit/child-tool-plan.test.ts +33 -0
- package/dist/extensions/pi-subagents/test/unit/compaction-resume.test.ts +18 -18
- package/dist/extensions/pi-subagents/test/unit/completion-evidence.test.ts +9 -9
- package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +8 -7
- package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +225 -65
- package/dist/extensions/pi-subagents/test/unit/extension-bindings.test.ts +17 -22
- package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +11 -1
- package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +47 -3
- package/dist/extensions/pi-subagents/test/unit/foreign-workflow-steering.test.ts +74 -0
- package/dist/extensions/pi-subagents/test/unit/fork-cache-key.test.ts +23 -29
- package/dist/extensions/pi-subagents/test/unit/host-peer-runtime-imports.test.ts +96 -4
- package/dist/extensions/pi-subagents/test/unit/host-step-status.test.ts +4 -4
- package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +116 -55
- package/dist/extensions/pi-subagents/test/unit/index-segment.test.ts +58 -1
- package/dist/extensions/pi-subagents/test/unit/llm-intent-arbiter.test.ts +104 -3
- package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +10 -1
- package/dist/extensions/pi-subagents/test/unit/mission-store.test.ts +31 -1
- package/dist/extensions/pi-subagents/test/unit/model-exclusions.test.ts +102 -51
- package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +196 -6
- package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +181 -38
- package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +62 -70
- package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +58 -53
- package/dist/extensions/pi-subagents/test/unit/notify-diagnostics.test.ts +42 -0
- package/dist/extensions/pi-subagents/test/unit/notify.test.ts +84 -0
- package/dist/extensions/pi-subagents/test/unit/orca-progress-tabs.test.ts +13 -5
- package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +21 -5
- package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +5 -4
- package/dist/extensions/pi-subagents/test/unit/permissions.test.ts +2 -6
- package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +28 -2
- package/dist/extensions/pi-subagents/test/unit/pi-web-session-liveness.test.ts +209 -0
- package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +38 -1
- package/dist/extensions/pi-subagents/test/unit/prompt-audit-optional-peers.test.ts +43 -0
- package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +24 -2
- package/dist/extensions/pi-subagents/test/unit/readonly-drain-observation.test.ts +174 -0
- package/dist/extensions/pi-subagents/test/unit/readonly-model-continuation.test.ts +94 -0
- package/dist/extensions/pi-subagents/test/unit/readonly-session-evidence.test.ts +1329 -0
- package/dist/extensions/pi-subagents/test/unit/recursion-guard.test.ts +29 -80
- package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +11 -8
- package/dist/extensions/pi-subagents/test/unit/result-files.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/retained-nested-route-tracker.test.ts +175 -0
- package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +38 -12
- package/dist/extensions/pi-subagents/test/unit/run-fanout-budget.test.ts +2 -5
- package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +89 -1
- package/dist/extensions/pi-subagents/test/unit/runtime-acknowledged-extensions.test.ts +2 -16
- package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +27 -3
- package/dist/extensions/pi-subagents/test/unit/scheduled-supervisor-demand.test.ts +215 -0
- package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +15 -11
- package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +237 -1
- package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +2 -5
- package/dist/extensions/pi-subagents/test/unit/streamed-progress-bounds.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/subagent-guide.test.ts +14 -1
- package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +130 -739
- package/dist/extensions/pi-subagents/test/unit/supervisor-ask-registration.test.ts +682 -0
- package/dist/extensions/pi-subagents/test/unit/supervisor-ui.test.ts +137 -0
- package/dist/extensions/pi-subagents/test/unit/tool-budget.test.ts +1 -11
- package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +23 -3
- package/dist/extensions/pi-subagents/test/unit/wait-completions.test.ts +8 -1
- package/dist/extensions/pi-subagents/test/unit/watchdog-tool-actions.test.ts +19 -1
- package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +72 -4
- package/dist/extensions/pi-subagents/test/unit/workflow-checklist.test.ts +17 -3
- package/dist/extensions/pi-subagents/test/unit/workflow-child-summary.test.ts +34 -0
- package/dist/extensions/pi-subagents/test/unit/workflow-detach-reconcile.test.ts +12 -2
- package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +46 -6
- package/dist/extensions/pi-subagents/test/unit/workflow-receipt.test.ts +3 -3
- package/dist/extensions/pi-subagents/test/unit/workflow-resources.test.ts +133 -1
- package/dist/extensions/pi-subagents/test/unit/workflow-resume-hint.test.ts +53 -2
- package/dist/extensions/pi-subagents/test/unit/worktree-cleanup-plan.test.ts +222 -14
- package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +526 -85
- package/dist/extensions/pi-web-agent/src/backends/config.ts +1 -0
- package/dist/extensions/pi-web-agent/src/backends/settings-reader.ts +5 -3
- package/dist/extensions/pi-web-agent/src/search/tokenin.ts +7 -3
- package/dist/extensions/pi-web-agent/src/types.ts +1 -1
- package/dist/extensions/pi-zentui/README.md +17 -0
- package/dist/extensions/pi-zentui/assets/screenshots/footer-status-hyperlink.png +0 -0
- package/dist/extensions/pi-zentui/docs/configuration.md +71 -2
- package/dist/extensions/pi-zentui/extensions/zentui/config.ts +11 -0
- package/dist/extensions/pi-zentui/extensions/zentui/editor-transfer.ts +14 -0
- package/dist/extensions/pi-zentui/extensions/zentui/extension-status.ts +29 -13
- package/dist/extensions/pi-zentui/extensions/zentui/footer-layout.ts +5 -4
- package/dist/extensions/pi-zentui/extensions/zentui/footer-text.ts +11 -0
- package/dist/extensions/pi-zentui/extensions/zentui/footer.ts +11 -10
- package/dist/extensions/pi-zentui/extensions/zentui/index.ts +77 -3
- package/dist/extensions/pi-zentui/extensions/zentui/presets.ts +77 -0
- package/dist/extensions/pi-zentui/extensions/zentui/settings-command.ts +103 -2
- package/dist/extensions/pi-zentui/extensions/zentui/working-line-extension-segments.ts +115 -0
- package/dist/extensions/pi-zentui/extensions/zentui/working-line.ts +87 -5
- package/dist/extensions/pi-zentui/package-lock.json +277 -517
- package/dist/extensions/pi-zentui/package.json +7 -4
- package/dist/extensions/pi-zentui/test/config-presets.test.ts +238 -0
- package/dist/extensions/pi-zentui/test/editor-transfer.test.ts +24 -1
- package/dist/extensions/pi-zentui/test/extension-compliance.test.ts +570 -2
- package/dist/extensions/pi-zentui/test/extension-status.test.ts +90 -0
- package/dist/extensions/pi-zentui/test/footer-hyperlink.test.ts +243 -0
- package/dist/extensions/pi-zentui/test/package-contents.mjs +1 -0
- package/dist/extensions/pi-zentui/test/presets.test.ts +121 -0
- package/dist/extensions/pi-zentui/test/settings-command.test.ts +205 -1
- package/dist/extensions/pi-zentui/test/working-line-extension-segments.test.ts +139 -0
- package/dist/extensions/pi-zentui/test/working-line-lifecycle.integration.test.ts +237 -3
- package/dist/extensions/pi-zentui/test/working-line.test.ts +94 -2
- package/dist/index.d.ts +1 -1
- package/dist/main.js +4 -1
- package/dist/modes/interactive/chat-viewport.d.ts +19 -0
- package/dist/modes/interactive/chat-viewport.js +27 -0
- package/dist/modes/interactive/components/assistant-message.d.ts +6 -2
- package/dist/modes/interactive/components/assistant-message.js +30 -13
- package/dist/modes/interactive/components/custom-editor.d.ts +10 -1
- package/dist/modes/interactive/components/custom-editor.js +39 -1
- package/dist/modes/interactive/components/first-time-setup.js +1 -1
- package/dist/modes/interactive/components/index.d.ts +1 -1
- package/dist/modes/interactive/components/markdown-transform.d.ts +2 -0
- package/dist/modes/interactive/components/markdown-transform.js +18 -0
- package/dist/modes/interactive/components/model-selector.js +19 -17
- package/dist/modes/interactive/components/scoped-models-selector.js +21 -23
- package/dist/modes/interactive/components/settings-selector.d.ts +7 -1
- package/dist/modes/interactive/components/settings-selector.js +128 -20
- package/dist/modes/interactive/components/settings-submenu.d.ts +71 -0
- package/dist/modes/interactive/components/settings-submenu.js +164 -0
- package/dist/modes/interactive/components/status-indicator.d.ts +3 -1
- package/dist/modes/interactive/components/status-indicator.js +10 -3
- package/dist/modes/interactive/components/thinking-selector.d.ts +15 -3
- package/dist/modes/interactive/components/thinking-selector.js +75 -18
- package/dist/modes/interactive/components/tool-execution.d.ts +21 -4
- package/dist/modes/interactive/components/tool-execution.js +35 -33
- package/dist/modes/interactive/components/trust-selector.js +2 -2
- package/dist/modes/interactive/interactive-mode.d.ts +13 -15
- package/dist/modes/interactive/interactive-mode.js +144 -80
- package/dist/modes/interactive/session-share.d.ts +15 -0
- package/dist/modes/interactive/session-share.js +183 -0
- package/dist/modes/interactive/theme/dark.json +2 -1
- package/dist/modes/interactive/theme/light.json +2 -1
- package/dist/modes/interactive/theme/theme-controller.d.ts +1 -0
- package/dist/modes/interactive/theme/theme-controller.js +5 -0
- package/dist/modes/interactive/theme/theme-json.d.ts +83 -0
- package/dist/modes/interactive/theme/theme-json.js +129 -0
- package/dist/modes/interactive/theme/theme-schema.json +9 -1
- package/dist/modes/interactive/theme/theme.d.ts +14 -5
- package/dist/modes/interactive/theme/theme.js +18 -119
- package/dist/modes/interactive/tui-renderer.d.ts +20 -0
- package/dist/modes/interactive/tui-renderer.js +65 -0
- package/dist/utils/exif-orientation.js +2 -3
- package/dist/utils/management-http.d.ts +24 -0
- package/dist/utils/management-http.js +53 -0
- package/dist/utils/text.d.ts +7 -0
- package/dist/utils/text.js +8 -0
- package/dist/utils/tools-manager.d.ts +1 -0
- package/dist/utils/tools-manager.js +43 -21
- package/docs/docs.json +0 -4
- package/package.json +4 -4
- package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +0 -415
- package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +0 -1059
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +0 -116
- package/dist/extensions/pi-subagents/src/shared/post-exit-stdio-guard.ts +0 -85
- package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +0 -224
- package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +0 -6986
- package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +0 -447
- package/dist/extensions/pi-subagents/test/support/real-session-child-cli.mjs +0 -185
- package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +0 -311
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling-pi-args.test.ts +0 -84
- package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +0 -202
- package/dist/extensions/pi-subagents/test/unit/close-grace-timer.test.ts +0 -101
- package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +0 -2347
- package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +0 -104
- package/dist/extensions/pi-subagents/test/unit/windows-hide-spawn.test.ts +0 -49
- package/dist/skills/imagegen-frontend-mobile/SKILL.md +0 -1465
- package/dist/skills/imagegen-frontend-web/SKILL.md +0 -987
- package/dist/skills/implanger/SKILL.md +0 -70
- package/dist/skills/output/SKILL.md +0 -49
- package/dist/skills/planger/SKILL.md +0 -167
- package/dist/skills/workflow/SKILL.md +0 -95
- package/docs/workflows.md +0 -18
- /package/dist/bun/{register-bedrock.d.ts → runtime-setup.d.ts} +0 -0
|
@@ -2,6 +2,7 @@ import { DatabaseManager } from './db.js';
|
|
|
2
2
|
import {
|
|
3
3
|
buildFallbackFts5Query,
|
|
4
4
|
buildNaturalLanguageFallbackQuery,
|
|
5
|
+
collectLikeTerms,
|
|
5
6
|
isFts5QueryError,
|
|
6
7
|
normalizeFts5Query,
|
|
7
8
|
normalizeNaturalLanguageFts5Query,
|
|
@@ -9,6 +10,8 @@ import {
|
|
|
9
10
|
import { normalizeMemoryLookupText } from './memory-lookup.js';
|
|
10
11
|
import type { MemoryCategory } from '../types.js';
|
|
11
12
|
|
|
13
|
+
export { isFts5QueryError };
|
|
14
|
+
|
|
12
15
|
const MEMORY_SELECT_COLUMNS = `
|
|
13
16
|
id,
|
|
14
17
|
project,
|
|
@@ -22,6 +25,13 @@ const MEMORY_SELECT_COLUMNS = `
|
|
|
22
25
|
last_referenced
|
|
23
26
|
`;
|
|
24
27
|
|
|
28
|
+
// The BM25-ranked search joins memory_fts, which also has a `content` column,
|
|
29
|
+
// so that one query needs the same list qualified with the `memories` alias.
|
|
30
|
+
const MEMORY_SELECT_COLUMNS_M = MEMORY_SELECT_COLUMNS
|
|
31
|
+
.split(',')
|
|
32
|
+
.map((column) => `m.${column.trim()}`)
|
|
33
|
+
.join(',\n ');
|
|
34
|
+
|
|
25
35
|
const FAILURE_CATEGORY_SET = new Set<MemoryCategory>([
|
|
26
36
|
'failure',
|
|
27
37
|
'correction',
|
|
@@ -84,6 +94,15 @@ export interface MarkdownMemoryReconcileResult {
|
|
|
84
94
|
inserted: number;
|
|
85
95
|
existing: number;
|
|
86
96
|
removed: number;
|
|
97
|
+
/**
|
|
98
|
+
* True when the scope was left un-reconciled because of a genuine FTS5
|
|
99
|
+
* search-index error. Markdown remains the source of truth and the write
|
|
100
|
+
* did not fail; search may be stale until /memory-sync-markdown rebuilds
|
|
101
|
+
* the index. Callers should surface that repair guidance to the user.
|
|
102
|
+
*/
|
|
103
|
+
degraded?: boolean;
|
|
104
|
+
/** Human-readable reason for the degraded state, when degraded is true. */
|
|
105
|
+
degradedReason?: string;
|
|
87
106
|
}
|
|
88
107
|
|
|
89
108
|
export interface ParsedMarkdownMemoryEntry extends SqliteMemorySyncInput {}
|
|
@@ -157,6 +176,21 @@ function buildScopeConditions(params: unknown[], target?: string, project?: stri
|
|
|
157
176
|
return conditions;
|
|
158
177
|
}
|
|
159
178
|
|
|
179
|
+
/** Maps memory_search target filters onto SQLite columns (search paths only). */
|
|
180
|
+
function buildSearchTargetConditions(params: unknown[], target: string | undefined, tablePrefix: string): string[] {
|
|
181
|
+
const conditions: string[] = [];
|
|
182
|
+
|
|
183
|
+
if (target === 'project') {
|
|
184
|
+
conditions.push(`${tablePrefix}.target = 'memory'`);
|
|
185
|
+
conditions.push(`${tablePrefix}.project IS NOT NULL`);
|
|
186
|
+
} else if (target) {
|
|
187
|
+
conditions.push(`${tablePrefix}.target = ?`);
|
|
188
|
+
params.push(target);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return conditions;
|
|
192
|
+
}
|
|
193
|
+
|
|
160
194
|
function getMemoryById(dbManager: DatabaseManager, id: number): SqliteMemoryEntry | null {
|
|
161
195
|
const db = dbManager.getDb();
|
|
162
196
|
const row = db.prepare(`
|
|
@@ -438,12 +472,17 @@ export function reconcileMarkdownMemoryScope(
|
|
|
438
472
|
target: 'memory' | 'user' | 'failure',
|
|
439
473
|
project: string | null = null,
|
|
440
474
|
): MarkdownMemoryReconcileResult {
|
|
441
|
-
const db = dbManager.getDb();
|
|
442
475
|
const normalizedProject = normalizeNullable(project);
|
|
443
476
|
|
|
477
|
+
// The full reconcile runs against the CURRENT database handle. It must fetch
|
|
478
|
+
// it via dbManager.getDb() rather than a pre-fetched handle: after corruption
|
|
479
|
+
// recovery quarantines the old file and rebuilds a fresh one, the retry has
|
|
480
|
+
// to run on the new handle.
|
|
444
481
|
const reconcile = (): MarkdownMemoryReconcileResult => {
|
|
482
|
+
const db = dbManager.getDb();
|
|
445
483
|
let inserted = 0;
|
|
446
484
|
let existing = 0;
|
|
485
|
+
let removed = 0;
|
|
447
486
|
const desiredIdentities = new Set<string>();
|
|
448
487
|
|
|
449
488
|
for (const rawEntry of rawEntries) {
|
|
@@ -476,7 +515,6 @@ export function reconcileMarkdownMemoryScope(
|
|
|
476
515
|
}
|
|
477
516
|
}
|
|
478
517
|
|
|
479
|
-
let removed = 0;
|
|
480
518
|
if (orphanIds.length > 0) {
|
|
481
519
|
const placeholders = orphanIds.map(() => '?').join(', ');
|
|
482
520
|
removed = db.prepare(`DELETE FROM memories WHERE id IN (${placeholders})`).run(...orphanIds).changes;
|
|
@@ -485,8 +523,32 @@ export function reconcileMarkdownMemoryScope(
|
|
|
485
523
|
return { inserted, existing, removed };
|
|
486
524
|
};
|
|
487
525
|
|
|
488
|
-
const
|
|
489
|
-
|
|
526
|
+
const run = (): MarkdownMemoryReconcileResult => {
|
|
527
|
+
const db = dbManager.getDb();
|
|
528
|
+
const transactional = db.transaction?.(reconcile);
|
|
529
|
+
return transactional ? transactional() : reconcile();
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
try {
|
|
533
|
+
// Corruption errors (e.g. "database disk image is malformed") are NOT
|
|
534
|
+
// search-index problems: they must stay on the recovery path so
|
|
535
|
+
// DatabaseManager quarantines the corrupt file, rebuilds a fresh one, and
|
|
536
|
+
// retries this sync (#186). Swallowing them would hide corruption and
|
|
537
|
+
// leave a corrupt database in place.
|
|
538
|
+
return dbManager.withCorruptionRecovery(run);
|
|
539
|
+
} catch (err) {
|
|
540
|
+
if (isFts5QueryError(err)) {
|
|
541
|
+
// A genuine FTS5 query/index error means the search index is stale or
|
|
542
|
+
// broken, not that the database is corrupt. Markdown is the source of
|
|
543
|
+
// truth, so the write must not fail: warn in the log and report a
|
|
544
|
+
// DEGRADED result so the caller can surface the /memory-sync-markdown
|
|
545
|
+
// repair guidance to the user.
|
|
546
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
547
|
+
console.warn(`[pi-hermes-memory] FTS5 search index error during markdown sync (search may be stale; run /memory-sync-markdown): ${detail}`);
|
|
548
|
+
return { inserted: 0, existing: 0, removed: 0, degraded: true, degradedReason: detail };
|
|
549
|
+
}
|
|
550
|
+
throw err;
|
|
551
|
+
}
|
|
490
552
|
}
|
|
491
553
|
|
|
492
554
|
function failureProject(rawEntry: string): string | null {
|
|
@@ -527,6 +589,12 @@ export function reconcileMarkdownFailureScopes(
|
|
|
527
589
|
total.inserted += result.inserted;
|
|
528
590
|
total.existing += result.existing;
|
|
529
591
|
total.removed += result.removed;
|
|
592
|
+
if (result.degraded && !total.degraded) {
|
|
593
|
+
// Surface the first degraded scope: repair guidance applies to the whole
|
|
594
|
+
// sync run, and the first reason is the one to act on.
|
|
595
|
+
total.degraded = true;
|
|
596
|
+
total.degradedReason = result.degradedReason;
|
|
597
|
+
}
|
|
530
598
|
}
|
|
531
599
|
|
|
532
600
|
return total;
|
|
@@ -703,11 +771,8 @@ export function searchMemories(
|
|
|
703
771
|
const conditions: string[] = [];
|
|
704
772
|
const params: unknown[] = [];
|
|
705
773
|
|
|
706
|
-
// FTS5 match via
|
|
774
|
+
// FTS5 match via JOIN with BM25 ranking
|
|
707
775
|
const normalizedQuery = normalizeFts5Query(query);
|
|
708
|
-
if (normalizedQuery.length === 0) {
|
|
709
|
-
return [];
|
|
710
|
-
}
|
|
711
776
|
|
|
712
777
|
let ftsParseError = false;
|
|
713
778
|
|
|
@@ -715,7 +780,7 @@ export function searchMemories(
|
|
|
715
780
|
const conditions: string[] = [];
|
|
716
781
|
const params: unknown[] = [];
|
|
717
782
|
|
|
718
|
-
conditions.push('
|
|
783
|
+
conditions.push('memory_fts MATCH ?');
|
|
719
784
|
params.push(matchQuery);
|
|
720
785
|
|
|
721
786
|
if (project !== undefined) {
|
|
@@ -727,10 +792,7 @@ export function searchMemories(
|
|
|
727
792
|
}
|
|
728
793
|
}
|
|
729
794
|
|
|
730
|
-
|
|
731
|
-
conditions.push('m.target = ?');
|
|
732
|
-
params.push(target);
|
|
733
|
-
}
|
|
795
|
+
conditions.push(...buildSearchTargetConditions(params, target, 'm'));
|
|
734
796
|
|
|
735
797
|
if (category) {
|
|
736
798
|
conditions.push('m.category = ?');
|
|
@@ -740,10 +802,13 @@ export function searchMemories(
|
|
|
740
802
|
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
|
|
741
803
|
|
|
742
804
|
const sql = `
|
|
743
|
-
SELECT
|
|
805
|
+
SELECT
|
|
806
|
+
${MEMORY_SELECT_COLUMNS_M},
|
|
807
|
+
bm25(memory_fts) AS rank_score
|
|
744
808
|
FROM memories m
|
|
809
|
+
JOIN memory_fts ON memory_fts.rowid = m.id
|
|
745
810
|
${whereClause}
|
|
746
|
-
ORDER BY m.last_referenced DESC
|
|
811
|
+
ORDER BY rank_score ASC, m.last_referenced DESC
|
|
747
812
|
LIMIT ?
|
|
748
813
|
`;
|
|
749
814
|
|
|
@@ -759,6 +824,7 @@ export function searchMemories(
|
|
|
759
824
|
corrected_to: string | null;
|
|
760
825
|
created: string;
|
|
761
826
|
last_referenced: string;
|
|
827
|
+
rank_score: number;
|
|
762
828
|
}>;
|
|
763
829
|
|
|
764
830
|
return rows.map(mapRow);
|
|
@@ -778,6 +844,55 @@ export function searchMemories(
|
|
|
778
844
|
const conditions: string[] = ["m.content LIKE ? ESCAPE '\\'"];
|
|
779
845
|
const params: unknown[] = [`%${escapeLikePattern(query.trim())}%`];
|
|
780
846
|
|
|
847
|
+
if (project !== undefined) {
|
|
848
|
+
if (project === null) {
|
|
849
|
+
conditions.push('m.project IS NULL');
|
|
850
|
+
} else {
|
|
851
|
+
conditions.push('m.project = ?');
|
|
852
|
+
params.push(project);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
conditions.push(...buildSearchTargetConditions(params, target, 'm'));
|
|
856
|
+
|
|
857
|
+
if (category) {
|
|
858
|
+
conditions.push('m.category = ?');
|
|
859
|
+
params.push(category);
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
const rows = db.prepare(`
|
|
863
|
+
SELECT ${MEMORY_SELECT_COLUMNS}
|
|
864
|
+
FROM memories m
|
|
865
|
+
WHERE ${conditions.join(' AND ')}
|
|
866
|
+
ORDER BY m.last_referenced DESC
|
|
867
|
+
LIMIT ?
|
|
868
|
+
`).all(...params, limit) as Array<{
|
|
869
|
+
id: number;
|
|
870
|
+
project: string | null;
|
|
871
|
+
target: string;
|
|
872
|
+
category: string | null;
|
|
873
|
+
content: string;
|
|
874
|
+
failure_reason: string | null;
|
|
875
|
+
tool_state: string | null;
|
|
876
|
+
corrected_to: string | null;
|
|
877
|
+
created: string;
|
|
878
|
+
last_referenced: string;
|
|
879
|
+
}>;
|
|
880
|
+
return rows.map(mapRow);
|
|
881
|
+
};
|
|
882
|
+
|
|
883
|
+
// Every term a stop word or connector leaves FTS5 nothing to match.
|
|
884
|
+
// Degrade to a scoped literal substring search (OR over the raw terms) —
|
|
885
|
+
// the same fallback session search uses for this case — instead of a hard
|
|
886
|
+
// [].
|
|
887
|
+
const runLiteralLikeFallback = (): SqliteMemoryEntry[] => {
|
|
888
|
+
const terms = collectLikeTerms(query);
|
|
889
|
+
if (terms.length === 0) return [];
|
|
890
|
+
|
|
891
|
+
const conditions: string[] = [
|
|
892
|
+
`(${terms.map(() => "m.content LIKE ? ESCAPE '\\'").join(' OR ')})`,
|
|
893
|
+
];
|
|
894
|
+
const params: unknown[] = terms.map((term) => `%${escapeLikePattern(term.trim())}%`);
|
|
895
|
+
|
|
781
896
|
if (project !== undefined) {
|
|
782
897
|
if (project === null) {
|
|
783
898
|
conditions.push('m.project IS NULL');
|
|
@@ -816,6 +931,10 @@ export function searchMemories(
|
|
|
816
931
|
return rows.map(mapRow);
|
|
817
932
|
};
|
|
818
933
|
|
|
934
|
+
if (normalizedQuery.length === 0) {
|
|
935
|
+
return runLiteralLikeFallback();
|
|
936
|
+
}
|
|
937
|
+
|
|
819
938
|
const exactResults = runSearch(normalizedQuery);
|
|
820
939
|
if (exactResults.length > 0) {
|
|
821
940
|
return exactResults;
|
|
@@ -36,6 +36,8 @@ Use cases:
|
|
|
36
36
|
- Find user preferences: "What are the user's testing preferences?"
|
|
37
37
|
- Search for past failures: "memory_search('auth', category='failure')"
|
|
38
38
|
|
|
39
|
+
target="project" returns only project-attributed memory entries (the ones labeled [target=project]); combine with project to search a named project.
|
|
40
|
+
|
|
39
41
|
Returns matching memory entries with their mutation target, scope, and dates. The displayed target is the value required by memory_replace and memory_remove.`,
|
|
40
42
|
promptSnippet: 'Search extended memory store (unlimited capacity)',
|
|
41
43
|
promptGuidelines: [
|
|
@@ -47,11 +49,11 @@ Returns matching memory entries with their mutation target, scope, and dates. Th
|
|
|
47
49
|
parameters: Type.Object({
|
|
48
50
|
query: Type.String({ description: 'Search query. Use natural language or specific terms.' }),
|
|
49
51
|
project: Type.Optional(Type.String({ description: 'Filter by project name. Pass null for global memories only.' })),
|
|
50
|
-
target: Type.Optional(StringEnum(['memory', 'user', 'failure'] as const, { description: 'Filter by target type
|
|
52
|
+
target: Type.Optional(StringEnum(['memory', 'user', 'failure', 'project'] as const, { description: 'Filter by target type: memory, user, failure, or project-attributed memories.' })),
|
|
51
53
|
category: Type.Optional(StringEnum(['failure', 'correction', 'insight', 'preference', 'convention', 'tool-quirk'] as const, { description: 'Filter by memory category.' })),
|
|
52
54
|
limit: Type.Optional(Type.Number({ description: 'Maximum results to return (default: 10, max: 20).' })),
|
|
53
55
|
}),
|
|
54
|
-
execute: async (_id: string, args: { query: string; project?: string; target?:
|
|
56
|
+
execute: async (_id: string, args: { query: string; project?: string; target?: 'memory' | 'user' | 'failure' | 'project'; category?: string; limit?: number }) => {
|
|
55
57
|
const query = args.query;
|
|
56
58
|
const project = args.project;
|
|
57
59
|
const target = args.target;
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
removeSyncedMemories,
|
|
18
18
|
replaceSyncedMemories,
|
|
19
19
|
syncMemoryEntry,
|
|
20
|
+
isFts5QueryError,
|
|
20
21
|
} from "../store/sqlite-memory-store.js";
|
|
21
22
|
import { MEMORY_TOOL_DESCRIPTION } from "../constants.js";
|
|
22
23
|
import { resolveProjectName, resolveProjectStore, type ProjectNameRef, type ProjectStoreRef } from "../project-context.js";
|
|
@@ -238,22 +239,36 @@ async function reconcileStoreScope(
|
|
|
238
239
|
if (!dbManager) return undefined;
|
|
239
240
|
try {
|
|
240
241
|
if (rawTarget === "failure") {
|
|
241
|
-
reconcileMarkdownFailureScopes(dbManager, entries);
|
|
242
|
-
return null;
|
|
242
|
+
return degradedRepairMessage(reconcileMarkdownFailureScopes(dbManager, entries));
|
|
243
243
|
}
|
|
244
244
|
const target = sqliteTargetFor(rawTarget);
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
245
|
+
return degradedRepairMessage(
|
|
246
|
+
reconcileMarkdownMemoryScope(
|
|
247
|
+
dbManager,
|
|
248
|
+
entries,
|
|
249
|
+
target,
|
|
250
|
+
sqliteProjectFor(rawTarget, projectName) ?? null,
|
|
251
|
+
),
|
|
250
252
|
);
|
|
251
|
-
return null;
|
|
252
253
|
} catch (err) {
|
|
253
|
-
|
|
254
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
255
|
+
if (isFts5QueryError(err)) {
|
|
256
|
+
return degradedRepairMessage({ degraded: true, degradedReason: detail });
|
|
257
|
+
}
|
|
258
|
+
return `Saved to Markdown, but SQLite search reconciliation failed: ${detail}`;
|
|
254
259
|
}
|
|
255
260
|
}
|
|
256
261
|
|
|
262
|
+
// A degraded reconcile result means the Markdown write succeeded but the
|
|
263
|
+
// SQLite search mirror could not be updated (genuine FTS5 index error). The
|
|
264
|
+
// caller must tell the user how to repair the index instead of looking like a
|
|
265
|
+
// plain success.
|
|
266
|
+
function degradedRepairMessage(result: { degraded?: boolean; degradedReason?: string }): string | null {
|
|
267
|
+
return result.degraded
|
|
268
|
+
? `Saved to Markdown. Search may be temporarily unavailable (FTS5 index error: ${result.degradedReason}). Run /memory-sync-markdown to rebuild the search index.`
|
|
269
|
+
: null;
|
|
270
|
+
}
|
|
271
|
+
|
|
257
272
|
type MemoryAction = "add" | "replace" | "remove";
|
|
258
273
|
|
|
259
274
|
type MemoryToolParams = {
|
|
@@ -52,8 +52,12 @@ export interface MemoryConfig {
|
|
|
52
52
|
projectsMemoryDir?: string;
|
|
53
53
|
/** Session search configuration. Default: { variant: "legacy" } */
|
|
54
54
|
sessionSearch?: SessionSearchConfig;
|
|
55
|
+
/** Run a full SQLite quick_check asynchronously after opening. Default: true */
|
|
56
|
+
quickCheckOnOpen?: boolean;
|
|
55
57
|
/** Override model used for child pi -p subprocess LLM calls. Default: unset */
|
|
56
58
|
llmModelOverride?: string;
|
|
59
|
+
/** Fallback model chain tried in order when the primary review model fails (rate limit, 401/403, 404, 500/503, invalid response). Default: unset */
|
|
60
|
+
llmFallbackModels?: string[];
|
|
57
61
|
/** Override thinking level used for child pi -p subprocess LLM calls. Default: unset */
|
|
58
62
|
llmThinkingOverride?: ThinkingLevel;
|
|
59
63
|
/** Trusted Pi extension sources required by child processes, such as custom providers or auth adapters. */
|
|
@@ -88,6 +92,13 @@ export interface MemoryConfig {
|
|
|
88
92
|
autoConsolidationWarnOnFailure: boolean;
|
|
89
93
|
/** Inject pinned STANDING.md instructions into every session. Default: true */
|
|
90
94
|
standingInstructionsEnabled: boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Session retention window in days. A positive value opts in to pruning
|
|
97
|
+
* sessions (and their messages) older than the window on startup; `0`/omitted
|
|
98
|
+
* disables pruning so no existing searchable history is silently deleted.
|
|
99
|
+
* Default: 0 (disabled).
|
|
100
|
+
*/
|
|
101
|
+
sessionRetentionDays?: number;
|
|
91
102
|
}
|
|
92
103
|
|
|
93
104
|
export type MemoryCategory =
|
|
@@ -41,6 +41,10 @@ describe("loadConfig", () => {
|
|
|
41
41
|
assert.strictEqual(config.llmModelOverride, undefined);
|
|
42
42
|
assert.strictEqual(config.llmThinkingOverride, undefined);
|
|
43
43
|
assert.strictEqual(config.standingInstructionsEnabled, true);
|
|
44
|
+
// Retention is disabled by default so existing history is never silently
|
|
45
|
+
// deleted; a positive value opts in, 0/omitted disables.
|
|
46
|
+
assert.strictEqual(config.sessionRetentionDays, 0);
|
|
47
|
+
assert.strictEqual(config.quickCheckOnOpen, true);
|
|
44
48
|
});
|
|
45
49
|
|
|
46
50
|
it("honors a configured consolidationTimeoutMs, warning only when it is below the default", () => {
|
|
@@ -85,6 +89,7 @@ describe("loadConfig", () => {
|
|
|
85
89
|
llmModelOverride: " openrouter/deepseek/deepseek-v4-flash ",
|
|
86
90
|
llmThinkingOverride: "minimal",
|
|
87
91
|
autoConsolidationWarnOnFailure: false,
|
|
92
|
+
quickCheckOnOpen: false,
|
|
88
93
|
}));
|
|
89
94
|
const config = loadConfig(TEST_CONFIG_PATH);
|
|
90
95
|
assert.strictEqual(config.memoryMode, "legacy-inject");
|
|
@@ -101,11 +106,48 @@ describe("loadConfig", () => {
|
|
|
101
106
|
assert.strictEqual(config.projectsMemoryDir, "my-memory");
|
|
102
107
|
assert.strictEqual(config.llmModelOverride, "openrouter/deepseek/deepseek-v4-flash");
|
|
103
108
|
assert.strictEqual(config.llmThinkingOverride, "minimal");
|
|
109
|
+
assert.strictEqual(config.quickCheckOnOpen, false);
|
|
104
110
|
// Unset values use defaults
|
|
105
111
|
assert.strictEqual(config.userCharLimit, 5000);
|
|
106
112
|
assert.strictEqual(config.reviewEnabled, true);
|
|
107
113
|
});
|
|
108
114
|
|
|
115
|
+
it("only accepts boolean quickCheckOnOpen overrides", () => {
|
|
116
|
+
fs.mkdirSync(path.dirname(TEST_CONFIG_PATH), { recursive: true });
|
|
117
|
+
fs.writeFileSync(TEST_CONFIG_PATH, JSON.stringify({ quickCheckOnOpen: "false" }));
|
|
118
|
+
assert.strictEqual(loadConfig(TEST_CONFIG_PATH).quickCheckOnOpen, true);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("merges array-form override tails with explicit llmFallbackModels", () => {
|
|
122
|
+
fs.mkdirSync(path.dirname(TEST_CONFIG_PATH), { recursive: true });
|
|
123
|
+
fs.writeFileSync(TEST_CONFIG_PATH, JSON.stringify({
|
|
124
|
+
llmModelOverride: ["p1/m1", "p2/m2"],
|
|
125
|
+
llmFallbackModels: ["p3/m3"],
|
|
126
|
+
}));
|
|
127
|
+
const config = loadConfig(TEST_CONFIG_PATH);
|
|
128
|
+
assert.strictEqual(config.llmModelOverride, "p1/m1");
|
|
129
|
+
assert.deepStrictEqual(config.llmFallbackModels, ["p2/m2", "p3/m3"]);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
it("parses sessionRetentionDays as opt-in, accepting explicit 0 to disable", () => {
|
|
134
|
+
fs.mkdirSync(path.dirname(TEST_CONFIG_PATH), { recursive: true });
|
|
135
|
+
|
|
136
|
+
// Positive value opts in to retention pruning.
|
|
137
|
+
fs.writeFileSync(TEST_CONFIG_PATH, JSON.stringify({ sessionRetentionDays: 45 }));
|
|
138
|
+
assert.strictEqual(loadConfig(TEST_CONFIG_PATH).sessionRetentionDays, 45);
|
|
139
|
+
|
|
140
|
+
// Explicit 0 disables retention (even after a prior positive value).
|
|
141
|
+
fs.writeFileSync(TEST_CONFIG_PATH, JSON.stringify({ sessionRetentionDays: 0 }));
|
|
142
|
+
assert.strictEqual(loadConfig(TEST_CONFIG_PATH).sessionRetentionDays, 0);
|
|
143
|
+
|
|
144
|
+
// Negative / non-numeric values are ignored, keeping the (disabled) default.
|
|
145
|
+
fs.writeFileSync(TEST_CONFIG_PATH, JSON.stringify({ sessionRetentionDays: -5 }));
|
|
146
|
+
assert.strictEqual(loadConfig(TEST_CONFIG_PATH).sessionRetentionDays, 0);
|
|
147
|
+
fs.writeFileSync(TEST_CONFIG_PATH, JSON.stringify({ sessionRetentionDays: "30" }));
|
|
148
|
+
assert.strictEqual(loadConfig(TEST_CONFIG_PATH).sessionRetentionDays, 0);
|
|
149
|
+
});
|
|
150
|
+
|
|
109
151
|
it("handles partial config (missing keys use defaults)", () => {
|
|
110
152
|
fs.mkdirSync(path.dirname(TEST_CONFIG_PATH), { recursive: true });
|
|
111
153
|
fs.writeFileSync(TEST_CONFIG_PATH, JSON.stringify({ reviewEnabled: false }));
|
|
@@ -771,7 +771,7 @@ describe("setupBackgroundReview", () => {
|
|
|
771
771
|
assert.strictEqual(directCalls.length, 1, "direct review should be attempted first");
|
|
772
772
|
assert.strictEqual(execCalls.length, 1, "subprocess should run as fallback");
|
|
773
773
|
});
|
|
774
|
-
it("inherits the active session model and
|
|
774
|
+
it("inherits the active session model and cwd without coupling fallback to the agent run signal", async () => {
|
|
775
775
|
const pi = createMockPi();
|
|
776
776
|
setupWithDirectDeps(pi, { ok: false, appliedCount: 0, fallbackReason: "no_auth" }, {
|
|
777
777
|
...defaultConfig,
|
|
@@ -781,14 +781,15 @@ describe("setupBackgroundReview", () => {
|
|
|
781
781
|
fireMessageEnd("user");
|
|
782
782
|
fireMessageEnd("user");
|
|
783
783
|
fireMessageEnd("user");
|
|
784
|
-
const
|
|
784
|
+
const controller = new AbortController();
|
|
785
785
|
for (let i = 0; i < 10; i++) {
|
|
786
786
|
fireTurnEnd(makeBranch(10), {
|
|
787
787
|
cwd: "/tmp/local-session",
|
|
788
788
|
model: { provider: "local-llama", id: "local-9b" },
|
|
789
|
-
signal,
|
|
789
|
+
signal: controller.signal,
|
|
790
790
|
});
|
|
791
791
|
}
|
|
792
|
+
controller.abort();
|
|
792
793
|
await reviewSettledSignal.promise;
|
|
793
794
|
|
|
794
795
|
assert.deepStrictEqual(logicalChildArgs(0).slice(0, 5), [
|
|
@@ -919,6 +920,161 @@ describe("setupBackgroundReview", () => {
|
|
|
919
920
|
assert.ok(directPrompt.includes("monorepo layout"));
|
|
920
921
|
});
|
|
921
922
|
|
|
923
|
+
it("does not forward the turn abort signal to the child review", async () => {
|
|
924
|
+
let capturedSignal: AbortSignal | undefined;
|
|
925
|
+
const childGate = Promise.withResolvers<void>();
|
|
926
|
+
const pi = createMockPi();
|
|
927
|
+
setup(pi, defaultConfig, {
|
|
928
|
+
execChildPrompt: async (_api, _prompt, _config, options) => {
|
|
929
|
+
capturedSignal = options.signal;
|
|
930
|
+
await childGate.promise;
|
|
931
|
+
return { code: 0, stdout: "Saved memory", stderr: "" };
|
|
932
|
+
},
|
|
933
|
+
});
|
|
934
|
+
|
|
935
|
+
fireMessageEnd("user");
|
|
936
|
+
fireMessageEnd("user");
|
|
937
|
+
fireMessageEnd("user");
|
|
938
|
+
const turnAbort = new AbortController();
|
|
939
|
+
for (let i = 0; i < 10; i++) {
|
|
940
|
+
fireTurnEnd(makeBranch(10), { signal: turnAbort.signal });
|
|
941
|
+
}
|
|
942
|
+
await settle(5);
|
|
943
|
+
|
|
944
|
+
assert.ok(capturedSignal, "child review must receive a session signal");
|
|
945
|
+
assert.notStrictEqual(capturedSignal, turnAbort.signal);
|
|
946
|
+
turnAbort.abort();
|
|
947
|
+
await settle(5);
|
|
948
|
+
assert.equal(capturedSignal.aborted, false, "turn abort must not cancel session review");
|
|
949
|
+
|
|
950
|
+
childGate.resolve();
|
|
951
|
+
await reviewSettledSignal.promise;
|
|
952
|
+
});
|
|
953
|
+
|
|
954
|
+
it("session_shutdown aborts the child signal, waits for review, and stays silent", async () => {
|
|
955
|
+
let capturedSignal: AbortSignal | undefined;
|
|
956
|
+
const childGate = Promise.withResolvers<void>();
|
|
957
|
+
let childStarted = 0;
|
|
958
|
+
const pi = createMockPi();
|
|
959
|
+
setup(pi, defaultConfig, {
|
|
960
|
+
execChildPrompt: async (_api, _prompt, _config, options) => {
|
|
961
|
+
childStarted++;
|
|
962
|
+
capturedSignal = options.signal;
|
|
963
|
+
await childGate.promise;
|
|
964
|
+
return { code: 0, stdout: "Saved memory", stderr: "" };
|
|
965
|
+
},
|
|
966
|
+
});
|
|
967
|
+
|
|
968
|
+
fireMessageEnd("user");
|
|
969
|
+
fireMessageEnd("user");
|
|
970
|
+
fireMessageEnd("user");
|
|
971
|
+
for (let i = 0; i < 10; i++) {
|
|
972
|
+
fireTurnEnd();
|
|
973
|
+
}
|
|
974
|
+
await settle(5);
|
|
975
|
+
assert.ok(capturedSignal);
|
|
976
|
+
assert.equal(capturedSignal.aborted, false);
|
|
977
|
+
|
|
978
|
+
const shutdownHandlers = handlers["session_shutdown"];
|
|
979
|
+
assert.ok(shutdownHandlers?.length, "session_shutdown handler must be registered");
|
|
980
|
+
const first = shutdownHandlers[0]({}, makeCtx());
|
|
981
|
+
const second = shutdownHandlers[0]({}, makeCtx());
|
|
982
|
+
assert.strictEqual(first, second, "repeated session_shutdown must reuse the same promise");
|
|
983
|
+
assert.equal(capturedSignal.aborted, true);
|
|
984
|
+
|
|
985
|
+
let shutdownDone = false;
|
|
986
|
+
void Promise.resolve(first).then(() => {
|
|
987
|
+
shutdownDone = true;
|
|
988
|
+
});
|
|
989
|
+
await settle(5);
|
|
990
|
+
assert.equal(shutdownDone, false, "shutdown must wait for the in-flight review");
|
|
991
|
+
|
|
992
|
+
childGate.resolve();
|
|
993
|
+
await first;
|
|
994
|
+
await reviewSettledSignal.promise;
|
|
995
|
+
assert.equal(shutdownDone, true);
|
|
996
|
+
assert.equal(
|
|
997
|
+
notifyCalls.some((n) => n.msg.includes("Memory auto-reviewed") || n.level === "warning"),
|
|
998
|
+
false,
|
|
999
|
+
"cancelled review must not notify success or failure",
|
|
1000
|
+
);
|
|
1001
|
+
|
|
1002
|
+
resetReviewSettledSignal();
|
|
1003
|
+
for (let i = 0; i < 10; i++) {
|
|
1004
|
+
fireTurnEnd();
|
|
1005
|
+
}
|
|
1006
|
+
await settle(10);
|
|
1007
|
+
assert.equal(childStarted, 1, "cancelled session must not start another review");
|
|
1008
|
+
});
|
|
1009
|
+
|
|
1010
|
+
it("does not start fallback after session cancellation", async () => {
|
|
1011
|
+
const directGate = Promise.withResolvers<void>();
|
|
1012
|
+
let childStarted = 0;
|
|
1013
|
+
const pi = createMockPi();
|
|
1014
|
+
setup(pi, { ...defaultConfig, reviewTransport: "direct" } as MemoryConfig, {
|
|
1015
|
+
runDirectReview: async () => {
|
|
1016
|
+
await directGate.promise;
|
|
1017
|
+
return { ok: true, appliedCount: 1 };
|
|
1018
|
+
},
|
|
1019
|
+
execChildPrompt: async () => {
|
|
1020
|
+
childStarted++;
|
|
1021
|
+
return { code: 0, stdout: "Saved memory", stderr: "" };
|
|
1022
|
+
},
|
|
1023
|
+
});
|
|
1024
|
+
|
|
1025
|
+
fireMessageEnd("user");
|
|
1026
|
+
fireMessageEnd("user");
|
|
1027
|
+
fireMessageEnd("user");
|
|
1028
|
+
for (let i = 0; i < 10; i++) {
|
|
1029
|
+
fireTurnEnd();
|
|
1030
|
+
}
|
|
1031
|
+
await settle(5);
|
|
1032
|
+
|
|
1033
|
+
const shutdown = handlers["session_shutdown"][0]({}, makeCtx());
|
|
1034
|
+
directGate.resolve();
|
|
1035
|
+
await shutdown;
|
|
1036
|
+
await reviewSettledSignal.promise;
|
|
1037
|
+
|
|
1038
|
+
assert.equal(childStarted, 0, "cancelled session must not start subprocess fallback");
|
|
1039
|
+
assert.equal(
|
|
1040
|
+
notifyCalls.some((n) => n.msg.includes("Memory auto-reviewed") || n.level === "warning"),
|
|
1041
|
+
false,
|
|
1042
|
+
);
|
|
1043
|
+
});
|
|
1044
|
+
|
|
1045
|
+
it("session_shutdown resolves after the grace bound when review ignores abort", async () => {
|
|
1046
|
+
let started = false;
|
|
1047
|
+
const pi = createMockPi();
|
|
1048
|
+
setup(pi, { ...defaultConfig, reviewTransport: "direct" } as MemoryConfig, {
|
|
1049
|
+
shutdownGraceMs: 20,
|
|
1050
|
+
runDirectReview: async () => {
|
|
1051
|
+
started = true;
|
|
1052
|
+
await new Promise(() => {});
|
|
1053
|
+
return { ok: true, appliedCount: 1 };
|
|
1054
|
+
},
|
|
1055
|
+
});
|
|
1056
|
+
|
|
1057
|
+
fireMessageEnd("user");
|
|
1058
|
+
fireMessageEnd("user");
|
|
1059
|
+
fireMessageEnd("user");
|
|
1060
|
+
for (let i = 0; i < 10; i++) {
|
|
1061
|
+
fireTurnEnd();
|
|
1062
|
+
}
|
|
1063
|
+
await settle(5);
|
|
1064
|
+
assert.equal(started, true);
|
|
1065
|
+
|
|
1066
|
+
const first = handlers["session_shutdown"][0]({}, makeCtx());
|
|
1067
|
+
const second = handlers["session_shutdown"][0]({}, makeCtx());
|
|
1068
|
+
assert.strictEqual(first, second);
|
|
1069
|
+
const startedAt = Date.now();
|
|
1070
|
+
await first;
|
|
1071
|
+
assert.ok(Date.now() - startedAt < 200, "shutdown must not wait for a review that ignores abort");
|
|
1072
|
+
assert.equal(
|
|
1073
|
+
notifyCalls.some((n) => n.msg.includes("Memory auto-reviewed") || n.level === "warning"),
|
|
1074
|
+
false,
|
|
1075
|
+
);
|
|
1076
|
+
});
|
|
1077
|
+
|
|
922
1078
|
it("falls back gracefully if getBranch throws", async () => {
|
|
923
1079
|
const config = { ...defaultConfig, nudgeToolCalls: 3 };
|
|
924
1080
|
const pi = createMockPi();
|