synabun 1.3.0 → 2.0.0-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +197 -662
- package/LICENSE-COMMERCIAL.md +33 -0
- package/NOTICE +17 -0
- package/README.md +175 -853
- package/THIRD-PARTY-LICENSES.md +131 -0
- package/benchmarks/browser-live-results.json +79 -0
- package/benchmarks/browser-v2-results.json +258 -0
- package/benchmarks/fixtures/browser/README.md +57 -0
- package/benchmarks/fixtures/browser/page-state.json +132 -0
- package/benchmarks/fixtures/browser/social.json +92 -0
- package/benchmarks/fixtures/browser/target.json +319 -0
- package/benchmarks/fixtures/desktop/README.md +58 -0
- package/benchmarks/fixtures/desktop/abstention.json +59 -0
- package/benchmarks/fixtures/desktop/adversarial.json +22 -0
- package/benchmarks/fixtures/desktop/forbidden.json +93 -0
- package/benchmarks/fixtures/desktop/generate.mjs +1023 -0
- package/benchmarks/fixtures/desktop/target.json +136 -0
- package/bin/synabun.js +30 -0
- package/docs/browser-v2.md +109 -0
- package/docs/hook-integrity.md +89 -0
- package/docs/judgments.md +182 -0
- package/docs/style-guide.md +246 -0
- package/docs/whatsapp.md +325 -0
- package/hooks/claude-code/post-plan.mjs +613 -391
- package/hooks/claude-code/post-remember.mjs +246 -122
- package/hooks/claude-code/pre-compact.mjs +171 -110
- package/hooks/claude-code/pre-task.mjs +133 -0
- package/hooks/claude-code/pre-websearch.mjs +15 -4
- package/hooks/claude-code/prompt-origin.mjs +94 -0
- package/hooks/claude-code/prompt-submit.mjs +1244 -861
- package/hooks/claude-code/session-start.mjs +114 -156
- package/hooks/claude-code/shared.mjs +1228 -368
- package/hooks/claude-code/state.mjs +167 -0
- package/hooks/claude-code/stop.mjs +515 -140
- package/hooks/claude-code/subagent-start.mjs +154 -0
- package/hooks/claude-code/subagent-stop.mjs +102 -0
- package/hooks/claude-code/task-gate.mjs +150 -0
- package/lib/claude-hooks.js +84 -0
- package/lib/claude-usage-audit.js +141 -0
- package/lib/client-config-repair.js +144 -0
- package/lib/data-home-migration.js +498 -0
- package/lib/first-launch-protection.js +240 -0
- package/lib/paths.d.ts +21 -0
- package/lib/paths.js +103 -0
- package/mcp-server/dist/config.d.ts +22 -0
- package/mcp-server/dist/config.d.ts.map +1 -0
- package/mcp-server/dist/config.js +109 -0
- package/mcp-server/dist/config.js.map +1 -0
- package/mcp-server/dist/http.d.ts +30 -0
- package/mcp-server/dist/http.d.ts.map +1 -0
- package/mcp-server/dist/http.js +276 -0
- package/mcp-server/dist/http.js.map +1 -0
- package/mcp-server/dist/index.d.ts +48 -0
- package/mcp-server/dist/index.d.ts.map +1 -0
- package/mcp-server/dist/index.js +538 -0
- package/mcp-server/dist/index.js.map +1 -0
- package/mcp-server/dist/preload-http.d.ts +3 -0
- package/mcp-server/dist/preload-http.d.ts.map +1 -0
- package/mcp-server/dist/preload-http.js +28 -0
- package/mcp-server/dist/preload-http.js.map +1 -0
- package/mcp-server/dist/preload.d.ts +3 -0
- package/mcp-server/dist/preload.d.ts.map +1 -0
- package/mcp-server/dist/preload.js +32 -0
- package/mcp-server/dist/preload.js.map +1 -0
- package/mcp-server/dist/scripts/migrate-qdrant-to-sqlite.d.ts +19 -0
- package/mcp-server/dist/scripts/migrate-qdrant-to-sqlite.d.ts.map +1 -0
- package/mcp-server/dist/scripts/migrate-qdrant-to-sqlite.js +403 -0
- package/mcp-server/dist/scripts/migrate-qdrant-to-sqlite.js.map +1 -0
- package/mcp-server/dist/scripts/setup-embeddings.d.ts +3 -0
- package/mcp-server/dist/scripts/setup-embeddings.d.ts.map +1 -0
- package/mcp-server/dist/scripts/setup-embeddings.js +15 -0
- package/mcp-server/dist/scripts/setup-embeddings.js.map +1 -0
- package/mcp-server/dist/services/assistant-judgments.d.ts +79 -0
- package/mcp-server/dist/services/assistant-judgments.d.ts.map +1 -0
- package/mcp-server/dist/services/assistant-judgments.js +128 -0
- package/mcp-server/dist/services/assistant-judgments.js.map +1 -0
- package/mcp-server/dist/services/browser-assist-gate.d.ts +314 -0
- package/mcp-server/dist/services/browser-assist-gate.d.ts.map +1 -0
- package/mcp-server/dist/services/browser-assist-gate.js +344 -0
- package/mcp-server/dist/services/browser-assist-gate.js.map +1 -0
- package/mcp-server/dist/services/browser-assist.d.ts +104 -0
- package/mcp-server/dist/services/browser-assist.d.ts.map +1 -0
- package/mcp-server/dist/services/browser-assist.js +282 -0
- package/mcp-server/dist/services/browser-assist.js.map +1 -0
- package/mcp-server/dist/services/browser-bench.d.ts +772 -0
- package/mcp-server/dist/services/browser-bench.d.ts.map +1 -0
- package/mcp-server/dist/services/browser-bench.js +424 -0
- package/mcp-server/dist/services/browser-bench.js.map +1 -0
- package/mcp-server/dist/services/browser-judgments.d.ts +196 -0
- package/mcp-server/dist/services/browser-judgments.d.ts.map +1 -0
- package/mcp-server/dist/services/browser-judgments.js +363 -0
- package/mcp-server/dist/services/browser-judgments.js.map +1 -0
- package/mcp-server/dist/services/browser-risk.d.ts +166 -0
- package/mcp-server/dist/services/browser-risk.d.ts.map +1 -0
- package/mcp-server/dist/services/browser-risk.js +458 -0
- package/mcp-server/dist/services/browser-risk.js.map +1 -0
- package/mcp-server/dist/services/categories.d.ts +61 -0
- package/mcp-server/dist/services/categories.d.ts.map +1 -0
- package/mcp-server/dist/services/categories.js +377 -0
- package/mcp-server/dist/services/categories.js.map +1 -0
- package/mcp-server/dist/services/codex-config-heal.d.ts +49 -0
- package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -0
- package/mcp-server/dist/services/codex-config-heal.js +346 -0
- package/mcp-server/dist/services/codex-config-heal.js.map +1 -0
- package/mcp-server/dist/services/desktop-assist-gate.d.ts +198 -0
- package/mcp-server/dist/services/desktop-assist-gate.d.ts.map +1 -0
- package/mcp-server/dist/services/desktop-assist-gate.js +202 -0
- package/mcp-server/dist/services/desktop-assist-gate.js.map +1 -0
- package/mcp-server/dist/services/desktop-assist.d.ts +104 -0
- package/mcp-server/dist/services/desktop-assist.d.ts.map +1 -0
- package/mcp-server/dist/services/desktop-assist.js +266 -0
- package/mcp-server/dist/services/desktop-assist.js.map +1 -0
- package/mcp-server/dist/services/desktop-bench.d.ts +553 -0
- package/mcp-server/dist/services/desktop-bench.d.ts.map +1 -0
- package/mcp-server/dist/services/desktop-bench.js +311 -0
- package/mcp-server/dist/services/desktop-bench.js.map +1 -0
- package/mcp-server/dist/services/desktop-client.d.ts +23 -0
- package/mcp-server/dist/services/desktop-client.d.ts.map +1 -0
- package/mcp-server/dist/services/desktop-client.js +79 -0
- package/mcp-server/dist/services/desktop-client.js.map +1 -0
- package/mcp-server/dist/services/desktop-judgments.d.ts +125 -0
- package/mcp-server/dist/services/desktop-judgments.d.ts.map +1 -0
- package/mcp-server/dist/services/desktop-judgments.js +177 -0
- package/mcp-server/dist/services/desktop-judgments.js.map +1 -0
- package/mcp-server/dist/services/desktop-risk.d.ts +283 -0
- package/mcp-server/dist/services/desktop-risk.d.ts.map +1 -0
- package/mcp-server/dist/services/desktop-risk.js +605 -0
- package/mcp-server/dist/services/desktop-risk.js.map +1 -0
- package/mcp-server/dist/services/discord.d.ts +112 -0
- package/mcp-server/dist/services/discord.d.ts.map +1 -0
- package/mcp-server/dist/services/discord.js +477 -0
- package/mcp-server/dist/services/discord.js.map +1 -0
- package/mcp-server/dist/services/edit-stale.d.ts +81 -0
- package/mcp-server/dist/services/edit-stale.d.ts.map +1 -0
- package/mcp-server/dist/services/edit-stale.js +358 -0
- package/mcp-server/dist/services/edit-stale.js.map +1 -0
- package/mcp-server/dist/services/embedding-service.d.ts +16 -0
- package/mcp-server/dist/services/embedding-service.d.ts.map +1 -0
- package/mcp-server/dist/services/embedding-service.js +126 -0
- package/mcp-server/dist/services/embedding-service.js.map +1 -0
- package/mcp-server/dist/services/embedding-worker.d.ts +2 -0
- package/mcp-server/dist/services/embedding-worker.d.ts.map +1 -0
- package/mcp-server/dist/services/embedding-worker.js +52 -0
- package/mcp-server/dist/services/embedding-worker.js.map +1 -0
- package/mcp-server/dist/services/fb-regions.d.ts +71 -0
- package/mcp-server/dist/services/fb-regions.d.ts.map +1 -0
- package/mcp-server/dist/services/fb-regions.js +211 -0
- package/mcp-server/dist/services/fb-regions.js.map +1 -0
- package/mcp-server/dist/services/file-checksums.d.ts +22 -0
- package/mcp-server/dist/services/file-checksums.d.ts.map +1 -0
- package/mcp-server/dist/services/file-checksums.js +55 -0
- package/mcp-server/dist/services/file-checksums.js.map +1 -0
- package/mcp-server/dist/services/file-excerpt.d.ts +24 -0
- package/mcp-server/dist/services/file-excerpt.d.ts.map +1 -0
- package/mcp-server/dist/services/file-excerpt.js +65 -0
- package/mcp-server/dist/services/file-excerpt.js.map +1 -0
- package/mcp-server/dist/services/identity.d.ts +124 -0
- package/mcp-server/dist/services/identity.d.ts.map +1 -0
- package/mcp-server/dist/services/identity.js +241 -0
- package/mcp-server/dist/services/identity.js.map +1 -0
- package/mcp-server/dist/services/local-embeddings.d.ts +2 -0
- package/mcp-server/dist/services/local-embeddings.d.ts.map +1 -0
- package/mcp-server/dist/services/local-embeddings.js +3 -0
- package/mcp-server/dist/services/local-embeddings.js.map +1 -0
- package/mcp-server/dist/services/memory-client.d.ts +4 -0
- package/mcp-server/dist/services/memory-client.d.ts.map +1 -0
- package/mcp-server/dist/services/memory-client.js +27 -0
- package/mcp-server/dist/services/memory-client.js.map +1 -0
- package/mcp-server/dist/services/memory-judge-backfill.d.ts +135 -0
- package/mcp-server/dist/services/memory-judge-backfill.d.ts.map +1 -0
- package/mcp-server/dist/services/memory-judge-backfill.js +510 -0
- package/mcp-server/dist/services/memory-judge-backfill.js.map +1 -0
- package/mcp-server/dist/services/memory-judgments.d.ts +362 -0
- package/mcp-server/dist/services/memory-judgments.d.ts.map +1 -0
- package/mcp-server/dist/services/memory-judgments.js +674 -0
- package/mcp-server/dist/services/memory-judgments.js.map +1 -0
- package/mcp-server/dist/services/memory-maintenance.d.ts +108 -0
- package/mcp-server/dist/services/memory-maintenance.d.ts.map +1 -0
- package/mcp-server/dist/services/memory-maintenance.js +403 -0
- package/mcp-server/dist/services/memory-maintenance.js.map +1 -0
- package/mcp-server/dist/services/memory-retrieval.d.ts +66 -0
- package/mcp-server/dist/services/memory-retrieval.d.ts.map +1 -0
- package/mcp-server/dist/services/memory-retrieval.js +412 -0
- package/mcp-server/dist/services/memory-retrieval.js.map +1 -0
- package/mcp-server/dist/services/memory-schema.d.ts +16 -0
- package/mcp-server/dist/services/memory-schema.d.ts.map +1 -0
- package/mcp-server/dist/services/memory-schema.js +282 -0
- package/mcp-server/dist/services/memory-schema.js.map +1 -0
- package/mcp-server/dist/services/memory-sessions.d.ts +24 -0
- package/mcp-server/dist/services/memory-sessions.d.ts.map +1 -0
- package/mcp-server/dist/services/memory-sessions.js +110 -0
- package/mcp-server/dist/services/memory-sessions.js.map +1 -0
- package/mcp-server/dist/services/memory-triage.d.ts +60 -0
- package/mcp-server/dist/services/memory-triage.d.ts.map +1 -0
- package/mcp-server/dist/services/memory-triage.js +189 -0
- package/mcp-server/dist/services/memory-triage.js.map +1 -0
- package/mcp-server/dist/services/memory-verification.d.ts +24 -0
- package/mcp-server/dist/services/memory-verification.d.ts.map +1 -0
- package/mcp-server/dist/services/memory-verification.js +92 -0
- package/mcp-server/dist/services/memory-verification.js.map +1 -0
- package/mcp-server/dist/services/memory-writer.d.ts +26 -0
- package/mcp-server/dist/services/memory-writer.d.ts.map +1 -0
- package/mcp-server/dist/services/memory-writer.js +126 -0
- package/mcp-server/dist/services/memory-writer.js.map +1 -0
- package/mcp-server/dist/services/neural-interface.d.ts +439 -0
- package/mcp-server/dist/services/neural-interface.d.ts.map +1 -0
- package/mcp-server/dist/services/neural-interface.js +1135 -0
- package/mcp-server/dist/services/neural-interface.js.map +1 -0
- package/mcp-server/dist/services/profiles.d.ts +120 -0
- package/mcp-server/dist/services/profiles.d.ts.map +1 -0
- package/mcp-server/dist/services/profiles.js +387 -0
- package/mcp-server/dist/services/profiles.js.map +1 -0
- package/mcp-server/dist/services/secret-gate.d.ts +29 -0
- package/mcp-server/dist/services/secret-gate.d.ts.map +1 -0
- package/mcp-server/dist/services/secret-gate.js +43 -0
- package/mcp-server/dist/services/secret-gate.js.map +1 -0
- package/mcp-server/dist/services/server-instructions.d.ts +10 -0
- package/mcp-server/dist/services/server-instructions.d.ts.map +1 -0
- package/mcp-server/dist/services/server-instructions.js +101 -0
- package/mcp-server/dist/services/server-instructions.js.map +1 -0
- package/mcp-server/dist/services/sqlite.d.ts +235 -0
- package/mcp-server/dist/services/sqlite.d.ts.map +1 -0
- package/mcp-server/dist/services/sqlite.js +1185 -0
- package/mcp-server/dist/services/sqlite.js.map +1 -0
- package/mcp-server/dist/services/typesafe-bench.d.ts +99 -0
- package/mcp-server/dist/services/typesafe-bench.d.ts.map +1 -0
- package/mcp-server/dist/services/typesafe-bench.js +218 -0
- package/mcp-server/dist/services/typesafe-bench.js.map +1 -0
- package/mcp-server/dist/services/typesafe-config.d.ts +342 -0
- package/mcp-server/dist/services/typesafe-config.d.ts.map +1 -0
- package/mcp-server/dist/services/typesafe-config.js +746 -0
- package/mcp-server/dist/services/typesafe-config.js.map +1 -0
- package/mcp-server/dist/services/typesafe.d.ts +213 -0
- package/mcp-server/dist/services/typesafe.d.ts.map +1 -0
- package/mcp-server/dist/services/typesafe.js +330 -0
- package/mcp-server/dist/services/typesafe.js.map +1 -0
- package/mcp-server/dist/services/vector-cache.d.ts +68 -0
- package/mcp-server/dist/services/vector-cache.d.ts.map +1 -0
- package/mcp-server/dist/services/vector-cache.js +271 -0
- package/mcp-server/dist/services/vector-cache.js.map +1 -0
- package/mcp-server/dist/services/whiteboard-geometry.d.ts +305 -0
- package/mcp-server/dist/services/whiteboard-geometry.d.ts.map +1 -0
- package/mcp-server/dist/services/whiteboard-geometry.js +666 -0
- package/mcp-server/dist/services/whiteboard-geometry.js.map +1 -0
- package/mcp-server/dist/tools/agents.d.ts +212 -0
- package/mcp-server/dist/tools/agents.d.ts.map +1 -0
- package/mcp-server/dist/tools/agents.js +407 -0
- package/mcp-server/dist/tools/agents.js.map +1 -0
- package/mcp-server/dist/tools/bluesky.d.ts +39 -0
- package/mcp-server/dist/tools/bluesky.d.ts.map +1 -0
- package/mcp-server/dist/tools/bluesky.js +1144 -0
- package/mcp-server/dist/tools/bluesky.js.map +1 -0
- package/mcp-server/dist/tools/browser-advanced.d.ts +58 -0
- package/mcp-server/dist/tools/browser-advanced.d.ts.map +1 -0
- package/mcp-server/dist/tools/browser-advanced.js +106 -0
- package/mcp-server/dist/tools/browser-advanced.js.map +1 -0
- package/mcp-server/dist/tools/browser-batch.d.ts +99 -0
- package/mcp-server/dist/tools/browser-batch.d.ts.map +1 -0
- package/mcp-server/dist/tools/browser-batch.js +187 -0
- package/mcp-server/dist/tools/browser-batch.js.map +1 -0
- package/mcp-server/dist/tools/browser-cheatsheet.d.ts +21 -0
- package/mcp-server/dist/tools/browser-cheatsheet.d.ts.map +1 -0
- package/mcp-server/dist/tools/browser-cheatsheet.js +144 -0
- package/mcp-server/dist/tools/browser-cheatsheet.js.map +1 -0
- package/mcp-server/dist/tools/browser-interact.d.ts +239 -0
- package/mcp-server/dist/tools/browser-interact.d.ts.map +1 -0
- package/mcp-server/dist/tools/browser-interact.js +300 -0
- package/mcp-server/dist/tools/browser-interact.js.map +1 -0
- package/mcp-server/dist/tools/browser-navigate.d.ts +90 -0
- package/mcp-server/dist/tools/browser-navigate.d.ts.map +1 -0
- package/mcp-server/dist/tools/browser-navigate.js +142 -0
- package/mcp-server/dist/tools/browser-navigate.js.map +1 -0
- package/mcp-server/dist/tools/browser-observe.d.ts +561 -0
- package/mcp-server/dist/tools/browser-observe.d.ts.map +1 -0
- package/mcp-server/dist/tools/browser-observe.js +2009 -0
- package/mcp-server/dist/tools/browser-observe.js.map +1 -0
- package/mcp-server/dist/tools/browser.d.ts +34 -0
- package/mcp-server/dist/tools/browser.d.ts.map +1 -0
- package/mcp-server/dist/tools/browser.js +112 -0
- package/mcp-server/dist/tools/browser.js.map +1 -0
- package/mcp-server/dist/tools/card-tools.d.ts +82 -0
- package/mcp-server/dist/tools/card-tools.d.ts.map +1 -0
- package/mcp-server/dist/tools/card-tools.js +137 -0
- package/mcp-server/dist/tools/card-tools.js.map +1 -0
- package/mcp-server/dist/tools/card.d.ts +8 -0
- package/mcp-server/dist/tools/card.d.ts.map +1 -0
- package/mcp-server/dist/tools/card.js +16 -0
- package/mcp-server/dist/tools/card.js.map +1 -0
- package/mcp-server/dist/tools/category.d.ts +32 -0
- package/mcp-server/dist/tools/category.d.ts.map +1 -0
- package/mcp-server/dist/tools/category.js +290 -0
- package/mcp-server/dist/tools/category.js.map +1 -0
- package/mcp-server/dist/tools/choice.d.ts +160 -0
- package/mcp-server/dist/tools/choice.d.ts.map +1 -0
- package/mcp-server/dist/tools/choice.js +80 -0
- package/mcp-server/dist/tools/choice.js.map +1 -0
- package/mcp-server/dist/tools/computer.d.ts +71 -0
- package/mcp-server/dist/tools/computer.d.ts.map +1 -0
- package/mcp-server/dist/tools/computer.js +174 -0
- package/mcp-server/dist/tools/computer.js.map +1 -0
- package/mcp-server/dist/tools/discord-channel.d.ts +44 -0
- package/mcp-server/dist/tools/discord-channel.d.ts.map +1 -0
- package/mcp-server/dist/tools/discord-channel.js +236 -0
- package/mcp-server/dist/tools/discord-channel.js.map +1 -0
- package/mcp-server/dist/tools/discord-guild.d.ts +20 -0
- package/mcp-server/dist/tools/discord-guild.d.ts.map +1 -0
- package/mcp-server/dist/tools/discord-guild.js +138 -0
- package/mcp-server/dist/tools/discord-guild.js.map +1 -0
- package/mcp-server/dist/tools/discord-member.d.ts +26 -0
- package/mcp-server/dist/tools/discord-member.d.ts.map +1 -0
- package/mcp-server/dist/tools/discord-member.js +122 -0
- package/mcp-server/dist/tools/discord-member.js.map +1 -0
- package/mcp-server/dist/tools/discord-message.d.ts +36 -0
- package/mcp-server/dist/tools/discord-message.d.ts.map +1 -0
- package/mcp-server/dist/tools/discord-message.js +184 -0
- package/mcp-server/dist/tools/discord-message.js.map +1 -0
- package/mcp-server/dist/tools/discord-onboarding.d.ts +32 -0
- package/mcp-server/dist/tools/discord-onboarding.d.ts.map +1 -0
- package/mcp-server/dist/tools/discord-onboarding.js +179 -0
- package/mcp-server/dist/tools/discord-onboarding.js.map +1 -0
- package/mcp-server/dist/tools/discord-role.d.ts +34 -0
- package/mcp-server/dist/tools/discord-role.d.ts.map +1 -0
- package/mcp-server/dist/tools/discord-role.js +178 -0
- package/mcp-server/dist/tools/discord-role.js.map +1 -0
- package/mcp-server/dist/tools/discord-thread.d.ts +28 -0
- package/mcp-server/dist/tools/discord-thread.d.ts.map +1 -0
- package/mcp-server/dist/tools/discord-thread.js +88 -0
- package/mcp-server/dist/tools/discord-thread.js.map +1 -0
- package/mcp-server/dist/tools/discord-webhook.d.ts +32 -0
- package/mcp-server/dist/tools/discord-webhook.d.ts.map +1 -0
- package/mcp-server/dist/tools/discord-webhook.js +154 -0
- package/mcp-server/dist/tools/discord-webhook.js.map +1 -0
- package/mcp-server/dist/tools/discord.d.ts +7 -0
- package/mcp-server/dist/tools/discord.d.ts.map +1 -0
- package/mcp-server/dist/tools/discord.js +25 -0
- package/mcp-server/dist/tools/discord.js.map +1 -0
- package/mcp-server/dist/tools/fb-groups.d.ts +98 -0
- package/mcp-server/dist/tools/fb-groups.d.ts.map +1 -0
- package/mcp-server/dist/tools/fb-groups.js +369 -0
- package/mcp-server/dist/tools/fb-groups.js.map +1 -0
- package/mcp-server/dist/tools/forget.d.ts +14 -0
- package/mcp-server/dist/tools/forget.d.ts.map +1 -0
- package/mcp-server/dist/tools/forget.js +26 -0
- package/mcp-server/dist/tools/forget.js.map +1 -0
- package/mcp-server/dist/tools/git-tools.d.ts +24 -0
- package/mcp-server/dist/tools/git-tools.d.ts.map +1 -0
- package/mcp-server/dist/tools/git-tools.js +107 -0
- package/mcp-server/dist/tools/git-tools.js.map +1 -0
- package/mcp-server/dist/tools/git.d.ts +7 -0
- package/mcp-server/dist/tools/git.d.ts.map +1 -0
- package/mcp-server/dist/tools/git.js +11 -0
- package/mcp-server/dist/tools/git.js.map +1 -0
- package/mcp-server/dist/tools/gsc/experience.d.ts +135 -0
- package/mcp-server/dist/tools/gsc/experience.d.ts.map +1 -0
- package/mcp-server/dist/tools/gsc/experience.js +351 -0
- package/mcp-server/dist/tools/gsc/experience.js.map +1 -0
- package/mcp-server/dist/tools/gsc/helpers.d.ts +78 -0
- package/mcp-server/dist/tools/gsc/helpers.d.ts.map +1 -0
- package/mcp-server/dist/tools/gsc/helpers.js +258 -0
- package/mcp-server/dist/tools/gsc/helpers.js.map +1 -0
- package/mcp-server/dist/tools/gsc/indexing.d.ts +121 -0
- package/mcp-server/dist/tools/gsc/indexing.d.ts.map +1 -0
- package/mcp-server/dist/tools/gsc/indexing.js +357 -0
- package/mcp-server/dist/tools/gsc/indexing.js.map +1 -0
- package/mcp-server/dist/tools/gsc/inspect.d.ts +78 -0
- package/mcp-server/dist/tools/gsc/inspect.d.ts.map +1 -0
- package/mcp-server/dist/tools/gsc/inspect.js +321 -0
- package/mcp-server/dist/tools/gsc/inspect.js.map +1 -0
- package/mcp-server/dist/tools/gsc/navigate.d.ts +44 -0
- package/mcp-server/dist/tools/gsc/navigate.d.ts.map +1 -0
- package/mcp-server/dist/tools/gsc/navigate.js +197 -0
- package/mcp-server/dist/tools/gsc/navigate.js.map +1 -0
- package/mcp-server/dist/tools/gsc/performance.d.ts +84 -0
- package/mcp-server/dist/tools/gsc/performance.d.ts.map +1 -0
- package/mcp-server/dist/tools/gsc/performance.js +274 -0
- package/mcp-server/dist/tools/gsc/performance.js.map +1 -0
- package/mcp-server/dist/tools/gsc/settings.d.ts +153 -0
- package/mcp-server/dist/tools/gsc/settings.d.ts.map +1 -0
- package/mcp-server/dist/tools/gsc/settings.js +425 -0
- package/mcp-server/dist/tools/gsc/settings.js.map +1 -0
- package/mcp-server/dist/tools/gsc.d.ts +7 -0
- package/mcp-server/dist/tools/gsc.d.ts.map +1 -0
- package/mcp-server/dist/tools/gsc.js +51 -0
- package/mcp-server/dist/tools/gsc.js.map +1 -0
- package/mcp-server/dist/tools/image-tools.d.ts +24 -0
- package/mcp-server/dist/tools/image-tools.d.ts.map +1 -0
- package/mcp-server/dist/tools/image-tools.js +80 -0
- package/mcp-server/dist/tools/image-tools.js.map +1 -0
- package/mcp-server/dist/tools/image.d.ts +10 -0
- package/mcp-server/dist/tools/image.d.ts.map +1 -0
- package/mcp-server/dist/tools/image.js +14 -0
- package/mcp-server/dist/tools/image.js.map +1 -0
- package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +97 -0
- package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +1 -0
- package/mcp-server/dist/tools/leonardo-browser-tools.js +228 -0
- package/mcp-server/dist/tools/leonardo-browser-tools.js.map +1 -0
- package/mcp-server/dist/tools/leonardo.d.ts +13 -0
- package/mcp-server/dist/tools/leonardo.d.ts.map +1 -0
- package/mcp-server/dist/tools/leonardo.js +21 -0
- package/mcp-server/dist/tools/leonardo.js.map +1 -0
- package/mcp-server/dist/tools/loop.d.ts +30 -0
- package/mcp-server/dist/tools/loop.d.ts.map +1 -0
- package/mcp-server/dist/tools/loop.js +401 -0
- package/mcp-server/dist/tools/loop.js.map +1 -0
- package/mcp-server/dist/tools/memories.d.ts +56 -0
- package/mcp-server/dist/tools/memories.d.ts.map +1 -0
- package/mcp-server/dist/tools/memories.js +171 -0
- package/mcp-server/dist/tools/memories.js.map +1 -0
- package/mcp-server/dist/tools/morelogin.d.ts +24 -0
- package/mcp-server/dist/tools/morelogin.d.ts.map +1 -0
- package/mcp-server/dist/tools/morelogin.js +79 -0
- package/mcp-server/dist/tools/morelogin.js.map +1 -0
- package/mcp-server/dist/tools/profile.d.ts +17 -0
- package/mcp-server/dist/tools/profile.d.ts.map +1 -0
- package/mcp-server/dist/tools/profile.js +114 -0
- package/mcp-server/dist/tools/profile.js.map +1 -0
- package/mcp-server/dist/tools/recall.d.ts +71 -0
- package/mcp-server/dist/tools/recall.d.ts.map +1 -0
- package/mcp-server/dist/tools/recall.js +147 -0
- package/mcp-server/dist/tools/recall.js.map +1 -0
- package/mcp-server/dist/tools/reflect.d.ts +56 -0
- package/mcp-server/dist/tools/reflect.d.ts.map +1 -0
- package/mcp-server/dist/tools/reflect.js +157 -0
- package/mcp-server/dist/tools/reflect.js.map +1 -0
- package/mcp-server/dist/tools/remember.d.ts +62 -0
- package/mcp-server/dist/tools/remember.d.ts.map +1 -0
- package/mcp-server/dist/tools/remember.js +201 -0
- package/mcp-server/dist/tools/remember.js.map +1 -0
- package/mcp-server/dist/tools/response.d.ts +23 -0
- package/mcp-server/dist/tools/response.d.ts.map +1 -0
- package/mcp-server/dist/tools/response.js +24 -0
- package/mcp-server/dist/tools/response.js.map +1 -0
- package/mcp-server/dist/tools/restore.d.ts +14 -0
- package/mcp-server/dist/tools/restore.d.ts.map +1 -0
- package/mcp-server/dist/tools/restore.js +23 -0
- package/mcp-server/dist/tools/restore.js.map +1 -0
- package/mcp-server/dist/tools/style-guide-tools.d.ts +51 -0
- package/mcp-server/dist/tools/style-guide-tools.d.ts.map +1 -0
- package/mcp-server/dist/tools/style-guide-tools.js +231 -0
- package/mcp-server/dist/tools/style-guide-tools.js.map +1 -0
- package/mcp-server/dist/tools/style-guide.d.ts +8 -0
- package/mcp-server/dist/tools/style-guide.d.ts.map +1 -0
- package/mcp-server/dist/tools/style-guide.js +12 -0
- package/mcp-server/dist/tools/style-guide.js.map +1 -0
- package/mcp-server/dist/tools/sync.d.ts +20 -0
- package/mcp-server/dist/tools/sync.d.ts.map +1 -0
- package/mcp-server/dist/tools/sync.js +156 -0
- package/mcp-server/dist/tools/sync.js.map +1 -0
- package/mcp-server/dist/tools/tictactoe-tools.d.ts +18 -0
- package/mcp-server/dist/tools/tictactoe-tools.d.ts.map +1 -0
- package/mcp-server/dist/tools/tictactoe-tools.js +78 -0
- package/mcp-server/dist/tools/tictactoe-tools.js.map +1 -0
- package/mcp-server/dist/tools/tictactoe.d.ts +7 -0
- package/mcp-server/dist/tools/tictactoe.d.ts.map +1 -0
- package/mcp-server/dist/tools/tictactoe.js +11 -0
- package/mcp-server/dist/tools/tictactoe.js.map +1 -0
- package/mcp-server/dist/tools/utils.d.ts +19 -0
- package/mcp-server/dist/tools/utils.d.ts.map +1 -0
- package/mcp-server/dist/tools/utils.js +54 -0
- package/mcp-server/dist/tools/utils.js.map +1 -0
- package/mcp-server/dist/tools/whiteboard-format.d.ts +88 -0
- package/mcp-server/dist/tools/whiteboard-format.d.ts.map +1 -0
- package/mcp-server/dist/tools/whiteboard-format.js +337 -0
- package/mcp-server/dist/tools/whiteboard-format.js.map +1 -0
- package/mcp-server/dist/tools/whiteboard-tools.d.ts +326 -0
- package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -0
- package/mcp-server/dist/tools/whiteboard-tools.js +222 -0
- package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -0
- package/mcp-server/dist/tools/whiteboard.d.ts +8 -0
- package/mcp-server/dist/tools/whiteboard.d.ts.map +1 -0
- package/mcp-server/dist/tools/whiteboard.js +16 -0
- package/mcp-server/dist/tools/whiteboard.js.map +1 -0
- package/mcp-server/dist/tools/youtube/analytics.d.ts +46 -0
- package/mcp-server/dist/tools/youtube/analytics.d.ts.map +1 -0
- package/mcp-server/dist/tools/youtube/analytics.js +83 -0
- package/mcp-server/dist/tools/youtube/analytics.js.map +1 -0
- package/mcp-server/dist/tools/youtube/dedup.d.ts +35 -0
- package/mcp-server/dist/tools/youtube/dedup.d.ts.map +1 -0
- package/mcp-server/dist/tools/youtube/dedup.js +56 -0
- package/mcp-server/dist/tools/youtube/dedup.js.map +1 -0
- package/mcp-server/dist/tools/youtube/download.d.ts +31 -0
- package/mcp-server/dist/tools/youtube/download.d.ts.map +1 -0
- package/mcp-server/dist/tools/youtube/download.js +30 -0
- package/mcp-server/dist/tools/youtube/download.js.map +1 -0
- package/mcp-server/dist/tools/youtube/helpers.d.ts +66 -0
- package/mcp-server/dist/tools/youtube/helpers.d.ts.map +1 -0
- package/mcp-server/dist/tools/youtube/helpers.js +143 -0
- package/mcp-server/dist/tools/youtube/helpers.js.map +1 -0
- package/mcp-server/dist/tools/youtube/media.d.ts +43 -0
- package/mcp-server/dist/tools/youtube/media.d.ts.map +1 -0
- package/mcp-server/dist/tools/youtube/media.js +97 -0
- package/mcp-server/dist/tools/youtube/media.js.map +1 -0
- package/mcp-server/dist/tools/youtube/metadata.d.ts +33 -0
- package/mcp-server/dist/tools/youtube/metadata.d.ts.map +1 -0
- package/mcp-server/dist/tools/youtube/metadata.js +106 -0
- package/mcp-server/dist/tools/youtube/metadata.js.map +1 -0
- package/mcp-server/dist/tools/youtube/navigate.d.ts +30 -0
- package/mcp-server/dist/tools/youtube/navigate.d.ts.map +1 -0
- package/mcp-server/dist/tools/youtube/navigate.js +71 -0
- package/mcp-server/dist/tools/youtube/navigate.js.map +1 -0
- package/mcp-server/dist/tools/youtube/playlist.d.ts +29 -0
- package/mcp-server/dist/tools/youtube/playlist.d.ts.map +1 -0
- package/mcp-server/dist/tools/youtube/playlist.js +128 -0
- package/mcp-server/dist/tools/youtube/playlist.js.map +1 -0
- package/mcp-server/dist/tools/youtube/schedule.d.ts +31 -0
- package/mcp-server/dist/tools/youtube/schedule.d.ts.map +1 -0
- package/mcp-server/dist/tools/youtube/schedule.js +147 -0
- package/mcp-server/dist/tools/youtube/schedule.js.map +1 -0
- package/mcp-server/dist/tools/youtube/source.d.ts +36 -0
- package/mcp-server/dist/tools/youtube/source.d.ts.map +1 -0
- package/mcp-server/dist/tools/youtube/source.js +85 -0
- package/mcp-server/dist/tools/youtube/source.js.map +1 -0
- package/mcp-server/dist/tools/youtube/upload.d.ts +53 -0
- package/mcp-server/dist/tools/youtube/upload.d.ts.map +1 -0
- package/mcp-server/dist/tools/youtube/upload.js +255 -0
- package/mcp-server/dist/tools/youtube/upload.js.map +1 -0
- package/mcp-server/dist/tools/youtube.d.ts +12 -0
- package/mcp-server/dist/tools/youtube.d.ts.map +1 -0
- package/mcp-server/dist/tools/youtube.js +38 -0
- package/mcp-server/dist/tools/youtube.js.map +1 -0
- package/mcp-server/dist/tui.d.ts +3 -0
- package/mcp-server/dist/tui.d.ts.map +1 -0
- package/mcp-server/dist/tui.js +806 -0
- package/mcp-server/dist/tui.js.map +1 -0
- package/mcp-server/dist/types.d.ts +77 -0
- package/mcp-server/dist/types.d.ts.map +1 -0
- package/mcp-server/dist/types.js +2 -0
- package/mcp-server/dist/types.js.map +1 -0
- package/mcp-server/package-lock.json +4798 -0
- package/mcp-server/package.json +55 -38
- package/mcp-server/run.mjs +12 -2
- package/mcp-server/src/config.ts +48 -3
- package/mcp-server/src/http.ts +296 -93
- package/mcp-server/src/index.ts +546 -203
- package/mcp-server/src/preload-http.ts +19 -18
- package/mcp-server/src/preload.ts +19 -18
- package/mcp-server/src/scripts/setup-embeddings.ts +9 -0
- package/mcp-server/src/services/assistant-judgments.ts +157 -0
- package/mcp-server/src/services/browser-assist-gate.ts +383 -0
- package/mcp-server/src/services/browser-assist.ts +267 -0
- package/mcp-server/src/services/browser-bench.ts +477 -0
- package/mcp-server/src/services/browser-judgments.ts +414 -0
- package/mcp-server/src/services/browser-risk.ts +484 -0
- package/mcp-server/src/services/categories.ts +36 -19
- package/mcp-server/src/services/codex-config-heal.ts +403 -0
- package/mcp-server/src/services/desktop-assist-gate.ts +251 -0
- package/mcp-server/src/services/desktop-assist.ts +308 -0
- package/mcp-server/src/services/desktop-bench.ts +372 -0
- package/mcp-server/src/services/desktop-client.ts +76 -0
- package/mcp-server/src/services/desktop-judgments.ts +218 -0
- package/mcp-server/src/services/desktop-risk.ts +743 -0
- package/mcp-server/src/services/edit-stale.ts +299 -0
- package/mcp-server/src/services/embedding-service.ts +108 -0
- package/mcp-server/src/services/embedding-worker.ts +46 -0
- package/mcp-server/src/services/fb-regions.ts +221 -0
- package/mcp-server/src/services/file-checksums.ts +26 -9
- package/mcp-server/src/services/file-excerpt.ts +59 -0
- package/mcp-server/src/services/identity.ts +291 -0
- package/mcp-server/src/services/local-embeddings.ts +2 -77
- package/mcp-server/src/services/memory-client.ts +23 -0
- package/mcp-server/src/services/memory-judge-backfill.ts +462 -0
- package/mcp-server/src/services/memory-judgments.ts +901 -0
- package/mcp-server/src/services/memory-maintenance.ts +360 -0
- package/mcp-server/src/services/memory-retrieval.ts +349 -0
- package/mcp-server/src/services/memory-schema.ts +280 -0
- package/mcp-server/src/services/memory-sessions.ts +87 -0
- package/mcp-server/src/services/memory-triage.ts +182 -0
- package/mcp-server/src/services/memory-verification.ts +68 -0
- package/mcp-server/src/services/memory-writer.ts +125 -0
- package/mcp-server/src/services/neural-interface.ts +1217 -73
- package/mcp-server/src/services/profiles.ts +428 -0
- package/mcp-server/src/services/secret-gate.ts +52 -0
- package/mcp-server/src/services/server-instructions.ts +122 -0
- package/mcp-server/src/services/sqlite.ts +1456 -823
- package/mcp-server/src/services/typesafe-bench.ts +247 -0
- package/mcp-server/src/services/typesafe-config.ts +790 -0
- package/mcp-server/src/services/typesafe.ts +390 -0
- package/mcp-server/src/services/vector-cache.ts +255 -0
- package/mcp-server/src/services/whiteboard-geometry.ts +711 -0
- package/mcp-server/src/tools/agents.ts +539 -0
- package/mcp-server/src/tools/bluesky.ts +1186 -0
- package/mcp-server/src/tools/browser-advanced.ts +15 -6
- package/mcp-server/src/tools/browser-batch.ts +178 -0
- package/mcp-server/src/tools/browser-cheatsheet.ts +155 -0
- package/mcp-server/src/tools/browser-interact.ts +362 -255
- package/mcp-server/src/tools/browser-navigate.ts +164 -77
- package/mcp-server/src/tools/browser-observe.ts +2222 -1330
- package/mcp-server/src/tools/browser.ts +181 -107
- package/mcp-server/src/tools/card.ts +7 -5
- package/mcp-server/src/tools/choice.ts +103 -0
- package/mcp-server/src/tools/computer.ts +190 -0
- package/mcp-server/src/tools/discord.ts +10 -23
- package/mcp-server/src/tools/fb-groups.ts +387 -0
- package/mcp-server/src/tools/forget.ts +1 -1
- package/mcp-server/src/tools/git.ts +3 -1
- package/mcp-server/src/tools/gsc/experience.ts +440 -0
- package/mcp-server/src/tools/gsc/helpers.ts +288 -0
- package/mcp-server/src/tools/gsc/indexing.ts +495 -0
- package/mcp-server/src/tools/gsc/inspect.ts +391 -0
- package/mcp-server/src/tools/gsc/navigate.ts +236 -0
- package/mcp-server/src/tools/gsc/performance.ts +352 -0
- package/mcp-server/src/tools/gsc/settings.ts +564 -0
- package/mcp-server/src/tools/gsc.ts +95 -0
- package/mcp-server/src/tools/image.ts +3 -1
- package/mcp-server/src/tools/leonardo-browser-tools.ts +47 -37
- package/mcp-server/src/tools/leonardo.ts +7 -5
- package/mcp-server/src/tools/loop.ts +118 -25
- package/mcp-server/src/tools/memories.ts +65 -5
- package/mcp-server/src/tools/morelogin.ts +81 -0
- package/mcp-server/src/tools/profile.ts +122 -0
- package/mcp-server/src/tools/recall.ts +105 -261
- package/mcp-server/src/tools/reflect.ts +171 -145
- package/mcp-server/src/tools/remember.ts +223 -115
- package/mcp-server/src/tools/style-guide-tools.ts +250 -0
- package/mcp-server/src/tools/style-guide.ts +16 -0
- package/mcp-server/src/tools/sync.ts +66 -9
- package/mcp-server/src/tools/tictactoe.ts +3 -1
- package/mcp-server/src/tools/utils.ts +22 -0
- package/mcp-server/src/tools/whiteboard-format.ts +394 -0
- package/mcp-server/src/tools/whiteboard-tools.ts +191 -183
- package/mcp-server/src/tools/whiteboard.ts +7 -5
- package/mcp-server/src/tools/youtube/analytics.ts +106 -0
- package/mcp-server/src/tools/youtube/dedup.ts +57 -0
- package/mcp-server/src/tools/youtube/download.ts +41 -0
- package/mcp-server/src/tools/youtube/helpers.ts +183 -0
- package/mcp-server/src/tools/youtube/media.ts +109 -0
- package/mcp-server/src/tools/youtube/metadata.ts +112 -0
- package/mcp-server/src/tools/youtube/navigate.ts +81 -0
- package/mcp-server/src/tools/youtube/playlist.ts +134 -0
- package/mcp-server/src/tools/youtube/schedule.ts +158 -0
- package/mcp-server/src/tools/youtube/source.ts +101 -0
- package/mcp-server/src/tools/youtube/upload.ts +296 -0
- package/mcp-server/src/tools/youtube.ts +47 -0
- package/mcp-server/src/tui.ts +8 -9
- package/neural-interface/games/TicTacToe/1.svg +1 -0
- package/neural-interface/games/TicTacToe/2.svg +1 -0
- package/neural-interface/games/TicTacToe/3.svg +1 -0
- package/neural-interface/games/TicTacToe/4.svg +1 -0
- package/neural-interface/games/TicTacToe/5.svg +1 -0
- package/neural-interface/games/TicTacToe/6.svg +1 -0
- package/neural-interface/games/TicTacToe/7.svg +1 -0
- package/neural-interface/games/TicTacToe/8.svg +1 -0
- package/neural-interface/games/TicTacToe/9.svg +1 -0
- package/neural-interface/games/TicTacToe/Board.svg +1 -0
- package/neural-interface/games/TicTacToe/Circle.svg +1 -0
- package/neural-interface/games/TicTacToe/Cross.svg +1 -0
- package/neural-interface/i18n/en.json +6983 -0
- package/neural-interface/i18n/pt-BR.json +6987 -0
- package/neural-interface/lib/assistant-api.js +1005 -0
- package/neural-interface/lib/assistant-attachments.js +121 -0
- package/neural-interface/lib/assistant-brains/claude.js +207 -0
- package/neural-interface/lib/assistant-brains/codex-browser-policy-hook.mjs +43 -0
- package/neural-interface/lib/assistant-brains/codex-route-gate-hook.mjs +56 -0
- package/neural-interface/lib/assistant-brains/codex.js +213 -0
- package/neural-interface/lib/assistant-brains/opencode-browser-policy.js +47 -0
- package/neural-interface/lib/assistant-brains/opencode-route-gate.js +62 -0
- package/neural-interface/lib/assistant-brains/opencode.js +320 -0
- package/neural-interface/lib/assistant-budget.js +318 -0
- package/neural-interface/lib/assistant-catalog.js +731 -0
- package/neural-interface/lib/assistant-clarify.js +664 -0
- package/neural-interface/lib/assistant-config.js +232 -0
- package/neural-interface/lib/assistant-dispatch.js +2744 -0
- package/neural-interface/lib/assistant-envelope.js +579 -0
- package/neural-interface/lib/assistant-evidence.js +236 -0
- package/neural-interface/lib/assistant-hidden-models.js +272 -0
- package/neural-interface/lib/assistant-jev.js +117 -0
- package/neural-interface/lib/assistant-judgments.js +111 -0
- package/neural-interface/lib/assistant-media.js +335 -0
- package/neural-interface/lib/assistant-memory.js +398 -0
- package/neural-interface/lib/assistant-persona.js +444 -0
- package/neural-interface/lib/assistant-plan-permissions.js +448 -0
- package/neural-interface/lib/assistant-playbooks/design.md +87 -0
- package/neural-interface/lib/assistant-playbooks.js +72 -0
- package/neural-interface/lib/assistant-pricing.js +159 -0
- package/neural-interface/lib/assistant-route-gate-codex.js +163 -0
- package/neural-interface/lib/assistant-route-gate.js +212 -0
- package/neural-interface/lib/assistant-router.js +1324 -0
- package/neural-interface/lib/assistant-runtime.js +3337 -0
- package/neural-interface/lib/assistant-task-prompt.js +472 -0
- package/neural-interface/lib/assistant-usage.js +1688 -0
- package/neural-interface/lib/augmented-path.js +50 -0
- package/neural-interface/lib/automation-storage-migration.js +54 -0
- package/neural-interface/lib/backup-service.js +851 -0
- package/neural-interface/lib/backup-zip-reader.js +262 -0
- package/neural-interface/lib/browser-assist-api.js +41 -0
- package/neural-interface/lib/browser-console.js +176 -0
- package/neural-interface/lib/browser-execution.js +241 -0
- package/neural-interface/lib/browser-extraction.js +191 -0
- package/neural-interface/lib/browser-screenshot.js +399 -0
- package/neural-interface/lib/browser-semantic-context.js +639 -0
- package/neural-interface/lib/browser-snapshots.js +192 -0
- package/neural-interface/lib/browser-tab-recovery.js +119 -0
- package/neural-interface/lib/browser-targets.js +70 -0
- package/neural-interface/lib/browser-tool-policy.js +926 -0
- package/neural-interface/lib/claude-accounts.js +230 -0
- package/neural-interface/lib/claude-agent-bridge.js +3296 -0
- package/neural-interface/lib/claude-bypass-policy.js +99 -0
- package/neural-interface/lib/claude-history.js +429 -0
- package/neural-interface/lib/claude-model-catalog.js +483 -0
- package/neural-interface/lib/claude-panel-requests.js +165 -0
- package/neural-interface/lib/claude-panel-session.js +272 -0
- package/neural-interface/lib/claude-permission-rules.js +153 -0
- package/neural-interface/lib/claude-session-cleanup.js +71 -0
- package/neural-interface/lib/claude-session-list.js +82 -0
- package/neural-interface/lib/claude-session-ops.js +140 -0
- package/neural-interface/lib/claude-settings-view.js +51 -0
- package/neural-interface/lib/claude-skin-connect.js +79 -0
- package/neural-interface/lib/claude-stall-policy.js +7 -0
- package/neural-interface/lib/claude-temporary.js +435 -0
- package/neural-interface/lib/cli-update-planner.js +312 -0
- package/neural-interface/lib/codex-capabilities.d.ts +41 -0
- package/neural-interface/lib/codex-capabilities.js +148 -0
- package/neural-interface/lib/codex-collaboration-mode.js +17 -0
- package/neural-interface/lib/codex-compat-rpc.js +241 -0
- package/neural-interface/lib/codex-mcp-approvals.js +56 -0
- package/neural-interface/lib/codex-mcp-apps.js +47 -0
- package/neural-interface/lib/codex-model-context.js +202 -0
- package/neural-interface/lib/codex-plan-store.js +71 -0
- package/neural-interface/lib/codex-request-journal.js +242 -0
- package/neural-interface/lib/codex-runtime-path.js +213 -0
- package/neural-interface/lib/codex-session-catalog.js +231 -0
- package/neural-interface/lib/codex-session-settings.js +46 -0
- package/neural-interface/lib/codex-sidepanel-permissions.js +110 -0
- package/neural-interface/lib/codex-thread-history.js +165 -0
- package/neural-interface/lib/codex-user-verification.js +34 -0
- package/neural-interface/lib/codex-writer-lifecycle.js +152 -0
- package/neural-interface/lib/confined-fs.js +256 -0
- package/neural-interface/lib/db.js +922 -0
- package/neural-interface/lib/design-md.js +9 -0
- package/neural-interface/lib/desktop/api.js +92 -0
- package/neural-interface/lib/desktop/audit.js +62 -0
- package/neural-interface/lib/desktop/build.js +423 -0
- package/neural-interface/lib/desktop/config.js +606 -0
- package/neural-interface/lib/desktop/coords.js +76 -0
- package/neural-interface/lib/desktop/fake-helper.js +1192 -0
- package/neural-interface/lib/desktop/frames.js +77 -0
- package/neural-interface/lib/desktop/grants.js +84 -0
- package/neural-interface/lib/desktop/guards.js +170 -0
- package/neural-interface/lib/desktop/helper/SynabunDesktop.swift +3056 -0
- package/neural-interface/lib/desktop/lease.js +51 -0
- package/neural-interface/lib/desktop/manager.js +545 -0
- package/neural-interface/lib/desktop/press-contexts.js +103 -0
- package/neural-interface/lib/desktop/protocol.js +495 -0
- package/neural-interface/lib/desktop/service.js +1202 -0
- package/neural-interface/lib/effort-levels.js +148 -0
- package/neural-interface/lib/event-loop-monitor.js +67 -0
- package/neural-interface/lib/exec-loop-command.js +209 -0
- package/neural-interface/lib/folder-picker.ps1 +77 -0
- package/neural-interface/lib/http-guards.js +287 -0
- package/neural-interface/lib/jsonl-lines.js +94 -0
- package/neural-interface/lib/loop-logger.js +127 -0
- package/neural-interface/lib/mcp-client-config.js +133 -0
- package/neural-interface/lib/mcp-installer.js +487 -0
- package/neural-interface/lib/mcp-profile-refresh-coordinator.js +78 -0
- package/neural-interface/lib/mcp-profile-servers.js +120 -0
- package/neural-interface/lib/memo-cache.js +84 -0
- package/neural-interface/lib/memory-api.js +758 -0
- package/neural-interface/lib/memory-map-api.js +1150 -0
- package/neural-interface/lib/memory-map-layout.js +872 -0
- package/neural-interface/lib/memory-map-worker.js +165 -0
- package/neural-interface/lib/memory-session-capture.js +81 -0
- package/neural-interface/lib/memory-timers.js +62 -0
- package/neural-interface/lib/morelogin.js +301 -0
- package/neural-interface/lib/native-binary-runtime.js +650 -0
- package/neural-interface/lib/native-loop-goal.js +33 -0
- package/neural-interface/lib/native-loop-providers.js +1016 -0
- package/neural-interface/lib/native-loop-runtime.js +747 -0
- package/neural-interface/lib/opencode-hidden-models.js +113 -0
- package/neural-interface/lib/opencode-history.js +253 -0
- package/neural-interface/lib/opencode-runtime-config.js +58 -0
- package/neural-interface/lib/opencode-v2-client.js +486 -0
- package/neural-interface/lib/opencode-v2-ws-requests.js +955 -0
- package/neural-interface/lib/path-confine.js +213 -0
- package/neural-interface/lib/plugin-installer.js +264 -0
- package/neural-interface/lib/project-storage.js +766 -0
- package/neural-interface/lib/pty-host/core.js +603 -0
- package/neural-interface/lib/pty-host/flow.js +43 -0
- package/neural-interface/lib/pty-host/host.js +47 -0
- package/neural-interface/lib/pty-host/manager.js +360 -0
- package/neural-interface/lib/pty-host/protocol.js +81 -0
- package/neural-interface/lib/pty-host/snapshot.js +133 -0
- package/neural-interface/lib/remote-policy.js +582 -0
- package/neural-interface/lib/rulesets/api.js +175 -0
- package/neural-interface/lib/rulesets/fs-safe.js +245 -0
- package/neural-interface/lib/rulesets/installer.js +1453 -0
- package/neural-interface/lib/rulesets/json-edit.js +186 -0
- package/neural-interface/lib/rulesets/lock.js +170 -0
- package/neural-interface/lib/rulesets/managed-text.js +314 -0
- package/neural-interface/lib/rulesets/normalise.js +24 -0
- package/neural-interface/lib/rulesets/render.js +84 -0
- package/neural-interface/lib/schedule-launch-intent.js +40 -0
- package/neural-interface/lib/session-cache-builder.js +524 -0
- package/neural-interface/lib/session-chunker.js +344 -0
- package/neural-interface/lib/session-indexer.js +327 -0
- package/neural-interface/lib/session-title-generator.js +227 -0
- package/neural-interface/lib/skill-prompt-bridge.js +11 -0
- package/neural-interface/lib/style-guide/api.js +375 -0
- package/neural-interface/lib/style-guide/color.js +352 -0
- package/neural-interface/lib/style-guide/export-css.js +99 -0
- package/neural-interface/lib/style-guide/export-dtcg.js +209 -0
- package/neural-interface/lib/style-guide/export-tailwind.js +102 -0
- package/neural-interface/lib/style-guide/fonts.json +227 -0
- package/neural-interface/lib/style-guide/import.js +1268 -0
- package/neural-interface/lib/style-guide/pointers.js +103 -0
- package/neural-interface/lib/style-guide/presets.js +232 -0
- package/neural-interface/lib/style-guide/render-design-md.js +319 -0
- package/neural-interface/lib/style-guide/schema.js +848 -0
- package/neural-interface/lib/style-guide/security.js +43 -0
- package/neural-interface/lib/style-guide/store.js +491 -0
- package/neural-interface/lib/style-guide/summary.js +106 -0
- package/neural-interface/lib/style-guide/tokens.js +170 -0
- package/neural-interface/lib/synabun-update-plan.js +305 -0
- package/neural-interface/lib/synabun-version.js +179 -0
- package/neural-interface/lib/system-restore.js +99 -0
- package/neural-interface/lib/terminal-env.js +86 -0
- package/neural-interface/lib/ui-blob-store.js +106 -0
- package/neural-interface/lib/vector-cache.js +2 -0
- package/neural-interface/lib/virtual-socket.js +60 -0
- package/neural-interface/lib/whatsapp/api.js +146 -0
- package/neural-interface/lib/whatsapp/auth-store.js +389 -0
- package/neural-interface/lib/whatsapp/baileys-adapter.js +457 -0
- package/neural-interface/lib/whatsapp/brain.js +128 -0
- package/neural-interface/lib/whatsapp/bridge.js +1499 -0
- package/neural-interface/lib/whatsapp/cards.js +519 -0
- package/neural-interface/lib/whatsapp/commands.js +92 -0
- package/neural-interface/lib/whatsapp/config.js +291 -0
- package/neural-interface/lib/whatsapp/connector/entry.mjs +25 -0
- package/neural-interface/lib/whatsapp/connector/manifest.json +6 -0
- package/neural-interface/lib/whatsapp/connector/npm-shrinkwrap.json +717 -0
- package/neural-interface/lib/whatsapp/connector/package.json +8 -0
- package/neural-interface/lib/whatsapp/fake-baileys.js +444 -0
- package/neural-interface/lib/whatsapp/format.js +552 -0
- package/neural-interface/lib/whatsapp/host-core.js +1225 -0
- package/neural-interface/lib/whatsapp/host.js +119 -0
- package/neural-interface/lib/whatsapp/identity.js +288 -0
- package/neural-interface/lib/whatsapp/inbound.js +149 -0
- package/neural-interface/lib/whatsapp/installer.js +562 -0
- package/neural-interface/lib/whatsapp/manager.js +638 -0
- package/neural-interface/lib/whatsapp/paths.js +81 -0
- package/neural-interface/lib/whatsapp/protocol.js +327 -0
- package/neural-interface/lib/whatsapp/qr-svg.js +57 -0
- package/neural-interface/lib/whatsapp/redact.js +130 -0
- package/neural-interface/lib/whatsapp/service.js +1305 -0
- package/neural-interface/lib/whatsapp/vendor/qrcodegen.js +848 -0
- package/neural-interface/package-lock.json +4682 -0
- package/neural-interface/package.json +58 -27
- package/neural-interface/public/apple-touch-icon.png +0 -0
- package/neural-interface/public/category-logos/synabun.png +0 -0
- package/neural-interface/public/claude.svg +1 -0
- package/neural-interface/public/favicon-16x16.png +0 -0
- package/neural-interface/public/favicon-32x32.png +0 -0
- package/neural-interface/public/icon-192.png +0 -0
- package/neural-interface/public/icon-512.png +0 -0
- package/neural-interface/public/index.html +32 -182
- package/neural-interface/public/index2d.html +2 -2
- package/neural-interface/public/logo-synabun.png +0 -0
- package/neural-interface/public/logoHD.png +0 -0
- package/neural-interface/public/mcp.svg +4 -0
- package/neural-interface/public/offline.html +335 -299
- package/neural-interface/public/onboarding.html +692 -155
- package/neural-interface/public/opencode-logo-dark-square.svg +1 -0
- package/neural-interface/public/shared/agent-runtime-options.js +596 -0
- package/neural-interface/public/shared/api.js +339 -28
- package/neural-interface/public/shared/assistant/asst-accounts.js +318 -0
- package/neural-interface/public/shared/assistant/asst-agents-dock.js +296 -0
- package/neural-interface/public/shared/assistant/asst-api.js +270 -0
- package/neural-interface/public/shared/assistant/asst-brain-picker.js +744 -0
- package/neural-interface/public/shared/assistant/asst-budget.js +333 -0
- package/neural-interface/public/shared/assistant/asst-composer.js +656 -0
- package/neural-interface/public/shared/assistant/asst-computer.js +803 -0
- package/neural-interface/public/shared/assistant/asst-control.js +1018 -0
- package/neural-interface/public/shared/assistant/asst-hosts.js +262 -0
- package/neural-interface/public/shared/assistant/asst-mascot.js +311 -0
- package/neural-interface/public/shared/assistant/asst-menu.js +375 -0
- package/neural-interface/public/shared/assistant/asst-panel.js +1845 -0
- package/neural-interface/public/shared/assistant/asst-rack-styles.js +589 -0
- package/neural-interface/public/shared/assistant/asst-render.js +3296 -0
- package/neural-interface/public/shared/assistant/asst-route.js +1653 -0
- package/neural-interface/public/shared/assistant/asst-roving.js +75 -0
- package/neural-interface/public/shared/assistant/asst-sanitize.js +117 -0
- package/neural-interface/public/shared/assistant/asst-sidepanel-styles.js +488 -0
- package/neural-interface/public/shared/assistant/asst-sidepanel.js +675 -0
- package/neural-interface/public/shared/assistant/asst-slash.js +258 -0
- package/neural-interface/public/shared/assistant/asst-state.js +727 -0
- package/neural-interface/public/shared/assistant/asst-styles.js +1684 -0
- package/neural-interface/public/shared/assistant/asst-tool-kinds.js +1017 -0
- package/neural-interface/public/shared/assistant/asst-usage.js +444 -0
- package/neural-interface/public/shared/assistant/asst-ws.js +175 -0
- package/neural-interface/public/shared/automation-context.js +75 -0
- package/neural-interface/public/shared/blob-store.js +99 -0
- package/neural-interface/public/shared/cdx/cdx-capabilities.js +118 -0
- package/neural-interface/public/shared/cdx/cdx-cards.js +37 -0
- package/neural-interface/public/shared/cdx/cdx-commands.js +171 -0
- package/neural-interface/public/shared/cdx/cdx-context-menu.js +402 -0
- package/neural-interface/public/shared/cdx/cdx-context-model.js +220 -0
- package/neural-interface/public/shared/cdx/cdx-features.js +408 -0
- package/neural-interface/public/shared/cdx/cdx-icons.js +89 -0
- package/neural-interface/public/shared/cdx/cdx-mcp-app-host.js +414 -0
- package/neural-interface/public/shared/cdx/cdx-mcp-app-proxy.html +6 -0
- package/neural-interface/public/shared/cdx/cdx-mcp-app-proxy.js +56 -0
- package/neural-interface/public/shared/cdx/cdx-mcp-app.js +178 -0
- package/neural-interface/public/shared/cdx/cdx-model-catalog.js +120 -0
- package/neural-interface/public/shared/cdx/cdx-output-model.js +261 -0
- package/neural-interface/public/shared/cdx/cdx-output.js +382 -0
- package/neural-interface/public/shared/cdx/cdx-panel.js +1372 -0
- package/neural-interface/public/shared/cdx/cdx-plan.js +266 -0
- package/neural-interface/public/shared/cdx/cdx-protocol.js +682 -0
- package/neural-interface/public/shared/cdx/cdx-render.js +3381 -0
- package/neural-interface/public/shared/cdx/cdx-requests.js +1136 -0
- package/neural-interface/public/shared/cdx/cdx-styles.js +3251 -0
- package/neural-interface/public/shared/cdx/cdx-tabs.js +7992 -0
- package/neural-interface/public/shared/cdx/cdx-ws.js +363 -0
- package/neural-interface/public/shared/cli-status.js +169 -0
- package/neural-interface/public/shared/constants.js +22 -5
- package/neural-interface/public/shared/cp/cp-agents.js +186 -0
- package/neural-interface/public/shared/cp/cp-bash.js +252 -0
- package/neural-interface/public/shared/cp/cp-compose.js +159 -0
- package/neural-interface/public/shared/cp/cp-context-menu.js +309 -0
- package/neural-interface/public/shared/cp/cp-context-model.js +157 -0
- package/neural-interface/public/shared/cp/cp-context-window.js +80 -0
- package/neural-interface/public/shared/cp/cp-ctx.js +11 -0
- package/neural-interface/public/shared/cp/cp-diff.js +255 -0
- package/neural-interface/public/shared/cp/cp-event-rows.js +637 -0
- package/neural-interface/public/shared/cp/cp-events.js +846 -0
- package/neural-interface/public/shared/cp/cp-markdown.js +104 -0
- package/neural-interface/public/shared/cp/cp-permission-model.js +905 -0
- package/neural-interface/public/shared/cp/cp-permissions.js +626 -0
- package/neural-interface/public/shared/cp/cp-rehydrate.js +113 -0
- package/neural-interface/public/shared/cp/cp-restore.js +224 -0
- package/neural-interface/public/shared/cp/cp-session-model.js +338 -0
- package/neural-interface/public/shared/cp/cp-session-settings.js +254 -0
- package/neural-interface/public/shared/cp/cp-sessions.js +227 -0
- package/neural-interface/public/shared/cp/cp-statusline.js +153 -0
- package/neural-interface/public/shared/cp/cp-styles.js +349 -0
- package/neural-interface/public/shared/cp/cp-tasks-model.js +282 -0
- package/neural-interface/public/shared/cp/cp-tasks.js +107 -0
- package/neural-interface/public/shared/cp/cp-temporary-view.js +56 -0
- package/neural-interface/public/shared/cp/cp-temporary.js +231 -0
- package/neural-interface/public/shared/cp/cp-tool-cards.js +326 -0
- package/neural-interface/public/shared/cp/cp-tool-results.js +618 -0
- package/neural-interface/public/shared/cp/cp-usage-model.js +124 -0
- package/neural-interface/public/shared/graph-activity.js +68 -0
- package/neural-interface/public/shared/html-shell.js +107 -12
- package/neural-interface/public/shared/i18n.js +132 -34
- package/neural-interface/public/shared/node-positions-store.js +44 -0
- package/neural-interface/public/shared/ocp-hidden-models.js +116 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-approvals.js +355 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-autoaccept-button.js +35 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-automation-ownership.js +72 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-binding.js +280 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-caps.js +67 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-changes-logic.js +179 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-changes.js +164 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +725 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-compact-button.js +75 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-composer-logic.js +1204 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-confirm-logic.js +117 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-confirm.js +59 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-context-gauge.js +252 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-context-menu.js +478 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-context-model.js +179 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-events.js +233 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-icons.js +30 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-manager.js +1065 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-mention-hints.js +182 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-modelpicker.js +655 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +2636 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-plan.js +601 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-profile-inheritance.js +78 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +649 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-providers.js +35 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +357 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-render-logic.js +189 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +1869 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-select.js +42 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-send-logic.js +117 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +1714 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-session-actions.js +468 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-session-widgets.js +63 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-sessions-logic.js +366 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-settings-link.js +19 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-slash-hints.js +343 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-state.js +746 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-status-logic.js +347 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-status.js +338 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +3543 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-subagents-logic.js +482 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-tools-logic.js +351 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-tools.js +168 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-variantpicker.js +315 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +545 -0
- package/neural-interface/public/shared/provider-icons.js +30 -0
- package/neural-interface/public/shared/session-title.js +100 -0
- package/neural-interface/public/shared/settings/settings-ia.js +389 -0
- package/neural-interface/public/shared/settings/settings-kit.js +234 -0
- package/neural-interface/public/shared/settings/settings-search.js +463 -0
- package/neural-interface/public/shared/settings/settings-shell.js +570 -0
- package/neural-interface/public/shared/state.js +5 -0
- package/neural-interface/public/shared/storage.js +50 -7
- package/neural-interface/public/shared/styleguide/sg-agents.js +42 -0
- package/neural-interface/public/shared/styleguide/sg-brand.js +4 -0
- package/neural-interface/public/shared/styleguide/sg-color-client.js +388 -0
- package/neural-interface/public/shared/styleguide/sg-colors.js +148 -0
- package/neural-interface/public/shared/styleguide/sg-components.js +35 -0
- package/neural-interface/public/shared/styleguide/sg-history.js +41 -0
- package/neural-interface/public/shared/styleguide/sg-icons-logo.js +38 -0
- package/neural-interface/public/shared/styleguide/sg-imagery.js +4 -0
- package/neural-interface/public/shared/styleguide/sg-import-export.js +47 -0
- package/neural-interface/public/shared/styleguide/sg-kit.js +281 -0
- package/neural-interface/public/shared/styleguide/sg-labels.js +318 -0
- package/neural-interface/public/shared/styleguide/sg-layout.js +4 -0
- package/neural-interface/public/shared/styleguide/sg-motion.js +5 -0
- package/neural-interface/public/shared/styleguide/sg-panel.js +229 -0
- package/neural-interface/public/shared/styleguide/sg-preview.js +138 -0
- package/neural-interface/public/shared/styleguide/sg-rules.js +9 -0
- package/neural-interface/public/shared/styleguide/sg-shape.js +24 -0
- package/neural-interface/public/shared/styleguide/sg-state.js +132 -0
- package/neural-interface/public/shared/styleguide/sg-typography.js +124 -0
- package/neural-interface/public/shared/styles.css +7883 -1155
- package/neural-interface/public/shared/synabun-mascot.js +1625 -0
- package/neural-interface/public/shared/synabun-ticker.js +376 -0
- package/neural-interface/public/shared/term-renderer.js +343 -0
- package/neural-interface/public/shared/ui-assistant-panel.js +10 -0
- package/neural-interface/public/shared/ui-assistant.js +77 -0
- package/neural-interface/public/shared/ui-automation-studio.js +5105 -3573
- package/neural-interface/public/shared/ui-claude-panel.js +11685 -6333
- package/neural-interface/public/shared/ui-codex-panel.js +12 -0
- package/neural-interface/public/shared/ui-cost-widget.js +55 -34
- package/neural-interface/public/shared/ui-detail.js +77 -14
- package/neural-interface/public/shared/ui-explorer.js +360 -181
- package/neural-interface/public/shared/ui-file-explorer.js +485 -107
- package/neural-interface/public/shared/ui-help.js +2 -2
- package/neural-interface/public/shared/ui-image-gallery.js +45 -21
- package/neural-interface/public/shared/ui-judgments.js +1346 -0
- package/neural-interface/public/shared/ui-keybinds.js +3 -2
- package/neural-interface/public/shared/ui-link.js +105 -51
- package/neural-interface/public/shared/ui-loading.js +4 -4
- package/neural-interface/public/shared/ui-memory-maintenance.js +111 -0
- package/neural-interface/public/shared/ui-menubar.js +89 -4
- package/neural-interface/public/shared/ui-native-loop-router-state.js +94 -0
- package/neural-interface/public/shared/ui-native-loop-router.js +493 -0
- package/neural-interface/public/shared/ui-native-window-id.js +7 -0
- package/neural-interface/public/shared/ui-navbar.js +357 -222
- package/neural-interface/public/shared/ui-notifications.js +58 -12
- package/neural-interface/public/shared/ui-opencode-panel-v2.js +17 -0
- package/neural-interface/public/shared/ui-panels.js +15 -7
- package/neural-interface/public/shared/ui-resume.js +823 -653
- package/neural-interface/public/shared/ui-schedule-queue.js +172 -0
- package/neural-interface/public/shared/ui-schedules-studio.js +1882 -0
- package/neural-interface/public/shared/ui-scroll-follow.js +194 -0
- package/neural-interface/public/shared/ui-sessions.js +789 -34
- package/neural-interface/public/shared/ui-settings.js +5793 -2190
- package/neural-interface/public/shared/ui-sidepanel-layout.js +109 -0
- package/neural-interface/public/shared/ui-sidepanel-runtime.js +19 -0
- package/neural-interface/public/shared/ui-sidepanel-session-entry.js +40 -0
- package/neural-interface/public/shared/ui-sidepanel-sessions.js +221 -0
- package/neural-interface/public/shared/ui-sidepanel-state.js +131 -0
- package/neural-interface/public/shared/ui-sidepanel-tray.js +547 -0
- package/neural-interface/public/shared/ui-sidepanel-windows.js +387 -0
- package/neural-interface/public/shared/ui-skills.js +18 -32
- package/neural-interface/public/shared/ui-styleguide.js +35 -0
- package/neural-interface/public/shared/ui-sync.js +87 -0
- package/neural-interface/public/shared/ui-terminal.js +7877 -6385
- package/neural-interface/public/shared/ui-tool-updates.js +292 -0
- package/neural-interface/public/shared/ui-tooltip.js +156 -15
- package/neural-interface/public/shared/ui-tutorial-draw.js +119 -683
- package/neural-interface/public/shared/ui-tutorial-layout.js +135 -0
- package/neural-interface/public/shared/ui-tutorial-steps.js +59 -2209
- package/neural-interface/public/shared/ui-tutorial.css +102 -0
- package/neural-interface/public/shared/ui-tutorial.js +557 -1076
- package/neural-interface/public/shared/ui-update.js +420 -68
- package/neural-interface/public/shared/ui-whatsapp.js +941 -0
- package/neural-interface/public/shared/ui-whiteboard.js +1076 -233
- package/neural-interface/public/shared/ui-workspaces.js +2 -1
- package/neural-interface/public/shared/utils.js +58 -0
- package/neural-interface/public/shared/vterm-buffer.js +15 -5
- package/neural-interface/public/shared/whatsapp/wa-phone.js +65 -0
- package/neural-interface/public/shared/whatsapp/wa-view.js +411 -0
- package/neural-interface/public/sidepanel-session.html +18 -0
- package/neural-interface/public/sw.js +8 -2
- package/neural-interface/public/synabun.png +0 -0
- package/neural-interface/public/variant/2d/graph.js +1707 -1635
- package/neural-interface/public/variant/2d/lasso.js +2 -1
- package/neural-interface/public/variant/2d/layout.js +595 -594
- package/neural-interface/public/variant/2d/main.js +556 -521
- package/neural-interface/public/variant/2d/settings-gfx.js +18 -24
- package/neural-interface/public/variant/3d/main.js +516 -500
- package/neural-interface/public/variant/3d/map-controls.js +144 -0
- package/neural-interface/public/variant/3d/map-data.js +251 -0
- package/neural-interface/public/variant/3d/map-labels.js +241 -0
- package/neural-interface/public/variant/3d/map-pick.js +90 -0
- package/neural-interface/public/variant/3d/map-renderer.js +521 -0
- package/neural-interface/public/variant/3d/map-shaders.js +158 -0
- package/neural-interface/public/variant/3d/map-view.js +618 -0
- package/neural-interface/public/vendor/three/manifest.json +3 -0
- package/neural-interface/public/vendor/three/three-0.169.0.min.js +3844 -0
- package/neural-interface/public/vendor/xterm/manifest.json +3 -0
- package/neural-interface/public/vendor/xterm/xterm-6.0.0.css +285 -0
- package/neural-interface/public/vendor/xterm/xterm-6.0.0.min.js +192 -0
- package/neural-interface/scripts/build-vendor.mjs +64 -0
- package/neural-interface/scripts/codex-protocol-fixture.mjs +83 -0
- package/neural-interface/scripts/rebuild-pty.js +37 -23
- package/neural-interface/scripts/vendor-three-entry.js +24 -0
- package/neural-interface/scripts/vendor-xterm-entry.js +8 -0
- package/neural-interface/server.js +33948 -15000
- package/neural-interface/skins/default/skin.css +90 -0
- package/neural-interface/skins/default/skin.json +8 -0
- package/neural-interface/templates/rulesets/README.md +9 -0
- package/neural-interface/templates/rulesets/claude.md +3 -0
- package/neural-interface/templates/rulesets/codex.md +2 -0
- package/neural-interface/templates/rulesets/coexistence.md +6 -0
- package/neural-interface/templates/rulesets/core.md +26 -0
- package/neural-interface/templates/rulesets/cursor.md +2 -0
- package/neural-interface/templates/rulesets/gemini.md +2 -0
- package/neural-interface/templates/rulesets/legacy-hashes.json +227 -0
- package/neural-interface/templates/rulesets/manifest.json +12 -0
- package/neural-interface/templates/rulesets/opencode.md +2 -0
- package/package.json +119 -53
- package/postinstall.js +125 -26
- package/preuninstall.js +187 -0
- package/scripts/audit-claude-hook-usage.mjs +12 -0
- package/scripts/audit-memory-duplicates.mjs +44 -0
- package/scripts/measure-claude-hook-overhead.mjs +77 -0
- package/scripts/recover-user-config.mjs +254 -0
- package/scripts/restore-data-home-from-backup.mjs +239 -0
- package/setup.js +804 -260
- package/skills/leonardo/SKILL.md +19 -10
- package/skills/leonardo/modules/image-prompter.md +18 -12
- package/skills/leonardo/modules/video-prompter.md +19 -13
- package/skills/synabun/SKILL.md +209 -185
- package/skills/synabun/icon.png +0 -0
- package/skills/synabun/modules/audit.md +380 -374
- package/skills/synabun/modules/changelog.md +15 -6
- package/skills/synabun/modules/idea.md +148 -144
- package/skills/synabun/modules/memorize.md +13 -4
- package/skills/synabun/modules/schedule.md +198 -0
- package/skills/synabun/synabunicon.png +0 -0
- package/updater.cmd +31 -0
- package/updater.mjs +382 -0
- package/updater.sh +29 -0
- package/hooks/claude-code/test-user-learning.mjs +0 -531
- package/neural-interface/public/claude-chat.css +0 -878
- package/neural-interface/public/claude-chat.html +0 -92
- package/neural-interface/public/claude-chat.js +0 -1168
- package/neural-interface/public/index-legacy.html +0 -14677
- package/neural-interface/public/index2d-legacy.html +0 -8193
- package/neural-interface/public/shared/html-term-renderer.js +0 -1022
- package/neural-interface/public/variant/3d/background.js +0 -884
- package/neural-interface/public/variant/3d/camera.js +0 -661
- package/neural-interface/public/variant/3d/gfx.js +0 -116
- package/neural-interface/public/variant/3d/graph.js +0 -2399
- package/neural-interface/public/variant/3d/settings-gfx.js +0 -228
- package/neural-interface/templates/CLAUDE-template.md +0 -211
|
@@ -1,368 +1,1228 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared utilities for SynaBun Claude Code hooks.
|
|
3
|
-
*
|
|
4
|
-
* Extracted to avoid duplication across session-start, prompt-submit,
|
|
5
|
-
* post-remember, pre-compact, and stop hooks.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { readFileSync, existsSync, writeFileSync, readdirSync, unlinkSync } from 'node:fs';
|
|
9
|
-
import { dirname, join, basename } from 'node:path';
|
|
10
|
-
import { fileURLToPath } from 'node:url';
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
return
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
return
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
{
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*/
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
{
|
|
183
|
-
{
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
if (
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
const
|
|
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
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
return
|
|
368
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Shared utilities for SynaBun Claude Code hooks.
|
|
3
|
+
*
|
|
4
|
+
* Extracted to avoid duplication across session-start, prompt-submit,
|
|
5
|
+
* post-remember, pre-compact, and stop hooks.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { readFileSync, existsSync, writeFileSync, readdirSync, unlinkSync, appendFileSync, mkdirSync, statSync, renameSync, openSync, readSync, closeSync, fstatSync } from 'node:fs';
|
|
9
|
+
import { dirname, join, basename, resolve as pathResolve } from 'node:path';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
11
|
+
import { getDataHome } from '../../lib/paths.js';
|
|
12
|
+
import { classifyPrompt, isTrivialPrompt } from './prompt-origin.mjs';
|
|
13
|
+
|
|
14
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
|
|
16
|
+
// --- Neural Interface endpoint, TypeSafe kill switch, hook budgets ---
|
|
17
|
+
|
|
18
|
+
export function niUrl() {
|
|
19
|
+
return (process.env.SYNABUN_NI_URL || 'http://localhost:3344').replace(/\/+$/, '');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* SYNABUN_TYPESAFE=off in the hook's own environment (the skin test and any
|
|
24
|
+
* CLI spawned with `typesafe:'off'` set it). Read on every call, never cached:
|
|
25
|
+
* no /api/hook-judge calls, recall with judge:false, no edit notices, no
|
|
26
|
+
* digest or plan-conflict requests.
|
|
27
|
+
*/
|
|
28
|
+
export function typesafeOff() {
|
|
29
|
+
return String(process.env.SYNABUN_TYPESAFE ?? '').trim().toLowerCase() === 'off' || isTemporaryChat();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* SYNABUN_TEMPORARY_CHAT=1 in the hook's own environment: a temporary chat of
|
|
34
|
+
* the Claude sidepanel (docs/claude-sidepanel.md), set by its bridge for that
|
|
35
|
+
* session's process. Nothing of such a session is stored, indexed, judged or
|
|
36
|
+
* asked for, and it is named to nobody: every hook takes one early branch on
|
|
37
|
+
* this, and a session without the marker never does. Read on every call,
|
|
38
|
+
* never cached.
|
|
39
|
+
*/
|
|
40
|
+
export function isTemporaryChat() {
|
|
41
|
+
return String(process.env.SYNABUN_TEMPORARY_CHAT ?? '').trim() === '1';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** A network call whose timeout would be shorter than this is skipped. */
|
|
45
|
+
export const MIN_CALL_MS = 250;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Deadline arithmetic for a hook with a fixed Claude Code timeout. The clock
|
|
49
|
+
* starts at process start (node startup and imports count against the budget),
|
|
50
|
+
* and `safetyMs` is left for writing the output and exiting.
|
|
51
|
+
* remaining() ms until the deadline
|
|
52
|
+
* callTimeout(reserve) timeout for a call that must leave `reserve` ms of
|
|
53
|
+
* work after it (150 ms of slack is always kept)
|
|
54
|
+
*/
|
|
55
|
+
export function hookBudget(totalMs, safetyMs = 250) {
|
|
56
|
+
const startedAt = Date.now() - process.uptime() * 1000;
|
|
57
|
+
const deadline = startedAt + totalMs - safetyMs;
|
|
58
|
+
return {
|
|
59
|
+
deadline,
|
|
60
|
+
remaining: () => Math.max(0, Math.floor(deadline - Date.now())),
|
|
61
|
+
callTimeout: (reserveMs = 0) => Math.max(0, Math.floor(deadline - Date.now() - 150 - reserveMs)),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The server refuses judgment text over 16000 characters, and prompts that
|
|
67
|
+
* long used to get neither a judgment nor a recall. Keep the head and the
|
|
68
|
+
* tail: requests usually open with the ask and close with the specifics.
|
|
69
|
+
*/
|
|
70
|
+
export function clipForJudge(text, max = 12000, head = 9000) {
|
|
71
|
+
const s = typeof text === 'string' ? text : '';
|
|
72
|
+
if (s.length <= max) return s;
|
|
73
|
+
const marker = '\n[…]\n';
|
|
74
|
+
return s.slice(0, head) + marker + s.slice(s.length - (max - head - marker.length));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Recall queries embed the head of the prompt only. */
|
|
78
|
+
export function clipQuery(text, max = 2000) {
|
|
79
|
+
return (typeof text === 'string' ? text : '').slice(0, max);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function clipLine(value, max) {
|
|
83
|
+
const s = String(value ?? '').replace(/\s+/g, ' ').trim();
|
|
84
|
+
return s.length > max ? `${s.slice(0, Math.max(0, max - 1))}…` : s;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function tailText(value, max) {
|
|
88
|
+
const s = String(value ?? '').trim();
|
|
89
|
+
return s.length > max ? `…${s.slice(s.length - (max - 1))}` : s;
|
|
90
|
+
}
|
|
91
|
+
const DATA_HOME = getDataHome();
|
|
92
|
+
export const DATA_DIR = join(DATA_HOME, 'data');
|
|
93
|
+
export const MCP_DATA_DIR = join(DATA_HOME, 'mcp-data');
|
|
94
|
+
export const ENV_PATH = join(DATA_HOME, '.env');
|
|
95
|
+
export const HOOK_FEATURES_PATH = join(DATA_DIR, 'hook-features.json');
|
|
96
|
+
export const PENDING_REMEMBER_DIR = join(DATA_DIR, 'pending-remember');
|
|
97
|
+
export const LOOP_LOG_DIR = join(DATA_DIR, 'logs');
|
|
98
|
+
|
|
99
|
+
// --- Loop logging (mirrors neural-interface/lib/loop-logger.js) ---
|
|
100
|
+
// Writes per-loop entries from inside hooks into the same logfile the server uses.
|
|
101
|
+
|
|
102
|
+
let _loopLogDirEnsured = false;
|
|
103
|
+
function ensureLoopLogDir() {
|
|
104
|
+
if (_loopLogDirEnsured) return;
|
|
105
|
+
try {
|
|
106
|
+
if (!existsSync(LOOP_LOG_DIR)) mkdirSync(LOOP_LOG_DIR, { recursive: true });
|
|
107
|
+
_loopLogDirEnsured = true;
|
|
108
|
+
} catch { /* ok */ }
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function safeJsonInline(obj) {
|
|
112
|
+
try {
|
|
113
|
+
return JSON.stringify(obj, (_k, v) => {
|
|
114
|
+
if (typeof v === 'string' && v.length > 800) return v.slice(0, 800) + `…(+${v.length - 800})`;
|
|
115
|
+
return v;
|
|
116
|
+
});
|
|
117
|
+
} catch { return '<unserializable>'; }
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Append a line to a logfile, rotating it once if it exceeds maxBytes.
|
|
122
|
+
* Hook debug logs (compact-debug.log, user-learning-debug.log, …) were plain
|
|
123
|
+
* appendFileSync with no bound and grew to tens of MB. This keeps one `.1`
|
|
124
|
+
* backup and starts fresh, capping on-disk size at ~2x maxBytes.
|
|
125
|
+
*/
|
|
126
|
+
export function appendCapped(filePath, line, maxBytes = 10 * 1024 * 1024) {
|
|
127
|
+
try {
|
|
128
|
+
if (existsSync(filePath) && statSync(filePath).size > maxBytes) {
|
|
129
|
+
try { renameSync(filePath, filePath + '.1'); } catch { /* fall through to append */ }
|
|
130
|
+
}
|
|
131
|
+
} catch { /* stat failed — just append */ }
|
|
132
|
+
try { appendFileSync(filePath, line); } catch { /* best effort */ }
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Delete pending-remember flag files older than maxAgeDays. These per-session
|
|
137
|
+
* flags are created on first user message and never deleted, so they pile up
|
|
138
|
+
* (hundreds of stale files). Safe to sweep by mtime — a live session rewrites
|
|
139
|
+
* its flag on every message, keeping mtime fresh.
|
|
140
|
+
*/
|
|
141
|
+
export function cleanupStalePendingRemember(maxAgeDays = 30) {
|
|
142
|
+
let deleted = 0;
|
|
143
|
+
try {
|
|
144
|
+
if (!existsSync(PENDING_REMEMBER_DIR)) return { deleted };
|
|
145
|
+
const cutoff = Date.now() - maxAgeDays * 24 * 60 * 60 * 1000;
|
|
146
|
+
for (const f of readdirSync(PENDING_REMEMBER_DIR)) {
|
|
147
|
+
if (!f.endsWith('.json')) continue;
|
|
148
|
+
const fp = join(PENDING_REMEMBER_DIR, f);
|
|
149
|
+
try {
|
|
150
|
+
if (statSync(fp).mtimeMs < cutoff) { unlinkSync(fp); deleted++; }
|
|
151
|
+
} catch { /* skip racing/unreadable */ }
|
|
152
|
+
}
|
|
153
|
+
} catch { /* ok */ }
|
|
154
|
+
return { deleted };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Delete the files in `dir` last modified more than `maxAgeMs` ago (per-session
|
|
159
|
+
* caches such as data/subagent-dispatch/ that nothing else removes).
|
|
160
|
+
*/
|
|
161
|
+
export function cleanupStaleFiles(dir, maxAgeMs) {
|
|
162
|
+
let deleted = 0;
|
|
163
|
+
try {
|
|
164
|
+
if (!existsSync(dir)) return { deleted };
|
|
165
|
+
const cutoff = Date.now() - maxAgeMs;
|
|
166
|
+
for (const f of readdirSync(dir)) {
|
|
167
|
+
const fp = join(dir, f);
|
|
168
|
+
try {
|
|
169
|
+
if (statSync(fp).mtimeMs < cutoff) { unlinkSync(fp); deleted++; }
|
|
170
|
+
} catch { /* skip racing/unreadable */ }
|
|
171
|
+
}
|
|
172
|
+
} catch { /* ok */ }
|
|
173
|
+
return { deleted };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Append one log entry to the per-loop logfile and stderr.
|
|
178
|
+
* tsid may be null/undefined; will fall back to SYNABUN_TERMINAL_SESSION env.
|
|
179
|
+
*/
|
|
180
|
+
export function appendLoopLog(tsid, tag, msg, meta = undefined) {
|
|
181
|
+
const sid = tsid || process.env.SYNABUN_TERMINAL_SESSION || null;
|
|
182
|
+
const line = `${new Date().toISOString()} | hook:${tag} | ${msg}${meta ? ' | ' + safeJsonInline(meta) : ''}\n`;
|
|
183
|
+
try { process.stderr.write(`[loop:hook:${tag}] ${msg}${meta ? ' ' + safeJsonInline(meta) : ''}\n`); } catch { /* ok */ }
|
|
184
|
+
if (!sid) return;
|
|
185
|
+
ensureLoopLogDir();
|
|
186
|
+
try {
|
|
187
|
+
appendFileSync(pathResolve(LOOP_LOG_DIR, `loop-${sid}.log`), line);
|
|
188
|
+
} catch { /* ok */ }
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// --- Stdin ---
|
|
192
|
+
|
|
193
|
+
export function readStdin() {
|
|
194
|
+
return new Promise((resolve) => {
|
|
195
|
+
if (process.stdin.isTTY) return resolve('{}');
|
|
196
|
+
let data = '';
|
|
197
|
+
process.stdin.setEncoding('utf8');
|
|
198
|
+
process.stdin.on('data', (chunk) => { data += chunk; });
|
|
199
|
+
process.stdin.on('end', () => { clearTimeout(guard); resolve(data); });
|
|
200
|
+
// unref + clearTimeout: without both, this timer keeps the event loop alive
|
|
201
|
+
// for its full duration AFTER 'end' already resolved, so every hook
|
|
202
|
+
// invocation stalled ~2s against a 3s configured timeout.
|
|
203
|
+
const guard = setTimeout(() => resolve(data || '{}'), 2000);
|
|
204
|
+
guard.unref?.();
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// --- Transcript reading (session-scoped plan storage) ---
|
|
209
|
+
|
|
210
|
+
const CLAUDE_PROJECTS_DIR = join(process.env.USERPROFILE || process.env.HOME || '', '.claude', 'projects');
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Convert a cwd to Claude Code's transcript project-dir key.
|
|
214
|
+
* Claude Code replaces every non-alphanumeric char with a hyphen, so
|
|
215
|
+
* /Users/foo/Apps/Synabun → -Users-foo-Apps-Synabun.
|
|
216
|
+
*/
|
|
217
|
+
function cwdToProjectKey(cwd) {
|
|
218
|
+
if (!cwd) return '';
|
|
219
|
+
return cwd.replace(/[^a-zA-Z0-9]/g, '-');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Resolve a readable transcript path for a session. Prefers the explicit
|
|
224
|
+
* transcriptPath from the hook input; falls back to deriving it from
|
|
225
|
+
* sessionId + cwd, then to scanning ~/.claude/projects/ for <sessionId>.jsonl
|
|
226
|
+
* (covers sessions that cd'd into a subdir after launch).
|
|
227
|
+
*
|
|
228
|
+
* Returns an absolute path or null. Never guesses across sessions — the
|
|
229
|
+
* returned transcript belongs to exactly the requested sessionId.
|
|
230
|
+
*/
|
|
231
|
+
export function resolveTranscriptPath(transcriptPath, sessionId, cwd) {
|
|
232
|
+
try {
|
|
233
|
+
if (transcriptPath && existsSync(transcriptPath)) return transcriptPath;
|
|
234
|
+
} catch { /* fall through */ }
|
|
235
|
+
|
|
236
|
+
if (!sessionId) return null;
|
|
237
|
+
|
|
238
|
+
// Fast path: derive ~/.claude/projects/<key>/<sessionId>.jsonl from cwd.
|
|
239
|
+
try {
|
|
240
|
+
const key = cwdToProjectKey(cwd);
|
|
241
|
+
if (key) {
|
|
242
|
+
const derived = join(CLAUDE_PROJECTS_DIR, key, `${sessionId}.jsonl`);
|
|
243
|
+
if (existsSync(derived)) return derived;
|
|
244
|
+
}
|
|
245
|
+
} catch { /* fall through */ }
|
|
246
|
+
|
|
247
|
+
// Robust path: scan every project dir for <sessionId>.jsonl.
|
|
248
|
+
try {
|
|
249
|
+
if (existsSync(CLAUDE_PROJECTS_DIR)) {
|
|
250
|
+
for (const dir of readdirSync(CLAUDE_PROJECTS_DIR)) {
|
|
251
|
+
const candidate = join(CLAUDE_PROJECTS_DIR, dir, `${sessionId}.jsonl`);
|
|
252
|
+
try { if (existsSync(candidate)) return candidate; } catch { /* skip */ }
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
} catch { /* ok */ }
|
|
256
|
+
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Read up to maxBytes from the END of a file as UTF-8. Bounded so a multi-MB
|
|
262
|
+
* transcript never blows the Stop hook's short timeout. The first line of the
|
|
263
|
+
* returned slice may be truncated — callers must tolerate unparseable lines.
|
|
264
|
+
*/
|
|
265
|
+
function readFileTail(filePath, maxBytes = 512 * 1024) {
|
|
266
|
+
let fd = null;
|
|
267
|
+
try {
|
|
268
|
+
fd = openSync(filePath, 'r');
|
|
269
|
+
const size = fstatSync(fd).size;
|
|
270
|
+
const readBytes = Math.min(size, maxBytes);
|
|
271
|
+
if (readBytes <= 0) return '';
|
|
272
|
+
const start = size - readBytes;
|
|
273
|
+
const buf = Buffer.allocUnsafe(readBytes);
|
|
274
|
+
readSync(fd, buf, 0, readBytes, start);
|
|
275
|
+
return buf.toString('utf-8');
|
|
276
|
+
} catch {
|
|
277
|
+
return '';
|
|
278
|
+
} finally {
|
|
279
|
+
if (fd !== null) { try { closeSync(fd); } catch { /* ok */ } }
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Scan a session transcript for the LAST ExitPlanMode tool_use and return its
|
|
285
|
+
* authoritative plan payload. Because the transcript belongs to exactly one
|
|
286
|
+
* session, this is session-scoped by construction — it can never surface
|
|
287
|
+
* another session's plan (the root cause of the cross-session leak).
|
|
288
|
+
*
|
|
289
|
+
* Returns { plan, planFilePath, slug } or null when the session has no
|
|
290
|
+
* ExitPlanMode (i.e. it never exited plan mode).
|
|
291
|
+
*/
|
|
292
|
+
export function readLastExitPlanMode(transcriptPath) {
|
|
293
|
+
if (!transcriptPath) return null;
|
|
294
|
+
const tail = readFileTail(transcriptPath);
|
|
295
|
+
if (!tail) return null;
|
|
296
|
+
|
|
297
|
+
const lines = tail.split('\n');
|
|
298
|
+
// Walk backwards: the first ExitPlanMode found = the LAST in the file,
|
|
299
|
+
// which is the final approved plan when a session re-plans. A declined one
|
|
300
|
+
// (the user kept planning, the approval card expired, the stream closed) is
|
|
301
|
+
// skipped: only an approved plan is owed to memory.
|
|
302
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
303
|
+
const line = lines[i];
|
|
304
|
+
if (!line || line.indexOf('ExitPlanMode') === -1) continue;
|
|
305
|
+
let entry;
|
|
306
|
+
try { entry = JSON.parse(line); } catch { continue; }
|
|
307
|
+
const content = entry?.message?.content;
|
|
308
|
+
if (!Array.isArray(content)) continue;
|
|
309
|
+
for (const block of content) {
|
|
310
|
+
if (block && block.type === 'tool_use' && block.name === 'ExitPlanMode') {
|
|
311
|
+
const result = exitPlanResult(lines, i, block.id);
|
|
312
|
+
if (result?.declined) break;
|
|
313
|
+
const input = block.input || {};
|
|
314
|
+
return {
|
|
315
|
+
plan: typeof input.plan === 'string' ? input.plan : '',
|
|
316
|
+
planFilePath: typeof input.planFilePath === 'string' ? input.planFilePath : '',
|
|
317
|
+
slug: typeof entry.slug === 'string' ? entry.slug : '',
|
|
318
|
+
// Where the CLI says the plan file is (it may never have been written).
|
|
319
|
+
resultFilePath: result?.filePath || '',
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* The result of the ExitPlanMode call on line `at`: { declined, filePath }, or
|
|
329
|
+
* null when none is there yet. An error result is a decline. "You are not in
|
|
330
|
+
* plan mode" is one too, unless the transcript shows an approval anyway: the
|
|
331
|
+
* session was in plan mode for that turn and the approval left it before the
|
|
332
|
+
* call ran (older CLIs did that to most approvals), or the Claude sidepanel's
|
|
333
|
+
* simulated plan mode was approved with its "Continue with implementation"
|
|
334
|
+
* prompt. Without either, the session was never in plan mode.
|
|
335
|
+
*/
|
|
336
|
+
function exitPlanResult(lines, at, id) {
|
|
337
|
+
if (!id) return null;
|
|
338
|
+
const needle = `"tool_use_id":"${id}"`;
|
|
339
|
+
for (let j = at + 1; j < lines.length; j++) {
|
|
340
|
+
if (lines[j].indexOf(needle) === -1) continue;
|
|
341
|
+
let entry;
|
|
342
|
+
try { entry = JSON.parse(lines[j]); } catch { continue; }
|
|
343
|
+
const content = Array.isArray(entry?.message?.content) ? entry.message.content : [];
|
|
344
|
+
const block = content.find((b) => b && b.type === 'tool_result' && b.tool_use_id === id);
|
|
345
|
+
if (!block) continue;
|
|
346
|
+
const text = typeof block.content === 'string' ? block.content : JSON.stringify(block.content ?? '');
|
|
347
|
+
const approvedAnyway = /not in plan mode/i.test(text) && (planModeTurn(lines, at) || sidepanelContinued(lines, j + 1));
|
|
348
|
+
return {
|
|
349
|
+
declined: block.is_error === true && !approvedAnyway,
|
|
350
|
+
filePath: typeof entry.toolUseResult?.filePath === 'string' ? entry.toolUseResult.filePath : '',
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
return null;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Transcript lines parsed only when they can decide (a plan-mode reminder, a
|
|
357
|
+
// mode change, a user entry).
|
|
358
|
+
function parsedIf(line, ...needles) {
|
|
359
|
+
if (!line || !needles.some((needle) => line.indexOf(needle) !== -1)) return null;
|
|
360
|
+
try { return JSON.parse(line); } catch { return null; }
|
|
361
|
+
}
|
|
362
|
+
// What the user sent, as the transcript records it: not a tool result, a hook's
|
|
363
|
+
// injected text (isMeta) or a compaction summary. Stamped or not, it starts a turn.
|
|
364
|
+
function isPrompt(entry) {
|
|
365
|
+
if (entry?.type !== 'user' || entry.isMeta || entry.isCompactSummary) return false;
|
|
366
|
+
const content = entry.message?.content;
|
|
367
|
+
return !(Array.isArray(content) && content.some((b) => b && b.type === 'tool_result'));
|
|
368
|
+
}
|
|
369
|
+
function promptText(entry) {
|
|
370
|
+
const content = entry.message?.content;
|
|
371
|
+
return typeof content === 'string' ? content
|
|
372
|
+
: Array.isArray(content) ? content.map((b) => (b && b.type === 'text' ? b.text || '' : '')).join('\n') : '';
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Whether the session was in plan mode during the turn of the entry on line
|
|
377
|
+
* `at`, walking back no further than the prompt that started it. The CLI writes
|
|
378
|
+
* a `plan_mode` attachment (its plan-mode reminder) only while the permission
|
|
379
|
+
* mode is plan, a `permission-mode` entry when the mode changes, and stamps a
|
|
380
|
+
* prompt with `permissionMode`. A `plan_mode_exit` attachment first means plan
|
|
381
|
+
* mode had already ended. The turn's prompt ends the walk: an unstamped one
|
|
382
|
+
* leaves the mode unknown, so nothing was approved, and nothing before it
|
|
383
|
+
* counts. The sidepanel's simulated plan mode runs in default and leaves none
|
|
384
|
+
* of them.
|
|
385
|
+
*/
|
|
386
|
+
function planModeTurn(lines, at) {
|
|
387
|
+
for (let k = at - 1; k >= 0; k--) {
|
|
388
|
+
const entry = parsedIf(lines[k], '"plan_mode', '"permission-mode"', '"type":"user"');
|
|
389
|
+
if (!entry) continue;
|
|
390
|
+
if (entry.type === 'attachment') {
|
|
391
|
+
if (entry.attachment?.type === 'plan_mode_exit') return false;
|
|
392
|
+
if (entry.attachment?.type === 'plan_mode') return true;
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
if (entry.type === 'permission-mode') return entry.permissionMode === 'plan';
|
|
396
|
+
if (isPrompt(entry)) return entry.permissionMode === 'plan';
|
|
397
|
+
}
|
|
398
|
+
return false;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// The Claude sidepanel's "Continue with implementation" prompts (ui-claude-panel.js
|
|
402
|
+
// renderPostPlanActions): the approval of a plan made in its simulated plan mode.
|
|
403
|
+
const SIDEPANEL_PLAN_APPROVAL = /(?:^|\n)(?:Continue with the implementation based on the approved plan\.|The user has reviewed and approved this updated plan:)/;
|
|
404
|
+
|
|
405
|
+
// A slash command and its output (the PLAN COMPLETE card's "Compact context" runs /compact).
|
|
406
|
+
const COMMAND_ECHO = /^\s*<(?:command-|local-command-)/;
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Whether the first prompt from line `from` on is the sidepanel's approval of
|
|
410
|
+
* the plan before it. A slash command or its output in between is not an answer.
|
|
411
|
+
*/
|
|
412
|
+
function sidepanelContinued(lines, from) {
|
|
413
|
+
for (let j = from; j < lines.length; j++) {
|
|
414
|
+
const entry = parsedIf(lines[j], '"type":"user"');
|
|
415
|
+
if (!isPrompt(entry)) continue;
|
|
416
|
+
const text = promptText(entry);
|
|
417
|
+
if (COMMAND_ECHO.test(text)) continue;
|
|
418
|
+
return SIDEPANEL_PLAN_APPROVAL.test(text);
|
|
419
|
+
}
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// --- Transcript entries (turn activity, recent prompts) ---
|
|
424
|
+
//
|
|
425
|
+
// Transcript lines are {type:'user'|'assistant', message:{role, content},
|
|
426
|
+
// isMeta?, isSidechain?, promptId?, promptSource?, toolUseResult?}. Other line
|
|
427
|
+
// types (attachment, file-history, ai-title, …) can be megabytes each, so a
|
|
428
|
+
// line is only parsed when its head carries a `"message":` key and no
|
|
429
|
+
// `"attachment":` key (checked on 7,878 live entries: `"message":` always sits
|
|
430
|
+
// in the first 180 characters).
|
|
431
|
+
|
|
432
|
+
const MEMORY_WRITE_TOOL = /(?:^|__)Syna[Bb]un_+(?:remember|reflect)$/;
|
|
433
|
+
const MEMORY_TOOL = /(?:^|__)Syna[Bb]un_+(?:remember|reflect|recall|memories|forget|restore|sync)$/;
|
|
434
|
+
const EDIT_TOOL_NAMES = new Set(['Edit', 'Write', 'NotebookEdit', 'MultiEdit']);
|
|
435
|
+
// Results that say nothing about whether the work succeeded.
|
|
436
|
+
const QUIET_TOOLS = new Set(['Read', 'Grep', 'Glob', 'LS', 'ToolSearch', 'TodoWrite', 'NotebookRead',
|
|
437
|
+
'EnterPlanMode', 'ExitPlanMode', 'AskUserQuestion', 'Edit', 'Write', 'NotebookEdit', 'MultiEdit']);
|
|
438
|
+
|
|
439
|
+
export function transcriptEntries(filePath, maxBytes = 2 * 1024 * 1024) {
|
|
440
|
+
if (!filePath) return [];
|
|
441
|
+
let fd = null;
|
|
442
|
+
let text = '';
|
|
443
|
+
let truncated = false;
|
|
444
|
+
try {
|
|
445
|
+
fd = openSync(filePath, 'r');
|
|
446
|
+
const size = fstatSync(fd).size;
|
|
447
|
+
const readBytes = Math.min(size, maxBytes);
|
|
448
|
+
if (readBytes <= 0) return [];
|
|
449
|
+
truncated = readBytes < size;
|
|
450
|
+
const buf = Buffer.allocUnsafe(readBytes);
|
|
451
|
+
readSync(fd, buf, 0, readBytes, size - readBytes);
|
|
452
|
+
text = buf.toString('utf-8');
|
|
453
|
+
} catch {
|
|
454
|
+
return [];
|
|
455
|
+
} finally {
|
|
456
|
+
if (fd !== null) { try { closeSync(fd); } catch { /* ok */ } }
|
|
457
|
+
}
|
|
458
|
+
const lines = text.split('\n');
|
|
459
|
+
if (truncated) lines.shift(); // started mid-line
|
|
460
|
+
const entries = [];
|
|
461
|
+
for (const line of lines) {
|
|
462
|
+
if (!line) continue;
|
|
463
|
+
const head = line.slice(0, 600);
|
|
464
|
+
if (head.includes('"attachment":') || !head.includes('"message":')) continue;
|
|
465
|
+
let entry;
|
|
466
|
+
try { entry = JSON.parse(line); } catch { continue; }
|
|
467
|
+
if (entry && (entry.type === 'user' || entry.type === 'assistant')) entries.push(entry);
|
|
468
|
+
}
|
|
469
|
+
return entries;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
function contentBlocks(entry) {
|
|
473
|
+
const content = entry?.message?.content;
|
|
474
|
+
if (Array.isArray(content)) return content;
|
|
475
|
+
if (typeof content === 'string') return [{ type: 'text', text: content }];
|
|
476
|
+
return [];
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
function blockText(content) {
|
|
480
|
+
if (typeof content === 'string') return content;
|
|
481
|
+
if (Array.isArray(content)) return content.map((b) => (b && b.type === 'text' ? b.text || '' : '')).filter(Boolean).join('\n');
|
|
482
|
+
return '';
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/** The text a user entry carries (tool results excluded). */
|
|
486
|
+
export function userEntryText(entry) {
|
|
487
|
+
const content = entry?.message?.content;
|
|
488
|
+
if (typeof content === 'string') return content;
|
|
489
|
+
if (!Array.isArray(content)) return '';
|
|
490
|
+
return content.map((b) => (b && b.type === 'text' ? b.text || '' : '')).filter(Boolean).join('\n');
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* A user entry that starts a turn: typed (or injected) text, not a tool result,
|
|
495
|
+
* not Claude Code's own meta line (Stop-hook feedback, caveats), not a sidechain.
|
|
496
|
+
*/
|
|
497
|
+
export function isTurnStart(entry) {
|
|
498
|
+
if (!entry || entry.type !== 'user' || entry.isMeta || entry.isSidechain) return false;
|
|
499
|
+
const content = entry.message?.content;
|
|
500
|
+
if (typeof content === 'string') return true;
|
|
501
|
+
if (!Array.isArray(content) || content.length === 0) return false;
|
|
502
|
+
return !content.some((b) => b && b.type === 'tool_result');
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/** Human-typed prompt text of a turn-start entry, or '' for system-injected ones. */
|
|
506
|
+
export function humanPromptText(entry) {
|
|
507
|
+
if (!isTurnStart(entry) || entry.promptSource === 'system') return '';
|
|
508
|
+
const cls = classifyPrompt(userEntryText(entry));
|
|
509
|
+
return cls.origin === 'human' ? cls.text : '';
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// Checks that could back a claim like "tests pass" or "it builds".
|
|
513
|
+
const TEST_OR_BUILD = /\b(?:(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?[\w:.-]*(?:test|build|check|lint|typecheck|verify)[\w:.-]*|npx\s+(?:vitest|jest|mocha|tsc|playwright|eslint)|node\s+(?:--test\b|\S*(?:test|spec|bench|verify)\S*)|vitest|jest|mocha|pytest|tsc|go\s+(?:test|build|vet)|cargo\s+(?:test|build|check|clippy)|make\b|mvn\b|gradle\w*|dotnet\s+(?:test|build)|swift\s+(?:test|build)|xcodebuild|ruff|eslint|playwright\s+test)/i;
|
|
514
|
+
|
|
515
|
+
export function isTestOrBuildCommand(command) {
|
|
516
|
+
return TEST_OR_BUILD.test(String(command || ''));
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const READ_ONLY_COMMAND = /^(?:ls|ll|cat|bat|head|tail|less|more|grep|egrep|fgrep|rg|ag|find|fd|pwd|echo|printf|wc|which|type|whereis|stat|file|du|df|tree|sort|uniq|cut|tr|awk|jq|column|diff|cmp|date|true|basename|dirname|realpath|readlink|env|printenv|cd|sed\s+-n|git\s+(?:status|log|diff|show|branch|rev-parse|remote|ls-files|blame|shortlog|describe|config\s+--get))\b/i;
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* True when every segment of a shell command only reads. A redirect into a
|
|
523
|
+
* file makes a segment a write. Used to decide whether a Bash-only turn did
|
|
524
|
+
* anything that could be worth a memory; the judgment makes the final call.
|
|
525
|
+
*/
|
|
526
|
+
export function isReadOnlyCommand(command) {
|
|
527
|
+
const segments = String(command || '').split(/&&|\|\||;|\||\n/).map((s) => s.trim()).filter(Boolean);
|
|
528
|
+
if (!segments.length) return true;
|
|
529
|
+
return segments.every((segment) => {
|
|
530
|
+
const bare = segment.replace(/^(?:[A-Za-z_][A-Za-z0-9_]*=\S*\s+)+/, '');
|
|
531
|
+
const withoutHarmless = bare.replace(/\d?>>?\s*\/dev\/null/g, '').replace(/\d?>&\d/g, '');
|
|
532
|
+
if (/>/.test(withoutHarmless)) return false;
|
|
533
|
+
return READ_ONLY_COMMAND.test(bare);
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
function bashResultText(result) {
|
|
538
|
+
if (!result) return '';
|
|
539
|
+
const fromBlock = blockText(result.block?.content);
|
|
540
|
+
if (fromBlock) return fromBlock;
|
|
541
|
+
const tur = result.tur;
|
|
542
|
+
if (tur && typeof tur === 'object') return [tur.stdout, tur.stderr].filter((s) => typeof s === 'string' && s).join('\n');
|
|
543
|
+
return typeof tur === 'string' ? tur : '';
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
function bashExit(input, result) {
|
|
547
|
+
if (!result) return input?.run_in_background ? 'background' : 'interrupted';
|
|
548
|
+
const tur = result.tur;
|
|
549
|
+
if (tur && typeof tur === 'object') {
|
|
550
|
+
if (tur.interrupted === true) return 'interrupted';
|
|
551
|
+
if (tur.backgroundTaskId) return 'background';
|
|
552
|
+
}
|
|
553
|
+
if (result.block?.is_error === true) {
|
|
554
|
+
return /interrupted by user/i.test(bashResultText(result)) ? 'interrupted' : 'error';
|
|
555
|
+
}
|
|
556
|
+
return input?.run_in_background ? 'background' : 'ok';
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/**
|
|
560
|
+
* What the current turn did, read from the transcript: everything after the
|
|
561
|
+
* last turn-start user entry (see isTurnStart).
|
|
562
|
+
*
|
|
563
|
+
* bash_commands ≤12 most recent Bash calls of the WHOLE turn:
|
|
564
|
+
* {command ≤240, description ≤100, exit, output_tail ≤300,
|
|
565
|
+
* after_memory_write}. The turn usually runs its tests, then
|
|
566
|
+
* calls `remember`, then reports — the claim check must see
|
|
567
|
+
* the test run, so the window is the turn, not the part
|
|
568
|
+
* after the last memory write.
|
|
569
|
+
* checks every test/build command of the turn (≤10 most recent)
|
|
570
|
+
* tool_results ≤6 non-Bash results that can show success or failure
|
|
571
|
+
* edited_files files edited this turn
|
|
572
|
+
* tool_counts tool name → calls this turn
|
|
573
|
+
* memory_written_this_turn a SynaBun remember/reflect ran this turn
|
|
574
|
+
* prompt_id promptId of the turn-start entry, when recorded
|
|
575
|
+
*/
|
|
576
|
+
export function readTurnActivity(transcriptPath, { maxBytes = 4 * 1024 * 1024 } = {}) {
|
|
577
|
+
const activity = {
|
|
578
|
+
prompt_id: null, bash_commands: [], checks: [], tool_results: [], edited_files: [],
|
|
579
|
+
tool_counts: {}, memory_written_this_turn: false, bash_total: 0,
|
|
580
|
+
};
|
|
581
|
+
const entries = transcriptEntries(transcriptPath, maxBytes);
|
|
582
|
+
if (!entries.length) return activity;
|
|
583
|
+
let start = 0;
|
|
584
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
585
|
+
if (isTurnStart(entries[i])) {
|
|
586
|
+
start = i + 1;
|
|
587
|
+
activity.prompt_id = typeof entries[i].promptId === 'string' ? entries[i].promptId : null;
|
|
588
|
+
break;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
const turn = entries.slice(start);
|
|
592
|
+
const results = new Map();
|
|
593
|
+
const uses = [];
|
|
594
|
+
for (const entry of turn) {
|
|
595
|
+
for (const block of contentBlocks(entry)) {
|
|
596
|
+
if (!block || typeof block !== 'object') continue;
|
|
597
|
+
if (entry.type === 'user' && block.type === 'tool_result' && block.tool_use_id) {
|
|
598
|
+
results.set(block.tool_use_id, { block, tur: entry.toolUseResult });
|
|
599
|
+
} else if (entry.type === 'assistant' && block.type === 'tool_use') {
|
|
600
|
+
uses.push(block);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
let lastWrite = -1;
|
|
605
|
+
uses.forEach((use, i) => { if (MEMORY_WRITE_TOOL.test(use.name || '')) lastWrite = i; });
|
|
606
|
+
activity.memory_written_this_turn = lastWrite >= 0;
|
|
607
|
+
|
|
608
|
+
const bash = [];
|
|
609
|
+
const others = [];
|
|
610
|
+
const edited = new Set();
|
|
611
|
+
uses.forEach((use, i) => {
|
|
612
|
+
const name = String(use.name || '');
|
|
613
|
+
activity.tool_counts[name] = (activity.tool_counts[name] || 0) + 1;
|
|
614
|
+
const input = use.input && typeof use.input === 'object' ? use.input : {};
|
|
615
|
+
const result = results.get(use.id);
|
|
616
|
+
if (name === 'Bash') {
|
|
617
|
+
const command = String(input.command || '');
|
|
618
|
+
const entry = {
|
|
619
|
+
command: clipLine(command, 240),
|
|
620
|
+
description: clipLine(input.description, 100),
|
|
621
|
+
exit: bashExit(input, result),
|
|
622
|
+
output_tail: tailText(bashResultText(result), 300),
|
|
623
|
+
after_memory_write: i > lastWrite,
|
|
624
|
+
};
|
|
625
|
+
bash.push(entry);
|
|
626
|
+
if (isTestOrBuildCommand(command)) activity.checks.push({ command: entry.command, exit: entry.exit, after_memory_write: entry.after_memory_write });
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
if (EDIT_TOOL_NAMES.has(name)) {
|
|
630
|
+
const file = input.file_path || input.notebook_path;
|
|
631
|
+
if (typeof file === 'string' && file) edited.add(file);
|
|
632
|
+
}
|
|
633
|
+
if (QUIET_TOOLS.has(name) || MEMORY_TOOL.test(name) || !result) return;
|
|
634
|
+
others.push({ order: i, tool: name, is_error: result.block?.is_error === true, tail: tailText(blockText(result.block?.content) || (typeof result.tur === 'string' ? result.tur : ''), 300) });
|
|
635
|
+
});
|
|
636
|
+
activity.bash_total = bash.length;
|
|
637
|
+
activity.bash_commands = bash.slice(-12);
|
|
638
|
+
activity.checks = activity.checks.slice(-10);
|
|
639
|
+
activity.edited_files = [...edited].slice(0, 50);
|
|
640
|
+
// ≤6 results, errors first (they are the evidence that matters), then the
|
|
641
|
+
// most recent; reported in the order they happened.
|
|
642
|
+
const errors = others.filter((r) => r.is_error).slice(-6);
|
|
643
|
+
const rest = others.filter((r) => !r.is_error).slice(-(6 - errors.length));
|
|
644
|
+
activity.tool_results = [...errors, ...rest].sort((a, b) => a.order - b.order)
|
|
645
|
+
.map(({ tool, is_error, tail }) => ({ tool, is_error, tail }));
|
|
646
|
+
return activity;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/** The last n non-trivial human prompts in the transcript, most recent first. */
|
|
650
|
+
export function readRecentHumanPrompts(transcriptPath, n = 2, maxBytes = 512 * 1024) {
|
|
651
|
+
const out = [];
|
|
652
|
+
const entries = transcriptEntries(transcriptPath, maxBytes);
|
|
653
|
+
for (let i = entries.length - 1; i >= 0 && out.length < n; i--) {
|
|
654
|
+
const text = humanPromptText(entries[i]);
|
|
655
|
+
if (text && !isTrivialPrompt(text)) out.push(text);
|
|
656
|
+
}
|
|
657
|
+
return out;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
/** Text of the last assistant text block in the transcript, clipped. */
|
|
661
|
+
export function readLastAssistantText(transcriptPath, maxChars = 1200, maxBytes = 512 * 1024) {
|
|
662
|
+
const entries = transcriptEntries(transcriptPath, maxBytes);
|
|
663
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
664
|
+
if (entries[i].type !== 'assistant') continue;
|
|
665
|
+
const blocks = contentBlocks(entries[i]).filter((b) => b && b.type === 'text' && typeof b.text === 'string' && b.text.trim());
|
|
666
|
+
if (blocks.length) return blocks[blocks.length - 1].text.trim().slice(0, maxChars);
|
|
667
|
+
}
|
|
668
|
+
return '';
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
// --- Hook features ---
|
|
672
|
+
|
|
673
|
+
export function getHookFeatures() {
|
|
674
|
+
try {
|
|
675
|
+
if (!existsSync(HOOK_FEATURES_PATH)) return {};
|
|
676
|
+
return JSON.parse(readFileSync(HOOK_FEATURES_PATH, 'utf-8'));
|
|
677
|
+
} catch { return {}; }
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
// --- Memory recall (shared by prompt-submit and subagent-start hooks) ---
|
|
681
|
+
|
|
682
|
+
function formatMemoryAge(isoDate) {
|
|
683
|
+
const diffMs = Date.now() - new Date(isoDate).getTime();
|
|
684
|
+
const days = Math.floor(diffMs / (1000 * 60 * 60 * 24));
|
|
685
|
+
if (days === 0) return 'today';
|
|
686
|
+
if (days === 1) return '1 day ago';
|
|
687
|
+
if (days < 30) return `${days} days ago`;
|
|
688
|
+
const months = Math.floor(days / 30);
|
|
689
|
+
return months === 1 ? '1 month ago' : `${months} months ago`;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
export const MEMORY_BLOCK_HEADER = '=== SynaBun: Related Memories ===';
|
|
693
|
+
export const MEMORY_BLOCK_END = '=== End Memories ===';
|
|
694
|
+
|
|
695
|
+
/**
|
|
696
|
+
* The `=== SynaBun: Related Memories ===` block (the header is load-bearing:
|
|
697
|
+
* the assistant persona and tests look for it). When the server ranked the
|
|
698
|
+
* shortlist, the closing line says so, with the number of candidates the
|
|
699
|
+
* relevance floor removed.
|
|
700
|
+
*/
|
|
701
|
+
export function formatMemoryBlock(data, { ranked = false, dropped = 0 } = {}) {
|
|
702
|
+
if (!data || !Array.isArray(data.results) || data.results.length === 0) return '';
|
|
703
|
+
const n = Number(dropped) || 0;
|
|
704
|
+
const tag = ranked ? ` [ranked by Jev${n > 0 ? `; ${n} low-relevance ${n === 1 ? 'match' : 'matches'} dropped` : ''}]` : '';
|
|
705
|
+
if (data.context) {
|
|
706
|
+
return [MEMORY_BLOCK_HEADER, data.context,
|
|
707
|
+
`Use these as evidence; fetch full UUIDs only when more detail is needed.${tag}`, MEMORY_BLOCK_END].join('\n');
|
|
708
|
+
}
|
|
709
|
+
const lines = data.results.map((r, i) => {
|
|
710
|
+
const score = (r.score * 100).toFixed(0);
|
|
711
|
+
const age = formatMemoryAge(r.created_at);
|
|
712
|
+
const tags = r.tags?.length ? r.tags.join(', ') : 'none';
|
|
713
|
+
const files = r.related_files?.length ? r.related_files.slice(0, 3).join(', ') : 'none';
|
|
714
|
+
return `${i + 1}. [${r.category} | importance ${r.importance}, ${age}, ${score}% match] ${r.content}\n Tags: ${tags} | Files: ${files}`;
|
|
715
|
+
});
|
|
716
|
+
return [MEMORY_BLOCK_HEADER, ...lines,
|
|
717
|
+
`These memories may be relevant. Use as context — call recall for deeper search if needed.${tag}`, MEMORY_BLOCK_END].join('\n');
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
/**
|
|
721
|
+
* Fetch relevant memories from the Neural Interface server and format them
|
|
722
|
+
* into the `=== SynaBun: Related Memories ===` block used for additionalContext.
|
|
723
|
+
*
|
|
724
|
+
* @param {object} opts
|
|
725
|
+
* @param {string} opts.query Text to search memories with.
|
|
726
|
+
* @param {string} [opts.project] Resolved project label (omit/'global' searches globally).
|
|
727
|
+
* @param {number} [opts.limit] Max results (default 3).
|
|
728
|
+
* @param {number} [opts.minScore] Minimum cosine score (default 0.4).
|
|
729
|
+
* @param {number} [opts.timeoutMs] Fetch timeout (default 1500).
|
|
730
|
+
* @param {number} [opts.tokenBudget] Compact context budget (default 600).
|
|
731
|
+
* @param {boolean} [opts.returnMeta] Return { context, alreadyPresent, ranked, rank_surface, dropped, stale }.
|
|
732
|
+
* @param {string} [opts.sessionId] Claude session: injection dedup ledger AND log attribution.
|
|
733
|
+
* @param {string} [opts.logSessionId] Log attribution only (a subagent must not be
|
|
734
|
+
* deduplicated against memories that live in its parent's context).
|
|
735
|
+
* @param {boolean} [opts.rank] Legacy flag: rank with surface brief-rank.
|
|
736
|
+
* @param {'rerank'|'brief-rank'} [opts.surface] Rank with this surface (implies ranking).
|
|
737
|
+
* @param {boolean} [opts.floor] Drop judged candidates under the surface's minScore.
|
|
738
|
+
* @param {number} [opts.budgetMs] Remaining hook budget for this call; also the fetch timeout.
|
|
739
|
+
* @param {boolean} [opts.wantStale] Return (and mark delivered) this session's stale verdicts.
|
|
740
|
+
* @param {string[]} [opts.staleAck] Verdicts already shown elsewhere: mark delivered, do not return.
|
|
741
|
+
* @returns {Promise<string|object>} Empty on failure.
|
|
742
|
+
*/
|
|
743
|
+
export async function recallMemories({ query, project, limit = 3, minScore = 0.4, timeoutMs = 1500, tokenBudget = 600,
|
|
744
|
+
returnMeta = false, sessionId, logSessionId, contextGeneration, rank = false, surface, floor = false, budgetMs,
|
|
745
|
+
wantStale = false, staleAck } = {}) {
|
|
746
|
+
// responded: the server answered (so staleAck was received and applied).
|
|
747
|
+
const meta = { responded: false, ranked: false, rank_surface: null, dropped: [], stale: [] };
|
|
748
|
+
const result = (context = '', alreadyPresent = false) => returnMeta ? { context, alreadyPresent, ...meta } : context;
|
|
749
|
+
const trimmed = (query || '').trim();
|
|
750
|
+
if (!trimmed) return result();
|
|
751
|
+
const effective = Math.floor(Math.min(Number(timeoutMs) || 0, budgetMs === undefined ? Infinity : Number(budgetMs) || 0));
|
|
752
|
+
if (!(effective >= MIN_CALL_MS)) return result();
|
|
753
|
+
const off = typesafeOff();
|
|
754
|
+
const ranking = !off && (rank || !!surface);
|
|
755
|
+
try {
|
|
756
|
+
const resp = await fetch(`${niUrl()}/api/hook-recall`, {
|
|
757
|
+
method: 'POST',
|
|
758
|
+
headers: { 'Content-Type': 'application/json' },
|
|
759
|
+
body: JSON.stringify({
|
|
760
|
+
query: trimmed,
|
|
761
|
+
project: project && project !== 'global' ? project : undefined,
|
|
762
|
+
limit,
|
|
763
|
+
min_score: minScore,
|
|
764
|
+
token_budget: tokenBudget, format: 'compact',
|
|
765
|
+
caller: 'claude-code-hook', claudeSessionId: sessionId, context_generation: contextGeneration,
|
|
766
|
+
session_id: sessionId || logSessionId || undefined,
|
|
767
|
+
// Ranking judges the shortlist server-side and must fit this hook's
|
|
768
|
+
// deadline. `rank:true` is what an older server understands (surface
|
|
769
|
+
// brief-rank); a `surface` alone implies ranking on a current server,
|
|
770
|
+
// so the prompt path stays unranked on an old one.
|
|
771
|
+
rank: (rank && !off) || undefined,
|
|
772
|
+
rank_timeout_ms: ranking ? Math.max(300, effective - 400) : undefined,
|
|
773
|
+
surface: surface || undefined,
|
|
774
|
+
floor: floor || undefined,
|
|
775
|
+
judge: off ? false : undefined,
|
|
776
|
+
budget_ms: budgetMs === undefined ? undefined : effective,
|
|
777
|
+
want_stale: wantStale || undefined,
|
|
778
|
+
stale_ack: Array.isArray(staleAck) && staleAck.length ? staleAck.slice(0, 50) : undefined,
|
|
779
|
+
}),
|
|
780
|
+
signal: AbortSignal.timeout(effective),
|
|
781
|
+
});
|
|
782
|
+
|
|
783
|
+
if (!resp.ok) return result();
|
|
784
|
+
const data = await resp.json();
|
|
785
|
+
if (!data || typeof data !== 'object') return result();
|
|
786
|
+
meta.responded = true;
|
|
787
|
+
meta.ranked = data.ranked === true;
|
|
788
|
+
meta.rank_surface = typeof data.rank_surface === 'string' ? data.rank_surface : null;
|
|
789
|
+
meta.dropped = Array.isArray(data.dropped) ? data.dropped : [];
|
|
790
|
+
meta.stale = Array.isArray(data.stale) ? data.stale.filter((v) => v && typeof v.memory_id === 'string') : [];
|
|
791
|
+
if (data.already_present) return result('', true);
|
|
792
|
+
if (!data.results || data.results.length === 0) return result();
|
|
793
|
+
return result(formatMemoryBlock(data, { ranked: meta.ranked, dropped: meta.dropped.length }));
|
|
794
|
+
} catch {
|
|
795
|
+
// NI down, timeout, or error — silently skip
|
|
796
|
+
return result();
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
/**
|
|
801
|
+
* POST /api/hook-judge. Hooks never hold the API key and never call the vendor
|
|
802
|
+
* directly. Always resolves; {} means "not judged" and every caller falls back
|
|
803
|
+
* to its own rule. No network at all when SYNABUN_TYPESAFE=off, when the
|
|
804
|
+
* request says judge:false, or when the budget left is under MIN_CALL_MS.
|
|
805
|
+
*/
|
|
806
|
+
export async function hookJudge(kind, fields = {}, { timeoutMs = 1500 } = {}) {
|
|
807
|
+
const body = fields && typeof fields === 'object' ? fields : {};
|
|
808
|
+
if (typesafeOff() || body.judge === false) return {};
|
|
809
|
+
const t = Math.floor(Number(timeoutMs) || 0);
|
|
810
|
+
if (!(t >= MIN_CALL_MS)) return {};
|
|
811
|
+
try {
|
|
812
|
+
const resp = await fetch(`${niUrl()}/api/hook-judge`, {
|
|
813
|
+
method: 'POST',
|
|
814
|
+
headers: { 'Content-Type': 'application/json' },
|
|
815
|
+
body: JSON.stringify({ ...body, kind, budget_ms: body.budget_ms ?? t }),
|
|
816
|
+
signal: AbortSignal.timeout(t),
|
|
817
|
+
});
|
|
818
|
+
if (!resp.ok) return {};
|
|
819
|
+
const data = await resp.json();
|
|
820
|
+
return data && typeof data === 'object' && !Array.isArray(data) ? data : {};
|
|
821
|
+
} catch {
|
|
822
|
+
return {};
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
/**
|
|
827
|
+
* Ask the Neural Interface for a typed judgment of a text (TypeSafe, server-side).
|
|
828
|
+
*
|
|
829
|
+
* @param {'prompt'|'agent-message'|'stop-turn'|'loop-goal'} kind
|
|
830
|
+
* @param {string} text
|
|
831
|
+
* @param {{project?:string, timeoutMs?:number, extra?:Record<string, any>,
|
|
832
|
+
* budget?:ReturnType<typeof hookBudget>, reserveMs?:number}} [opts]
|
|
833
|
+
* `extra` carries kind-specific state (files edited, loop task and journal).
|
|
834
|
+
* With `budget`, the timeout is also bounded by budget.callTimeout(reserveMs).
|
|
835
|
+
* @returns {Promise<Record<string, any>>}
|
|
836
|
+
*/
|
|
837
|
+
export async function judgeText(kind, text, { project, timeoutMs = 1500, extra = {}, budget, reserveMs = 0 } = {}) {
|
|
838
|
+
const trimmed = (text || '').trim();
|
|
839
|
+
if (!trimmed) return {};
|
|
840
|
+
const t = budget ? Math.min(timeoutMs, budget.callTimeout(reserveMs)) : timeoutMs;
|
|
841
|
+
return hookJudge(kind, { ...extra, text: trimmed, project }, { timeoutMs: t });
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
/**
|
|
845
|
+
* Fire-and-forget POST that may wait at most `waitMs` for the answer and never
|
|
846
|
+
* keeps the process alive past that. Resolves true only on a 2xx.
|
|
847
|
+
*/
|
|
848
|
+
export async function postNotice(path, body, waitMs = 200) {
|
|
849
|
+
let timer;
|
|
850
|
+
try {
|
|
851
|
+
const request = fetch(`${niUrl()}${path}`, {
|
|
852
|
+
method: 'POST',
|
|
853
|
+
headers: { 'Content-Type': 'application/json' },
|
|
854
|
+
body: JSON.stringify(body),
|
|
855
|
+
signal: AbortSignal.timeout(Math.max(50, waitMs)),
|
|
856
|
+
}).then((resp) => resp.ok, () => false);
|
|
857
|
+
const giveUp = new Promise((resolve) => { timer = setTimeout(() => resolve(false), waitMs); timer.unref?.(); });
|
|
858
|
+
return await Promise.race([request, giveUp]);
|
|
859
|
+
} catch {
|
|
860
|
+
return false;
|
|
861
|
+
} finally {
|
|
862
|
+
clearTimeout(timer);
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
/**
|
|
867
|
+
* Edit-time stale verdicts (StaleVerdict[] from /api/hook-recall or stop-turn)
|
|
868
|
+
* as one short advisory block: at most 3, excerpts clipped to 160 characters.
|
|
869
|
+
*/
|
|
870
|
+
export function formatStaleNotices(list) {
|
|
871
|
+
const items = (Array.isArray(list) ? list : []).filter((v) => v && typeof v.memory_id === 'string').slice(0, 3);
|
|
872
|
+
if (!items.length) return '';
|
|
873
|
+
const lines = items.map((v) => {
|
|
874
|
+
const parts = [];
|
|
875
|
+
if (v.category) parts.push(String(v.category));
|
|
876
|
+
const p = Number(v.probability);
|
|
877
|
+
if (v.probability !== undefined && v.probability !== null && Number.isFinite(p)) parts.push(`p(still accurate)=${p.toFixed(2)}`);
|
|
878
|
+
if (v.file) parts.push(String(v.file));
|
|
879
|
+
const excerpt = clipLine(v.excerpt, 160);
|
|
880
|
+
return `- [${v.memory_id}]${parts.length ? ` (${parts.join(', ')})` : ''}${excerpt ? ` "${excerpt}"` : ''}`;
|
|
881
|
+
});
|
|
882
|
+
return [
|
|
883
|
+
'SynaBun [Jev] stale-memory check: a recent edit may have made these memories inaccurate.',
|
|
884
|
+
...lines,
|
|
885
|
+
'Check each against the current code, then `reflect` to correct it or `forget` it if it no longer holds.',
|
|
886
|
+
].join('\n');
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
// --- Environment / connection ---
|
|
890
|
+
|
|
891
|
+
function parseEnvFile(filePath) {
|
|
892
|
+
try {
|
|
893
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
894
|
+
const vars = {};
|
|
895
|
+
for (const line of content.split('\n')) {
|
|
896
|
+
const trimmed = line.trim();
|
|
897
|
+
if (!trimmed || trimmed.startsWith('#')) continue;
|
|
898
|
+
const eq = trimmed.indexOf('=');
|
|
899
|
+
if (eq === -1) continue;
|
|
900
|
+
vars[trimmed.slice(0, eq)] = trimmed.slice(eq + 1);
|
|
901
|
+
}
|
|
902
|
+
return vars;
|
|
903
|
+
} catch { return {}; }
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
export function getActiveConnectionId() {
|
|
907
|
+
const vars = parseEnvFile(ENV_PATH);
|
|
908
|
+
return vars.SYNABUN_ACTIVE_CONNECTION || vars.QDRANT_ACTIVE || 'default';
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
export function getCategoriesPath() {
|
|
912
|
+
const connId = getActiveConnectionId();
|
|
913
|
+
return join(MCP_DATA_DIR, `custom-categories-${connId}.json`);
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
/**
|
|
917
|
+
* Returns the path to the MCP server's categories file (no connection suffix).
|
|
918
|
+
* This is the file the MCP server watches — hooks that need the MCP server to
|
|
919
|
+
* pick up changes (e.g., schema refresh) MUST write to this file.
|
|
920
|
+
*/
|
|
921
|
+
export function getMcpCategoriesPath() {
|
|
922
|
+
return join(MCP_DATA_DIR, 'custom-categories.json');
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
// --- Project detection (reads from claude-code-projects.json) ---
|
|
926
|
+
|
|
927
|
+
const PROJECTS_PATH = join(DATA_DIR, 'claude-code-projects.json');
|
|
928
|
+
|
|
929
|
+
export function loadRegisteredProjects() {
|
|
930
|
+
try {
|
|
931
|
+
if (!existsSync(PROJECTS_PATH)) return [];
|
|
932
|
+
return JSON.parse(readFileSync(PROJECTS_PATH, 'utf-8'));
|
|
933
|
+
} catch { return []; }
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
export function normalizeLabel(label) {
|
|
937
|
+
return label.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
export function detectProject(cwd) {
|
|
941
|
+
if (!cwd) return 'global';
|
|
942
|
+
const lower = cwd.toLowerCase().replace(/\\/g, '/');
|
|
943
|
+
const projects = loadRegisteredProjects();
|
|
944
|
+
|
|
945
|
+
// Sort by path length descending — most specific match wins
|
|
946
|
+
const sorted = projects
|
|
947
|
+
.map((p) => ({
|
|
948
|
+
path: p.path.toLowerCase().replace(/\\/g, '/'),
|
|
949
|
+
label: normalizeLabel(p.label),
|
|
950
|
+
}))
|
|
951
|
+
.sort((a, b) => b.path.length - a.path.length);
|
|
952
|
+
|
|
953
|
+
// 1. Exact path prefix match (cwd is inside a registered project)
|
|
954
|
+
for (const p of sorted) {
|
|
955
|
+
if (lower.startsWith(p.path + '/') || lower === p.path) return p.label;
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
// 2. Substring match — cwd folder name contains a registered project's folder name
|
|
959
|
+
// e.g. "MyAppWebsite" contains "myapp" → matches the MyApp project
|
|
960
|
+
for (const p of sorted) {
|
|
961
|
+
const projFolder = basename(p.path).toLowerCase();
|
|
962
|
+
if (lower.includes(projFolder)) return p.label;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
// 3. Fallback to directory basename
|
|
966
|
+
const base = basename(cwd).toLowerCase().replace(/[^a-z0-9-]/g, '-');
|
|
967
|
+
return base || 'global';
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
// --- Category tree ---
|
|
971
|
+
|
|
972
|
+
export function loadCategories() {
|
|
973
|
+
try {
|
|
974
|
+
const data = JSON.parse(readFileSync(getCategoriesPath(), 'utf-8'));
|
|
975
|
+
if (data.version === 1 && Array.isArray(data.categories)) {
|
|
976
|
+
return data.categories;
|
|
977
|
+
}
|
|
978
|
+
} catch { /* no categories available */ }
|
|
979
|
+
return [];
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
export function buildCategoryTree(categories) {
|
|
983
|
+
if (!categories || categories.length === 0) {
|
|
984
|
+
return '(No categories defined yet. Use `category` with action "create" to set up your first category.)';
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
const parents = categories.filter((c) => c.is_parent);
|
|
988
|
+
const children = categories.filter((c) => c.parent);
|
|
989
|
+
const standalone = categories.filter((c) => !c.is_parent && !c.parent);
|
|
990
|
+
|
|
991
|
+
const lines = [];
|
|
992
|
+
|
|
993
|
+
for (const parent of parents) {
|
|
994
|
+
const kids = children.filter((c) => c.parent === parent.name);
|
|
995
|
+
lines.push(`${parent.name} (PARENT) — ${parent.description}`);
|
|
996
|
+
for (const kid of kids) {
|
|
997
|
+
lines.push(` └─ ${kid.name} — ${kid.description}`);
|
|
998
|
+
}
|
|
999
|
+
if (kids.length === 0) {
|
|
1000
|
+
lines.push(` (no children yet)`);
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
if (standalone.length > 0) {
|
|
1005
|
+
for (const cat of standalone) {
|
|
1006
|
+
lines.push(`${cat.name} — ${cat.description}`);
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
return lines.join('\n');
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
// --- Auto-category creation ---
|
|
1014
|
+
|
|
1015
|
+
/**
|
|
1016
|
+
* Standalone categories required by hooks. Always created regardless of projects.
|
|
1017
|
+
*/
|
|
1018
|
+
const STANDALONE_DEFAULTS = [
|
|
1019
|
+
{ name: 'conversations', description: 'Session summaries and conversation indexing' },
|
|
1020
|
+
{ name: 'communication-style', description: 'User communication patterns and preferences' },
|
|
1021
|
+
{ name: 'plans', description: 'Implementation plans stored after plan mode approval', is_parent: true, color: '#06d6a0' },
|
|
1022
|
+
];
|
|
1023
|
+
|
|
1024
|
+
/**
|
|
1025
|
+
* Default child categories for every registered project.
|
|
1026
|
+
* Created under a project parent, never standalone.
|
|
1027
|
+
*/
|
|
1028
|
+
const PROJECT_CHILDREN = [
|
|
1029
|
+
{ suffix: 'project', description: 'General project knowledge, decisions, and milestones' },
|
|
1030
|
+
{ suffix: 'architecture', description: 'System design, tech stack, data flow, and component architecture' },
|
|
1031
|
+
{ suffix: 'bugs', description: 'Bug fixes, debugging sessions, and known issues' },
|
|
1032
|
+
{ suffix: 'config', description: 'Configuration, deployment, environment, and infrastructure' },
|
|
1033
|
+
];
|
|
1034
|
+
|
|
1035
|
+
/**
|
|
1036
|
+
* Ensure all registered projects have a parent category with default children,
|
|
1037
|
+
* and that standalone hook-required categories exist.
|
|
1038
|
+
*
|
|
1039
|
+
* Writes to the MCP server's categories file (no connection suffix) so the
|
|
1040
|
+
* MCP server's file watcher picks up changes and refreshes tool schemas.
|
|
1041
|
+
*
|
|
1042
|
+
* Idempotent: only adds missing categories, never modifies or removes existing ones.
|
|
1043
|
+
*
|
|
1044
|
+
* @returns {{ created: string[], total: number }}
|
|
1045
|
+
*/
|
|
1046
|
+
export function ensureProjectCategories() {
|
|
1047
|
+
const projects = loadRegisteredProjects();
|
|
1048
|
+
const catPath = getMcpCategoriesPath();
|
|
1049
|
+
|
|
1050
|
+
let data;
|
|
1051
|
+
try {
|
|
1052
|
+
data = JSON.parse(readFileSync(catPath, 'utf-8'));
|
|
1053
|
+
} catch {
|
|
1054
|
+
data = { version: 1, categories: [] };
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
const categories = data.categories || [];
|
|
1058
|
+
const existingNames = new Set(categories.map((c) => c.name));
|
|
1059
|
+
const created = [];
|
|
1060
|
+
const now = new Date().toISOString();
|
|
1061
|
+
|
|
1062
|
+
// 1. Ensure standalone defaults exist
|
|
1063
|
+
for (const def of STANDALONE_DEFAULTS) {
|
|
1064
|
+
if (!existingNames.has(def.name)) {
|
|
1065
|
+
const cat = { name: def.name, description: def.description, created_at: now };
|
|
1066
|
+
if (def.is_parent) cat.is_parent = true;
|
|
1067
|
+
if (def.color) cat.color = def.color;
|
|
1068
|
+
categories.push(cat);
|
|
1069
|
+
existingNames.add(def.name);
|
|
1070
|
+
created.push(def.name);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
// 2. Ensure project parents + children exist
|
|
1075
|
+
for (const proj of projects) {
|
|
1076
|
+
let label = normalizeLabel(proj.label);
|
|
1077
|
+
// Truncate to 16 chars so children stay within 30-char limit (16 + 1 + 12 = 29)
|
|
1078
|
+
if (label.length > 16) label = label.slice(0, 16).replace(/-$/, '');
|
|
1079
|
+
|
|
1080
|
+
// Ensure parent exists
|
|
1081
|
+
if (!existingNames.has(label)) {
|
|
1082
|
+
categories.push({
|
|
1083
|
+
name: label,
|
|
1084
|
+
description: `Knowledge and context for the ${proj.label} project`,
|
|
1085
|
+
is_parent: true,
|
|
1086
|
+
created_at: now,
|
|
1087
|
+
});
|
|
1088
|
+
existingNames.add(label);
|
|
1089
|
+
created.push(label);
|
|
1090
|
+
} else {
|
|
1091
|
+
// Parent exists — ensure it has is_parent flag
|
|
1092
|
+
const existing = categories.find((c) => c.name === label);
|
|
1093
|
+
if (existing && !existing.is_parent) existing.is_parent = true;
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
// Ensure each default child exists
|
|
1097
|
+
for (const child of PROJECT_CHILDREN) {
|
|
1098
|
+
const childName = `${label}-${child.suffix}`;
|
|
1099
|
+
if (!existingNames.has(childName)) {
|
|
1100
|
+
categories.push({
|
|
1101
|
+
name: childName,
|
|
1102
|
+
description: `${child.description} for ${proj.label}`,
|
|
1103
|
+
parent: label,
|
|
1104
|
+
created_at: now,
|
|
1105
|
+
});
|
|
1106
|
+
existingNames.add(childName);
|
|
1107
|
+
created.push(childName);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
// Only write if we created something new
|
|
1113
|
+
if (created.length > 0) {
|
|
1114
|
+
data.categories = categories;
|
|
1115
|
+
writeFileSync(catPath, JSON.stringify(data, null, 2), 'utf-8');
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
return { created, total: categories.length };
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
/**
|
|
1122
|
+
* Build the full category reference block for lazy injection.
|
|
1123
|
+
* Includes tree, available names, selection rules, project scoping, and tool notes.
|
|
1124
|
+
*/
|
|
1125
|
+
export function buildCategoryReference(categories, project) {
|
|
1126
|
+
const tree = buildCategoryTree(categories);
|
|
1127
|
+
const names = categories.map((c) => c.name).join(', ');
|
|
1128
|
+
|
|
1129
|
+
return [
|
|
1130
|
+
`## SynaBun Category Reference`,
|
|
1131
|
+
``,
|
|
1132
|
+
`### Project: ${project}`,
|
|
1133
|
+
``,
|
|
1134
|
+
tree,
|
|
1135
|
+
``,
|
|
1136
|
+
`Available names: ${names || '(none)'}`,
|
|
1137
|
+
``,
|
|
1138
|
+
`### Category Selection`,
|
|
1139
|
+
``,
|
|
1140
|
+
`1. Match existing child category by description → use it.`,
|
|
1141
|
+
`2. No child fits but parent does → \`category\` with action "create" for a new child under that parent → use it.`,
|
|
1142
|
+
`3. No parent fits → \`category\` with action "create" for a new parent + child → use it.`,
|
|
1143
|
+
`4. Uncertain → \`AskUserQuestion\` with 2-3 options + "Create new category" → use what user picks.`,
|
|
1144
|
+
``,
|
|
1145
|
+
`NEVER guess. NEVER use parent directly. NEVER skip categorization.`,
|
|
1146
|
+
``,
|
|
1147
|
+
`### Project Scoping`,
|
|
1148
|
+
``,
|
|
1149
|
+
`- Project-specific (bugs, architecture, config) → "${project}"`,
|
|
1150
|
+
`- Universal (language features, library APIs) → "global"`,
|
|
1151
|
+
`- Cross-project (shared infra) → "shared"`,
|
|
1152
|
+
].join('\n');
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
// --- Loop staleness cleanup ---
|
|
1156
|
+
|
|
1157
|
+
const LOOP_STALE_INACTIVITY_MS = 45 * 60 * 1000; // 45 min — browser iterations can be long
|
|
1158
|
+
|
|
1159
|
+
/**
|
|
1160
|
+
* Scan loop directory and delete stale/inactive loop files.
|
|
1161
|
+
* No history keeping — ended loops are removed immediately.
|
|
1162
|
+
*
|
|
1163
|
+
* A loop is stale if:
|
|
1164
|
+
* 1. active + exceeded its maxMinutes + 5min grace
|
|
1165
|
+
* 2. active + no iteration activity for 10 minutes (session died)
|
|
1166
|
+
*
|
|
1167
|
+
* @param {string} loopDir - path to data/loop/
|
|
1168
|
+
* @returns {{ deactivated: string[], deleted: string[] }}
|
|
1169
|
+
*/
|
|
1170
|
+
export function cleanupStaleLoops(loopDir) {
|
|
1171
|
+
const deactivated = [];
|
|
1172
|
+
const deleted = [];
|
|
1173
|
+
if (!existsSync(loopDir)) return { deactivated, deleted };
|
|
1174
|
+
|
|
1175
|
+
const now = Date.now();
|
|
1176
|
+
try {
|
|
1177
|
+
const files = readdirSync(loopDir).filter(f => f.endsWith('.json') && !f.startsWith('pending-') && f !== 'active-pointer.json');
|
|
1178
|
+
for (const f of files) {
|
|
1179
|
+
const fp = join(loopDir, f);
|
|
1180
|
+
try {
|
|
1181
|
+
const loop = JSON.parse(readFileSync(fp, 'utf-8'));
|
|
1182
|
+
|
|
1183
|
+
if (loop.active) {
|
|
1184
|
+
const lastActivity = new Date(loop.lastIterationAt || loop.startedAt || 0).getTime();
|
|
1185
|
+
const noRecentActivity = (now - lastActivity) >= LOOP_STALE_INACTIVITY_MS;
|
|
1186
|
+
|
|
1187
|
+
if (noRecentActivity) {
|
|
1188
|
+
// Stale loop (no activity for 45 min) — delete immediately
|
|
1189
|
+
try { unlinkSync(fp); deleted.push(f); } catch { /* ok */ }
|
|
1190
|
+
}
|
|
1191
|
+
} else {
|
|
1192
|
+
// Inactive loop — delete immediately (no history keeping)
|
|
1193
|
+
try { unlinkSync(fp); deleted.push(f); } catch { /* ok */ }
|
|
1194
|
+
}
|
|
1195
|
+
} catch { /* skip corrupt files */ }
|
|
1196
|
+
}
|
|
1197
|
+
} catch { /* ok */ }
|
|
1198
|
+
|
|
1199
|
+
// Drop active-pointer.json if its target flag no longer exists
|
|
1200
|
+
try {
|
|
1201
|
+
const ptrPath = join(loopDir, 'active-pointer.json');
|
|
1202
|
+
if (existsSync(ptrPath)) {
|
|
1203
|
+
const ptr = JSON.parse(readFileSync(ptrPath, 'utf-8'));
|
|
1204
|
+
const targetPath = ptr?.sessionId ? join(loopDir, `${ptr.sessionId}.json`) : null;
|
|
1205
|
+
if (!targetPath || !existsSync(targetPath)) {
|
|
1206
|
+
try { unlinkSync(ptrPath); } catch { /* ok */ }
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
} catch { /* ok */ }
|
|
1210
|
+
|
|
1211
|
+
// Delete stale pending-*.json files (client never claimed them)
|
|
1212
|
+
try {
|
|
1213
|
+
const pendingFiles = readdirSync(loopDir)
|
|
1214
|
+
.filter(f => f.startsWith('pending-') && f.endsWith('.json'));
|
|
1215
|
+
for (const f of pendingFiles) {
|
|
1216
|
+
const fp = join(loopDir, f);
|
|
1217
|
+
try {
|
|
1218
|
+
const loop = JSON.parse(readFileSync(fp, 'utf-8'));
|
|
1219
|
+
const lastActivity = new Date(loop.lastIterationAt || loop.startedAt || 0).getTime();
|
|
1220
|
+
if ((now - lastActivity) >= LOOP_STALE_INACTIVITY_MS) {
|
|
1221
|
+
try { unlinkSync(fp); deleted.push(f); } catch { /* ok */ }
|
|
1222
|
+
}
|
|
1223
|
+
} catch { /* skip corrupt */ }
|
|
1224
|
+
}
|
|
1225
|
+
} catch { /* ok */ }
|
|
1226
|
+
|
|
1227
|
+
return { deactivated, deleted };
|
|
1228
|
+
}
|