@vinaes/succ 1.3.31 → 1.5.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -11
- package/agents/succ-code-reviewer.md +1 -1
- package/agents/succ-diff-reviewer.md +1 -1
- package/agents/succ-general.md +1 -1
- package/dist/cli.js +84 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/agents-md.d.ts.map +1 -1
- package/dist/commands/agents-md.js +3 -2
- package/dist/commands/agents-md.js.map +1 -1
- package/dist/commands/analyze-agents.d.ts.map +1 -1
- package/dist/commands/analyze-agents.js +10 -11
- package/dist/commands/analyze-agents.js.map +1 -1
- package/dist/commands/analyze-profile.d.ts.map +1 -1
- package/dist/commands/analyze-profile.js +32 -8
- package/dist/commands/analyze-profile.js.map +1 -1
- package/dist/commands/analyze-recursive.d.ts.map +1 -1
- package/dist/commands/analyze-recursive.js +8 -3
- package/dist/commands/analyze-recursive.js.map +1 -1
- package/dist/commands/analyze-utils.d.ts.map +1 -1
- package/dist/commands/analyze-utils.js +17 -4
- package/dist/commands/analyze-utils.js.map +1 -1
- package/dist/commands/benchmark-quality.d.ts.map +1 -1
- package/dist/commands/benchmark-quality.js +11 -4
- package/dist/commands/benchmark-quality.js.map +1 -1
- package/dist/commands/benchmark-sqlite-vec.d.ts.map +1 -1
- package/dist/commands/benchmark-sqlite-vec.js +4 -0
- package/dist/commands/benchmark-sqlite-vec.js.map +1 -1
- package/dist/commands/benchmark.d.ts.map +1 -1
- package/dist/commands/benchmark.js +5 -1
- package/dist/commands/benchmark.js.map +1 -1
- package/dist/commands/codex-chat.d.ts +8 -0
- package/dist/commands/codex-chat.d.ts.map +1 -0
- package/dist/commands/codex-chat.js +161 -0
- package/dist/commands/codex-chat.js.map +1 -0
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +32 -4
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/daemon.d.ts.map +1 -1
- package/dist/commands/daemon.js +13 -4
- package/dist/commands/daemon.js.map +1 -1
- package/dist/commands/index-code.d.ts +4 -0
- package/dist/commands/index-code.d.ts.map +1 -1
- package/dist/commands/index-code.js +1 -1
- package/dist/commands/index-code.js.map +1 -1
- package/dist/commands/init-templates.js +2 -2
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +305 -203
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/memories.d.ts.map +1 -1
- package/dist/commands/memories.js +25 -14
- package/dist/commands/memories.js.map +1 -1
- package/dist/commands/progress.d.ts.map +1 -1
- package/dist/commands/progress.js +3 -2
- package/dist/commands/progress.js.map +1 -1
- package/dist/commands/reindex.d.ts.map +1 -1
- package/dist/commands/reindex.js +54 -36
- package/dist/commands/reindex.js.map +1 -1
- package/dist/commands/retention.d.ts.map +1 -1
- package/dist/commands/retention.js +7 -5
- package/dist/commands/retention.js.map +1 -1
- package/dist/commands/scan-code.d.ts +76 -0
- package/dist/commands/scan-code.d.ts.map +1 -0
- package/dist/commands/scan-code.js +385 -0
- package/dist/commands/scan-code.js.map +1 -0
- package/dist/commands/score.d.ts.map +1 -1
- package/dist/commands/score.js +3 -2
- package/dist/commands/score.js.map +1 -1
- package/dist/commands/session.d.ts +33 -0
- package/dist/commands/session.d.ts.map +1 -0
- package/dist/commands/session.js +163 -0
- package/dist/commands/session.js.map +1 -0
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +254 -15
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/soul.d.ts.map +1 -1
- package/dist/commands/soul.js +7 -46
- package/dist/commands/soul.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +14 -5
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/watch.d.ts.map +1 -1
- package/dist/commands/watch.js +13 -4
- package/dist/commands/watch.js.map +1 -1
- package/dist/daemon/analyzer.d.ts.map +1 -1
- package/dist/daemon/analyzer.js +23 -7
- package/dist/daemon/analyzer.js.map +1 -1
- package/dist/daemon/client.d.ts.map +1 -1
- package/dist/daemon/client.js +32 -8
- package/dist/daemon/client.js.map +1 -1
- package/dist/daemon/routes/analyzer.d.ts +3 -0
- package/dist/daemon/routes/analyzer.d.ts.map +1 -0
- package/dist/daemon/routes/analyzer.js +27 -0
- package/dist/daemon/routes/analyzer.js.map +1 -0
- package/dist/daemon/routes/hooks.d.ts +14 -0
- package/dist/daemon/routes/hooks.d.ts.map +1 -0
- package/dist/daemon/routes/hooks.js +1212 -0
- package/dist/daemon/routes/hooks.js.map +1 -0
- package/dist/daemon/routes/memory.d.ts +4 -0
- package/dist/daemon/routes/memory.d.ts.map +1 -0
- package/dist/daemon/routes/memory.js +71 -0
- package/dist/daemon/routes/memory.js.map +1 -0
- package/dist/daemon/routes/reflection.d.ts +10 -0
- package/dist/daemon/routes/reflection.d.ts.map +1 -0
- package/dist/daemon/routes/reflection.js +397 -0
- package/dist/daemon/routes/reflection.js.map +1 -0
- package/dist/daemon/routes/search.d.ts +5 -0
- package/dist/daemon/routes/search.d.ts.map +1 -0
- package/dist/daemon/routes/search.js +93 -0
- package/dist/daemon/routes/search.js.map +1 -0
- package/dist/daemon/routes/sessions.d.ts +3 -0
- package/dist/daemon/routes/sessions.d.ts.map +1 -0
- package/dist/daemon/routes/sessions.js +160 -0
- package/dist/daemon/routes/sessions.js.map +1 -0
- package/dist/daemon/routes/skills.d.ts +3 -0
- package/dist/daemon/routes/skills.d.ts.map +1 -0
- package/dist/daemon/routes/skills.js +36 -0
- package/dist/daemon/routes/skills.js.map +1 -0
- package/dist/daemon/routes/status.d.ts +3 -0
- package/dist/daemon/routes/status.d.ts.map +1 -0
- package/dist/daemon/routes/status.js +47 -0
- package/dist/daemon/routes/status.js.map +1 -0
- package/dist/daemon/routes/types.d.ts +240 -0
- package/dist/daemon/routes/types.d.ts.map +1 -0
- package/dist/daemon/routes/types.js +97 -0
- package/dist/daemon/routes/types.js.map +1 -0
- package/dist/daemon/routes/versioning.d.ts +27 -0
- package/dist/daemon/routes/versioning.d.ts.map +1 -0
- package/dist/daemon/routes/versioning.js +44 -0
- package/dist/daemon/routes/versioning.js.map +1 -0
- package/dist/daemon/routes/watcher.d.ts +3 -0
- package/dist/daemon/routes/watcher.d.ts.map +1 -0
- package/dist/daemon/routes/watcher.js +28 -0
- package/dist/daemon/routes/watcher.js.map +1 -0
- package/dist/daemon/service.d.ts +5 -23
- package/dist/daemon/service.d.ts.map +1 -1
- package/dist/daemon/service.js +177 -934
- package/dist/daemon/service.js.map +1 -1
- package/dist/daemon/session-processor.d.ts +4 -8
- package/dist/daemon/session-processor.d.ts.map +1 -1
- package/dist/daemon/session-processor.js +49 -222
- package/dist/daemon/session-processor.js.map +1 -1
- package/dist/lib/ai-readiness.d.ts.map +1 -1
- package/dist/lib/ai-readiness.js +33 -8
- package/dist/lib/ai-readiness.js.map +1 -1
- package/dist/lib/analyze-state.d.ts.map +1 -1
- package/dist/lib/analyze-state.js +25 -3
- package/dist/lib/analyze-state.js.map +1 -1
- package/dist/lib/auto-memory/consolidation.d.ts +41 -0
- package/dist/lib/auto-memory/consolidation.d.ts.map +1 -0
- package/dist/lib/auto-memory/consolidation.js +151 -0
- package/dist/lib/auto-memory/consolidation.js.map +1 -0
- package/dist/lib/bpe.d.ts.map +1 -1
- package/dist/lib/bpe.js +9 -10
- package/dist/lib/bpe.js.map +1 -1
- package/dist/lib/brain-export.d.ts +65 -0
- package/dist/lib/brain-export.d.ts.map +1 -0
- package/dist/lib/brain-export.js +413 -0
- package/dist/lib/brain-export.js.map +1 -0
- package/dist/lib/checkpoint.d.ts.map +1 -1
- package/dist/lib/checkpoint.js +22 -6
- package/dist/lib/checkpoint.js.map +1 -1
- package/dist/lib/chunker.d.ts.map +1 -1
- package/dist/lib/chunker.js +6 -1
- package/dist/lib/chunker.js.map +1 -1
- package/dist/lib/claude-ws-transport.d.ts.map +1 -1
- package/dist/lib/claude-ws-transport.js +12 -4
- package/dist/lib/claude-ws-transport.js.map +1 -1
- package/dist/lib/command-safety.d.ts +64 -0
- package/dist/lib/command-safety.d.ts.map +1 -0
- package/dist/lib/command-safety.js +625 -0
- package/dist/lib/command-safety.js.map +1 -0
- package/dist/lib/compact-briefing.d.ts.map +1 -1
- package/dist/lib/compact-briefing.js +18 -17
- package/dist/lib/compact-briefing.js.map +1 -1
- package/dist/lib/config-defaults.d.ts.map +1 -1
- package/dist/lib/config-defaults.js +3 -0
- package/dist/lib/config-defaults.js.map +1 -1
- package/dist/lib/config-display.d.ts +4 -0
- package/dist/lib/config-display.d.ts.map +1 -1
- package/dist/lib/config-display.js +6 -1
- package/dist/lib/config-display.js.map +1 -1
- package/dist/lib/config-types.d.ts +157 -0
- package/dist/lib/config-types.d.ts.map +1 -1
- package/dist/lib/config-validation.d.ts.map +1 -1
- package/dist/lib/config-validation.js +6 -0
- package/dist/lib/config-validation.js.map +1 -1
- package/dist/lib/config.d.ts +8 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +108 -9
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/consolidate.d.ts.map +1 -1
- package/dist/lib/consolidate.js +73 -49
- package/dist/lib/consolidate.js.map +1 -1
- package/dist/lib/content-sanitizer.d.ts +29 -0
- package/dist/lib/content-sanitizer.d.ts.map +1 -0
- package/dist/lib/content-sanitizer.js +72 -0
- package/dist/lib/content-sanitizer.js.map +1 -0
- package/dist/lib/cross-repo.d.ts +44 -0
- package/dist/lib/cross-repo.d.ts.map +1 -0
- package/dist/lib/cross-repo.js +108 -0
- package/dist/lib/cross-repo.js.map +1 -0
- package/dist/lib/daemon-port.d.ts +12 -0
- package/dist/lib/daemon-port.d.ts.map +1 -0
- package/dist/lib/daemon-port.js +20 -0
- package/dist/lib/daemon-port.js.map +1 -0
- package/dist/lib/db/auto-memory.d.ts +40 -0
- package/dist/lib/db/auto-memory.d.ts.map +1 -0
- package/dist/lib/db/auto-memory.js +74 -0
- package/dist/lib/db/auto-memory.js.map +1 -0
- package/dist/lib/db/bm25-indexes.d.ts.map +1 -1
- package/dist/lib/db/bm25-indexes.js +16 -4
- package/dist/lib/db/bm25-indexes.js.map +1 -1
- package/dist/lib/db/connection.d.ts.map +1 -1
- package/dist/lib/db/connection.js +8 -1
- package/dist/lib/db/connection.js.map +1 -1
- package/dist/lib/db/documents.d.ts.map +1 -1
- package/dist/lib/db/documents.js +4 -1
- package/dist/lib/db/documents.js.map +1 -1
- package/dist/lib/db/global-memories.d.ts +2 -10
- package/dist/lib/db/global-memories.d.ts.map +1 -1
- package/dist/lib/db/global-memories.js +13 -6
- package/dist/lib/db/global-memories.js.map +1 -1
- package/dist/lib/db/graph.d.ts +5 -1
- package/dist/lib/db/graph.d.ts.map +1 -1
- package/dist/lib/db/graph.js +38 -8
- package/dist/lib/db/graph.js.map +1 -1
- package/dist/lib/db/hybrid-search.d.ts +4 -2
- package/dist/lib/db/hybrid-search.d.ts.map +1 -1
- package/dist/lib/db/hybrid-search.js +29 -11
- package/dist/lib/db/hybrid-search.js.map +1 -1
- package/dist/lib/db/index.d.ts +6 -1
- package/dist/lib/db/index.d.ts.map +1 -1
- package/dist/lib/db/index.js +5 -1
- package/dist/lib/db/index.js.map +1 -1
- package/dist/lib/db/memories.d.ts +19 -14
- package/dist/lib/db/memories.d.ts.map +1 -1
- package/dist/lib/db/memories.js +100 -37
- package/dist/lib/db/memories.js.map +1 -1
- package/dist/lib/db/parse-helpers.d.ts +14 -0
- package/dist/lib/db/parse-helpers.d.ts.map +1 -0
- package/dist/lib/db/parse-helpers.js +59 -0
- package/dist/lib/db/parse-helpers.js.map +1 -0
- package/dist/lib/db/recall-events.d.ts +49 -0
- package/dist/lib/db/recall-events.d.ts.map +1 -0
- package/dist/lib/db/recall-events.js +196 -0
- package/dist/lib/db/recall-events.js.map +1 -0
- package/dist/lib/db/retention.d.ts +4 -3
- package/dist/lib/db/retention.d.ts.map +1 -1
- package/dist/lib/db/retention.js +12 -1
- package/dist/lib/db/retention.js.map +1 -1
- package/dist/lib/db/schema.d.ts +2 -0
- package/dist/lib/db/schema.d.ts.map +1 -1
- package/dist/lib/db/schema.js +140 -80
- package/dist/lib/db/schema.js.map +1 -1
- package/dist/lib/db/skills.d.ts.map +1 -1
- package/dist/lib/db/skills.js +10 -6
- package/dist/lib/db/skills.js.map +1 -1
- package/dist/lib/diff-brain.d.ts +24 -0
- package/dist/lib/diff-brain.d.ts.map +1 -0
- package/dist/lib/diff-brain.js +114 -0
- package/dist/lib/diff-brain.js.map +1 -0
- package/dist/lib/diff-parser.d.ts +74 -0
- package/dist/lib/diff-parser.d.ts.map +1 -0
- package/dist/lib/diff-parser.js +200 -0
- package/dist/lib/diff-parser.js.map +1 -0
- package/dist/lib/embedding-pool.d.ts.map +1 -1
- package/dist/lib/embedding-pool.js +5 -1
- package/dist/lib/embedding-pool.js.map +1 -1
- package/dist/lib/embeddings.d.ts +12 -0
- package/dist/lib/embeddings.d.ts.map +1 -1
- package/dist/lib/embeddings.js +77 -19
- package/dist/lib/embeddings.js.map +1 -1
- package/dist/lib/errors.d.ts +2 -0
- package/dist/lib/errors.d.ts.map +1 -1
- package/dist/lib/errors.js +4 -0
- package/dist/lib/errors.js.map +1 -1
- package/dist/lib/fault-logger.d.ts.map +1 -1
- package/dist/lib/fault-logger.js +22 -7
- package/dist/lib/fault-logger.js.map +1 -1
- package/dist/lib/git/co-change.d.ts +39 -0
- package/dist/lib/git/co-change.d.ts.map +1 -0
- package/dist/lib/git/co-change.js +139 -0
- package/dist/lib/git/co-change.js.map +1 -0
- package/dist/lib/graph/bridge-edges.d.ts +93 -0
- package/dist/lib/graph/bridge-edges.d.ts.map +1 -0
- package/dist/lib/graph/bridge-edges.js +276 -0
- package/dist/lib/graph/bridge-edges.js.map +1 -0
- package/dist/lib/graph/centrality.d.ts +11 -0
- package/dist/lib/graph/centrality.d.ts.map +1 -1
- package/dist/lib/graph/centrality.js +51 -3
- package/dist/lib/graph/centrality.js.map +1 -1
- package/dist/lib/graph/cleanup.d.ts.map +1 -1
- package/dist/lib/graph/cleanup.js +2 -1
- package/dist/lib/graph/cleanup.js.map +1 -1
- package/dist/lib/graph/community-detection.d.ts +17 -2
- package/dist/lib/graph/community-detection.d.ts.map +1 -1
- package/dist/lib/graph/community-detection.js +147 -48
- package/dist/lib/graph/community-detection.js.map +1 -1
- package/dist/lib/graph/community-summaries.d.ts +26 -0
- package/dist/lib/graph/community-summaries.d.ts.map +1 -0
- package/dist/lib/graph/community-summaries.js +130 -0
- package/dist/lib/graph/community-summaries.js.map +1 -0
- package/dist/lib/graph/contextual-proximity.d.ts.map +1 -1
- package/dist/lib/graph/contextual-proximity.js +11 -4
- package/dist/lib/graph/contextual-proximity.js.map +1 -1
- package/dist/lib/graph/graphology-bridge.d.ts +101 -0
- package/dist/lib/graph/graphology-bridge.d.ts.map +1 -0
- package/dist/lib/graph/graphology-bridge.js +488 -0
- package/dist/lib/graph/graphology-bridge.js.map +1 -0
- package/dist/lib/graph/llm-relations.d.ts.map +1 -1
- package/dist/lib/graph/llm-relations.js +34 -45
- package/dist/lib/graph/llm-relations.js.map +1 -1
- package/dist/lib/graph-export.d.ts.map +1 -1
- package/dist/lib/graph-export.js +2 -2
- package/dist/lib/graph-export.js.map +1 -1
- package/dist/lib/graph-scheduler.d.ts +0 -5
- package/dist/lib/graph-scheduler.d.ts.map +1 -1
- package/dist/lib/graph-scheduler.js +5 -1
- package/dist/lib/graph-scheduler.js.map +1 -1
- package/dist/lib/guardrails.d.ts +50 -0
- package/dist/lib/guardrails.d.ts.map +1 -0
- package/dist/lib/guardrails.js +502 -0
- package/dist/lib/guardrails.js.map +1 -0
- package/dist/lib/hook-rules.d.ts +1 -1
- package/dist/lib/hook-rules.d.ts.map +1 -1
- package/dist/lib/hook-rules.js +8 -2
- package/dist/lib/hook-rules.js.map +1 -1
- package/dist/lib/ifc/file-labels.d.ts +35 -0
- package/dist/lib/ifc/file-labels.d.ts.map +1 -0
- package/dist/lib/ifc/file-labels.js +208 -0
- package/dist/lib/ifc/file-labels.js.map +1 -0
- package/dist/lib/ifc/label.d.ts +38 -0
- package/dist/lib/ifc/label.d.ts.map +1 -0
- package/dist/lib/ifc/label.js +80 -0
- package/dist/lib/ifc/label.js.map +1 -0
- package/dist/lib/ifc/session-ifc.d.ts +92 -0
- package/dist/lib/ifc/session-ifc.d.ts.map +1 -0
- package/dist/lib/ifc/session-ifc.js +222 -0
- package/dist/lib/ifc/session-ifc.js.map +1 -0
- package/dist/lib/indexer.js +2 -2
- package/dist/lib/indexer.js.map +1 -1
- package/dist/lib/injection-detector.d.ts +83 -0
- package/dist/lib/injection-detector.d.ts.map +1 -0
- package/dist/lib/injection-detector.js +586 -0
- package/dist/lib/injection-detector.js.map +1 -0
- package/dist/lib/injection-semantic.d.ts +31 -0
- package/dist/lib/injection-semantic.d.ts.map +1 -0
- package/dist/lib/injection-semantic.js +230 -0
- package/dist/lib/injection-semantic.js.map +1 -0
- package/dist/lib/llm.d.ts +14 -0
- package/dist/lib/llm.d.ts.map +1 -1
- package/dist/lib/llm.js +44 -8
- package/dist/lib/llm.js.map +1 -1
- package/dist/lib/lock.d.ts.map +1 -1
- package/dist/lib/lock.js +24 -3
- package/dist/lib/lock.js.map +1 -1
- package/dist/lib/md-fetch.d.ts.map +1 -1
- package/dist/lib/md-fetch.js +9 -2
- package/dist/lib/md-fetch.js.map +1 -1
- package/dist/lib/observability.d.ts +75 -0
- package/dist/lib/observability.d.ts.map +1 -0
- package/dist/lib/observability.js +201 -0
- package/dist/lib/observability.js.map +1 -0
- package/dist/lib/ort-session.d.ts +26 -0
- package/dist/lib/ort-session.d.ts.map +1 -1
- package/dist/lib/ort-session.js +107 -3
- package/dist/lib/ort-session.js.map +1 -1
- package/dist/lib/prd/codebase-context.d.ts.map +1 -1
- package/dist/lib/prd/codebase-context.js +9 -2
- package/dist/lib/prd/codebase-context.js.map +1 -1
- package/dist/lib/prd/context.d.ts.map +1 -1
- package/dist/lib/prd/context.js +11 -3
- package/dist/lib/prd/context.js.map +1 -1
- package/dist/lib/prd/export.js +1 -1
- package/dist/lib/prd/export.js.map +1 -1
- package/dist/lib/prd/generate.d.ts.map +1 -1
- package/dist/lib/prd/generate.js +19 -5
- package/dist/lib/prd/generate.js.map +1 -1
- package/dist/lib/prd/parse.d.ts.map +1 -1
- package/dist/lib/prd/parse.js +8 -2
- package/dist/lib/prd/parse.js.map +1 -1
- package/dist/lib/prd/prompt-builder.d.ts +9 -2
- package/dist/lib/prd/prompt-builder.d.ts.map +1 -1
- package/dist/lib/prd/prompt-builder.js +7 -8
- package/dist/lib/prd/prompt-builder.js.map +1 -1
- package/dist/lib/prd/runner.d.ts +1 -2
- package/dist/lib/prd/runner.d.ts.map +1 -1
- package/dist/lib/prd/runner.js +45 -33
- package/dist/lib/prd/runner.js.map +1 -1
- package/dist/lib/prd/team-runner.js +2 -1
- package/dist/lib/prd/team-runner.js.map +1 -1
- package/dist/lib/prd/worktree.d.ts +1 -2
- package/dist/lib/prd/worktree.d.ts.map +1 -1
- package/dist/lib/prd/worktree.js +62 -70
- package/dist/lib/prd/worktree.js.map +1 -1
- package/dist/lib/precompute-context.d.ts.map +1 -1
- package/dist/lib/precompute-context.js +22 -36
- package/dist/lib/precompute-context.js.map +1 -1
- package/dist/lib/pricing.d.ts.map +1 -1
- package/dist/lib/pricing.js +5 -1
- package/dist/lib/pricing.js.map +1 -1
- package/dist/lib/process-registry.js +3 -3
- package/dist/lib/process-registry.js.map +1 -1
- package/dist/lib/public-api.d.ts +54 -4
- package/dist/lib/public-api.d.ts.map +1 -1
- package/dist/lib/public-api.js +52 -2
- package/dist/lib/public-api.js.map +1 -1
- package/dist/lib/quality.d.ts.map +1 -1
- package/dist/lib/quality.js +15 -6
- package/dist/lib/quality.js.map +1 -1
- package/dist/lib/query-expansion.d.ts +32 -0
- package/dist/lib/query-expansion.d.ts.map +1 -1
- package/dist/lib/query-expansion.js +64 -13
- package/dist/lib/query-expansion.js.map +1 -1
- package/dist/lib/reference-embeddings.d.ts.map +1 -1
- package/dist/lib/reference-embeddings.js +17 -4
- package/dist/lib/reference-embeddings.js.map +1 -1
- package/dist/lib/reflection-synthesizer.d.ts.map +1 -1
- package/dist/lib/reflection-synthesizer.js +9 -17
- package/dist/lib/reflection-synthesizer.js.map +1 -1
- package/dist/lib/reranker.d.ts +41 -0
- package/dist/lib/reranker.d.ts.map +1 -0
- package/dist/lib/reranker.js +294 -0
- package/dist/lib/reranker.js.map +1 -0
- package/dist/lib/retrieval-feedback.d.ts +100 -0
- package/dist/lib/retrieval-feedback.d.ts.map +1 -0
- package/dist/lib/retrieval-feedback.js +174 -0
- package/dist/lib/retrieval-feedback.js.map +1 -0
- package/dist/lib/review/context-pack.d.ts +58 -0
- package/dist/lib/review/context-pack.d.ts.map +1 -0
- package/dist/lib/review/context-pack.js +300 -0
- package/dist/lib/review/context-pack.js.map +1 -0
- package/dist/lib/search/hierarchical-summaries.d.ts +65 -0
- package/dist/lib/search/hierarchical-summaries.d.ts.map +1 -0
- package/dist/lib/search/hierarchical-summaries.js +423 -0
- package/dist/lib/search/hierarchical-summaries.js.map +1 -0
- package/dist/lib/search/hyde.d.ts +27 -0
- package/dist/lib/search/hyde.d.ts.map +1 -0
- package/dist/lib/search/hyde.js +141 -0
- package/dist/lib/search/hyde.js.map +1 -0
- package/dist/lib/search/late-chunking.d.ts +53 -0
- package/dist/lib/search/late-chunking.d.ts.map +1 -0
- package/dist/lib/search/late-chunking.js +230 -0
- package/dist/lib/search/late-chunking.js.map +1 -0
- package/dist/lib/search/ppr-retrieval.d.ts +49 -0
- package/dist/lib/search/ppr-retrieval.d.ts.map +1 -0
- package/dist/lib/search/ppr-retrieval.js +135 -0
- package/dist/lib/search/ppr-retrieval.js.map +1 -0
- package/dist/lib/search/repo-map.d.ts +43 -0
- package/dist/lib/search/repo-map.d.ts.map +1 -0
- package/dist/lib/search/repo-map.js +165 -0
- package/dist/lib/search/repo-map.js.map +1 -0
- package/dist/lib/session-analyzer.d.ts +90 -0
- package/dist/lib/session-analyzer.d.ts.map +1 -0
- package/dist/lib/session-analyzer.js +467 -0
- package/dist/lib/session-analyzer.js.map +1 -0
- package/dist/lib/session-observations.d.ts.map +1 -1
- package/dist/lib/session-observations.js +13 -3
- package/dist/lib/session-observations.js.map +1 -1
- package/dist/lib/session-summary.d.ts.map +1 -1
- package/dist/lib/session-summary.js +64 -52
- package/dist/lib/session-summary.js.map +1 -1
- package/dist/lib/session-surgeon.d.ts +53 -0
- package/dist/lib/session-surgeon.d.ts.map +1 -0
- package/dist/lib/session-surgeon.js +501 -0
- package/dist/lib/session-surgeon.js.map +1 -0
- package/dist/lib/similarity-utils.d.ts +26 -0
- package/dist/lib/similarity-utils.d.ts.map +1 -0
- package/dist/lib/similarity-utils.js +66 -0
- package/dist/lib/similarity-utils.js.map +1 -0
- package/dist/lib/skills.d.ts.map +1 -1
- package/dist/lib/skills.js +16 -16
- package/dist/lib/skills.js.map +1 -1
- package/dist/lib/storage/backends/interface.d.ts +13 -3
- package/dist/lib/storage/backends/interface.d.ts.map +1 -1
- package/dist/lib/storage/backends/postgresql.d.ts +52 -3
- package/dist/lib/storage/backends/postgresql.d.ts.map +1 -1
- package/dist/lib/storage/backends/postgresql.js +694 -49
- package/dist/lib/storage/backends/postgresql.js.map +1 -1
- package/dist/lib/storage/benchmark.js +2 -2
- package/dist/lib/storage/benchmark.js.map +1 -1
- package/dist/lib/storage/dispatcher/base.d.ts +114 -0
- package/dist/lib/storage/dispatcher/base.d.ts.map +1 -0
- package/dist/lib/storage/dispatcher/base.js +160 -0
- package/dist/lib/storage/dispatcher/base.js.map +1 -0
- package/dist/lib/storage/dispatcher/documents.d.ts +25 -0
- package/dist/lib/storage/dispatcher/documents.d.ts.map +1 -0
- package/dist/lib/storage/dispatcher/documents.js +194 -0
- package/dist/lib/storage/dispatcher/documents.js.map +1 -0
- package/dist/lib/storage/dispatcher/embeddings.d.ts +34 -0
- package/dist/lib/storage/dispatcher/embeddings.d.ts.map +1 -0
- package/dist/lib/storage/dispatcher/embeddings.js +144 -0
- package/dist/lib/storage/dispatcher/embeddings.js.map +1 -0
- package/dist/lib/storage/dispatcher/export-import.d.ts +139 -0
- package/dist/lib/storage/dispatcher/export-import.d.ts.map +1 -0
- package/dist/lib/storage/dispatcher/export-import.js +191 -0
- package/dist/lib/storage/dispatcher/export-import.js.map +1 -0
- package/dist/lib/storage/dispatcher/file-hashes.d.ts +13 -0
- package/dist/lib/storage/dispatcher/file-hashes.d.ts.map +1 -0
- package/dist/lib/storage/dispatcher/file-hashes.js +36 -0
- package/dist/lib/storage/dispatcher/file-hashes.js.map +1 -0
- package/dist/lib/storage/dispatcher/global-memories.d.ts +28 -0
- package/dist/lib/storage/dispatcher/global-memories.d.ts.map +1 -0
- package/dist/lib/storage/dispatcher/global-memories.js +151 -0
- package/dist/lib/storage/dispatcher/global-memories.js.map +1 -0
- package/dist/lib/storage/dispatcher/graph.d.ts +32 -0
- package/dist/lib/storage/dispatcher/graph.d.ts.map +1 -0
- package/dist/lib/storage/dispatcher/graph.js +146 -0
- package/dist/lib/storage/dispatcher/graph.js.map +1 -0
- package/dist/lib/storage/dispatcher/index.d.ts +34 -0
- package/dist/lib/storage/dispatcher/index.d.ts.map +1 -0
- package/dist/lib/storage/dispatcher/index.js +139 -0
- package/dist/lib/storage/dispatcher/index.js.map +1 -0
- package/dist/lib/storage/dispatcher/memories.d.ts +65 -0
- package/dist/lib/storage/dispatcher/memories.d.ts.map +1 -0
- package/dist/lib/storage/dispatcher/memories.js +466 -0
- package/dist/lib/storage/dispatcher/memories.js.map +1 -0
- package/dist/lib/storage/dispatcher/mixin-helper.d.ts +6 -0
- package/dist/lib/storage/dispatcher/mixin-helper.d.ts.map +1 -0
- package/dist/lib/storage/dispatcher/mixin-helper.js +10 -0
- package/dist/lib/storage/dispatcher/mixin-helper.js.map +1 -0
- package/dist/lib/storage/dispatcher/retention.d.ts +20 -0
- package/dist/lib/storage/dispatcher/retention.d.ts.map +1 -0
- package/dist/lib/storage/dispatcher/retention.js +123 -0
- package/dist/lib/storage/dispatcher/retention.js.map +1 -0
- package/dist/lib/storage/dispatcher/search.d.ts +34 -0
- package/dist/lib/storage/dispatcher/search.d.ts.map +1 -0
- package/dist/lib/storage/dispatcher/search.js +222 -0
- package/dist/lib/storage/dispatcher/search.js.map +1 -0
- package/dist/lib/storage/dispatcher/skills.d.ts +53 -0
- package/dist/lib/storage/dispatcher/skills.d.ts.map +1 -0
- package/dist/lib/storage/dispatcher/skills.js +98 -0
- package/dist/lib/storage/dispatcher/skills.js.map +1 -0
- package/dist/lib/storage/dispatcher/token-stats.d.ts +23 -0
- package/dist/lib/storage/dispatcher/token-stats.d.ts.map +1 -0
- package/dist/lib/storage/dispatcher/token-stats.js +92 -0
- package/dist/lib/storage/dispatcher/token-stats.js.map +1 -0
- package/dist/lib/storage/dispatcher/web-search.d.ts +10 -0
- package/dist/lib/storage/dispatcher/web-search.d.ts.map +1 -0
- package/dist/lib/storage/dispatcher/web-search.js +39 -0
- package/dist/lib/storage/dispatcher/web-search.js.map +1 -0
- package/dist/lib/storage/dispatcher-export.d.ts.map +1 -1
- package/dist/lib/storage/dispatcher-export.js +48 -39
- package/dist/lib/storage/dispatcher-export.js.map +1 -1
- package/dist/lib/storage/dispatcher.d.ts +1 -468
- package/dist/lib/storage/dispatcher.d.ts.map +1 -1
- package/dist/lib/storage/dispatcher.js +1 -1931
- package/dist/lib/storage/dispatcher.js.map +1 -1
- package/dist/lib/storage/index.d.ts +20 -5
- package/dist/lib/storage/index.d.ts.map +1 -1
- package/dist/lib/storage/index.js +36 -7
- package/dist/lib/storage/index.js.map +1 -1
- package/dist/lib/storage/migration/export-import.d.ts.map +1 -1
- package/dist/lib/storage/migration/export-import.js +9 -2
- package/dist/lib/storage/migration/export-import.js.map +1 -1
- package/dist/lib/storage/types.d.ts +152 -10
- package/dist/lib/storage/types.d.ts.map +1 -1
- package/dist/lib/storage/types.js +13 -0
- package/dist/lib/storage/types.js.map +1 -1
- package/dist/lib/storage/vector/interface.d.ts +4 -0
- package/dist/lib/storage/vector/interface.d.ts.map +1 -1
- package/dist/lib/storage/vector/qdrant.d.ts +13 -2
- package/dist/lib/storage/vector/qdrant.d.ts.map +1 -1
- package/dist/lib/storage/vector/qdrant.js +147 -61
- package/dist/lib/storage/vector/qdrant.js.map +1 -1
- package/dist/lib/supersession.d.ts.map +1 -1
- package/dist/lib/supersession.js +2 -15
- package/dist/lib/supersession.js.map +1 -1
- package/dist/lib/token-budget.d.ts.map +1 -1
- package/dist/lib/token-budget.js +9 -2
- package/dist/lib/token-budget.js.map +1 -1
- package/dist/lib/transcript-utils.d.ts +60 -0
- package/dist/lib/transcript-utils.d.ts.map +1 -0
- package/dist/lib/transcript-utils.js +69 -0
- package/dist/lib/transcript-utils.js.map +1 -0
- package/dist/lib/tree-sitter/extractor.d.ts +1 -1
- package/dist/lib/tree-sitter/extractor.d.ts.map +1 -1
- package/dist/lib/tree-sitter/extractor.js +34 -9
- package/dist/lib/tree-sitter/extractor.js.map +1 -1
- package/dist/lib/tree-sitter/parser.d.ts.map +1 -1
- package/dist/lib/tree-sitter/parser.js +45 -11
- package/dist/lib/tree-sitter/parser.js.map +1 -1
- package/dist/lib/tree-sitter/public.d.ts +12 -0
- package/dist/lib/tree-sitter/public.d.ts.map +1 -1
- package/dist/lib/tree-sitter/public.js +33 -1
- package/dist/lib/tree-sitter/public.js.map +1 -1
- package/dist/lib/tree-sitter/queries.d.ts.map +1 -1
- package/dist/lib/tree-sitter/queries.js +8 -0
- package/dist/lib/tree-sitter/queries.js.map +1 -1
- package/dist/lib/working-memory-pipeline.d.ts.map +1 -1
- package/dist/lib/working-memory-pipeline.js +12 -3
- package/dist/lib/working-memory-pipeline.js.map +1 -1
- package/dist/lib/worktree-detect.d.ts +43 -0
- package/dist/lib/worktree-detect.d.ts.map +1 -0
- package/dist/lib/worktree-detect.js +154 -0
- package/dist/lib/worktree-detect.js.map +1 -0
- package/dist/lsp/client.d.ts +96 -0
- package/dist/lsp/client.d.ts.map +1 -0
- package/dist/lsp/client.js +435 -0
- package/dist/lsp/client.js.map +1 -0
- package/dist/lsp/installer.d.ts +39 -0
- package/dist/lsp/installer.d.ts.map +1 -0
- package/dist/lsp/installer.js +275 -0
- package/dist/lsp/installer.js.map +1 -0
- package/dist/lsp/manager.d.ts +62 -0
- package/dist/lsp/manager.d.ts.map +1 -0
- package/dist/lsp/manager.js +234 -0
- package/dist/lsp/manager.js.map +1 -0
- package/dist/lsp/servers.d.ts +52 -0
- package/dist/lsp/servers.d.ts.map +1 -0
- package/dist/lsp/servers.js +162 -0
- package/dist/lsp/servers.js.map +1 -0
- package/dist/mcp/helpers.d.ts +11 -0
- package/dist/mcp/helpers.d.ts.map +1 -1
- package/dist/mcp/helpers.js +43 -2
- package/dist/mcp/helpers.js.map +1 -1
- package/dist/mcp/profile.d.ts +16 -0
- package/dist/mcp/profile.d.ts.map +1 -0
- package/dist/mcp/profile.js +64 -0
- package/dist/mcp/profile.js.map +1 -0
- package/dist/mcp/server.d.ts +17 -15
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +135 -22
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools/config.d.ts +1 -5
- package/dist/mcp/tools/config.d.ts.map +1 -1
- package/dist/mcp/tools/config.js +169 -215
- package/dist/mcp/tools/config.js.map +1 -1
- package/dist/mcp/tools/dead-end.d.ts.map +1 -1
- package/dist/mcp/tools/dead-end.js +24 -14
- package/dist/mcp/tools/dead-end.js.map +1 -1
- package/dist/mcp/tools/debug.d.ts.map +1 -1
- package/dist/mcp/tools/debug.js +103 -179
- package/dist/mcp/tools/debug.js.map +1 -1
- package/dist/mcp/tools/graph.d.ts +0 -1
- package/dist/mcp/tools/graph.d.ts.map +1 -1
- package/dist/mcp/tools/graph.js +225 -233
- package/dist/mcp/tools/graph.js.map +1 -1
- package/dist/mcp/tools/indexing.d.ts +1 -7
- package/dist/mcp/tools/indexing.d.ts.map +1 -1
- package/dist/mcp/tools/indexing.js +180 -268
- package/dist/mcp/tools/indexing.js.map +1 -1
- package/dist/mcp/tools/memory/forget.d.ts +3 -0
- package/dist/mcp/tools/memory/forget.d.ts.map +1 -0
- package/dist/mcp/tools/memory/forget.js +175 -0
- package/dist/mcp/tools/memory/forget.js.map +1 -0
- package/dist/mcp/tools/memory/memory-helpers.d.ts +45 -0
- package/dist/mcp/tools/memory/memory-helpers.d.ts.map +1 -0
- package/dist/mcp/tools/memory/memory-helpers.js +291 -0
- package/dist/mcp/tools/memory/memory-helpers.js.map +1 -0
- package/dist/mcp/tools/memory/recall.d.ts +3 -0
- package/dist/mcp/tools/memory/recall.d.ts.map +1 -0
- package/dist/mcp/tools/memory/recall.js +495 -0
- package/dist/mcp/tools/memory/recall.js.map +1 -0
- package/dist/mcp/tools/memory/remember.d.ts +3 -0
- package/dist/mcp/tools/memory/remember.d.ts.map +1 -0
- package/dist/mcp/tools/memory/remember.js +256 -0
- package/dist/mcp/tools/memory/remember.js.map +1 -0
- package/dist/mcp/tools/memory/temporal-query.d.ts +8 -0
- package/dist/mcp/tools/memory/temporal-query.d.ts.map +1 -0
- package/dist/mcp/tools/memory/temporal-query.js +68 -0
- package/dist/mcp/tools/memory/temporal-query.js.map +1 -0
- package/dist/mcp/tools/memory.d.ts +0 -11
- package/dist/mcp/tools/memory.d.ts.map +1 -1
- package/dist/mcp/tools/memory.js +6 -1184
- package/dist/mcp/tools/memory.js.map +1 -1
- package/dist/mcp/tools/prd.d.ts +1 -7
- package/dist/mcp/tools/prd.d.ts.map +1 -1
- package/dist/mcp/tools/prd.js +198 -255
- package/dist/mcp/tools/prd.js.map +1 -1
- package/dist/mcp/tools/review.d.ts +8 -0
- package/dist/mcp/tools/review.d.ts.map +1 -0
- package/dist/mcp/tools/review.js +133 -0
- package/dist/mcp/tools/review.js.map +1 -0
- package/dist/mcp/tools/search.d.ts.map +1 -1
- package/dist/mcp/tools/search.js +168 -47
- package/dist/mcp/tools/search.js.map +1 -1
- package/dist/mcp/tools/status.d.ts +1 -5
- package/dist/mcp/tools/status.d.ts.map +1 -1
- package/dist/mcp/tools/status.js +270 -273
- package/dist/mcp/tools/status.js.map +1 -1
- package/dist/mcp/tools/web-fetch.d.ts +2 -1
- package/dist/mcp/tools/web-fetch.d.ts.map +1 -1
- package/dist/mcp/tools/web-fetch.js +72 -43
- package/dist/mcp/tools/web-fetch.js.map +1 -1
- package/dist/mcp/tools/web-search.d.ts +1 -6
- package/dist/mcp/tools/web-search.d.ts.map +1 -1
- package/dist/mcp/tools/web-search.js +199 -276
- package/dist/mcp/tools/web-search.js.map +1 -1
- package/dist/prompts/briefing.d.ts +10 -4
- package/dist/prompts/briefing.d.ts.map +1 -1
- package/dist/prompts/briefing.js +33 -35
- package/dist/prompts/briefing.js.map +1 -1
- package/dist/prompts/daemon.d.ts +5 -10
- package/dist/prompts/daemon.d.ts.map +1 -1
- package/dist/prompts/daemon.js +9 -18
- package/dist/prompts/daemon.js.map +1 -1
- package/dist/prompts/extraction.d.ts +19 -3
- package/dist/prompts/extraction.d.ts.map +1 -1
- package/dist/prompts/extraction.js +33 -46
- package/dist/prompts/extraction.js.map +1 -1
- package/dist/prompts/graph.d.ts +9 -0
- package/dist/prompts/graph.d.ts.map +1 -0
- package/dist/prompts/graph.js +27 -0
- package/dist/prompts/graph.js.map +1 -0
- package/dist/prompts/guardrails.d.ts +14 -0
- package/dist/prompts/guardrails.d.ts.map +1 -0
- package/dist/prompts/guardrails.js +115 -0
- package/dist/prompts/guardrails.js.map +1 -0
- package/dist/prompts/index.d.ts +17 -7
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/index.js +23 -7
- package/dist/prompts/index.js.map +1 -1
- package/dist/prompts/memory.d.ts +6 -3
- package/dist/prompts/memory.d.ts.map +1 -1
- package/dist/prompts/memory.js +9 -8
- package/dist/prompts/memory.js.map +1 -1
- package/dist/prompts/onboarding.d.ts +1 -1
- package/dist/prompts/onboarding.d.ts.map +1 -1
- package/dist/prompts/onboarding.js +2 -3
- package/dist/prompts/onboarding.js.map +1 -1
- package/dist/prompts/prd.d.ts +13 -6
- package/dist/prompts/prd.d.ts.map +1 -1
- package/dist/prompts/prd.js +42 -38
- package/dist/prompts/prd.js.map +1 -1
- package/dist/prompts/query-expansion.d.ts +8 -0
- package/dist/prompts/query-expansion.d.ts.map +1 -0
- package/dist/prompts/query-expansion.js +17 -0
- package/dist/prompts/query-expansion.js.map +1 -0
- package/dist/prompts/skills.d.ts +5 -10
- package/dist/prompts/skills.d.ts.map +1 -1
- package/dist/prompts/skills.js +9 -17
- package/dist/prompts/skills.js.map +1 -1
- package/dist/prompts/soul.d.ts +9 -0
- package/dist/prompts/soul.d.ts.map +1 -0
- package/dist/prompts/soul.js +47 -0
- package/dist/prompts/soul.js.map +1 -0
- package/dist/prompts/supersession.d.ts +9 -0
- package/dist/prompts/supersession.d.ts.map +1 -0
- package/dist/prompts/supersession.js +21 -0
- package/dist/prompts/supersession.js.map +1 -0
- package/dist/prompts/synthesis.d.ts +9 -0
- package/dist/prompts/synthesis.d.ts.map +1 -0
- package/dist/prompts/synthesis.js +22 -0
- package/dist/prompts/synthesis.js.map +1 -0
- package/hooks/core/__tests__/adapter.test.cjs +340 -0
- package/hooks/core/adapter.cjs +463 -0
- package/hooks/core/config.cjs +83 -0
- package/hooks/core/daemon-boot.cjs +140 -0
- package/hooks/core/log.cjs +41 -0
- package/hooks/core/worktree.cjs +119 -0
- package/hooks/succ-post-tool.cjs +198 -134
- package/hooks/succ-pre-compact.cjs +262 -0
- package/hooks/succ-pre-tool.cjs +526 -182
- package/hooks/succ-session-end.cjs +40 -64
- package/hooks/succ-session-start.cjs +504 -450
- package/hooks/succ-stop-reflection.cjs +36 -62
- package/hooks/succ-user-prompt.cjs +137 -180
- package/package.json +18 -7
package/dist/daemon/service.js
CHANGED
|
@@ -16,52 +16,36 @@
|
|
|
16
16
|
import http from 'http';
|
|
17
17
|
import fs from 'fs';
|
|
18
18
|
import path from 'path';
|
|
19
|
-
import {
|
|
19
|
+
import { createIdleWatcher, createSessionManager } from './sessions.js';
|
|
20
20
|
import { logError, logWarn } from '../lib/fault-logger.js';
|
|
21
21
|
import { processRegistry } from '../lib/process-registry.js';
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
35
|
-
import {
|
|
36
|
-
import {
|
|
37
|
-
import {
|
|
38
|
-
import {
|
|
39
|
-
import {
|
|
40
|
-
import {
|
|
41
|
-
import {
|
|
42
|
-
|
|
43
|
-
// Constants
|
|
44
|
-
// ============================================================================
|
|
22
|
+
import { NotFoundError, NetworkError, ValidationError } from '../lib/errors.js';
|
|
23
|
+
import { startWatcher, stopWatcher } from './watcher.js';
|
|
24
|
+
import { startAnalyzer, stopAnalyzer } from './analyzer.js';
|
|
25
|
+
import { getConfig, getIdleReflectionConfig, getIdleWatcherConfig, getProjectRoot, getSuccDir, } from '../lib/config.js';
|
|
26
|
+
import { getStablePort } from '../lib/daemon-port.js';
|
|
27
|
+
import { closeDb, closeGlobalDb, closeStorageDispatcher, initStorageDispatcher, } from '../lib/storage/index.js';
|
|
28
|
+
import { cleanupEmbeddings } from '../lib/embeddings.js';
|
|
29
|
+
import { cleanupReranker } from '../lib/reranker.js';
|
|
30
|
+
import { cleanupQualityScoring } from '../lib/quality.js';
|
|
31
|
+
import { loadBudgets } from '../lib/token-budget.js';
|
|
32
|
+
import { getErrorMessage, } from './routes/types.js';
|
|
33
|
+
import { sessionRoutes } from './routes/sessions.js';
|
|
34
|
+
import { searchRoutes, resetSearchRoutesState } from './routes/search.js';
|
|
35
|
+
import { memoryRoutes, resetMemoryRoutesState } from './routes/memory.js';
|
|
36
|
+
import { clearBriefingCache, initReflectionMaintenance, performReflection, preGenerateBriefing, reflectionRoutes, resetReflectionRoutesState, } from './routes/reflection.js';
|
|
37
|
+
import { statusRoutes } from './routes/status.js';
|
|
38
|
+
import { watcherRoutes } from './routes/watcher.js';
|
|
39
|
+
import { analyzerRoutes } from './routes/analyzer.js';
|
|
40
|
+
import { skillRoutes } from './routes/skills.js';
|
|
41
|
+
import { hookRoutes } from './routes/hooks.js';
|
|
42
|
+
import { addVersionedRoutes, getApiVersionInfo } from './routes/versioning.js';
|
|
45
43
|
const DEFAULT_PORT_RANGE_START = 37842;
|
|
46
44
|
const MAX_PORT_ATTEMPTS = 100;
|
|
47
|
-
//
|
|
48
|
-
// Daemon State
|
|
49
|
-
// ============================================================================
|
|
45
|
+
const MAX_BODY_SIZE = 10 * 1024 * 1024; // 10MB
|
|
50
46
|
let state = null;
|
|
51
47
|
let sessionManager = null;
|
|
52
48
|
let idleWatcher = null;
|
|
53
|
-
const briefingCache = new Map();
|
|
54
|
-
const briefingGenerationInProgress = new Set();
|
|
55
|
-
// In-flight dedup: prevents race condition when identical /api/remember requests
|
|
56
|
-
// arrive within a short window (e.g. hook fires twice for same tool_use)
|
|
57
|
-
const rememberInFlight = new Map();
|
|
58
|
-
const REMEMBER_DEDUP_TTL_MS = 5000;
|
|
59
|
-
// Hook rules cache — stores all hook-rule memories, invalidated on remember with hook-rule tag
|
|
60
|
-
let hookRulesCache = null;
|
|
61
|
-
const HOOK_RULES_CACHE_TTL = 60_000; // 60s
|
|
62
|
-
// ============================================================================
|
|
63
|
-
// File Paths
|
|
64
|
-
// ============================================================================
|
|
65
49
|
function getDaemonPidFile() {
|
|
66
50
|
const succDir = getSuccDir();
|
|
67
51
|
const tmpDir = path.join(succDir, '.tmp');
|
|
@@ -70,13 +54,6 @@ function getDaemonPidFile() {
|
|
|
70
54
|
}
|
|
71
55
|
return path.join(tmpDir, 'daemon.pid');
|
|
72
56
|
}
|
|
73
|
-
// ============================================================================
|
|
74
|
-
// Progress File Management
|
|
75
|
-
// ============================================================================
|
|
76
|
-
/**
|
|
77
|
-
* Get path to session progress file
|
|
78
|
-
* Progress files accumulate idle reflection briefings for session-end processing
|
|
79
|
-
*/
|
|
80
57
|
function getProgressFilePath(sessionId) {
|
|
81
58
|
const succDir = getSuccDir();
|
|
82
59
|
const tmpDir = path.join(succDir, '.tmp');
|
|
@@ -85,10 +62,6 @@ function getProgressFilePath(sessionId) {
|
|
|
85
62
|
}
|
|
86
63
|
return path.join(tmpDir, `session-${sessionId}-progress.md`);
|
|
87
64
|
}
|
|
88
|
-
/**
|
|
89
|
-
* Append a briefing to the session progress file
|
|
90
|
-
* Creates file with header if it doesn't exist
|
|
91
|
-
*/
|
|
92
65
|
export function appendToProgressFile(sessionId, briefing) {
|
|
93
66
|
const progressPath = getProgressFilePath(sessionId);
|
|
94
67
|
const timestamp = new Date().toISOString();
|
|
@@ -106,10 +79,6 @@ export function appendToProgressFile(sessionId, briefing) {
|
|
|
106
79
|
content += '\n\n---\n\n';
|
|
107
80
|
fs.appendFileSync(progressPath, content);
|
|
108
81
|
}
|
|
109
|
-
/**
|
|
110
|
-
* Read tail of transcript file (for fallback when no progress file)
|
|
111
|
-
* Returns the last maxBytes of the file, starting from a complete line
|
|
112
|
-
*/
|
|
113
82
|
export function readTailTranscript(transcriptPath, maxBytes = 2 * 1024 * 1024) {
|
|
114
83
|
if (!fs.existsSync(transcriptPath)) {
|
|
115
84
|
return '';
|
|
@@ -118,107 +87,14 @@ export function readTailTranscript(transcriptPath, maxBytes = 2 * 1024 * 1024) {
|
|
|
118
87
|
if (stats.size <= maxBytes) {
|
|
119
88
|
return fs.readFileSync(transcriptPath, 'utf8');
|
|
120
89
|
}
|
|
121
|
-
// Read only tail
|
|
122
90
|
const fd = fs.openSync(transcriptPath, 'r');
|
|
123
91
|
const buffer = Buffer.alloc(maxBytes);
|
|
124
92
|
fs.readSync(fd, buffer, 0, maxBytes, stats.size - maxBytes);
|
|
125
93
|
fs.closeSync(fd);
|
|
126
|
-
// Find first complete line (skip partial line at start)
|
|
127
94
|
const content = buffer.toString('utf8');
|
|
128
95
|
const firstNewline = content.indexOf('\n');
|
|
129
96
|
return firstNewline > 0 ? content.slice(firstNewline + 1) : content;
|
|
130
97
|
}
|
|
131
|
-
// ============================================================================
|
|
132
|
-
// Briefing Pre-Generation
|
|
133
|
-
// ============================================================================
|
|
134
|
-
const BRIEFING_CACHE_MAX_AGE_MS = 5 * 60 * 1000; // 5 minutes
|
|
135
|
-
const BRIEFING_MIN_TRANSCRIPT_GROWTH = 5000; // Re-generate after 5KB growth
|
|
136
|
-
// const BRIEFING_PREGENERATE_IDLE_MS = 120 * 1000; // Pre-generate after 2 min idle
|
|
137
|
-
/**
|
|
138
|
-
* Pre-generate briefing for a session in background
|
|
139
|
-
* Called when session is idle or transcript grows significantly
|
|
140
|
-
*/
|
|
141
|
-
async function preGenerateBriefing(sessionId, transcriptPath) {
|
|
142
|
-
// Skip if already generating
|
|
143
|
-
if (briefingGenerationInProgress.has(sessionId)) {
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
if (!fs.existsSync(transcriptPath)) {
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
const stats = fs.statSync(transcriptPath);
|
|
150
|
-
const currentSize = stats.size;
|
|
151
|
-
// Check if we need to regenerate
|
|
152
|
-
const cached = briefingCache.get(sessionId);
|
|
153
|
-
if (cached) {
|
|
154
|
-
const age = Date.now() - cached.generatedAt;
|
|
155
|
-
const growth = currentSize - cached.transcriptSize;
|
|
156
|
-
// Skip if cache is fresh and transcript hasn't grown much
|
|
157
|
-
if (age < BRIEFING_CACHE_MAX_AGE_MS && growth < BRIEFING_MIN_TRANSCRIPT_GROWTH) {
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
briefingGenerationInProgress.add(sessionId);
|
|
162
|
-
log(`[briefing] Pre-generating for session ${sessionId.slice(0, 8)}...`);
|
|
163
|
-
try {
|
|
164
|
-
const transcriptContent = fs.readFileSync(transcriptPath, 'utf-8');
|
|
165
|
-
const result = await generateCompactBriefing(transcriptContent);
|
|
166
|
-
if (result.success && result.briefing) {
|
|
167
|
-
briefingCache.set(sessionId, {
|
|
168
|
-
briefing: result.briefing,
|
|
169
|
-
generatedAt: Date.now(),
|
|
170
|
-
transcriptSize: currentSize,
|
|
171
|
-
});
|
|
172
|
-
log(`[briefing] Pre-generated for session ${sessionId.slice(0, 8)} (${result.briefing.length} chars)`);
|
|
173
|
-
}
|
|
174
|
-
else {
|
|
175
|
-
log(`[briefing] Pre-generation failed: ${result.error}`);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
catch (error) {
|
|
179
|
-
log(`[briefing] Pre-generation error: ${error}`);
|
|
180
|
-
}
|
|
181
|
-
finally {
|
|
182
|
-
briefingGenerationInProgress.delete(sessionId);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
/**
|
|
186
|
-
* Get cached briefing or generate on-demand
|
|
187
|
-
*/
|
|
188
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
189
|
-
async function getCachedBriefing(sessionId, transcriptPath) {
|
|
190
|
-
const cached = briefingCache.get(sessionId);
|
|
191
|
-
if (cached) {
|
|
192
|
-
// Check if cache is still valid
|
|
193
|
-
const age = Date.now() - cached.generatedAt;
|
|
194
|
-
if (age < BRIEFING_CACHE_MAX_AGE_MS) {
|
|
195
|
-
return { briefing: cached.briefing, cached: true };
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
// Cache miss or stale - generate fresh
|
|
199
|
-
if (!fs.existsSync(transcriptPath)) {
|
|
200
|
-
return { cached: false };
|
|
201
|
-
}
|
|
202
|
-
const transcriptContent = fs.readFileSync(transcriptPath, 'utf-8');
|
|
203
|
-
const result = await generateCompactBriefing(transcriptContent);
|
|
204
|
-
if (result.success && result.briefing) {
|
|
205
|
-
const stats = fs.statSync(transcriptPath);
|
|
206
|
-
briefingCache.set(sessionId, {
|
|
207
|
-
briefing: result.briefing,
|
|
208
|
-
generatedAt: Date.now(),
|
|
209
|
-
transcriptSize: stats.size,
|
|
210
|
-
});
|
|
211
|
-
return { briefing: result.briefing, cached: false };
|
|
212
|
-
}
|
|
213
|
-
return { cached: false };
|
|
214
|
-
}
|
|
215
|
-
/**
|
|
216
|
-
* Clear briefing cache for a session (called when session ends)
|
|
217
|
-
*/
|
|
218
|
-
function clearBriefingCache(sessionId) {
|
|
219
|
-
briefingCache.delete(sessionId);
|
|
220
|
-
briefingGenerationInProgress.delete(sessionId);
|
|
221
|
-
}
|
|
222
98
|
function getDaemonPortFile() {
|
|
223
99
|
const succDir = getSuccDir();
|
|
224
100
|
const tmpDir = path.join(succDir, '.tmp');
|
|
@@ -231,13 +107,9 @@ function getDaemonLogFile() {
|
|
|
231
107
|
const succDir = getSuccDir();
|
|
232
108
|
return path.join(succDir, 'daemon.log');
|
|
233
109
|
}
|
|
234
|
-
// ============================================================================
|
|
235
|
-
// Logging
|
|
236
|
-
// ============================================================================
|
|
237
110
|
function log(message) {
|
|
238
111
|
const timestamp = new Date().toISOString();
|
|
239
112
|
const line = `[${timestamp}] ${message}\n`;
|
|
240
|
-
// Write to daemon.log
|
|
241
113
|
try {
|
|
242
114
|
fs.appendFileSync(getDaemonLogFile(), line);
|
|
243
115
|
}
|
|
@@ -246,290 +118,43 @@ function log(message) {
|
|
|
246
118
|
error: err instanceof Error ? err.message : String(err),
|
|
247
119
|
});
|
|
248
120
|
}
|
|
249
|
-
// Also write to stderr for debugging
|
|
250
121
|
process.stderr.write(line);
|
|
251
122
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
// ============================================================================
|
|
255
|
-
/**
|
|
256
|
-
* Write a human-like reflection to the brain vault
|
|
257
|
-
* Uses Claude CLI or local LLM to generate introspective text
|
|
258
|
-
*/
|
|
259
|
-
async function writeReflection(transcript, _idleConfig) {
|
|
260
|
-
const projectRoot = getProjectRoot();
|
|
261
|
-
const reflectionsDir = path.join(projectRoot, '.succ', 'brain', 'reflections');
|
|
262
|
-
// Create reflections directory if needed
|
|
263
|
-
if (!fs.existsSync(reflectionsDir)) {
|
|
264
|
-
fs.mkdirSync(reflectionsDir, { recursive: true });
|
|
265
|
-
}
|
|
266
|
-
const now = new Date();
|
|
267
|
-
const dateStr = now.toISOString().split('T')[0];
|
|
268
|
-
const timeStr = now.toTimeString().split(' ')[0].substring(0, 5);
|
|
269
|
-
const timestamp = `${dateStr} ${timeStr}`;
|
|
270
|
-
const prompt = REFLECTION_PROMPT.replace('{transcript}', transcript.substring(0, 3000));
|
|
271
|
-
let reflectionText = null;
|
|
272
|
-
// Use sleep agent for background reflection if enabled
|
|
273
|
-
try {
|
|
274
|
-
reflectionText = await callLLM(prompt, {
|
|
275
|
-
timeout: 60000,
|
|
276
|
-
useSleepAgent: true, // Use sleep_agent config if available
|
|
277
|
-
});
|
|
278
|
-
}
|
|
279
|
-
catch (err) {
|
|
280
|
-
log(`[reflection] LLM call failed: ${err}`);
|
|
281
|
-
reflectionText = null;
|
|
282
|
-
}
|
|
283
|
-
if (!reflectionText || reflectionText.trim().length < 50) {
|
|
284
|
-
log(`[reflection] Reflection text too short or empty, skipping`);
|
|
285
|
-
return;
|
|
286
|
-
}
|
|
287
|
-
// Write reflection file with YAML frontmatter
|
|
288
|
-
const reflectionFile = path.join(reflectionsDir, `${timestamp}.md`);
|
|
289
|
-
const content = `---
|
|
290
|
-
date: ${dateStr}
|
|
291
|
-
time: ${timeStr}
|
|
292
|
-
trigger: idle
|
|
293
|
-
tags:
|
|
294
|
-
- reflection
|
|
295
|
-
---
|
|
296
|
-
|
|
297
|
-
# Reflection ${dateStr} ${timeStr}
|
|
298
|
-
|
|
299
|
-
${reflectionText.trim()}
|
|
300
|
-
`;
|
|
301
|
-
fs.writeFileSync(reflectionFile, content);
|
|
302
|
-
// Also save to memory (with dedup to prevent duplicate reflections)
|
|
303
|
-
const embedding = await getEmbedding(reflectionText.trim());
|
|
304
|
-
await saveMemory(reflectionText.trim(), embedding, ['reflection'], 'observation', {
|
|
305
|
-
qualityScore: { score: 0.6, factors: { hasContext: 1 } },
|
|
306
|
-
deduplicate: true,
|
|
307
|
-
});
|
|
123
|
+
function isErrnoException(error) {
|
|
124
|
+
return typeof error === 'object' && error !== null && 'code' in error;
|
|
308
125
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
}
|
|
338
|
-
catch {
|
|
339
|
-
/* transcript file gone — skip size check */
|
|
340
|
-
}
|
|
341
|
-
// Check memory count for consolidation skip
|
|
342
|
-
const memStats = await getMemoryStats();
|
|
343
|
-
const currentMemCount = memStats.total;
|
|
344
|
-
if (session.lastMemoryCount !== undefined && currentMemCount === session.lastMemoryCount) {
|
|
345
|
-
memoriesChanged = false;
|
|
346
|
-
}
|
|
347
|
-
session.lastMemoryCount = currentMemCount;
|
|
348
|
-
// ── Mid-conversation observer: extract facts when enough new content ──
|
|
349
|
-
const observerConfig = getObserverConfig();
|
|
350
|
-
if (observerConfig.enabled && transcriptChanged) {
|
|
351
|
-
try {
|
|
352
|
-
const currentSize = session.lastTranscriptSize ?? 0;
|
|
353
|
-
const lastObsSize = session.lastObservationSize ?? 0;
|
|
354
|
-
const lastObsTime = session.lastObservation ?? session.registeredAt;
|
|
355
|
-
const now = Date.now();
|
|
356
|
-
// Read new content and track real token count via budget
|
|
357
|
-
const newBytes = currentSize - lastObsSize;
|
|
358
|
-
const timeThresholdMs = observerConfig.max_minutes * 60 * 1000;
|
|
359
|
-
const enoughTime = now - lastObsTime >= timeThresholdMs;
|
|
360
|
-
// Use byte-estimated token check first (cheap), then verify with real count
|
|
361
|
-
const estimatedTokens = Math.ceil(newBytes / 3.5);
|
|
362
|
-
const enoughNewContent = estimatedTokens >= observerConfig.min_tokens;
|
|
363
|
-
if (enoughNewContent || enoughTime) {
|
|
364
|
-
const newContent = readTailTranscript(session.transcriptPath, newBytes);
|
|
365
|
-
// Track real tokens in budget
|
|
366
|
-
const realTokens = recordTranscriptTokens(sessionId, newContent);
|
|
367
|
-
log(`[observer] Triggering extraction (tokens: ~${realTokens}, time: ${Math.round((now - lastObsTime) / 60000)}min)`);
|
|
368
|
-
if (newContent.length > 200) {
|
|
369
|
-
const result = await extractSessionSummary(newContent, { verbose: false });
|
|
370
|
-
recordExtraction(sessionId, result.transcriptTokens ?? 0, result.summaryTokens ?? 0, result.factsExtracted, result.factsSaved);
|
|
371
|
-
resetTranscriptCounter(sessionId);
|
|
372
|
-
// Persist extraction metadata to session observations (append-only)
|
|
373
|
-
if (result.factsSaved > 0) {
|
|
374
|
-
appendObservations(sessionId, [
|
|
375
|
-
{
|
|
376
|
-
content: `Extracted ${result.factsExtracted} facts, saved ${result.factsSaved}`,
|
|
377
|
-
type: 'observation',
|
|
378
|
-
tags: ['mid-session'],
|
|
379
|
-
extractedAt: new Date().toISOString(),
|
|
380
|
-
source: 'mid-session-observer',
|
|
381
|
-
transcriptOffset: currentSize,
|
|
382
|
-
memoryId: null,
|
|
383
|
-
},
|
|
384
|
-
]);
|
|
385
|
-
}
|
|
386
|
-
log(`[observer] Extracted ${result.factsExtracted} facts, saved ${result.factsSaved} (skipped ${result.factsSkipped})`);
|
|
387
|
-
}
|
|
388
|
-
session.lastObservation = now;
|
|
389
|
-
session.lastObservationSize = currentSize;
|
|
390
|
-
flushBudgets();
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
catch (err) {
|
|
394
|
-
log(`[observer] Mid-session extraction failed: ${err}`);
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
// ── Generate briefing (skip if transcript unchanged) ──
|
|
398
|
-
let briefingResult = { success: false };
|
|
399
|
-
if (transcriptChanged) {
|
|
400
|
-
const transcriptContent = readTailTranscript(session.transcriptPath, 100 * 1024); // 100KB max
|
|
401
|
-
briefingResult = await generateCompactBriefing(transcriptContent, {
|
|
402
|
-
format: 'structured',
|
|
403
|
-
include_memories: true,
|
|
404
|
-
max_memories: 3,
|
|
405
|
-
});
|
|
406
|
-
if (briefingResult.success && briefingResult.briefing) {
|
|
407
|
-
appendToProgressFile(sessionId, briefingResult.briefing);
|
|
408
|
-
log(`[reflection] Appended briefing to progress file (${briefingResult.briefing.length} chars)`);
|
|
409
|
-
}
|
|
410
|
-
else {
|
|
411
|
-
log(`[reflection] Failed to generate briefing for ${sessionId}`);
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
// ── Parallel operations ──
|
|
415
|
-
const globalConfig = getConfig();
|
|
416
|
-
const parallelOps = [];
|
|
417
|
-
// memory_consolidation - skip if no new memories (disabled by default, opt-in only)
|
|
418
|
-
if (memoriesChanged && idleConfig.operations?.memory_consolidation === true) {
|
|
419
|
-
parallelOps.push((async () => {
|
|
420
|
-
const threshold = idleConfig.thresholds?.similarity_for_merge ?? 0.92;
|
|
421
|
-
const limit = idleConfig.max_memories_to_process ?? 50;
|
|
422
|
-
log(`[reflection] Running memory consolidation (threshold=${threshold}, limit=${limit})`);
|
|
423
|
-
const { consolidate } = await import('../commands/consolidate.js');
|
|
424
|
-
await consolidate({
|
|
425
|
-
threshold: String(threshold),
|
|
426
|
-
limit: String(limit),
|
|
427
|
-
llm: true,
|
|
428
|
-
verbose: false,
|
|
429
|
-
});
|
|
430
|
-
log(`[reflection] Memory consolidation complete`);
|
|
431
|
-
})());
|
|
432
|
-
}
|
|
433
|
-
// retention_cleanup - independent (always runs if enabled)
|
|
434
|
-
if (globalConfig.retention?.enabled && idleConfig.operations?.retention_cleanup !== false) {
|
|
435
|
-
parallelOps.push((async () => {
|
|
436
|
-
log(`[reflection] Running retention cleanup`);
|
|
437
|
-
const { retention } = await import('../commands/retention.js');
|
|
438
|
-
await retention({ apply: true, verbose: false });
|
|
439
|
-
log(`[reflection] Retention cleanup complete`);
|
|
440
|
-
})());
|
|
441
|
-
}
|
|
442
|
-
await Promise.all(parallelOps);
|
|
443
|
-
// ── Graph cleanup: prune → enrich → orphans → communities → centrality ──
|
|
444
|
-
if (idleConfig.operations?.graph_refinement !== false ||
|
|
445
|
-
idleConfig.operations?.graph_enrichment !== false) {
|
|
446
|
-
const shouldRun = memoriesChanged || session.lastLinkCount === undefined;
|
|
447
|
-
if (shouldRun) {
|
|
448
|
-
log(`[reflection] Running graph cleanup pipeline`);
|
|
449
|
-
try {
|
|
450
|
-
const { graphCleanup } = await import('../lib/graph/cleanup.js');
|
|
451
|
-
const cleanupResult = await graphCleanup({
|
|
452
|
-
skipEnrich: idleConfig.operations?.graph_enrichment === false,
|
|
453
|
-
onProgress: (step, detail) => log(`[reflection] [${step}] ${detail}`),
|
|
454
|
-
});
|
|
455
|
-
log(`[reflection] Cleanup: pruned ${cleanupResult.pruned}, enriched ${cleanupResult.enriched}, orphans ${cleanupResult.orphansConnected}, communities ${cleanupResult.communitiesDetected}, centrality ${cleanupResult.centralityUpdated}`);
|
|
456
|
-
// Proximity links from co-occurrence (not part of cleanup pipeline)
|
|
457
|
-
try {
|
|
458
|
-
const { createProximityLinks } = await import('../lib/graph/contextual-proximity.js');
|
|
459
|
-
const r = await createProximityLinks({ minCooccurrence: 2 });
|
|
460
|
-
log(`[reflection] Created ${r.created} proximity links`);
|
|
461
|
-
}
|
|
462
|
-
catch (err) {
|
|
463
|
-
log(`[reflection] Proximity failed: ${err}`);
|
|
464
|
-
}
|
|
465
|
-
// Synthesize patterns from community clusters (uses cleanup's community result)
|
|
466
|
-
if (cleanupResult.communityResult &&
|
|
467
|
-
cleanupResult.communityResult.communities.length > 0) {
|
|
468
|
-
try {
|
|
469
|
-
const { synthesizeFromCommunities } = await import('../lib/reflection-synthesizer.js');
|
|
470
|
-
const synthResult = await synthesizeFromCommunities(cleanupResult.communityResult, {
|
|
471
|
-
log,
|
|
472
|
-
});
|
|
473
|
-
const hasSynthActivity = synthResult.patternsCreated > 0 ||
|
|
474
|
-
synthResult.duplicatesSkipped > 0 ||
|
|
475
|
-
synthResult.reinforced > 0;
|
|
476
|
-
if (hasSynthActivity) {
|
|
477
|
-
log(`[reflection] Synthesized ${synthResult.patternsCreated} patterns from ${synthResult.clustersProcessed} clusters` +
|
|
478
|
-
(synthResult.reinforced > 0
|
|
479
|
-
? `, reinforced ${synthResult.reinforced} existing`
|
|
480
|
-
: '') +
|
|
481
|
-
(synthResult.duplicatesSkipped > 0
|
|
482
|
-
? `, skipped ${synthResult.duplicatesSkipped} duplicates`
|
|
483
|
-
: '') +
|
|
484
|
-
(synthResult.observationsMarked > 0
|
|
485
|
-
? `, marked ${synthResult.observationsMarked} as reflected`
|
|
486
|
-
: ''));
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
catch (err) {
|
|
490
|
-
log(`[reflection] Synthesis failed: ${err}`);
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
session.lastLinkCount = (session.lastLinkCount ?? 0) + cleanupResult.orphansConnected;
|
|
494
|
-
}
|
|
495
|
-
catch (err) {
|
|
496
|
-
log(`[reflection] Graph cleanup failed: ${err}`);
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
else {
|
|
500
|
-
log(`[reflection] Skipping graph cleanup (no changes)`);
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
// ── Write reflection (runs last, may use LLM) ──
|
|
504
|
-
if (idleConfig.operations?.write_reflection !== false) {
|
|
505
|
-
log(`[reflection] Writing reflection for ${sessionId}`);
|
|
506
|
-
try {
|
|
507
|
-
const progressPath = getProgressFilePath(sessionId);
|
|
508
|
-
const briefingContent = fs.existsSync(progressPath)
|
|
509
|
-
? fs.readFileSync(progressPath, 'utf-8')
|
|
510
|
-
: briefingResult.briefing || '';
|
|
511
|
-
if (briefingContent.length >= 100) {
|
|
512
|
-
await writeReflection(briefingContent, idleConfig);
|
|
513
|
-
log(`[reflection] Reflection written`);
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
catch (err) {
|
|
517
|
-
log(`[reflection] Write reflection error: ${err}`);
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
log(`[reflection] Completed reflection for session ${sessionId}`);
|
|
521
|
-
}
|
|
522
|
-
catch (err) {
|
|
523
|
-
log(`[reflection] Error for session ${sessionId}: ${err}`);
|
|
524
|
-
}
|
|
126
|
+
function createRouteContext() {
|
|
127
|
+
return {
|
|
128
|
+
state,
|
|
129
|
+
sessionManager,
|
|
130
|
+
log,
|
|
131
|
+
checkShutdown,
|
|
132
|
+
clearBriefingCache,
|
|
133
|
+
appendToProgressFile,
|
|
134
|
+
readTailTranscript,
|
|
135
|
+
getProgressFilePath,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function buildRoutes(ctx) {
|
|
139
|
+
const baseRoutes = {
|
|
140
|
+
...statusRoutes(ctx),
|
|
141
|
+
...sessionRoutes(ctx),
|
|
142
|
+
...searchRoutes(ctx),
|
|
143
|
+
...memoryRoutes(ctx),
|
|
144
|
+
...reflectionRoutes(ctx),
|
|
145
|
+
...watcherRoutes(ctx),
|
|
146
|
+
...analyzerRoutes(ctx),
|
|
147
|
+
...skillRoutes(ctx),
|
|
148
|
+
...hookRoutes(ctx),
|
|
149
|
+
// API version info endpoint
|
|
150
|
+
'GET /api/version': async () => getApiVersionInfo(),
|
|
151
|
+
};
|
|
152
|
+
// Add /v1/api/* aliases for all /api/* routes
|
|
153
|
+
return addVersionedRoutes(baseRoutes);
|
|
525
154
|
}
|
|
526
|
-
// ============================================================================
|
|
527
|
-
// HTTP Request Handler
|
|
528
|
-
// ============================================================================
|
|
529
155
|
async function handleRequest(req, res) {
|
|
530
156
|
const reqUrl = new URL(req.url || '/', `http://localhost`);
|
|
531
157
|
const method = req.method || 'GET';
|
|
532
|
-
// CORS headers (for potential web clients)
|
|
533
158
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
534
159
|
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS');
|
|
535
160
|
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
@@ -538,500 +163,120 @@ async function handleRequest(req, res) {
|
|
|
538
163
|
res.end();
|
|
539
164
|
return;
|
|
540
165
|
}
|
|
541
|
-
// Parse JSON body for POST requests
|
|
542
166
|
let body = null;
|
|
543
167
|
if (method === 'POST') {
|
|
544
|
-
|
|
168
|
+
try {
|
|
169
|
+
body = await parseBody(req);
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
const message = getErrorMessage(error);
|
|
173
|
+
if (message.includes('too large')) {
|
|
174
|
+
res.writeHead(413, { 'Content-Type': 'application/json' });
|
|
175
|
+
res.end(JSON.stringify({ error: 'Request body too large' }));
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
179
|
+
res.end(JSON.stringify({ error: 'Invalid request body' }));
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
545
182
|
}
|
|
546
183
|
try {
|
|
547
|
-
// Route request
|
|
548
184
|
const result = await routeRequest(method, reqUrl.pathname, reqUrl.searchParams, body);
|
|
549
185
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
550
186
|
res.end(JSON.stringify(result));
|
|
551
187
|
}
|
|
552
188
|
catch (err) {
|
|
553
|
-
|
|
189
|
+
const message = getErrorMessage(err);
|
|
190
|
+
log(`[http] Error: ${message}`);
|
|
191
|
+
if (err instanceof ValidationError) {
|
|
192
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
193
|
+
res.end(JSON.stringify({ error: message }));
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
if (err instanceof NotFoundError) {
|
|
197
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
198
|
+
res.end(JSON.stringify({ error: message }));
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
554
201
|
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
555
|
-
res.end(JSON.stringify({ error:
|
|
202
|
+
res.end(JSON.stringify({ error: 'Internal server error' }));
|
|
556
203
|
}
|
|
557
204
|
}
|
|
558
205
|
export async function parseBody(req) {
|
|
559
206
|
return new Promise((resolve, reject) => {
|
|
560
207
|
let data = '';
|
|
561
|
-
|
|
208
|
+
let size = 0;
|
|
209
|
+
let settled = false;
|
|
210
|
+
const settle = (fn) => {
|
|
211
|
+
if (settled)
|
|
212
|
+
return;
|
|
213
|
+
settled = true;
|
|
214
|
+
fn();
|
|
215
|
+
};
|
|
216
|
+
req.on('data', (chunk) => {
|
|
217
|
+
if (settled)
|
|
218
|
+
return;
|
|
219
|
+
const chunkSize = Buffer.isBuffer(chunk) ? chunk.length : Buffer.byteLength(String(chunk));
|
|
220
|
+
size += chunkSize;
|
|
221
|
+
if (size > MAX_BODY_SIZE) {
|
|
222
|
+
req.destroy();
|
|
223
|
+
settle(() => reject(new Error('Request body too large')));
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
data += chunk;
|
|
227
|
+
});
|
|
562
228
|
req.on('end', () => {
|
|
229
|
+
if (settled)
|
|
230
|
+
return;
|
|
563
231
|
try {
|
|
564
|
-
|
|
232
|
+
const parsed = data ? JSON.parse(data) : {};
|
|
233
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
234
|
+
settle(() => reject(new Error('Invalid request body')));
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
settle(() => resolve(parsed));
|
|
565
238
|
}
|
|
566
|
-
catch
|
|
567
|
-
|
|
568
|
-
error: err instanceof Error ? err.message : String(err),
|
|
569
|
-
});
|
|
570
|
-
resolve({});
|
|
239
|
+
catch {
|
|
240
|
+
settle(() => reject(new Error('Invalid request body')));
|
|
571
241
|
}
|
|
572
242
|
});
|
|
573
|
-
req.on('error',
|
|
243
|
+
req.on('error', (error) => {
|
|
244
|
+
settle(() => reject(error));
|
|
245
|
+
});
|
|
574
246
|
});
|
|
575
247
|
}
|
|
576
248
|
/** @internal Exported for testing */
|
|
577
249
|
export async function routeRequest(method, pathname, searchParams, body) {
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
uptime: Date.now() - (state?.startedAt || Date.now()),
|
|
584
|
-
activeSessions: sessionManager?.count() || 0,
|
|
585
|
-
cwd: state?.cwd || process.cwd(),
|
|
586
|
-
};
|
|
250
|
+
const routes = buildRoutes(createRouteContext());
|
|
251
|
+
const key = `${method} ${pathname}`;
|
|
252
|
+
const handler = routes[key];
|
|
253
|
+
if (!handler) {
|
|
254
|
+
throw new NotFoundError(`Unknown endpoint: ${method} ${pathname}`);
|
|
587
255
|
}
|
|
588
|
-
|
|
589
|
-
if (pathname === '/api/session/register' && method === 'POST') {
|
|
590
|
-
const { session_id, transcript_path, is_service = false } = body;
|
|
591
|
-
if (!session_id) {
|
|
592
|
-
throw new ValidationError('session_id required');
|
|
593
|
-
}
|
|
594
|
-
const session = sessionManager.register(session_id, transcript_path || '', is_service);
|
|
595
|
-
log(`[session] Registered: ${session_id}${is_service ? ' (service)' : ''}`);
|
|
596
|
-
return { success: true, session };
|
|
597
|
-
}
|
|
598
|
-
if (pathname === '/api/session/unregister' && method === 'POST') {
|
|
599
|
-
const { session_id, transcript_path, run_reflection } = body;
|
|
600
|
-
if (!session_id) {
|
|
601
|
-
throw new ValidationError('session_id required');
|
|
602
|
-
}
|
|
603
|
-
const session = sessionManager.get(session_id);
|
|
604
|
-
const transcriptFile = transcript_path || session?.transcriptPath || '';
|
|
605
|
-
// Flush session counters to learning_deltas before unregister
|
|
606
|
-
try {
|
|
607
|
-
const d = await getStorageDispatcher();
|
|
608
|
-
await d.flushSessionCounters('daemon-session');
|
|
609
|
-
}
|
|
610
|
-
catch (err) {
|
|
611
|
-
log(`[session] Failed to flush session counters: ${err}`);
|
|
612
|
-
}
|
|
613
|
-
// Unregister the session immediately (don't block on processing)
|
|
614
|
-
const removed = sessionManager.unregister(session_id);
|
|
615
|
-
clearBriefingCache(session_id); // Clean up any cached briefing
|
|
616
|
-
removeBudget(session_id); // Clean up token budget
|
|
617
|
-
removeObservations(session_id); // Clean up observation JSONL
|
|
618
|
-
flushBudgets();
|
|
619
|
-
log(`[session] Unregistered: ${session_id} (removed=${removed})`);
|
|
620
|
-
// Process session asynchronously (summarize transcript, extract learnings, save to memory)
|
|
621
|
-
if (run_reflection && transcriptFile) {
|
|
622
|
-
sessionManager.incrementPendingWork();
|
|
623
|
-
log(`[session] Queuing async processing for ${session_id}`);
|
|
624
|
-
// Fire-and-forget async processing
|
|
625
|
-
(async () => {
|
|
626
|
-
try {
|
|
627
|
-
const result = await processSessionEnd(transcriptFile, session_id, log);
|
|
628
|
-
log(`[session] Processing complete for ${session_id}: summary=${result.summary.length}chars, learnings=${result.learnings.length}, saved=${result.saved}`);
|
|
629
|
-
}
|
|
630
|
-
catch (err) {
|
|
631
|
-
log(`[session] Processing failed for ${session_id}: ${err}`);
|
|
632
|
-
}
|
|
633
|
-
finally {
|
|
634
|
-
sessionManager.decrementPendingWork();
|
|
635
|
-
// Check shutdown after work completes
|
|
636
|
-
checkShutdown();
|
|
637
|
-
}
|
|
638
|
-
})();
|
|
639
|
-
}
|
|
640
|
-
else {
|
|
641
|
-
// No processing needed, check shutdown immediately
|
|
642
|
-
checkShutdown();
|
|
643
|
-
}
|
|
644
|
-
return { success: removed, remaining_sessions: sessionManager.count() };
|
|
645
|
-
}
|
|
646
|
-
if (pathname === '/api/session/activity' && method === 'POST') {
|
|
647
|
-
const { session_id, type, transcript_path, is_service = false } = body;
|
|
648
|
-
if (!session_id || !type) {
|
|
649
|
-
throw new ValidationError('session_id and type required');
|
|
650
|
-
}
|
|
651
|
-
let session = sessionManager.activity(session_id, type);
|
|
652
|
-
if (!session) {
|
|
653
|
-
// Auto-register if session not found (with transcript_path if provided)
|
|
654
|
-
sessionManager.register(session_id, transcript_path || '', is_service);
|
|
655
|
-
session = sessionManager.activity(session_id, type);
|
|
656
|
-
log(`[session] Auto-registered and activity: ${session_id} (${type})${is_service ? ' (service)' : ''}`);
|
|
657
|
-
}
|
|
658
|
-
else if (transcript_path && !session.transcriptPath) {
|
|
659
|
-
// Update transcript path if not set
|
|
660
|
-
session.transcriptPath = transcript_path;
|
|
661
|
-
log(`[session] Activity: ${session_id} (${type}) + updated transcript`);
|
|
662
|
-
}
|
|
663
|
-
else {
|
|
664
|
-
log(`[session] Activity: ${session_id} (${type})`);
|
|
665
|
-
}
|
|
666
|
-
return { success: true };
|
|
667
|
-
}
|
|
668
|
-
if (pathname === '/api/sessions' && method === 'GET') {
|
|
669
|
-
const includeService = searchParams.get('includeService') === 'true';
|
|
670
|
-
const sessions = {};
|
|
671
|
-
for (const [id, session] of sessionManager.getAll(includeService)) {
|
|
672
|
-
sessions[id] = session;
|
|
673
|
-
}
|
|
674
|
-
return { sessions, count: sessionManager.count(includeService) };
|
|
675
|
-
}
|
|
676
|
-
// Search endpoints
|
|
677
|
-
if (pathname === '/api/search' && method === 'POST') {
|
|
678
|
-
const { query, limit = 5, threshold = 0.3 } = body;
|
|
679
|
-
if (!query) {
|
|
680
|
-
throw new ValidationError('query required');
|
|
681
|
-
}
|
|
682
|
-
const queryEmbedding = await getEmbedding(query);
|
|
683
|
-
const results = await hybridSearchDocs(query, queryEmbedding, limit, threshold);
|
|
684
|
-
// Track access for returned memories
|
|
685
|
-
const accesses = results
|
|
686
|
-
.filter((r) => r.memory_id)
|
|
687
|
-
.map((r) => ({ memoryId: r.memory_id, weight: 0.5 }));
|
|
688
|
-
if (accesses.length > 0) {
|
|
689
|
-
await incrementMemoryAccessBatch(accesses);
|
|
690
|
-
}
|
|
691
|
-
return { results };
|
|
692
|
-
}
|
|
693
|
-
if (pathname === '/api/search-code' && method === 'POST') {
|
|
694
|
-
const { query, limit = 5, threshold = 0.3 } = body;
|
|
695
|
-
if (!query) {
|
|
696
|
-
throw new ValidationError('query required');
|
|
697
|
-
}
|
|
698
|
-
const queryEmbedding = await getEmbedding(query);
|
|
699
|
-
const results = await hybridSearchCode(query, queryEmbedding, limit, threshold);
|
|
700
|
-
return { results };
|
|
701
|
-
}
|
|
702
|
-
if (pathname === '/api/recall' && method === 'POST') {
|
|
703
|
-
const { query, limit = 5 } = body;
|
|
704
|
-
// Empty query returns recent memories
|
|
705
|
-
if (!query) {
|
|
706
|
-
const memories = await getRecentMemories(limit);
|
|
707
|
-
return { results: memories };
|
|
708
|
-
}
|
|
709
|
-
// Generate embedding for semantic search
|
|
710
|
-
const queryEmbedding = await getEmbedding(query);
|
|
711
|
-
const results = await hybridSearchMemories(query, queryEmbedding, limit, 0.3);
|
|
712
|
-
// Track access for returned memories
|
|
713
|
-
const accesses = results
|
|
714
|
-
.filter((r) => r.id)
|
|
715
|
-
.map((r) => ({ memoryId: r.id, weight: 1.0 }));
|
|
716
|
-
if (accesses.length > 0) {
|
|
717
|
-
await incrementMemoryAccessBatch(accesses);
|
|
718
|
-
}
|
|
719
|
-
return { results };
|
|
720
|
-
}
|
|
721
|
-
if (pathname === '/api/pinned' && method === 'GET') {
|
|
722
|
-
const pinned = await getPinnedMemories();
|
|
723
|
-
return { results: pinned };
|
|
724
|
-
}
|
|
725
|
-
if (pathname === '/api/pinned/cleanup' && method === 'POST') {
|
|
726
|
-
// Remove false invariant flags from observation-type memories
|
|
727
|
-
const pinned = await getPinnedMemories();
|
|
728
|
-
let cleaned = 0;
|
|
729
|
-
for (const mem of pinned) {
|
|
730
|
-
if (mem.type === 'observation' && mem.is_invariant) {
|
|
731
|
-
await setMemoryInvariant(mem.id, false);
|
|
732
|
-
cleaned++;
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
return { cleaned, total: pinned.length };
|
|
736
|
-
}
|
|
737
|
-
if (pathname === '/api/recall-by-tag' && method === 'POST') {
|
|
738
|
-
const { tag, limit = 5 } = body;
|
|
739
|
-
if (!tag) {
|
|
740
|
-
throw new ValidationError('tag required');
|
|
741
|
-
}
|
|
742
|
-
const results = await getMemoriesByTag(tag, limit);
|
|
743
|
-
return { results };
|
|
744
|
-
}
|
|
745
|
-
if (pathname === '/api/hook-rules' && method === 'POST') {
|
|
746
|
-
const { tool_name, tool_input: rawInput } = body;
|
|
747
|
-
if (!tool_name) {
|
|
748
|
-
throw new ValidationError('tool_name required');
|
|
749
|
-
}
|
|
750
|
-
const tool_input = rawInput && typeof rawInput === 'object' && !Array.isArray(rawInput)
|
|
751
|
-
? rawInput
|
|
752
|
-
: {};
|
|
753
|
-
// Check cache
|
|
754
|
-
const now = Date.now();
|
|
755
|
-
if (!hookRulesCache || now - hookRulesCache.timestamp > HOOK_RULES_CACHE_TTL) {
|
|
756
|
-
const memories = await getMemoriesByTag('hook-rule', 50);
|
|
757
|
-
hookRulesCache = { memories, timestamp: now };
|
|
758
|
-
}
|
|
759
|
-
const rules = matchRules(hookRulesCache.memories, tool_name, tool_input);
|
|
760
|
-
return { rules };
|
|
761
|
-
}
|
|
762
|
-
if (pathname === '/api/remember' && method === 'POST') {
|
|
763
|
-
const { content, tags = [], type = 'observation', source, global = false, valid_from, valid_until, } = body;
|
|
764
|
-
if (!content) {
|
|
765
|
-
throw new ValidationError('content required');
|
|
766
|
-
}
|
|
767
|
-
// In-flight dedup: if an identical request is already being processed, wait for it
|
|
768
|
-
// Prevents race condition when hooks fire twice for the same tool_use
|
|
769
|
-
const contentHash = content.slice(0, 200) + '|' + (tags || []).join(',');
|
|
770
|
-
const existing = rememberInFlight.get(contentHash);
|
|
771
|
-
if (existing) {
|
|
772
|
-
const result = await existing;
|
|
773
|
-
return { success: false, id: result.id, isDuplicate: true, reason: 'in-flight dedup' };
|
|
774
|
-
}
|
|
775
|
-
const processRemember = async () => {
|
|
776
|
-
// Check for sensitive content
|
|
777
|
-
const config = getConfig();
|
|
778
|
-
let finalContent = content;
|
|
779
|
-
if (config.sensitive_filter_enabled !== false) {
|
|
780
|
-
const scanResult = scanSensitive(content);
|
|
781
|
-
if (scanResult.hasSensitive) {
|
|
782
|
-
if (config.sensitive_auto_redact) {
|
|
783
|
-
finalContent = scanResult.redactedText;
|
|
784
|
-
}
|
|
785
|
-
else {
|
|
786
|
-
throw new ValidationError('Content contains sensitive information');
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
// Get embedding
|
|
791
|
-
const embedding = await getEmbedding(finalContent);
|
|
792
|
-
// Score quality
|
|
793
|
-
const qualityResult = await scoreMemory(finalContent);
|
|
794
|
-
if (!passesQualityThreshold(qualityResult)) {
|
|
795
|
-
return { success: false, reason: 'Below quality threshold', score: qualityResult.score };
|
|
796
|
-
}
|
|
797
|
-
// Save to appropriate DB
|
|
798
|
-
let result;
|
|
799
|
-
if (global) {
|
|
800
|
-
result = await saveGlobalMemory(finalContent, embedding, tags, type);
|
|
801
|
-
}
|
|
802
|
-
else {
|
|
803
|
-
result = await saveMemory(finalContent, embedding, tags, source ?? type, {
|
|
804
|
-
qualityScore: { score: qualityResult.score, factors: qualityResult.factors },
|
|
805
|
-
validFrom: valid_from,
|
|
806
|
-
validUntil: valid_until,
|
|
807
|
-
});
|
|
808
|
-
}
|
|
809
|
-
// Invalidate hook-rules cache if this memory is a hook rule
|
|
810
|
-
if (Array.isArray(tags) && tags.includes('hook-rule')) {
|
|
811
|
-
hookRulesCache = null;
|
|
812
|
-
}
|
|
813
|
-
return { success: !result.isDuplicate, id: result.id, isDuplicate: result.isDuplicate };
|
|
814
|
-
};
|
|
815
|
-
const promise = processRemember();
|
|
816
|
-
rememberInFlight.set(contentHash, promise);
|
|
817
|
-
setTimeout(() => rememberInFlight.delete(contentHash), REMEMBER_DEDUP_TTL_MS);
|
|
818
|
-
try {
|
|
819
|
-
return await promise;
|
|
820
|
-
}
|
|
821
|
-
finally {
|
|
822
|
-
rememberInFlight.delete(contentHash);
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
// Reflection endpoint
|
|
826
|
-
if (pathname === '/api/reflect' && method === 'POST') {
|
|
827
|
-
const { session_id } = body;
|
|
828
|
-
const watcherConfig = getIdleWatcherConfig();
|
|
829
|
-
if (session_id) {
|
|
830
|
-
const session = sessionManager.get(session_id);
|
|
831
|
-
if (!session) {
|
|
832
|
-
throw new NotFoundError('Session not found');
|
|
833
|
-
}
|
|
834
|
-
await handleReflection(session_id, session);
|
|
835
|
-
sessionManager.markReflection(session_id);
|
|
836
|
-
return { success: true, session_id };
|
|
837
|
-
}
|
|
838
|
-
else {
|
|
839
|
-
// Run for all idle sessions
|
|
840
|
-
const idleSessions = sessionManager.getIdleSessions(watcherConfig.idle_minutes);
|
|
841
|
-
for (const { sessionId, session } of idleSessions) {
|
|
842
|
-
await handleReflection(sessionId, session);
|
|
843
|
-
sessionManager.markReflection(sessionId);
|
|
844
|
-
}
|
|
845
|
-
return { success: true, sessions_processed: idleSessions.length };
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
// Compact briefing endpoint (for /compact hook)
|
|
849
|
-
// Supports pre-generated cache for instant responses
|
|
850
|
-
if (pathname === '/api/briefing' && method === 'POST') {
|
|
851
|
-
const { transcript, transcript_path, session_id, format, include_learnings, include_memories, max_memories, use_cache, } = body;
|
|
852
|
-
// Try cached briefing first if session_id provided and use_cache not explicitly false
|
|
853
|
-
if (session_id && use_cache !== false) {
|
|
854
|
-
const cached = briefingCache.get(session_id);
|
|
855
|
-
if (cached) {
|
|
856
|
-
const age = Date.now() - cached.generatedAt;
|
|
857
|
-
if (age < BRIEFING_CACHE_MAX_AGE_MS) {
|
|
858
|
-
log(`[briefing] Serving cached briefing for ${session_id.slice(0, 8)} (age: ${Math.round(age / 1000)}s)`);
|
|
859
|
-
return { success: true, briefing: cached.briefing, cached: true };
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
|
-
// Either transcript content or path to transcript file
|
|
864
|
-
let transcriptContent;
|
|
865
|
-
if (transcript) {
|
|
866
|
-
transcriptContent = transcript;
|
|
867
|
-
}
|
|
868
|
-
else if (transcript_path && fs.existsSync(transcript_path)) {
|
|
869
|
-
transcriptContent = fs.readFileSync(transcript_path, 'utf-8');
|
|
870
|
-
}
|
|
871
|
-
else {
|
|
872
|
-
throw new ValidationError('transcript or transcript_path required');
|
|
873
|
-
}
|
|
874
|
-
const result = await generateCompactBriefing(transcriptContent, {
|
|
875
|
-
format,
|
|
876
|
-
include_learnings,
|
|
877
|
-
include_memories,
|
|
878
|
-
max_memories,
|
|
879
|
-
});
|
|
880
|
-
// Cache the result if session_id provided
|
|
881
|
-
if (session_id && result.success && result.briefing && transcript_path) {
|
|
882
|
-
const stats = fs.existsSync(transcript_path) ? fs.statSync(transcript_path) : null;
|
|
883
|
-
briefingCache.set(session_id, {
|
|
884
|
-
briefing: result.briefing,
|
|
885
|
-
generatedAt: Date.now(),
|
|
886
|
-
transcriptSize: stats?.size || 0,
|
|
887
|
-
});
|
|
888
|
-
}
|
|
889
|
-
return { ...result, cached: false };
|
|
890
|
-
}
|
|
891
|
-
// Status endpoints
|
|
892
|
-
if (pathname === '/api/status' && method === 'GET') {
|
|
893
|
-
const stats = await getStats();
|
|
894
|
-
const memStats = await getMemoryStats();
|
|
895
|
-
const watchStatus = getWatcherStatus();
|
|
896
|
-
const analyzeStatus = getAnalyzerStatus();
|
|
897
|
-
return {
|
|
898
|
-
daemon: {
|
|
899
|
-
pid: process.pid,
|
|
900
|
-
uptime: Date.now() - (state?.startedAt || Date.now()),
|
|
901
|
-
sessions: sessionManager.count(),
|
|
902
|
-
},
|
|
903
|
-
index: stats,
|
|
904
|
-
memories: memStats,
|
|
905
|
-
services: {
|
|
906
|
-
watch: watchStatus,
|
|
907
|
-
analyze: analyzeStatus,
|
|
908
|
-
},
|
|
909
|
-
};
|
|
910
|
-
}
|
|
911
|
-
// Watch service endpoints
|
|
912
|
-
if (pathname === '/api/watch/start' && method === 'POST') {
|
|
913
|
-
const { patterns, includeCode } = body;
|
|
914
|
-
const watchState = await startWatcher({ patterns, includeCode }, log);
|
|
915
|
-
return {
|
|
916
|
-
success: true,
|
|
917
|
-
active: watchState.active,
|
|
918
|
-
patterns: watchState.patterns,
|
|
919
|
-
includeCode: watchState.includeCode,
|
|
920
|
-
};
|
|
921
|
-
}
|
|
922
|
-
if (pathname === '/api/watch/stop' && method === 'POST') {
|
|
923
|
-
await stopWatcher(log);
|
|
924
|
-
return { success: true };
|
|
925
|
-
}
|
|
926
|
-
if (pathname === '/api/watch/status' && method === 'GET') {
|
|
927
|
-
return getWatcherStatus();
|
|
928
|
-
}
|
|
929
|
-
if (pathname === '/api/watch/index' && method === 'POST') {
|
|
930
|
-
const { file } = body;
|
|
931
|
-
if (!file) {
|
|
932
|
-
throw new ValidationError('file required');
|
|
933
|
-
}
|
|
934
|
-
await indexFileOnDemand(file, log);
|
|
935
|
-
return { success: true, file };
|
|
936
|
-
}
|
|
937
|
-
// Analyze service endpoints
|
|
938
|
-
if (pathname === '/api/analyze/start' && method === 'POST') {
|
|
939
|
-
const { intervalMinutes, mode } = body;
|
|
940
|
-
const analyzeState = startAnalyzer({ intervalMinutes, mode }, log);
|
|
941
|
-
return {
|
|
942
|
-
success: true,
|
|
943
|
-
active: analyzeState.active,
|
|
944
|
-
runsCompleted: analyzeState.runsCompleted,
|
|
945
|
-
};
|
|
946
|
-
}
|
|
947
|
-
if (pathname === '/api/analyze/stop' && method === 'POST') {
|
|
948
|
-
stopAnalyzer(log);
|
|
949
|
-
return { success: true };
|
|
950
|
-
}
|
|
951
|
-
if (pathname === '/api/analyze/status' && method === 'GET') {
|
|
952
|
-
return getAnalyzerStatus();
|
|
953
|
-
}
|
|
954
|
-
if (pathname === '/api/analyze' && method === 'POST') {
|
|
955
|
-
const { mode = 'claude' } = body;
|
|
956
|
-
await triggerAnalysis(mode, log);
|
|
957
|
-
return { success: true };
|
|
958
|
-
}
|
|
959
|
-
// Skills endpoints
|
|
960
|
-
if (pathname === '/api/skills/suggest' && method === 'POST') {
|
|
961
|
-
const { prompt, limit = 2 } = body;
|
|
962
|
-
if (!prompt) {
|
|
963
|
-
throw new ValidationError('prompt required');
|
|
964
|
-
}
|
|
965
|
-
const { suggestSkills, getSkillsConfig } = await import('../lib/skills.js');
|
|
966
|
-
const config = getSkillsConfig();
|
|
967
|
-
if (!config.enabled || !config.auto_suggest?.enabled) {
|
|
968
|
-
return { success: true, skills: [], disabled: true };
|
|
969
|
-
}
|
|
970
|
-
const suggestions = await suggestSkills(prompt, config);
|
|
971
|
-
return {
|
|
972
|
-
success: true,
|
|
973
|
-
skills: suggestions.slice(0, limit),
|
|
974
|
-
};
|
|
975
|
-
}
|
|
976
|
-
if (pathname === '/api/skills/index' && method === 'POST') {
|
|
977
|
-
const { indexLocalSkills } = await import('../lib/skills.js');
|
|
978
|
-
const cwd = state?.cwd || process.cwd();
|
|
979
|
-
const count = indexLocalSkills(cwd);
|
|
980
|
-
return { success: true, indexed: count };
|
|
981
|
-
}
|
|
982
|
-
if (pathname === '/api/skills/track' && method === 'POST') {
|
|
983
|
-
const { skill_name } = body;
|
|
984
|
-
if (!skill_name) {
|
|
985
|
-
throw new ValidationError('skill_name required');
|
|
986
|
-
}
|
|
987
|
-
const { trackSkillUsage } = await import('../lib/skills.js');
|
|
988
|
-
trackSkillUsage(skill_name);
|
|
989
|
-
return { success: true };
|
|
990
|
-
}
|
|
991
|
-
// Skyll status endpoint
|
|
992
|
-
if (pathname === '/api/skills/skyll' && method === 'GET') {
|
|
993
|
-
const { getSkyllStatus } = await import('../lib/skyll-client.js');
|
|
994
|
-
return getSkyllStatus();
|
|
995
|
-
}
|
|
996
|
-
// Services endpoint (list all services status)
|
|
997
|
-
if (pathname === '/api/services' && method === 'GET') {
|
|
998
|
-
return {
|
|
999
|
-
watch: getWatcherStatus(),
|
|
1000
|
-
analyze: getAnalyzerStatus(),
|
|
1001
|
-
idle: {
|
|
1002
|
-
enabled: true,
|
|
1003
|
-
sessions: sessionManager.count(),
|
|
1004
|
-
},
|
|
1005
|
-
};
|
|
1006
|
-
}
|
|
1007
|
-
throw new NotFoundError(`Unknown endpoint: ${method} ${pathname}`);
|
|
256
|
+
return handler(body, searchParams);
|
|
1008
257
|
}
|
|
1009
|
-
// ============================================================================
|
|
1010
|
-
// Daemon Lifecycle
|
|
1011
|
-
// ============================================================================
|
|
1012
258
|
export async function startDaemon() {
|
|
1013
259
|
if (state?.server) {
|
|
1014
260
|
return { port: state.port, pid: process.pid };
|
|
1015
261
|
}
|
|
1016
|
-
// Check if another daemon is already running (prevent duplicate processes)
|
|
1017
262
|
const existingPidFile = getDaemonPidFile();
|
|
1018
263
|
if (fs.existsSync(existingPidFile)) {
|
|
1019
264
|
try {
|
|
1020
265
|
const existingPid = parseInt(fs.readFileSync(existingPidFile, 'utf8').trim(), 10);
|
|
1021
266
|
if (existingPid && existingPid !== process.pid) {
|
|
1022
|
-
// Check if process is actually running
|
|
1023
267
|
try {
|
|
1024
|
-
process.kill(existingPid, 0);
|
|
1025
|
-
// Process exists, read port and return
|
|
268
|
+
process.kill(existingPid, 0);
|
|
1026
269
|
const portFile = getDaemonPortFile();
|
|
1027
270
|
if (fs.existsSync(portFile)) {
|
|
1028
271
|
const port = parseInt(fs.readFileSync(portFile, 'utf8').trim(), 10);
|
|
1029
272
|
log(`[daemon] Another daemon already running (pid=${existingPid}, port=${port})`);
|
|
1030
|
-
process.exit(0);
|
|
273
|
+
process.exit(0);
|
|
1031
274
|
}
|
|
1032
275
|
}
|
|
1033
|
-
catch {
|
|
1034
|
-
|
|
276
|
+
catch (error) {
|
|
277
|
+
logWarn('service', 'Failed to signal existing daemon process for liveness check', {
|
|
278
|
+
error: error instanceof Error ? error.message : String(error),
|
|
279
|
+
});
|
|
1035
280
|
log(`[daemon] Cleaning up stale PID file (pid=${existingPid} not running)`);
|
|
1036
281
|
fs.unlinkSync(existingPidFile);
|
|
1037
282
|
const portFile = getDaemonPortFile();
|
|
@@ -1050,15 +295,10 @@ export async function startDaemon() {
|
|
|
1050
295
|
const cwd = getProjectRoot();
|
|
1051
296
|
const watcherConfig = getIdleWatcherConfig();
|
|
1052
297
|
getIdleReflectionConfig();
|
|
1053
|
-
// Initialize storage dispatcher (routes to SQLite or PG based on config)
|
|
1054
298
|
await initStorageDispatcher();
|
|
1055
|
-
// Initialize session manager
|
|
1056
299
|
sessionManager = createSessionManager();
|
|
1057
|
-
// Load token budgets from previous daemon run
|
|
1058
300
|
loadBudgets();
|
|
1059
|
-
|
|
1060
|
-
cleanupStaleObservations();
|
|
1061
|
-
// Create HTTP server
|
|
301
|
+
initReflectionMaintenance();
|
|
1062
302
|
const server = http.createServer((req, res) => {
|
|
1063
303
|
handleRequest(req, res).catch((err) => {
|
|
1064
304
|
log(`[http] Unhandled error: ${err.message}`);
|
|
@@ -1066,14 +306,25 @@ export async function startDaemon() {
|
|
|
1066
306
|
res.end();
|
|
1067
307
|
});
|
|
1068
308
|
});
|
|
1069
|
-
//
|
|
1070
|
-
const
|
|
1071
|
-
|
|
1072
|
-
|
|
309
|
+
// Try stable port first (config or hash-based), then fall back to scan
|
|
310
|
+
const config = getConfig();
|
|
311
|
+
const stablePort = config.daemon?.port ?? getStablePort(cwd);
|
|
312
|
+
const fallbackStart = config.daemon?.port_range_start ?? DEFAULT_PORT_RANGE_START;
|
|
313
|
+
let port = stablePort;
|
|
314
|
+
let portAttempts = 0;
|
|
315
|
+
const maxAttempts = 1 + MAX_PORT_ATTEMPTS; // 1 stable + 100 fallback
|
|
316
|
+
for (let i = 0; i < maxAttempts; i++) {
|
|
1073
317
|
await new Promise((resolve, reject) => {
|
|
1074
318
|
server.once('error', (err) => {
|
|
1075
319
|
if (err.code === 'EADDRINUSE') {
|
|
1076
|
-
|
|
320
|
+
portAttempts++;
|
|
321
|
+
if (portAttempts === 1) {
|
|
322
|
+
// Stable port busy — switch to fallback range
|
|
323
|
+
port = fallbackStart;
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
port++;
|
|
327
|
+
}
|
|
1077
328
|
resolve();
|
|
1078
329
|
}
|
|
1079
330
|
else {
|
|
@@ -1089,33 +340,28 @@ export async function startDaemon() {
|
|
|
1089
340
|
}
|
|
1090
341
|
}
|
|
1091
342
|
if (!server.listening) {
|
|
1092
|
-
throw new NetworkError(`Could not find available port
|
|
343
|
+
throw new NetworkError(`Could not find available port (tried ${stablePort}, then ${fallbackStart}-${fallbackStart + MAX_PORT_ATTEMPTS})`);
|
|
1093
344
|
}
|
|
1094
|
-
// Save state
|
|
1095
345
|
state = {
|
|
1096
346
|
cwd,
|
|
1097
347
|
startedAt: Date.now(),
|
|
1098
348
|
port,
|
|
1099
349
|
server,
|
|
1100
350
|
};
|
|
1101
|
-
// Write PID and port files
|
|
1102
351
|
fs.writeFileSync(getDaemonPidFile(), String(process.pid));
|
|
1103
352
|
fs.writeFileSync(getDaemonPortFile(), String(port));
|
|
1104
|
-
// Start idle watcher with briefing pre-generation
|
|
1105
353
|
idleWatcher = createIdleWatcher({
|
|
1106
354
|
sessionManager,
|
|
1107
|
-
onIdle:
|
|
1108
|
-
onPreGenerateBriefing: preGenerateBriefing,
|
|
355
|
+
onIdle: (sessionId, session) => performReflection(createRouteContext(), sessionId, session),
|
|
356
|
+
onPreGenerateBriefing: (sessionId, transcriptPath) => preGenerateBriefing(createRouteContext(), sessionId, transcriptPath),
|
|
1109
357
|
checkIntervalSeconds: watcherConfig.check_interval,
|
|
1110
358
|
idleMinutes: watcherConfig.idle_minutes,
|
|
1111
359
|
reflectionCooldownMinutes: watcherConfig.reflection_cooldown_minutes,
|
|
1112
|
-
preGenerateIdleSeconds: 120,
|
|
360
|
+
preGenerateIdleSeconds: 120,
|
|
1113
361
|
log,
|
|
1114
362
|
});
|
|
1115
363
|
idleWatcher.start();
|
|
1116
364
|
log(`[daemon] Started on port ${port} (pid=${process.pid})`);
|
|
1117
|
-
// Auto-start watch service if configured
|
|
1118
|
-
const config = getConfig();
|
|
1119
365
|
if (config.daemon?.watch?.auto_start) {
|
|
1120
366
|
const watchConfig = config.daemon.watch;
|
|
1121
367
|
await startWatcher({
|
|
@@ -1125,7 +371,6 @@ export async function startDaemon() {
|
|
|
1125
371
|
}, log);
|
|
1126
372
|
log(`[daemon] Auto-started watch service`);
|
|
1127
373
|
}
|
|
1128
|
-
// Auto-start analyze service if configured
|
|
1129
374
|
if (config.daemon?.analyze?.auto_start) {
|
|
1130
375
|
const analyzeConfig = config.daemon.analyze;
|
|
1131
376
|
startAnalyzer({
|
|
@@ -1134,7 +379,6 @@ export async function startDaemon() {
|
|
|
1134
379
|
}, log);
|
|
1135
380
|
log(`[daemon] Auto-started analyze service`);
|
|
1136
381
|
}
|
|
1137
|
-
// Setup graceful shutdown
|
|
1138
382
|
setupShutdownHandlers();
|
|
1139
383
|
return { port, pid: process.pid };
|
|
1140
384
|
}
|
|
@@ -1142,14 +386,18 @@ function setupShutdownHandlers() {
|
|
|
1142
386
|
const shutdown = () => shutdownDaemon();
|
|
1143
387
|
process.on('SIGTERM', shutdown);
|
|
1144
388
|
process.on('SIGINT', shutdown);
|
|
1145
|
-
// SIGHUP only exists on Unix
|
|
1146
389
|
if (process.platform !== 'win32') {
|
|
1147
390
|
process.on('SIGHUP', shutdown);
|
|
1148
391
|
}
|
|
392
|
+
// Prevent silent crashes — log and keep running
|
|
393
|
+
process.on('uncaughtException', (err) => {
|
|
394
|
+
log(`[daemon] UNCAUGHT EXCEPTION: ${err.message}\n${err.stack}`);
|
|
395
|
+
});
|
|
396
|
+
process.on('unhandledRejection', (reason) => {
|
|
397
|
+
const msg = reason instanceof Error ? `${reason.message}\n${reason.stack}` : String(reason);
|
|
398
|
+
log(`[daemon] UNHANDLED REJECTION: ${msg}`);
|
|
399
|
+
});
|
|
1149
400
|
}
|
|
1150
|
-
/**
|
|
1151
|
-
* Check if daemon should shutdown (no sessions and no pending work)
|
|
1152
|
-
*/
|
|
1153
401
|
function checkShutdown() {
|
|
1154
402
|
if (sessionManager?.canShutdown()) {
|
|
1155
403
|
log(`[daemon] No more sessions and no pending work, scheduling shutdown`);
|
|
@@ -1157,54 +405,52 @@ function checkShutdown() {
|
|
|
1157
405
|
if (sessionManager?.canShutdown()) {
|
|
1158
406
|
shutdownDaemon();
|
|
1159
407
|
}
|
|
1160
|
-
}, 5000);
|
|
408
|
+
}, 5000);
|
|
1161
409
|
}
|
|
1162
410
|
}
|
|
1163
|
-
export function shutdownDaemon() {
|
|
411
|
+
export async function shutdownDaemon() {
|
|
1164
412
|
log('[daemon] Shutting down...');
|
|
1165
|
-
// Stop idle watcher
|
|
1166
413
|
if (idleWatcher) {
|
|
1167
414
|
idleWatcher.stop();
|
|
1168
415
|
idleWatcher = null;
|
|
1169
416
|
}
|
|
1170
|
-
|
|
1171
|
-
stopWatcher(log).catch((err) => log(`[shutdown] Watcher stop failed: ${err}`));
|
|
1172
|
-
// Stop analyze service
|
|
417
|
+
const watcherPromise = stopWatcher(log).catch((err) => log(`[shutdown] Watcher stop failed: ${err}`));
|
|
1173
418
|
stopAnalyzer(log);
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
419
|
+
const serverPromise = state?.server
|
|
420
|
+
? new Promise((resolve) => {
|
|
421
|
+
state.server.close(() => resolve());
|
|
422
|
+
state.server = null;
|
|
423
|
+
})
|
|
424
|
+
: Promise.resolve();
|
|
1180
425
|
processRegistry.killAll();
|
|
1181
|
-
//
|
|
1182
|
-
|
|
426
|
+
// Wait for watcher and HTTP server to finish before closing storage,
|
|
427
|
+
// so in-flight requests don't hit a closed DB.
|
|
428
|
+
await Promise.allSettled([watcherPromise, serverPromise]);
|
|
429
|
+
await closeStorageDispatcher().catch((err) => log(`[shutdown] Storage close failed: ${err}`));
|
|
1183
430
|
cleanupEmbeddings();
|
|
431
|
+
await cleanupReranker().catch((err) => log(`[shutdown] Reranker cleanup failed: ${err}`));
|
|
1184
432
|
cleanupQualityScoring();
|
|
1185
433
|
closeDb();
|
|
1186
434
|
closeGlobalDb();
|
|
1187
|
-
// Remove PID and port files
|
|
1188
435
|
try {
|
|
1189
436
|
fs.unlinkSync(getDaemonPidFile());
|
|
1190
437
|
}
|
|
1191
438
|
catch (err) {
|
|
1192
|
-
if (err.code !== 'ENOENT')
|
|
1193
|
-
log(`[shutdown] PID file removal failed: ${err}`);
|
|
439
|
+
if (!isErrnoException(err) || err.code !== 'ENOENT') {
|
|
440
|
+
log(`[shutdown] PID file removal failed: ${getErrorMessage(err)}`);
|
|
441
|
+
}
|
|
1194
442
|
}
|
|
1195
443
|
try {
|
|
1196
444
|
fs.unlinkSync(getDaemonPortFile());
|
|
1197
445
|
}
|
|
1198
446
|
catch (err) {
|
|
1199
|
-
if (err.code !== 'ENOENT')
|
|
1200
|
-
log(`[shutdown] Port file removal failed: ${err}`);
|
|
447
|
+
if (!isErrnoException(err) || err.code !== 'ENOENT') {
|
|
448
|
+
log(`[shutdown] Port file removal failed: ${getErrorMessage(err)}`);
|
|
449
|
+
}
|
|
1201
450
|
}
|
|
1202
451
|
log('[daemon] Shutdown complete');
|
|
1203
452
|
process.exit(0);
|
|
1204
453
|
}
|
|
1205
|
-
// ============================================================================
|
|
1206
|
-
// Test Helpers (exported for unit testing)
|
|
1207
|
-
// ============================================================================
|
|
1208
454
|
/** @internal Initialize module state for testing without starting HTTP server */
|
|
1209
455
|
export function _initTestState(cwd = process.cwd()) {
|
|
1210
456
|
sessionManager = createSessionManager();
|
|
@@ -1215,13 +461,10 @@ export function _resetTestState() {
|
|
|
1215
461
|
sessionManager = null;
|
|
1216
462
|
idleWatcher = null;
|
|
1217
463
|
state = null;
|
|
1218
|
-
|
|
1219
|
-
|
|
464
|
+
resetReflectionRoutesState();
|
|
465
|
+
resetMemoryRoutesState();
|
|
466
|
+
resetSearchRoutesState();
|
|
1220
467
|
}
|
|
1221
|
-
// ============================================================================
|
|
1222
|
-
// CLI Entry Point
|
|
1223
|
-
// ============================================================================
|
|
1224
|
-
// If run directly, start daemon
|
|
1225
468
|
if (process.argv[1]?.endsWith('service.js') || process.argv[1]?.endsWith('service.ts')) {
|
|
1226
469
|
startDaemon()
|
|
1227
470
|
.then(({ port, pid }) => {
|