@selesai/code 0.13.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 +12 -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/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/modes/interactive/interactive-mode.js +7 -7
- 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,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-shot snapshot retention sweep across every memory store on disk (#202).
|
|
3
|
+
*
|
|
4
|
+
* Snapshot pruning normally runs inside saveToDisk(), so a store that stops
|
|
5
|
+
* being written keeps its .recovery-* and .retired-* artifacts forever. This
|
|
6
|
+
* sweep applies the identical per-file policy to dormant stores once per
|
|
7
|
+
* session start. Enumeration never follows symlinks and never enters hidden
|
|
8
|
+
* or nested directories.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import * as fs from "node:fs/promises";
|
|
12
|
+
import * as path from "node:path";
|
|
13
|
+
import { resolveProjectsRoot } from "../paths.js";
|
|
14
|
+
import { MemoryStore } from "./memory-store.js";
|
|
15
|
+
import type { MemoryConfig } from "../types.js";
|
|
16
|
+
|
|
17
|
+
export interface RecoveryMaintenanceOptions {
|
|
18
|
+
config: MemoryConfig;
|
|
19
|
+
globalDir: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface RecoveryMaintenanceResult {
|
|
23
|
+
storesMaintained: number;
|
|
24
|
+
failedStores: string[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// loadConfig only ever stores a single AGENT_ROOT-relative segment here; an
|
|
28
|
+
// absolute value is a direct-injection seam for tests and embedding hosts.
|
|
29
|
+
function resolveProjectsRootFor(projectsMemoryDir: MemoryConfig["projectsMemoryDir"]): string {
|
|
30
|
+
return projectsMemoryDir && path.isAbsolute(projectsMemoryDir)
|
|
31
|
+
? projectsMemoryDir
|
|
32
|
+
: resolveProjectsRoot(projectsMemoryDir);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function listMemoryStoreDirs(options: RecoveryMaintenanceOptions): Promise<string[]> {
|
|
36
|
+
const dirs = [options.globalDir];
|
|
37
|
+
const projectsRoot = resolveProjectsRootFor(options.config.projectsMemoryDir);
|
|
38
|
+
let entries;
|
|
39
|
+
try {
|
|
40
|
+
entries = await fs.readdir(projectsRoot, { withFileTypes: true });
|
|
41
|
+
} catch {
|
|
42
|
+
return dirs;
|
|
43
|
+
}
|
|
44
|
+
for (const entry of entries) {
|
|
45
|
+
if (entry.isSymbolicLink() || !entry.isDirectory()) continue;
|
|
46
|
+
if (entry.name.startsWith(".") || entry.name === "skills") continue;
|
|
47
|
+
dirs.push(path.join(projectsRoot, entry.name));
|
|
48
|
+
}
|
|
49
|
+
return dirs;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export async function runRecoveryMaintenance(options: RecoveryMaintenanceOptions): Promise<RecoveryMaintenanceResult> {
|
|
53
|
+
const result: RecoveryMaintenanceResult = { storesMaintained: 0, failedStores: [] };
|
|
54
|
+
for (const memoryDir of await listMemoryStoreDirs(options)) {
|
|
55
|
+
// The constructor only assigns config; maintainRecoveryFiles touches
|
|
56
|
+
// sidecar files without loading or writing MEMORY.md/USER.md/failures.md.
|
|
57
|
+
const store = new MemoryStore({ ...options.config, memoryDir });
|
|
58
|
+
try {
|
|
59
|
+
await store.maintainRecoveryFiles();
|
|
60
|
+
result.storesMaintained++;
|
|
61
|
+
} catch {
|
|
62
|
+
result.failedStores.push(memoryDir);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLite schema for pi-hermes-memory v0.4
|
|
3
|
+
*
|
|
4
|
+
* Tables:
|
|
5
|
+
* - sessions — Pi session metadata
|
|
6
|
+
* - session_files — indexed JSONL metadata for incremental backfill
|
|
7
|
+
* - messages — all conversation messages
|
|
8
|
+
* - message_fts — FTS5 index for full-text search across messages
|
|
9
|
+
* - memories — extended memory entries (unlimited, searchable)
|
|
10
|
+
* - memory_fts — FTS5 index for memory search
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export const SCHEMA_SQL = `
|
|
14
|
+
-- Extension key/value metadata
|
|
15
|
+
CREATE TABLE IF NOT EXISTS extension_metadata (
|
|
16
|
+
key TEXT PRIMARY KEY,
|
|
17
|
+
value TEXT NOT NULL
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
-- Session metadata
|
|
21
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
22
|
+
id TEXT PRIMARY KEY,
|
|
23
|
+
project TEXT NOT NULL,
|
|
24
|
+
cwd TEXT NOT NULL,
|
|
25
|
+
started_at TEXT NOT NULL,
|
|
26
|
+
ended_at TEXT,
|
|
27
|
+
message_count INTEGER DEFAULT 0
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
-- Indexed session file metadata for cheap incremental backfill
|
|
31
|
+
CREATE TABLE IF NOT EXISTS session_files (
|
|
32
|
+
path TEXT PRIMARY KEY,
|
|
33
|
+
session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
34
|
+
size INTEGER NOT NULL,
|
|
35
|
+
mtime_ms INTEGER NOT NULL,
|
|
36
|
+
indexed_at TEXT NOT NULL
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
-- All messages from all sessions
|
|
40
|
+
CREATE TABLE IF NOT EXISTS messages (
|
|
41
|
+
id TEXT PRIMARY KEY,
|
|
42
|
+
session_id TEXT NOT NULL REFERENCES sessions(id),
|
|
43
|
+
role TEXT NOT NULL CHECK (role IN ('user', 'assistant', 'system')),
|
|
44
|
+
content TEXT NOT NULL,
|
|
45
|
+
timestamp TEXT NOT NULL,
|
|
46
|
+
tool_calls TEXT
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
-- FTS5 trigram indexes support substring search for CJK and retain
|
|
50
|
+
-- normal token search for English. Queries shorter than three characters
|
|
51
|
+
-- are not indexed by the trigram tokenizer.
|
|
52
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS message_fts USING fts5(
|
|
53
|
+
content,
|
|
54
|
+
content='messages',
|
|
55
|
+
content_rowid='rowid',
|
|
56
|
+
tokenize='trigram'
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
-- Triggers to keep message_fts in sync with messages table
|
|
60
|
+
CREATE TRIGGER IF NOT EXISTS messages_ai AFTER INSERT ON messages BEGIN
|
|
61
|
+
INSERT INTO message_fts(rowid, content) VALUES (new.rowid, new.content);
|
|
62
|
+
END;
|
|
63
|
+
|
|
64
|
+
CREATE TRIGGER IF NOT EXISTS messages_ad AFTER DELETE ON messages BEGIN
|
|
65
|
+
INSERT INTO message_fts(message_fts, rowid, content) VALUES ('delete', old.rowid, old.content);
|
|
66
|
+
END;
|
|
67
|
+
|
|
68
|
+
CREATE TRIGGER IF NOT EXISTS messages_au AFTER UPDATE ON messages BEGIN
|
|
69
|
+
INSERT INTO message_fts(message_fts, rowid, content) VALUES ('delete', old.rowid, old.content);
|
|
70
|
+
INSERT INTO message_fts(rowid, content) VALUES (new.rowid, new.content);
|
|
71
|
+
END;
|
|
72
|
+
|
|
73
|
+
-- Extended memory entries (beyond MEMORY.md limit)
|
|
74
|
+
CREATE TABLE IF NOT EXISTS memories (
|
|
75
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
76
|
+
project TEXT,
|
|
77
|
+
target TEXT NOT NULL CHECK (target IN ('memory', 'user', 'failure')),
|
|
78
|
+
category TEXT CHECK (category IN ('failure', 'correction', 'insight', 'preference', 'convention', 'tool-quirk')),
|
|
79
|
+
content TEXT NOT NULL,
|
|
80
|
+
failure_reason TEXT,
|
|
81
|
+
tool_state TEXT,
|
|
82
|
+
corrected_to TEXT,
|
|
83
|
+
created DATE NOT NULL,
|
|
84
|
+
last_referenced DATE NOT NULL
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
-- FTS5 trigram index for memory substring search
|
|
88
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS memory_fts USING fts5(
|
|
89
|
+
content,
|
|
90
|
+
content='memories',
|
|
91
|
+
content_rowid='id',
|
|
92
|
+
tokenize='trigram'
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
-- Triggers to keep memory_fts in sync with memories table
|
|
96
|
+
CREATE TRIGGER IF NOT EXISTS memories_ai AFTER INSERT ON memories BEGIN
|
|
97
|
+
INSERT INTO memory_fts(rowid, content) VALUES (new.id, new.content);
|
|
98
|
+
END;
|
|
99
|
+
|
|
100
|
+
CREATE TRIGGER IF NOT EXISTS memories_ad AFTER DELETE ON memories BEGIN
|
|
101
|
+
INSERT INTO memory_fts(memory_fts, rowid, content) VALUES ('delete', old.id, old.content);
|
|
102
|
+
END;
|
|
103
|
+
|
|
104
|
+
CREATE TRIGGER IF NOT EXISTS memories_au AFTER UPDATE ON memories BEGIN
|
|
105
|
+
INSERT INTO memory_fts(memory_fts, rowid, content) VALUES ('delete', old.id, old.content);
|
|
106
|
+
INSERT INTO memory_fts(rowid, content) VALUES (new.id, new.content);
|
|
107
|
+
END;
|
|
108
|
+
|
|
109
|
+
-- Indexes for common queries
|
|
110
|
+
CREATE INDEX IF NOT EXISTS idx_messages_session_id ON messages(session_id);
|
|
111
|
+
CREATE INDEX IF NOT EXISTS idx_messages_timestamp ON messages(timestamp);
|
|
112
|
+
CREATE INDEX IF NOT EXISTS idx_memories_project ON memories(project);
|
|
113
|
+
CREATE INDEX IF NOT EXISTS idx_memories_target ON memories(target);
|
|
114
|
+
CREATE INDEX IF NOT EXISTS idx_memories_category ON memories(category);
|
|
115
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_project ON sessions(project);
|
|
116
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_started_at ON sessions(started_at);
|
|
117
|
+
CREATE INDEX IF NOT EXISTS idx_session_files_session_id ON session_files(session_id);
|
|
118
|
+
`;
|
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
|
|
4
|
+
const DEFAULT_LIMIT = 50;
|
|
5
|
+
const MAX_LIMIT = 100;
|
|
6
|
+
const DEFAULT_MAX_FILES = 5000;
|
|
7
|
+
const DEFAULT_MAX_LINES = 500000;
|
|
8
|
+
const LIST_FIELDS = new Set(["all", "any", "exclude"]);
|
|
9
|
+
const VALUE_FIELDS = new Set(["from", "to", "cwd", "limit"]);
|
|
10
|
+
|
|
11
|
+
export interface SessionAnchorRange {
|
|
12
|
+
path: string;
|
|
13
|
+
startLine: number;
|
|
14
|
+
endLine: number;
|
|
15
|
+
sessionId?: string;
|
|
16
|
+
cwd?: string;
|
|
17
|
+
startTime?: string;
|
|
18
|
+
endTime?: string;
|
|
19
|
+
score?: number;
|
|
20
|
+
reason: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface SessionAnchorSearchResult {
|
|
24
|
+
success: boolean;
|
|
25
|
+
ranges: SessionAnchorRange[];
|
|
26
|
+
message?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface SessionAnchorSearchOptions {
|
|
30
|
+
sessionsDir?: string;
|
|
31
|
+
maxFiles?: number;
|
|
32
|
+
maxLines?: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface ParsedAnchorRequest {
|
|
36
|
+
from?: Date;
|
|
37
|
+
to?: Date;
|
|
38
|
+
cwd?: string;
|
|
39
|
+
limit: number;
|
|
40
|
+
all: string[];
|
|
41
|
+
any: string[];
|
|
42
|
+
exclude: string[];
|
|
43
|
+
hasTimeConstraint: boolean;
|
|
44
|
+
hasTextConstraint: boolean;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface LineHit {
|
|
48
|
+
path: string;
|
|
49
|
+
lineNumber: number;
|
|
50
|
+
sessionId?: string;
|
|
51
|
+
cwd?: string;
|
|
52
|
+
timestamp?: string;
|
|
53
|
+
timestampMs?: number;
|
|
54
|
+
text: string;
|
|
55
|
+
score: number;
|
|
56
|
+
reason: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
interface PendingRange {
|
|
60
|
+
path: string;
|
|
61
|
+
startLine: number;
|
|
62
|
+
endLine: number;
|
|
63
|
+
sessionId?: string;
|
|
64
|
+
cwd?: string;
|
|
65
|
+
startTime?: string;
|
|
66
|
+
endTime?: string;
|
|
67
|
+
score: number;
|
|
68
|
+
reason: string;
|
|
69
|
+
text: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function searchSessionAnchors(
|
|
73
|
+
markdown: string,
|
|
74
|
+
options: SessionAnchorSearchOptions = {},
|
|
75
|
+
): SessionAnchorSearchResult {
|
|
76
|
+
const parsed = parseMarkdownRequest(markdown);
|
|
77
|
+
if (!parsed.success) {
|
|
78
|
+
return { success: false, ranges: [], message: parsed.message };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (!options.sessionsDir) {
|
|
82
|
+
return { success: false, ranges: [], message: "sessionsDir is required" };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (!fs.existsSync(options.sessionsDir)) {
|
|
86
|
+
return { success: false, ranges: [], message: `sessionsDir does not exist: ${options.sessionsDir}` };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const files = findJsonlFiles(options.sessionsDir).sort();
|
|
90
|
+
const maxFiles = options.maxFiles ?? DEFAULT_MAX_FILES;
|
|
91
|
+
const maxLines = options.maxLines ?? DEFAULT_MAX_LINES;
|
|
92
|
+
if (files.length > maxFiles) {
|
|
93
|
+
return {
|
|
94
|
+
success: false,
|
|
95
|
+
ranges: [],
|
|
96
|
+
message: `Request too broad: ${files.length} session files exceed the configured scan cap of ${maxFiles}. Add from/to, cwd, all, or any constraints.`,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const ranges: PendingRange[] = [];
|
|
101
|
+
let scannedLines = 0;
|
|
102
|
+
|
|
103
|
+
for (const file of files) {
|
|
104
|
+
const remainingLines = maxLines - scannedLines;
|
|
105
|
+
const fileResult = searchJsonlFile(file, parsed.request, remainingLines, scannedLines, maxLines);
|
|
106
|
+
if (!fileResult.success) {
|
|
107
|
+
return { success: false, ranges: [], message: fileResult.message };
|
|
108
|
+
}
|
|
109
|
+
scannedLines += fileResult.scannedLines;
|
|
110
|
+
ranges.push(...fileResult.ranges);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const filtered = ranges.filter((range) => !containsAny(range.text, parsed.request.exclude));
|
|
114
|
+
const sorted = sortRanges(filtered, parsed.request.hasTextConstraint);
|
|
115
|
+
const limited = sorted.slice(0, parsed.request.limit).map(({ text: _text, ...range }) => range);
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
success: true,
|
|
119
|
+
ranges: limited,
|
|
120
|
+
message: limited.length === 0 ? "No matching session anchors found." : undefined,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function parseMarkdownRequest(markdown: string): { success: true; request: ParsedAnchorRequest } | { success: false; message: string } {
|
|
125
|
+
if (!markdown || markdown.trim().length === 0) {
|
|
126
|
+
return { success: false, message: "markdown is required" };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const fields = new Map<string, string>();
|
|
130
|
+
const lists: Record<"all" | "any" | "exclude", string[]> = { all: [], any: [], exclude: [] };
|
|
131
|
+
const seen = new Set<string>();
|
|
132
|
+
let currentList: "all" | "any" | "exclude" | null = null;
|
|
133
|
+
|
|
134
|
+
const lines = markdown.split(/\r?\n/);
|
|
135
|
+
for (const line of lines) {
|
|
136
|
+
const trimmed = line.trim();
|
|
137
|
+
if (trimmed.length === 0) continue;
|
|
138
|
+
|
|
139
|
+
const fieldMatch = /^([A-Za-z][A-Za-z0-9_-]*):\s*(.*)$/.exec(trimmed);
|
|
140
|
+
if (fieldMatch) {
|
|
141
|
+
const field = fieldMatch[1];
|
|
142
|
+
const value = fieldMatch[2];
|
|
143
|
+
|
|
144
|
+
if (!VALUE_FIELDS.has(field) && !LIST_FIELDS.has(field)) {
|
|
145
|
+
return {
|
|
146
|
+
success: false,
|
|
147
|
+
message: `Invalid field '${field}'. Supported fields: from, to, cwd, limit, all, any, exclude.`,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
if (seen.has(field)) {
|
|
151
|
+
return { success: false, message: `Duplicate field '${field}'. Keep one value.` };
|
|
152
|
+
}
|
|
153
|
+
seen.add(field);
|
|
154
|
+
|
|
155
|
+
if (LIST_FIELDS.has(field)) {
|
|
156
|
+
if (value.trim().length > 0) {
|
|
157
|
+
return { success: false, message: `Invalid list section '${field}'. Use '${field}:' followed by '- item' lines.` };
|
|
158
|
+
}
|
|
159
|
+
currentList = field as "all" | "any" | "exclude";
|
|
160
|
+
} else {
|
|
161
|
+
fields.set(field, value.trim());
|
|
162
|
+
currentList = null;
|
|
163
|
+
}
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const listMatch = /^-\s+(.*)$/.exec(trimmed);
|
|
168
|
+
if (listMatch && currentList) {
|
|
169
|
+
const term = listMatch[1].trim();
|
|
170
|
+
if (term.length === 0) {
|
|
171
|
+
return { success: false, message: `Empty term in '${currentList}'. Remove it or provide text.` };
|
|
172
|
+
}
|
|
173
|
+
lists[currentList].push(term);
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (listMatch && !currentList) {
|
|
178
|
+
return { success: false, message: "List item found outside all, any, or exclude section." };
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return { success: false, message: `Invalid markdown line: ${trimmed}` };
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const limitValue = fields.get("limit");
|
|
185
|
+
let limit = DEFAULT_LIMIT;
|
|
186
|
+
if (limitValue !== undefined) {
|
|
187
|
+
if (!/^\d+$/.test(limitValue)) {
|
|
188
|
+
return { success: false, message: "Invalid limit. Use a positive integer." };
|
|
189
|
+
}
|
|
190
|
+
const parsedLimit = Number(limitValue);
|
|
191
|
+
if (!Number.isSafeInteger(parsedLimit) || parsedLimit <= 0) {
|
|
192
|
+
return { success: false, message: "Invalid limit. Use a positive integer." };
|
|
193
|
+
}
|
|
194
|
+
limit = Math.min(parsedLimit, MAX_LIMIT);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const fromValue = fields.get("from");
|
|
198
|
+
const toValue = fields.get("to");
|
|
199
|
+
const from = fromValue === undefined ? undefined : parseDateTime(fromValue, "from");
|
|
200
|
+
if (from === null) return { success: false, message: "Invalid from. Use YYYY-MM-DD or an ISO timestamp." };
|
|
201
|
+
const to = toValue === undefined ? undefined : parseDateTime(toValue, "to");
|
|
202
|
+
if (to === null) return { success: false, message: "Invalid to. Use YYYY-MM-DD or an ISO timestamp." };
|
|
203
|
+
if (from && to && from.getTime() > to.getTime()) {
|
|
204
|
+
return { success: false, message: "Invalid time window. 'from' must be before or equal to 'to'." };
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const cwd = fields.get("cwd");
|
|
208
|
+
if (fields.has("cwd") && (!cwd || cwd.trim().length === 0)) {
|
|
209
|
+
return { success: false, message: "Invalid cwd. Provide a non-empty path." };
|
|
210
|
+
}
|
|
211
|
+
const all = lists.all;
|
|
212
|
+
const any = lists.any;
|
|
213
|
+
const exclude = lists.exclude;
|
|
214
|
+
const hasTimeConstraint = Boolean(from || to);
|
|
215
|
+
const hasCwdConstraint = Boolean(cwd);
|
|
216
|
+
const hasTextConstraint = all.length > 0 || any.length > 0;
|
|
217
|
+
|
|
218
|
+
if (!hasTimeConstraint && !hasCwdConstraint && !hasTextConstraint) {
|
|
219
|
+
return {
|
|
220
|
+
success: false,
|
|
221
|
+
message: "Request needs at least one constraint: provide from/to, cwd, all, or any.",
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
return {
|
|
225
|
+
success: true,
|
|
226
|
+
request: { from, to, cwd, limit, all, any, exclude, hasTimeConstraint, hasTextConstraint },
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function parseDateTime(value: string, boundary: "from" | "to"): Date | null {
|
|
231
|
+
const dateOnly = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
|
|
232
|
+
if (dateOnly) {
|
|
233
|
+
const year = Number(dateOnly[1]);
|
|
234
|
+
const month = Number(dateOnly[2]);
|
|
235
|
+
const day = Number(dateOnly[3]);
|
|
236
|
+
const date = boundary === "from"
|
|
237
|
+
? new Date(year, month - 1, day, 0, 0, 0, 0)
|
|
238
|
+
: new Date(year, month - 1, day, 23, 59, 59, 999);
|
|
239
|
+
if (date.getFullYear() !== year || date.getMonth() !== month - 1 || date.getDate() !== day) {
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
return date;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const date = new Date(value);
|
|
246
|
+
return Number.isNaN(date.getTime()) ? null : date;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function findJsonlFiles(dir: string): string[] {
|
|
250
|
+
const files: string[] = [];
|
|
251
|
+
|
|
252
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
253
|
+
const fullPath = path.join(dir, entry.name);
|
|
254
|
+
if (entry.isDirectory()) {
|
|
255
|
+
files.push(...findJsonlFiles(fullPath));
|
|
256
|
+
} else if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
257
|
+
files.push(fullPath);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return files;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function searchJsonlFile(
|
|
265
|
+
filePath: string,
|
|
266
|
+
request: ParsedAnchorRequest,
|
|
267
|
+
maxLines: number,
|
|
268
|
+
scannedBefore: number,
|
|
269
|
+
scanCap: number,
|
|
270
|
+
): { success: true; ranges: PendingRange[]; scannedLines: number } | { success: false; message: string } {
|
|
271
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
272
|
+
const lines = content.split(/\r?\n/);
|
|
273
|
+
const hits: LineHit[] = [];
|
|
274
|
+
let currentSessionId: string | undefined;
|
|
275
|
+
let currentCwd: string | undefined;
|
|
276
|
+
|
|
277
|
+
let scannedLines = 0;
|
|
278
|
+
|
|
279
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
280
|
+
const line = lines[index];
|
|
281
|
+
if (line.trim().length === 0) continue;
|
|
282
|
+
|
|
283
|
+
scannedLines += 1;
|
|
284
|
+
if (scannedLines > maxLines) {
|
|
285
|
+
return {
|
|
286
|
+
success: false,
|
|
287
|
+
message: `Request too broad: scanned ${scannedBefore + scannedLines} session lines, exceeding the configured scan cap of ${scanCap}. Add from/to, cwd, all, or any constraints.`,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
let event: unknown;
|
|
292
|
+
try {
|
|
293
|
+
event = JSON.parse(line);
|
|
294
|
+
} catch {
|
|
295
|
+
return { success: false, message: `Invalid JSON in ${filePath}:${index + 1}` };
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const sessionId = getSessionId(event) ?? currentSessionId;
|
|
299
|
+
if (sessionId) currentSessionId = sessionId;
|
|
300
|
+
|
|
301
|
+
const cwd = getCwd(event) ?? currentCwd;
|
|
302
|
+
if (cwd) currentCwd = cwd;
|
|
303
|
+
|
|
304
|
+
if (request.cwd && cwd !== request.cwd) continue;
|
|
305
|
+
|
|
306
|
+
const timestamp = getTimestamp(event);
|
|
307
|
+
const timestampMs = timestamp ? Date.parse(timestamp) : undefined;
|
|
308
|
+
const hasValidTimestamp = timestampMs !== undefined && !Number.isNaN(timestampMs);
|
|
309
|
+
if (request.hasTimeConstraint) {
|
|
310
|
+
if (!hasValidTimestamp) continue;
|
|
311
|
+
if (request.from && timestampMs < request.from.getTime()) continue;
|
|
312
|
+
if (request.to && timestampMs > request.to.getTime()) continue;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const text = textualizeEvent(event);
|
|
316
|
+
const termScore = scoreTerms(text, request);
|
|
317
|
+
const matchesTerms = request.hasTextConstraint ? termScore > 0 : true;
|
|
318
|
+
if (!matchesTerms) continue;
|
|
319
|
+
|
|
320
|
+
if (!request.hasTextConstraint && !hasValidTimestamp) continue;
|
|
321
|
+
|
|
322
|
+
hits.push({
|
|
323
|
+
path: filePath,
|
|
324
|
+
lineNumber: index + 1,
|
|
325
|
+
sessionId,
|
|
326
|
+
cwd,
|
|
327
|
+
timestamp: hasValidTimestamp ? timestamp : undefined,
|
|
328
|
+
timestampMs: hasValidTimestamp ? timestampMs : undefined,
|
|
329
|
+
text,
|
|
330
|
+
score: request.hasTextConstraint ? termScore : 1,
|
|
331
|
+
reason: buildReason(request, text),
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
return { success: true, ranges: mergeAdjacentHits(hits), scannedLines };
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function mergeAdjacentHits(hits: LineHit[]): PendingRange[] {
|
|
339
|
+
const ranges: PendingRange[] = [];
|
|
340
|
+
|
|
341
|
+
for (const hit of hits) {
|
|
342
|
+
const last = ranges.at(-1);
|
|
343
|
+
if (last && last.path === hit.path && last.endLine + 1 === hit.lineNumber && last.reason === hit.reason) {
|
|
344
|
+
last.endLine = hit.lineNumber;
|
|
345
|
+
last.score += hit.score;
|
|
346
|
+
last.text += "\n" + hit.text;
|
|
347
|
+
last.sessionId ??= hit.sessionId;
|
|
348
|
+
last.cwd ??= hit.cwd;
|
|
349
|
+
if (!last.startTime && hit.timestamp) last.startTime = hit.timestamp;
|
|
350
|
+
if (hit.timestamp) last.endTime = hit.timestamp;
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
ranges.push({
|
|
355
|
+
path: hit.path,
|
|
356
|
+
startLine: hit.lineNumber,
|
|
357
|
+
endLine: hit.lineNumber,
|
|
358
|
+
sessionId: hit.sessionId,
|
|
359
|
+
cwd: hit.cwd,
|
|
360
|
+
startTime: hit.timestamp,
|
|
361
|
+
endTime: hit.timestamp,
|
|
362
|
+
score: hit.score,
|
|
363
|
+
reason: hit.reason,
|
|
364
|
+
text: hit.text,
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
return ranges;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
function sortRanges(ranges: PendingRange[], textConstrained: boolean): PendingRange[] {
|
|
372
|
+
return [...ranges].sort((a, b) => {
|
|
373
|
+
if (textConstrained && b.score !== a.score) return b.score - a.score;
|
|
374
|
+
const timeCompare = Date.parse(a.startTime ?? "") - Date.parse(b.startTime ?? "");
|
|
375
|
+
if (!Number.isNaN(timeCompare) && timeCompare !== 0) return timeCompare;
|
|
376
|
+
const pathCompare = a.path.localeCompare(b.path);
|
|
377
|
+
if (pathCompare !== 0) return pathCompare;
|
|
378
|
+
return a.startLine - b.startLine;
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function scoreTerms(text: string, request: ParsedAnchorRequest): number {
|
|
383
|
+
const lower = text.toLocaleLowerCase();
|
|
384
|
+
const matchedAll = request.all.filter((term) => lower.includes(term.toLocaleLowerCase()));
|
|
385
|
+
const matchedAny = request.any.filter((term) => lower.includes(term.toLocaleLowerCase()));
|
|
386
|
+
|
|
387
|
+
if (request.all.length > 0 && matchedAll.length !== request.all.length) return 0;
|
|
388
|
+
if (request.any.length > 0 && matchedAny.length === 0) return 0;
|
|
389
|
+
|
|
390
|
+
if (request.all.length === 0 && request.any.length === 0) return 1;
|
|
391
|
+
return matchedAll.length * 2 + matchedAny.length;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function buildReason(request: ParsedAnchorRequest, text: string): string {
|
|
395
|
+
if (!request.hasTextConstraint) {
|
|
396
|
+
if (request.hasTimeConstraint && request.cwd) return "cwd+time window";
|
|
397
|
+
if (request.hasTimeConstraint) return "time window";
|
|
398
|
+
return "cwd";
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
const lower = text.toLocaleLowerCase();
|
|
402
|
+
const parts: string[] = [];
|
|
403
|
+
if (request.all.length > 0) parts.push(`matched all: ${request.all.join(", ")}`);
|
|
404
|
+
const matchedAny = request.any.filter((term) => lower.includes(term.toLocaleLowerCase()));
|
|
405
|
+
if (matchedAny.length > 0) parts.push(`matched any: ${matchedAny.join(", ")}`);
|
|
406
|
+
return parts.join("; ");
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function containsAny(text: string, terms: string[]): boolean {
|
|
410
|
+
const lower = text.toLocaleLowerCase();
|
|
411
|
+
return terms.some((term) => lower.includes(term.toLocaleLowerCase()));
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
function getTimestamp(event: unknown): string | undefined {
|
|
415
|
+
if (!isRecord(event)) return undefined;
|
|
416
|
+
if (typeof event.timestamp === "string") return event.timestamp;
|
|
417
|
+
if (isRecord(event.message) && typeof event.message.timestamp === "string") return event.message.timestamp;
|
|
418
|
+
return undefined;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function getSessionId(event: unknown): string | undefined {
|
|
422
|
+
if (!isRecord(event)) return undefined;
|
|
423
|
+
if (typeof event.sessionId === "string") return event.sessionId;
|
|
424
|
+
if (typeof event.session_id === "string") return event.session_id;
|
|
425
|
+
if (event.type === "session" && typeof event.id === "string") return event.id;
|
|
426
|
+
if (isRecord(event.session) && typeof event.session.id === "string") return event.session.id;
|
|
427
|
+
return undefined;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function getCwd(event: unknown): string | undefined {
|
|
431
|
+
if (!isRecord(event)) return undefined;
|
|
432
|
+
if (typeof event.cwd === "string") return event.cwd;
|
|
433
|
+
if (isRecord(event.session) && typeof event.session.cwd === "string") return event.session.cwd;
|
|
434
|
+
return undefined;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function textualizeEvent(event: unknown): string {
|
|
438
|
+
const parts: string[] = [];
|
|
439
|
+
collectStrings(event, parts);
|
|
440
|
+
return parts.join("\n");
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
const METADATA_TEXT_KEYS = new Set([
|
|
444
|
+
"type",
|
|
445
|
+
"id",
|
|
446
|
+
"parentId",
|
|
447
|
+
"sessionId",
|
|
448
|
+
"session_id",
|
|
449
|
+
"timestamp",
|
|
450
|
+
"cwd",
|
|
451
|
+
"role",
|
|
452
|
+
"customType",
|
|
453
|
+
]);
|
|
454
|
+
|
|
455
|
+
function collectStrings(value: unknown, parts: string[], key?: string): void {
|
|
456
|
+
if (typeof value === "string") {
|
|
457
|
+
if (!key || !METADATA_TEXT_KEYS.has(key)) parts.push(value);
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
if (Array.isArray(value)) {
|
|
462
|
+
for (const item of value) collectStrings(item, parts, key);
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
if (!isRecord(value)) return;
|
|
467
|
+
for (const [childKey, item] of Object.entries(value)) collectStrings(item, parts, childKey);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
471
|
+
return typeof value === "object" && value !== null;
|
|
472
|
+
}
|