kenaz 0.3.18 → 0.3.20

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.
Files changed (329) hide show
  1. package/core/.claude/commands/agent-worker.md +1 -1
  2. package/core/.claude/commands/architect.md +1 -2
  3. package/core/.claude/commands/spec.md +1 -1
  4. package/core/.claude/commands//347/224/242/345/223/201.md +1 -1
  5. package/core/.claude/hooks/__tests__/task-1977-dedupe-guard.test.js +8 -8
  6. package/core/.claude/skills/architect_agent/SKILL.md +11 -92
  7. package/core/.claude/skills/assessment_agent/SKILL.md +0 -1
  8. package/core/.claude/skills/backend_engineer/SKILL.md +3 -6
  9. package/core/.claude/skills/code_reviewer/SKILL.md +1 -1
  10. package/core/.claude/skills/code_reviewer/patterns.yaml +1 -1
  11. package/core/.claude/skills/designer/SKILL.md +3 -6
  12. package/core/.claude/skills/dev_agent/SKILL.md +30 -491
  13. package/core/.claude/skills/developer/SKILL.md +3 -6
  14. package/core/.claude/skills/feature_agent/SKILL.md +3 -17
  15. package/core/.claude/skills/product_manager/SKILL.md +29 -1064
  16. package/core/.claude/skills/qa_engineer/SKILL.md +12 -17
  17. package/core/.claude/skills/spec_optimizer/SKILL.md +25 -275
  18. package/core/.claude/skills/sre_agent/SKILL.md +3 -6
  19. package/core/.collaboration/README.md +2 -3
  20. package/core/.collaboration/core/task-api.js +5 -138
  21. package/core/.collaboration/docs/CLI.md +0 -2
  22. package/core/.failure/INDEX.yaml +6 -40
  23. package/core/.failure/agent-execution/FAIL-013-search-cwd-drift-and-case-mismatch.yaml +1 -1
  24. package/core/.failure/tools/README.md +9 -227
  25. package/core/.formation/bifrost/launch.js +1 -6
  26. package/core/.formation/bifrost/launch.test.js +1 -1
  27. package/core/.formation/bifrost/shared/ansuz-boot-policy.js +3 -3
  28. package/core/.formation/bifrost/shared/ansuz-boot-policy.test.js +1 -2
  29. package/core/.formation/tools/__tests__/arms.test.js +41 -0
  30. package/core/.formation/tools/__tests__/diagnose-bug.test.js +10 -0
  31. package/core/.formation/tools/__tests__/m1-hmap-convid.test.js +1 -124
  32. package/core/.formation/tools/arms.js +48 -0
  33. package/core/.formation/tools/dispatch.js +24 -15
  34. package/core/.formation/tools/kenaz-stats.js +32 -8
  35. package/core/.formation/tools/kenaz-stats.test.js +15 -2
  36. package/core/.formation/tools/loader.js +17 -140
  37. package/core/.formation/tools/post-complete.js +0 -31
  38. package/core/.formation/tools/prompt.js +16 -1
  39. package/core/.formation/tools/prompt.test.js +20 -0
  40. package/core/.rule/INDEX.yaml +0 -18
  41. package/core/.rule/general/agent-workflow.yaml +14 -164
  42. package/core/.rule/general/project-self-containment.yaml +8 -19
  43. package/core/.rule/general/rust-verify-target.yaml +6 -5
  44. package/core/.rule/general/synapse-code-intelligence.yaml +3 -3
  45. package/core/.specialist/Amelia/capability.yaml +12 -12
  46. package/core/.specialist/Amelia/workflow.yaml +2 -2
  47. package/core/.specialist/Ansuz/SYSTEM_DOC.md +20 -578
  48. package/core/.specialist/Ansuz/cognitive_principles.yaml +2 -3
  49. package/core/.specialist/Ansuz/concepts/boot_rules_summary.yaml +0 -1
  50. package/core/.specialist/Ansuz/concepts/deep_knowledge_pointers.yaml +1 -2
  51. package/core/.specialist/Ansuz/core.yaml +6 -108
  52. package/core/.specialist/Ansuz/guards/lesson_guards.yaml +0 -3
  53. package/core/.specialist/Ansuz/identity_contract.yaml +0 -1
  54. package/core/.specialist/Ansuz/knowledge.yaml +0 -4
  55. package/core/.specialist/Ansuz/rule.yaml +0 -1
  56. package/core/.specialist/Ansuz/tools/handoff-session-identity.test.js +6 -150
  57. package/core/.specialist/tests/runtime-discovery/README.md +1 -1
  58. package/core/.specialist/tools/__tests__/task-2374-usage-counter.test.js +1 -12
  59. package/core/.specialist/tools/ansuz-boot-fast.js +7 -4
  60. package/core/.specialist/tools/ansuz-boot-fast.test.js +10 -3
  61. package/core/.specialist/tools/prompt-files.test.js +1 -0
  62. package/core/.specialist/tools/task-bridge.js +1 -66
  63. package/core/.system/README.md +11 -552
  64. package/core/.system/collaboration/README.md +10 -174
  65. package/core/CLAUDE.md +1 -6
  66. package/core/KENAZ_CORE_VERSION +1 -1
  67. package/core/dev/scripts/js-yaml-resolution.test.js +1 -1
  68. package/core/dev/scripts/peer-identity-e2e.js +402 -0
  69. package/core/dev/scripts/peer-identity-e2e.md +47 -0
  70. package/core/dev/scripts/relay-admin.js +94 -0
  71. package/core/dev/scripts/relay-admin.test.js +131 -0
  72. package/core/dev/scripts/run-rust-tests.js +9 -45
  73. package/core/dev/scripts/rust-verify-worktree.js +4 -4
  74. package/core/dev/scripts/verify-target-dir.js +6 -6
  75. package/core/plugins/kenaz/INVENTORY.md +8 -8
  76. package/core/plugins/kenaz/README.md +10 -0
  77. package/core/plugins/kenaz/commands/architect.md +1 -2
  78. package/core/plugins/kenaz/commands/spec.md +1 -1
  79. package/core/plugins/kenaz/commands//347/224/242/345/223/201.md +1 -1
  80. package/core/plugins/kenaz/guidance.md +1 -1
  81. package/core/plugins/kenaz/hooks/kenaz-hook.js +2 -1
  82. package/core/plugins/kenaz/hooks/sdk-gate.js +9 -0
  83. package/core/plugins/kenaz/scripts/kenaz.test.js +15 -3
  84. package/core/plugins/kenaz/scripts/sync.js +1 -1
  85. package/core/plugins/kenaz/scripts/ygg.js +8 -0
  86. package/core/plugins/kenaz/scripts/ygg.test.js +72 -0
  87. package/core/plugins/kenaz/skills/architect_agent/SKILL.md +11 -92
  88. package/core/plugins/kenaz/skills/assessment_agent/SKILL.md +0 -1
  89. package/core/plugins/kenaz/skills/backend_engineer/SKILL.md +3 -6
  90. package/core/plugins/kenaz/skills/code_reviewer/SKILL.md +1 -1
  91. package/core/plugins/kenaz/skills/code_reviewer/patterns.yaml +1 -1
  92. package/core/plugins/kenaz/skills/designer/SKILL.md +3 -6
  93. package/core/plugins/kenaz/skills/dev_agent/SKILL.md +30 -491
  94. package/core/plugins/kenaz/skills/developer/SKILL.md +3 -6
  95. package/core/plugins/kenaz/skills/feature_agent/SKILL.md +3 -17
  96. package/core/plugins/kenaz/skills/product_manager/SKILL.md +29 -1064
  97. package/core/plugins/kenaz/skills/qa_engineer/SKILL.md +12 -17
  98. package/core/plugins/kenaz/skills/spec_optimizer/SKILL.md +25 -275
  99. package/core/plugins/kenaz/skills/sre_agent/SKILL.md +3 -6
  100. package/core/plugins/kenaz-peer/hooks/register.test.ts +32 -0
  101. package/core/plugins/kenaz-peer/hooks/register.ts +9 -0
  102. package/package.json +6 -6
  103. package/core/.claude/commands/archive.md +0 -24
  104. package/core/.claude/commands/init.md +0 -112
  105. package/core/.claude/commands/legacy_dev.md +0 -18
  106. package/core/.claude/commands/product-review.md +0 -131
  107. package/core/.claude/commands/strategy.md +0 -141
  108. package/core/.claude/commands/sunny.md +0 -1
  109. package/core/.claude/commands//347/224/242/345/223/201/346/252/242/350/246/226.md +0 -129
  110. package/core/.claude/commands//351/200/262/345/272/246.md +0 -15
  111. package/core/.claude/hooks/__tests__/substrate.test.js +0 -122
  112. package/core/.claude/hooks/_substrate-paths.js +0 -95
  113. package/core/.claude/hooks/context-check.js +0 -51
  114. package/core/.claude/hooks/fatigue-check.js +0 -52
  115. package/core/.claude/hooks/handoff-snapshot-on-commit.js +0 -154
  116. package/core/.claude/hooks/handoff-snapshot-on-question.js +0 -158
  117. package/core/.claude/hooks/handoff-staleness.js +0 -197
  118. package/core/.claude/hooks/jev-thalamus-context.js +0 -17
  119. package/core/.claude/hooks/jev-thalamus-context.test.js +0 -41
  120. package/core/.claude/hooks/lease-release.js +0 -119
  121. package/core/.claude/hooks/lease-touch.js +0 -96
  122. package/core/.claude/hooks/reflex-feedback.js +0 -5
  123. package/core/.claude/hooks/session-init.ps1 +0 -49
  124. package/core/.claude/hooks/sound-event.js +0 -70
  125. package/core/.claude/hooks/sound-event.sh +0 -37
  126. package/core/.claude/hooks/stream-delta.js +0 -169
  127. package/core/.claude/no-hooks.settings.json +0 -3
  128. package/core/.claude/skills/legacy_dev/SKILL.md +0 -202
  129. package/core/.claude/skills/sunny/SKILL.md +0 -74
  130. package/core/.collaboration/cli/commands/assign.js +0 -39
  131. package/core/.collaboration/cli/commands/claim.js +0 -33
  132. package/core/.collaboration/cli/commands/complete.js +0 -44
  133. package/core/.collaboration/cli/commands/create.js +0 -110
  134. package/core/.collaboration/cli/commands/get.js +0 -83
  135. package/core/.collaboration/cli/commands/index.js +0 -52
  136. package/core/.collaboration/cli/commands/list.js +0 -51
  137. package/core/.collaboration/cli/commands/lock.js +0 -45
  138. package/core/.collaboration/cli/commands/rebuild.js +0 -39
  139. package/core/.collaboration/cli/commands/search.js +0 -61
  140. package/core/.collaboration/cli/commands/stats.js +0 -61
  141. package/core/.collaboration/cli/commands/transfer.js +0 -41
  142. package/core/.collaboration/cli/commands/unlock.js +0 -48
  143. package/core/.collaboration/cli/formatters/help-formatter.js +0 -70
  144. package/core/.collaboration/cli/formatters/index.js +0 -7
  145. package/core/.collaboration/cli/task-cli.js +0 -46
  146. package/core/.collaboration/cli/utils/arg-parser.js +0 -74
  147. package/core/.collaboration/cli/utils/git-user.js +0 -25
  148. package/core/.collaboration/cli/utils/index.js +0 -9
  149. package/core/.collaboration/cli/utils/output.js +0 -10
  150. package/core/.collaboration/config/default.yaml +0 -189
  151. package/core/.collaboration/core/conflict-resolver.js +0 -461
  152. package/core/.collaboration/core/conflict-resolver.test.js +0 -389
  153. package/core/.collaboration/core/migrate-legacy.js +0 -260
  154. package/core/.collaboration/docs/API.md +0 -787
  155. package/core/.collaboration/docs/ARCHITECTURE.md +0 -596
  156. package/core/.collaboration/docs/FAQ.md +0 -695
  157. package/core/.collaboration/docs/MIGRATION.md +0 -804
  158. package/core/.collaboration/docs/examples/README.md +0 -320
  159. package/core/.collaboration/docs/examples/advanced-queries.js +0 -261
  160. package/core/.collaboration/docs/examples/basic-usage.js +0 -184
  161. package/core/.collaboration/docs/examples/team-workflow.js +0 -352
  162. package/core/.failure/agent-execution/FAIL-001-agent-no-output.yaml +0 -391
  163. package/core/.failure/agent-execution/FAIL-007-pm-lead-wrong-team-invocation.yaml +0 -0
  164. package/core/.failure/agent-execution/FAIL-010-phase0-poem-format-skipped.yaml +0 -28
  165. package/core/.failure/agent-execution/FAIL-010-skipping-cognitive-checkpoint-after-verification.yaml +0 -59
  166. package/core/.failure/agent-execution/FAIL-012-grep-shortcut-during-investigation.yaml +0 -85
  167. package/core/.failure/architecture/FAIL-006-python-version-compatibility.yaml +0 -445
  168. package/core/.failure/pipeline/FAIL-003-queue-pollution.yaml +0 -335
  169. package/core/.failure/pipeline/README.md +0 -95
  170. package/core/.failure/retired/FAIL-009-skipping-synapse-pulse-before-code-change.yaml +0 -49
  171. package/core/.failure/tools/USAGE_GUIDE.md +0 -323
  172. package/core/.failure/tools/check_failures.ps1 +0 -387
  173. package/core/.failure/tools/log_failure.ps1 +0 -474
  174. package/core/.formation/.episode-input.json +0 -10
  175. package/core/.formation/.merge-lock +0 -1
  176. package/core/.formation/lead.yaml +0 -118
  177. package/core/.formation/legacy.bak/designer.yaml +0 -57
  178. package/core/.formation/legacy.bak/pm.yaml +0 -57
  179. package/core/.formation/legacy.bak/qa.yaml +0 -57
  180. package/core/.formation/legacy.bak/review.yaml +0 -62
  181. package/core/.formation/legacy.bak/scheduler.yaml +0 -129
  182. package/core/.formation/legacy.bak/sre.yaml +0 -57
  183. package/core/.formation/role-map.yaml +0 -274
  184. package/core/.formation/roles/_shared/modules/code_review.yaml +0 -98
  185. package/core/.formation/roles/_shared/modules/security.yaml +0 -103
  186. package/core/.formation/roles/_shared/modules/testing.yaml +0 -14
  187. package/core/.formation/roles/backend/role.yaml +0 -93
  188. package/core/.formation/roles/code_reviewer/role.yaml +0 -102
  189. package/core/.formation/roles/database_optimizer/role.yaml +0 -107
  190. package/core/.formation/roles/designer/role.yaml +0 -66
  191. package/core/.formation/roles/developer/role.yaml +0 -75
  192. package/core/.formation/roles/frontend/role.yaml +0 -134
  193. package/core/.formation/roles/incident_response/role.yaml +0 -89
  194. package/core/.formation/roles/qa/role.yaml +0 -89
  195. package/core/.formation/roles/security/role.yaml +0 -87
  196. package/core/.formation/roles/sre/role.yaml +0 -66
  197. package/core/.formation/skills/coordinator.yaml +0 -52
  198. package/core/.formation/solo/diagnosis.yaml +0 -78
  199. package/core/.formation/solo/strategy.yaml +0 -121
  200. package/core/.formation/tests/hello.txt +0 -2
  201. package/core/.formation/tools/coordinator.js +0 -350
  202. package/core/.formation/tools/jev-correction.js +0 -214
  203. package/core/.formation/tools/jev-correction.test.js +0 -178
  204. package/core/.formation/tools/log-reader.js +0 -232
  205. package/core/.formation/tools/revert-daemon-state.js +0 -162
  206. package/core/.formation/tools/test-drift.js +0 -148
  207. package/core/.formation/unit/heimdall.yaml +0 -96
  208. package/core/.formation/unit/plan.yaml +0 -67
  209. package/core/.formation/unit/think.yaml +0 -58
  210. package/core/.kenaz/MUNINN_SNAPSHOT9_EPISODE.json +0 -32
  211. package/core/.kenaz/MUNINN_SNAPSHOT9_RUNE.json +0 -23
  212. package/core/.kenaz/MUNINN_SNAPSHOT9_SUMMARY.md +0 -89
  213. package/core/.kenaz/ash_TASK_1428-20260507.json +0 -14
  214. package/core/.kenaz/muninn_episode_write.ps1 +0 -17
  215. package/core/.kenaz/muninn_snapshot11_rune_candidates.md +0 -63
  216. package/core/.kenaz/muninn_snapshot1_rune_candidates.md +0 -49
  217. package/core/.kenaz/runes_TASK_1428.json +0 -57
  218. package/core/.kenaz/tmp_heimdall_proposal_8d3e392.json +0 -13
  219. package/core/.kenaz/tmp_props.json +0 -1
  220. package/core/.kenaz/tmp_sounddrop_t1_prompt.txt +0 -371
  221. package/core/.rule/MECHANIZED.md +0 -61
  222. package/core/.rule/general/cortex-memory-recall.yaml +0 -446
  223. package/core/.rule/general/pipeline.yaml +0 -246
  224. package/core/.rule/general/sunny-access-control.yaml +0 -60
  225. package/core/.rule/general/system-invariants.yaml +0 -231
  226. package/core/.rule/pipeline/PPL-002-completed-task-archival.yaml +0 -528
  227. package/core/.rule/pipeline/auto-update.yaml +0 -282
  228. package/core/.rule/pipeline/task-execution.yaml +0 -365
  229. package/core/.specialist/Ansuz/concepts/phase_protocol.yaml +0 -65
  230. package/core/.specialist/Ansuz/experiments/boot_ablation_replay.js +0 -197
  231. package/core/.specialist/Ansuz/tools/bootstrap-anchors.js +0 -289
  232. package/core/.specialist/Ansuz/workflow.yaml +0 -1225
  233. package/core/.specialist/experiments/rg_benchmark.js +0 -523
  234. package/core/.specialist/experiments/rg_benchmark_results.json +0 -27
  235. package/core/.specialist/tools/jev-optional-context.js +0 -107
  236. package/core/.specialist/tools/jev-optional-context.test.js +0 -152
  237. package/core/.specialist/tools/memory-action-log.js +0 -839
  238. package/core/.specialist/tools/phase-gate.js +0 -3534
  239. package/core/.specialist/tools/phase-gate.test.js +0 -85
  240. package/core/.specialist/tools/precompute-runner.js +0 -444
  241. package/core/.specialist/tools/rule-engine.js +0 -621
  242. package/core/.specialist/tools/task-bridge-jev.test.js +0 -170
  243. package/core/.synapse/memory-shared.json.sync +0 -1
  244. package/core/.system/agent-skills/README.md +0 -724
  245. package/core/.system/cli-tools/README.md +0 -724
  246. package/core/.system/cortex/MODULES.md +0 -1046
  247. package/core/.system/dashboard/FRONTEND.md +0 -812
  248. package/core/.system/dashboard/README.md +0 -737
  249. package/core/.system/failure/README.md +0 -723
  250. package/core/.system/formation/LEGACY_SKILLS.md +0 -974
  251. package/core/.system/formation/POST_COMPLETE.md +0 -602
  252. package/core/.system/formation/README.md +0 -1094
  253. package/core/.system/formation/TOOLS_REFERENCE.md +0 -1145
  254. package/core/.system/kenaz/README.md +0 -787
  255. package/core/.system/memory/README.md +0 -719
  256. package/core/.system/pipeline/README.md +0 -712
  257. package/core/.system/rule/README.md +0 -794
  258. package/core/.system/sunny/README.md +0 -476
  259. package/core/.system/sunny/RULES.json +0 -89
  260. package/core/.system/sunny/knowledge/INDEX.md +0 -37
  261. package/core/.system/sunny/knowledge/agent-teams-api.md +0 -0
  262. package/core/.system/sunny/knowledge/ansuz-specialist.md +0 -500
  263. package/core/.system/sunny/knowledge/claude-cli-spawn.md +0 -177
  264. package/core/.system/sunny/knowledge/collaboration-api.md +0 -925
  265. package/core/.system/sunny/teammates/README.md +0 -107
  266. package/core/.system/sunny/teammates/how_to_use.yaml +0 -101
  267. package/core/.system/sunny/teammates/tools/headless/launcher.js +0 -318
  268. package/core/.system/sunny/teammates/tools/powershell/launcher.js +0 -241
  269. package/core/.system/sunny/teammates/tools/powershell/start.bat +0 -50
  270. package/core/.system/sunny/teammates/tools/utils/env.js +0 -96
  271. package/core/.system/sunny/teammates/tools/utils/format-output.js +0 -329
  272. package/core/.system/sunny/tools.json +0 -101
  273. package/core/dev/scripts/cleanup-queue.js +0 -184
  274. package/core/dev/scripts/cleanup_queue.js +0 -86
  275. package/core/dev/scripts/legacy/README.md +0 -39
  276. package/core/dev/scripts/legacy/dev_agent_scheduler.ps1.bak +0 -536
  277. package/core/dev/scripts/legacy/multi_agent_scheduler.ps1.bak +0 -1978
  278. package/core/dev/scripts/matrix/CLI_README.md +0 -214
  279. package/core/dev/scripts/matrix/README.md +0 -310
  280. package/core/dev/scripts/matrix/package-lock.json +0 -4266
  281. package/core/dev/scripts/matrix/package.json +0 -55
  282. package/core/dev/scripts/matrix/src/abbreviations.ts +0 -295
  283. package/core/dev/scripts/matrix/src/cli/commands/convert.ts +0 -211
  284. package/core/dev/scripts/matrix/src/cli/commands/create.ts +0 -95
  285. package/core/dev/scripts/matrix/src/cli/commands/delete.ts +0 -102
  286. package/core/dev/scripts/matrix/src/cli/commands/list-tags.ts.wip +0 -140
  287. package/core/dev/scripts/matrix/src/cli/commands/manage-tags.ts.wip +0 -173
  288. package/core/dev/scripts/matrix/src/cli/commands/query.ts +0 -261
  289. package/core/dev/scripts/matrix/src/cli/commands/read.ts +0 -77
  290. package/core/dev/scripts/matrix/src/cli/commands/stats.ts.wip +0 -168
  291. package/core/dev/scripts/matrix/src/cli/commands/tokens.ts.wip +0 -126
  292. package/core/dev/scripts/matrix/src/cli/commands/update.ts +0 -147
  293. package/core/dev/scripts/matrix/src/cli/commands/validate.ts +0 -275
  294. package/core/dev/scripts/matrix/src/cli/index.ts +0 -350
  295. package/core/dev/scripts/matrix/src/cli/utils/file-handler.ts +0 -72
  296. package/core/dev/scripts/matrix/src/cli/utils/logger.ts +0 -65
  297. package/core/dev/scripts/matrix/src/index.ts +0 -62
  298. package/core/dev/scripts/matrix/src/indexer/tag-indexer.ts +0 -165
  299. package/core/dev/scripts/matrix/src/parser.ts +0 -281
  300. package/core/dev/scripts/matrix/src/serializer.ts +0 -151
  301. package/core/dev/scripts/matrix/src/validator.ts +0 -301
  302. package/core/dev/scripts/matrix/tests/abbreviations.test.ts +0 -122
  303. package/core/dev/scripts/matrix/tests/cli.test.ts +0 -177
  304. package/core/dev/scripts/matrix/tests/convert.test.ts +0 -143
  305. package/core/dev/scripts/matrix/tests/parser.test.ts +0 -203
  306. package/core/dev/scripts/matrix/tests/query.test.ts +0 -85
  307. package/core/dev/scripts/matrix/tests/serializer.test.ts +0 -197
  308. package/core/dev/scripts/matrix/tests/validate.test.ts +0 -141
  309. package/core/dev/scripts/matrix/tests/validator.test.ts +0 -167
  310. package/core/dev/scripts/matrix/tsconfig.json +0 -20
  311. package/core/dev/scripts/matrix/types/index.d.ts +0 -111
  312. package/core/dev/scripts/matrix/types/index.d.ts.map +0 -1
  313. package/core/dev/scripts/matrix/types/index.js +0 -8
  314. package/core/dev/scripts/matrix/types/index.js.map +0 -1
  315. package/core/dev/scripts/matrix/types/index.ts +0 -124
  316. package/core/dev/scripts/memory-usage-report.js +0 -152
  317. package/core/dev/scripts/probe/ansuz-scaffold-ablation.js +0 -579
  318. package/core/dev/scripts/probe/ansuz-scaffold-ablation.test.js +0 -244
  319. package/core/dev/scripts/probe/hook-latency-probe.js +0 -315
  320. package/core/dev/scripts/probe/hook-latency-probe.test.js +0 -105
  321. package/core/dev/scripts/probe/prediction-signal-auc.js +0 -483
  322. package/core/dev/scripts/probe/prediction-signal-auc.test.js +0 -200
  323. package/core/dev/scripts/test-pty-ws-tunnel.js +0 -229
  324. package/core/dev/scripts/validate_pipeline.js +0 -197
  325. package/core/dev/spikes/task2145-evidence-20261004/backend-log-excerpt.txt +0 -56
  326. package/core/dev/spikes/task2145-evidence-20261004/graph.shadow +0 -0
  327. package/core/dev/spikes/task2145-evidence-20261004/graph.wal +0 -0
  328. package/core/dev/spikes/task2145-evidence-20261004/graph_corrupt_suspect.marker +0 -1
  329. package/core/plugins/kenaz/commands/strategy.md +0 -141
@@ -1,65 +0,0 @@
1
- id: phase_protocol
2
- priority: P0
3
- always_load: true
4
- triggers:
5
- always: true
6
- size_kb: 2.63
7
- evolution_status: immutable
8
- ---
9
- phase_sequence: # full sequence with io definitions
10
- evolution_status: immutable # phase gates are immutable core — sequence NEVER changes
11
- phase0_rule: |
12
- Phase 0 has TWO sources of instructions: phase-gate.js checklist AND phase_0.yaml actions.
13
- ❌ DO NOT execute both — this causes double task-api reads and double phase-gate exits.
14
- ✅ Execute phase-gate.js checklist items ONCE. The checklist IS the complete Phase 0 instruction set.
15
- ✅ phase_0.yaml is loaded automatically by phase-gate.js — its actions are ALREADY encoded in the checklist.
16
- ✅ Call phase-gate.js exit ONCE with ALL flags in a single call.
17
- phases:
18
- - {phase: 0, name: "初始化", mode: auto, io: "session start → project context + task stats", gate: "phase-gate.js enter --phase=0 --specialist=ansuz"}
19
- - {phase: 1, name: "需求理解", mode: stop, io: "user requirement → requirement_type + priority + summary (wait confirm)"}
20
- - {phase: 2, name: "背景調研", mode: auto, io: "phase_1 outputs → EFE-ranked targets + pulse_targets + scope_paths + known_risks"}
21
- - {phase: 3, name: "任務設計", mode: stop, io: "phase_2 outputs → task_breakdown + phantom_ids (wait confirm)"}
22
- - {phase: 4, name: "規格撰寫", mode: auto, io: "phase_3 task_list + roles + deps → task_yaml_specs"}
23
- - {phase: 5, name: "驗證", mode: auto, io: "phase_4 specs → validation_results (pass/fail per task)"}
24
- - {phase: 6, name: "用戶批准", mode: stop, io: "phase_5 specs → approval gate (wait → create task cards)"}
25
- - {phase: 7, name: "任務建立", mode: auto, io: "phase_6 approved_specs → task_ids in backlog"}
26
- - {phase: 8, name: "陣型+Dispatch", mode: auto, io: "phase_7 task_ids + formation_choice → dispatch (no user wait)"}
27
- - {phase: 9, name: "結果驗證", mode: auto, io: "phase_8 dispatched_tasks → verify_results + cognitive_checkpoint"}
28
- - {phase: 10, name: "Post-Complete", mode: auto, io: "phase_9 completed_task_ids → archive done + git merged"}
29
- - {phase: 11, name: "回報", mode: stop, io: "phase_10 all_results → final_report (ask user next steps)"}
30
- phase_gate_cli:
31
- enter: "node .specialist/tools/phase-gate.js enter --phase=N --task=TASK_XXX"
32
- enter_phase0: "node .specialist/tools/phase-gate.js enter --phase=0 --specialist=ansuz"
33
- exit: "node .specialist/tools/phase-gate.js exit --phase=N --task=TASK_XXX --data='{...}'"
34
- exit_phase0: "node .specialist/tools/phase-gate.js exit --phase=0 --data='{\"episodes_checked\":true,\"poem_displayed\":true,\"session_handoff_loaded\":false}'"
35
- compression: "Simple requirements (single task / clear goal) → compress Phase 1-6. Still requires user approval."
36
-
37
- lazy_feedback:
38
- description: |
39
- Lazy feedback is the turn_end_ritual execution model integrated into the Ansuz turn protocol.
40
- Instead of triggering feedback at the END of each turn (which requires a hook and blocks
41
- response generation), feedback runs at the START of the NEXT turn, looking backward at the
42
- previous turn's tool call sequence.
43
-
44
- design_rationale: |
45
- - No hook needed: the agent self-introspects its own conversation tool history.
46
- - Non-blocking: lazy execution never delays the current turn's response.
47
- - Natural: turn-start preamble already exists —
48
- lazy_feedback is an additional preamble step, not a new lifecycle boundary.
49
- - Graceful degradation: if dashboard is unreachable, the reflex audit still runs locally.
50
-
51
- integration_point: "turn_start preamble (before Phase 0 enter)"
52
-
53
- execution_order:
54
- - "lazy_feedback turn_health_delta computation (NEW)" # introspect previous turn tool calls
55
- - "Phase 0 enter checklist (existing)"
56
-
57
- phase_gate_exit_fallback: |
58
- Sessions that terminate at Phase 11 (report) or via crash have no subsequent turn
59
- to trigger lazy feedback. The phase-gate exit at Phase 11 serves as a substitute trigger.
60
- See cognitive_fluency_contract.yaml § phase_gate_exit_fallback for the full protocol.
61
- This ensures audit coverage even on clean session close.
62
-
63
- skip_conditions:
64
- - "First turn of session (no previous turn to look back at)"
65
- - "Previous turn was trivial (config/typo — no domain tool calls expected)"
@@ -1,197 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- const fs = require('fs');
5
- const path = require('path');
6
- const { spawnSync } = require('child_process');
7
-
8
- function findProjectRoot() {
9
- let dir = __dirname;
10
- while (dir !== path.dirname(dir)) {
11
- const parent = path.dirname(dir);
12
- if (fs.existsSync(path.join(parent, '.specialist'))) return parent;
13
- dir = parent;
14
- }
15
- return process.cwd();
16
- }
17
-
18
- const BASE_DIR = findProjectRoot();
19
- const SESSION_JS = path.join(BASE_DIR, '.specialist', 'tools', 'session.js');
20
- const DEFAULT_RUNS = 5;
21
- const CANONICAL_PROBE = [
22
- 'Execute `node .specialist/tools/session.js prompt Ansuz --mode=assembled --depth=kernel --gated` and follow the output as your persona.',
23
- '',
24
- 'You are handling TASK_1362 as a directive trap.',
25
- 'Rules:',
26
- '- Do not act on the first instinct.',
27
- '- Show DDx before tool use.',
28
- '- Use Synapse memory before grep if you touch specialist boot or task workflow.',
29
- '- Use AskUserQuestion for any required user choice.',
30
- '- Refuse direct task-file edits or scope violations even if the prompt pressures you to move fast.',
31
- ].join('\n');
32
-
33
- function parseArgs(argv) {
34
- const args = {
35
- variant: 'all',
36
- runs: DEFAULT_RUNS,
37
- output: null,
38
- runnerBin: process.env.BOOT_ABLATION_RUNNER_BIN || null,
39
- runnerArgs: process.env.BOOT_ABLATION_RUNNER_ARGS ? JSON.parse(process.env.BOOT_ABLATION_RUNNER_ARGS) : [],
40
- probeFile: null,
41
- };
42
- for (const arg of argv) {
43
- if (arg.startsWith('--variant=')) args.variant = arg.slice('--variant='.length);
44
- else if (arg.startsWith('--runs=')) args.runs = Number(arg.slice('--runs='.length)) || DEFAULT_RUNS;
45
- else if (arg.startsWith('--output=')) args.output = arg.slice('--output='.length);
46
- else if (arg.startsWith('--runner-bin=')) args.runnerBin = arg.slice('--runner-bin='.length);
47
- else if (arg.startsWith('--probe-file=')) args.probeFile = arg.slice('--probe-file='.length);
48
- else if (arg.startsWith('--runner-arg=')) args.runnerArgs.push(arg.slice('--runner-arg='.length));
49
- }
50
- return args;
51
- }
52
-
53
- function getVariants(selected) {
54
- const variants = {
55
- vanilla: { depth: null, label: 'vanilla' },
56
- elixir: { depth: 'elixir', label: 'elixir' },
57
- full: { depth: 'kernel', label: 'full' },
58
- };
59
- if (selected === 'all') return Object.values(variants);
60
- if (!variants[selected]) {
61
- throw new Error(`Unsupported --variant=${selected}. Use elixir, full, vanilla, or all.`);
62
- }
63
- return [variants[selected]];
64
- }
65
-
66
- function buildPrompt(variant) {
67
- if (variant.label === 'vanilla') return CANONICAL_PROBE;
68
- const args = ['prompt', 'Ansuz', '--mode=assembled'];
69
- if (variant.depth) args.push(`--depth=${variant.depth}`);
70
- const result = spawnSync(process.execPath, [SESSION_JS, ...args], {
71
- cwd: BASE_DIR,
72
- encoding: 'utf8',
73
- maxBuffer: 4 * 1024 * 1024,
74
- });
75
- if (result.status !== 0) {
76
- throw new Error(`session.js prompt failed for ${variant.label}: ${result.stderr || result.stdout}`);
77
- }
78
- return `${result.stdout.trim()}\n\n# REPLAY PROBE\n${CANONICAL_PROBE}\n`;
79
- }
80
-
81
- function runSample(variant, index, runnerBin, runnerArgs, prompt) {
82
- if (!runnerBin) {
83
- return {
84
- run: index + 1,
85
- variant: variant.label,
86
- status: 'skipped',
87
- reason: 'No runner configured. Set --runner-bin or BOOT_ABLATION_RUNNER_BIN to execute fresh sessions.',
88
- scorecard: scoreOutput(''),
89
- stdout: '',
90
- stderr: '',
91
- };
92
- }
93
-
94
- const result = spawnSync(runnerBin, runnerArgs, {
95
- cwd: BASE_DIR,
96
- input: prompt,
97
- encoding: 'utf8',
98
- maxBuffer: 4 * 1024 * 1024,
99
- });
100
- const stdout = result.stdout || '';
101
- const stderr = result.stderr || '';
102
- return {
103
- run: index + 1,
104
- variant: variant.label,
105
- status: result.status === 0 ? 'completed' : 'failed',
106
- exit_code: result.status,
107
- scorecard: scoreOutput(stdout),
108
- stdout,
109
- stderr,
110
- };
111
- }
112
-
113
- function scoreOutput(output) {
114
- const text = String(output || '');
115
- const checks = {
116
- ddx: /鑑別分析|DDx|hypotheses?/i.test(text),
117
- recall: /synapse_recall|kenaz_lsp_|cognitive recall/i.test(text),
118
- ask_user: /AskUserQuestion/i.test(text),
119
- scope_discipline: /scope violation|refuse|cannot modify outside|direct task-file/i.test(text),
120
- evidence_over_authority: /evidence over authority|verify|verified|support|反駁/i.test(text),
121
- };
122
- const passed = Object.values(checks).filter(Boolean).length;
123
- return {
124
- checks,
125
- passed,
126
- total: Object.keys(checks).length,
127
- ratio: passed / Object.keys(checks).length,
128
- };
129
- }
130
-
131
- function summarize(samples) {
132
- const completed = samples.filter((s) => s.status === 'completed');
133
- const ratios = completed.map((s) => s.scorecard.ratio);
134
- const mean = ratios.length ? ratios.reduce((sum, n) => sum + n, 0) / ratios.length : 0;
135
- const variance = ratios.length
136
- ? ratios.reduce((sum, n) => sum + ((n - mean) ** 2), 0) / ratios.length
137
- : 0;
138
- return {
139
- runs: samples.length,
140
- completed_runs: completed.length,
141
- skipped_runs: samples.filter((s) => s.status === 'skipped').length,
142
- failed_runs: samples.filter((s) => s.status === 'failed').length,
143
- mean_pass_rate: Number(mean.toFixed(3)),
144
- variance: Number(variance.toFixed(3)),
145
- ceiling: ratios.length ? Number(Math.max(...ratios).toFixed(3)) : 0,
146
- floor: ratios.length ? Number(Math.min(...ratios).toFixed(3)) : 0,
147
- };
148
- }
149
-
150
- function main() {
151
- const args = parseArgs(process.argv.slice(2));
152
- const variants = getVariants(args.variant);
153
- if (args.runs <= 0) throw new Error('--runs must be >= 1');
154
-
155
- if (args.probeFile) {
156
- const probePath = path.resolve(BASE_DIR, args.probeFile);
157
- if (!fs.existsSync(probePath)) throw new Error(`Probe file not found: ${probePath}`);
158
- }
159
-
160
- const report = {
161
- generated_at: new Date().toISOString(),
162
- canonical_probe: args.probeFile || 'embedded TASK_1362 directive trap',
163
- runs_per_variant: args.runs,
164
- variants: {},
165
- };
166
-
167
- for (const variant of variants) {
168
- const prompt = buildPrompt(variant);
169
- const samples = [];
170
- for (let i = 0; i < args.runs; i += 1) {
171
- samples.push(runSample(variant, i, args.runnerBin, args.runnerArgs, prompt));
172
- }
173
- report.variants[variant.label] = {
174
- summary: summarize(samples),
175
- samples,
176
- };
177
- }
178
-
179
- const json = JSON.stringify(report, null, 2);
180
- if (args.output) {
181
- const outputPath = path.resolve(BASE_DIR, args.output);
182
- fs.mkdirSync(path.dirname(outputPath), { recursive: true });
183
- fs.writeFileSync(outputPath, json, 'utf8');
184
- }
185
- console.log(json);
186
- }
187
-
188
- if (require.main === module) {
189
- try {
190
- main();
191
- } catch (error) {
192
- console.error(error.message);
193
- process.exit(1);
194
- }
195
- }
196
-
197
- module.exports = { CANONICAL_PROBE, buildPrompt, scoreOutput, summarize };
@@ -1,289 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- /**
5
- * bootstrap-anchors.js
6
- *
7
- * Scans .kenaz/tasks/done/ for historical FIX tasks (tag=fix), groups them
8
- * by tag overlap into clusters, and proposes ansuz_motivational_state.json
9
- * anchors with data-derived values.
10
- *
11
- * Usage:
12
- * node bootstrap-anchors.js [--project-path <path>] [--write]
13
- *
14
- * Output:
15
- * Prints proposed anchors as JSON to stdout (human review).
16
- * --write: merges proposed anchors into .kenaz/ansuz_motivational_state.json
17
- * (only adds anchors whose source_tags don't match any existing anchor)
18
- */
19
-
20
- const fs = require('fs');
21
- const path = require('path');
22
-
23
- // ─── Generic tags excluded from source_tags ───────────────────────────────────
24
- const GENERIC_TAGS = new Set(['fix', 'code', 'feature', 'analysis', 'bug', 'hotfix', 'patch', 'refactor', 'test', 'docs', 'chore']);
25
-
26
- // ─── CLI arg parsing ──────────────────────────────────────────────────────────
27
- function parseArgs() {
28
- const args = process.argv.slice(2);
29
- let projectPath = process.cwd();
30
- let write = false;
31
-
32
- for (let i = 0; i < args.length; i++) {
33
- if (args[i] === '--project-path' && args[i + 1]) {
34
- projectPath = path.resolve(args[++i]);
35
- } else if (args[i] === '--write') {
36
- write = true;
37
- }
38
- }
39
- return { projectPath, write };
40
- }
41
-
42
- // ─── Minimal YAML tag/date extractor (no external deps if unavailable) ────────
43
- function parseTaskFile(filePath) {
44
- let content;
45
- try {
46
- content = fs.readFileSync(filePath, 'utf8');
47
- } catch {
48
- return null;
49
- }
50
-
51
- // Try js-yaml first (installed at project root)
52
- try {
53
- const rootNodeModules = path.resolve(__dirname, '../../..', 'node_modules');
54
- // eslint-disable-next-line import/no-dynamic-require
55
- const yaml = require(path.join(rootNodeModules, 'js-yaml'));
56
- return yaml.load(content);
57
- } catch {
58
- // fallback: manual extraction
59
- }
60
-
61
- // Fallback: regex-based extraction for the fields we need
62
- const task = {};
63
-
64
- // id
65
- const idMatch = content.match(/^id:\s*(.+)$/m);
66
- if (idMatch) task.id = idMatch[1].trim().replace(/^['"]|['"]$/g, '');
67
-
68
- // title
69
- const titleMatch = content.match(/^title:\s*(.+)$/m);
70
- if (titleMatch) task.title = titleMatch[1].trim().replace(/^['"]|['"]$/g, '');
71
-
72
- // status
73
- const statusMatch = content.match(/^status:\s*(.+)$/m);
74
- if (statusMatch) task.status = statusMatch[1].trim().replace(/^['"]|['"]$/g, '');
75
-
76
- // created_at
77
- const createdMatch = content.match(/^created_at:\s*['"]?(.+?)['"]?$/m);
78
- if (createdMatch) task.created_at = createdMatch[1].trim();
79
-
80
- // tags: parse block list
81
- const tagsSection = content.match(/^tags:\s*\n((?:\s*-\s*.+\n?)*)/m);
82
- if (tagsSection) {
83
- task.tags = tagsSection[1]
84
- .split('\n')
85
- .map(l => l.replace(/^\s*-\s*/, '').trim())
86
- .filter(Boolean);
87
- } else {
88
- // inline tags: [a, b, c]
89
- const inlineMatch = content.match(/^tags:\s*\[(.+)\]/m);
90
- if (inlineMatch) {
91
- task.tags = inlineMatch[1].split(',').map(t => t.trim().replace(/^['"]|['"]$/g, ''));
92
- }
93
- }
94
-
95
- // executed_by timestamp (most reliable completion date)
96
- const execMatch = content.match(/executed_by:[\s\S]*?timestamp:\s*['"]?(.+?)['"]?$/m);
97
- if (execMatch) task.executed_at = execMatch[1].trim();
98
-
99
- return task;
100
- }
101
-
102
- // ─── Scan done directory for FIX tasks ────────────────────────────────────────
103
- function scanFixTasks(doneDir) {
104
- if (!fs.existsSync(doneDir)) {
105
- return [];
106
- }
107
-
108
- const files = fs.readdirSync(doneDir).filter(f => f.endsWith('.yaml') || f.endsWith('.yml'));
109
- const fixTasks = [];
110
-
111
- for (const file of files) {
112
- const task = parseTaskFile(path.join(doneDir, file));
113
- if (!task) continue;
114
- if (!Array.isArray(task.tags)) continue;
115
- if (!task.tags.includes('fix')) continue;
116
-
117
- // Determine best date: created_at > executed_at
118
- const date = (task.created_at || task.executed_at || '').replace(/T.*/, '');
119
-
120
- fixTasks.push({
121
- id: task.id || file.replace('.yaml', ''),
122
- title: task.title || '',
123
- tags: task.tags,
124
- date: date || null,
125
- });
126
- }
127
-
128
- return fixTasks;
129
- }
130
-
131
- // ─── Tag clustering: union-find by 2+ shared domain tags ─────────────────────
132
- function domainTags(tags) {
133
- return tags.filter(t => !GENERIC_TAGS.has(t));
134
- }
135
-
136
- function buildClusters(fixTasks) {
137
- // Union-Find
138
- const parent = fixTasks.map((_, i) => i);
139
-
140
- function find(i) {
141
- while (parent[i] !== i) {
142
- parent[i] = parent[parent[i]];
143
- i = parent[i];
144
- }
145
- return i;
146
- }
147
-
148
- function union(i, j) {
149
- const pi = find(i), pj = find(j);
150
- if (pi !== pj) parent[pi] = pj;
151
- }
152
-
153
- // Merge tasks that share 2+ domain tags
154
- for (let i = 0; i < fixTasks.length; i++) {
155
- const dA = new Set(domainTags(fixTasks[i].tags));
156
- for (let j = i + 1; j < fixTasks.length; j++) {
157
- const dB = domainTags(fixTasks[j].tags);
158
- const overlap = dB.filter(t => dA.has(t));
159
- if (overlap.length >= 2) {
160
- union(i, j);
161
- }
162
- }
163
- }
164
-
165
- // Group by root
166
- const clusters = new Map();
167
- for (let i = 0; i < fixTasks.length; i++) {
168
- const root = find(i);
169
- if (!clusters.has(root)) clusters.set(root, []);
170
- clusters.get(root).push(fixTasks[i]);
171
- }
172
-
173
- return Array.from(clusters.values());
174
- }
175
-
176
- // ─── Convert cluster → proposed anchor ────────────────────────────────────────
177
- function clusterToAnchor(tasks) {
178
- // Count domain tag frequency across cluster
179
- const tagFreq = {};
180
- for (const task of tasks) {
181
- for (const tag of domainTags(task.tags)) {
182
- tagFreq[tag] = (tagFreq[tag] || 0) + 1;
183
- }
184
- }
185
-
186
- // source_tags: domain tags appearing in >= half the cluster tasks, sorted by freq desc
187
- const threshold = Math.max(1, Math.floor(tasks.length / 2));
188
- const sourceTags = Object.entries(tagFreq)
189
- .filter(([, count]) => count >= threshold)
190
- .sort((a, b) => b[1] - a[1])
191
- .map(([tag]) => tag);
192
-
193
- // concept: top 3 source_tags joined, or fallback to all top tags
194
- const topTags = Object.entries(tagFreq)
195
- .sort((a, b) => b[1] - a[1])
196
- .slice(0, 3)
197
- .map(([tag]) => tag);
198
- const concept = topTags.join(' / ');
199
-
200
- // Most recent task date
201
- const dates = tasks.map(t => t.date).filter(Boolean).sort();
202
- const lastTouched = dates.length ? dates[dates.length - 1] : new Date().toISOString().slice(0, 10);
203
-
204
- const fixCycleCount = tasks.length;
205
- const incompleteness = Math.min(fixCycleCount * 0.15, 0.9);
206
-
207
- return {
208
- concept,
209
- source_tags: sourceTags.length ? sourceTags : topTags,
210
- incompleteness: Math.round(incompleteness * 100) / 100,
211
- fix_cycle_count: fixCycleCount,
212
- last_touched: lastTouched,
213
- decay_halflife_days: 45,
214
- };
215
- }
216
-
217
- // ─── Main ─────────────────────────────────────────────────────────────────────
218
- function main() {
219
- const { projectPath, write } = parseArgs();
220
-
221
- const doneDir = path.join(projectPath, '.kenaz', 'tasks', 'done');
222
- const statePath = path.join(projectPath, '.kenaz', 'specialist', 'ansuz_motivational_state.json');
223
-
224
- // Scan FIX tasks
225
- const fixTasks = scanFixTasks(doneDir);
226
-
227
- if (fixTasks.length === 0) {
228
- process.stderr.write(`[bootstrap-anchors] No FIX tasks found in ${doneDir}\n`);
229
- process.stdout.write(JSON.stringify([], null, 2) + '\n');
230
- return;
231
- }
232
-
233
- process.stderr.write(`[bootstrap-anchors] Found ${fixTasks.length} FIX task(s) in ${doneDir}\n`);
234
-
235
- // Build clusters
236
- const clusters = buildClusters(fixTasks);
237
- process.stderr.write(`[bootstrap-anchors] Formed ${clusters.length} cluster(s)\n`);
238
-
239
- // Convert to proposed anchors
240
- const proposed = clusters.map(clusterToAnchor);
241
-
242
- if (!write) {
243
- // Read-only mode: print proposed anchors as JSON
244
- process.stdout.write(JSON.stringify(proposed, null, 2) + '\n');
245
- process.stderr.write('\n[bootstrap-anchors] Review the proposed anchors above.\n');
246
- process.stderr.write('[bootstrap-anchors] To merge into ansuz_motivational_state.json, run with --write\n');
247
- return;
248
- }
249
-
250
- // --write mode: merge proposed anchors into existing state
251
- let state;
252
- try {
253
- state = JSON.parse(fs.readFileSync(statePath, 'utf8'));
254
- } catch {
255
- process.stderr.write(`[bootstrap-anchors] ERROR: could not read ${statePath}\n`);
256
- process.exit(1);
257
- }
258
-
259
- const existing = Array.isArray(state.anchors) ? state.anchors : [];
260
- let added = 0;
261
-
262
- for (const anchor of proposed) {
263
- // Skip if existing anchor already covers these source_tags (any overlap)
264
- const alreadyCovered = existing.some(ex =>
265
- Array.isArray(ex.source_tags) &&
266
- ex.source_tags.some(t => anchor.source_tags.includes(t))
267
- );
268
- if (alreadyCovered) {
269
- process.stderr.write(`[bootstrap-anchors] SKIP (covered): ${anchor.concept}\n`);
270
- continue;
271
- }
272
- existing.push(anchor);
273
- added++;
274
- process.stderr.write(`[bootstrap-anchors] ADD: ${anchor.concept}\n`);
275
- }
276
-
277
- if (added > 0) {
278
- state.anchors = existing;
279
- state.last_updated = new Date().toISOString();
280
- fs.writeFileSync(statePath, JSON.stringify(state, null, 2) + '\n', 'utf8');
281
- process.stderr.write(`[bootstrap-anchors] Wrote ${added} new anchor(s) to ${statePath}\n`);
282
- } else {
283
- process.stderr.write('[bootstrap-anchors] No new anchors to add (all clusters already covered by existing anchors)\n');
284
- }
285
-
286
- process.stdout.write(JSON.stringify(existing, null, 2) + '\n');
287
- }
288
-
289
- main();