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,178 +0,0 @@
1
- 'use strict';
2
- const { test } = require('node:test');
3
- const assert = require('node:assert/strict');
4
- const fs = require('fs');
5
- const os = require('os');
6
- const path = require('path');
7
- const vm = require('vm');
8
- const helper = require('./jev-correction');
9
- const { applyJevCorrection, buildBatch, makeRequest, makeBatchRequest, requestJev, requestBatch, safeText, MODEL } = helper;
10
- const KEY = 'synthetic-test-credential';
11
- function setup(t) {
12
- const projectPath = fs.mkdtempSync(path.join(os.tmpdir(), 'jev-correction-'));
13
- t.after(() => fs.rmSync(projectPath, { recursive: true, force: true }));
14
- const config = path.join(projectPath, '.kenaz', 'dashboard-models.json');
15
- fs.mkdirSync(path.dirname(config));
16
- const toggle = value => fs.writeFileSync(config, JSON.stringify({ jevCorrectionEnabled: value }));
17
- toggle(true);
18
- const lines = ['[12:00:00][Agent] I will change production.', '[12:00:01][User] Change the development version instead.', '[12:00:02][Agent] I will inspect the development files.', '[12:00:03][User] What is the current status?'];
19
- const userMessages = [{ idx: 0, lineIndex: 1, text: lines[1].split('[User] ')[1] }, { idx: 1, lineIndex: 3, text: lines[3].split('[User] ')[1] }];
20
- const baseline = [{ idx: 0, translated: 'Existing English translation.', labels: ['delegation'] }, { idx: 1, translated: 'Existing second translation.', labels: ['correction', 'question', 'length_too_short'] }];
21
- return { projectPath, config, toggle, lines, userMessages, baseline };
22
- }
23
- function body(ids = ['message_0', 'message_1'], probabilities = [0.9, 0.1]) {
24
- return { model: MODEL, answers: Object.fromEntries(ids.map((id, i) => [id, { type: 'noul', noul: probabilities[i] ?? 0.7 }])), usage: { input_tokens: 10, output_tokens: 2 } };
25
- }
26
- const spawned = (response = body()) => ({ status: 0, stdout: JSON.stringify({ status: 'ok', body: response }) });
27
- const options = spawnSync => ({ key: KEY, spawnSync });
28
-
29
- test('OFF, malformed config, missing/invalid key and another project never spawn', t => {
30
- const ctx = setup(t); let calls = 0;
31
- const deps = options(() => { calls++; throw Error('must not spawn'); });
32
- for (const flag of [false, undefined, 'true', 1]) { ctx.toggle(flag); assert.equal(applyJevCorrection(ctx, deps), ctx.baseline); }
33
- fs.writeFileSync(ctx.config, '{'); assert.equal(applyJevCorrection(ctx, deps), ctx.baseline);
34
- fs.unlinkSync(ctx.config); assert.equal(applyJevCorrection(ctx, deps), ctx.baseline);
35
- ctx.toggle(true);
36
- for (const key of ['', ' ', '\n', 'value\n', 'a b']) assert.equal(applyJevCorrection(ctx, { ...deps, key }), ctx.baseline);
37
- assert.equal(applyJevCorrection({ ...ctx, projectPath: path.join(ctx.projectPath, 'other') }, deps), ctx.baseline);
38
- assert.equal(applyJevCorrection({ ...ctx, projectPath: undefined }, deps), ctx.baseline);
39
- assert.equal(calls, 0);
40
- });
41
- test('active decisions add/remove correction, preserve other labels/translations, never mutate baseline', t => {
42
- const ctx = setup(t), original = structuredClone(ctx.baseline);
43
- const result = applyJevCorrection(ctx, options(() => spawned()));
44
- assert.deepEqual(result.map(x => x.labels), [['correction', 'delegation'], ['question', 'length_too_short']]);
45
- assert.deepEqual(result.map(x => x.translated), original.map(x => x.translated));
46
- assert.deepEqual(ctx.baseline, original);
47
- assert.notEqual(result, ctx.baseline);
48
- });
49
- test('existing secondary correction becomes primary without reordering remaining labels or fields', t => {
50
- const ctx = setup(t);
51
- ctx.baseline[0] = { ...ctx.baseline[0], labels: ['delegation', 'question', 'correction', 'challenge'], extra: 'preserved' };
52
- const original = structuredClone(ctx.baseline);
53
- const result = applyJevCorrection(ctx, options(() => spawned()));
54
- assert.deepEqual(result[0], { ...original[0], labels: ['correction', 'delegation', 'question', 'challenge'] });
55
- assert.deepEqual(ctx.baseline, original);
56
- ctx.toggle(false);
57
- assert.equal(applyJevCorrection(ctx, options(() => spawned())), ctx.baseline);
58
- ctx.toggle(true);
59
- assert.equal(applyJevCorrection(ctx, options(() => ({ status: 1 }))), ctx.baseline);
60
- });
61
- test('null baseline supplies only positive correction without invented translation; threshold is inclusive', t => {
62
- const ctx = setup(t);
63
- assert.deepEqual(applyJevCorrection({ ...ctx, baseline: null }, options(() => spawned(body(undefined, [0.5, 0.499])))), [{ idx: 0, labels: ['correction'] }]);
64
- assert.deepEqual(applyJevCorrection({ ...ctx, baseline: [] }, options(() => spawned())), [{ idx: 0, labels: ['correction'] }]);
65
- const partial = applyJevCorrection({ ...ctx, baseline: [ctx.baseline[1]] }, options(() => spawned()));
66
- assert.deepEqual(partial.find(item => item.idx === 0), { idx: 0, labels: ['correction'] });
67
- });
68
- test('hidden bounded Node child uses stdin; no credential or message in argv', t => {
69
- const ctx = setup(t); let calls = 0;
70
- applyJevCorrection(ctx, options((command, args, opts) => {
71
- calls++;
72
- assert.equal(command, process.execPath); assert.equal(args.length, 2); assert.equal(args[1], '--worker');
73
- assert.equal(opts.timeout, 1500); assert.equal(opts.maxBuffer, 65536); assert.equal(opts.windowsHide, true); assert.equal(opts.shell, false);
74
- assert.equal(JSON.stringify(args).includes(ctx.userMessages[0].text), false);
75
- assert.equal(JSON.stringify({ args, opts }).includes(KEY), false);
76
- const packet = JSON.parse(opts.input); assert.equal(packet.requests.length, 2);
77
- assert.equal(packet.requests[0].state.message, ctx.userMessages[0].text);
78
- return spawned();
79
- }));
80
- assert.equal(calls, 1);
81
- });
82
- test('in-flight disable discards results and preserves baseline reference', t => {
83
- const ctx = setup(t);
84
- assert.equal(applyJevCorrection(ctx, options(() => { ctx.toggle(false); return spawned(); })), ctx.baseline);
85
- assert.equal(JSON.parse(fs.readFileSync(path.join(ctx.projectPath, '.kenaz/jev/decisions.jsonl'), 'utf8')).fallback_reason, 'disabled_in_flight');
86
- });
87
- test('malformed JSON, wrong model/IDs, bounds/types/usage and arbitrary worker failure all preserve baseline', t => {
88
- const ctx = setup(t);
89
- const variants = [b => { b.model = 'jev'; }, b => { b.answers.extra = { type: 'noul', noul: 1 }; }, b => { delete b.answers.message_0; },
90
- b => { b.answers.message_0.noul = null; }, b => { b.answers.message_0.noul = '0.5'; }, b => { b.answers.message_0.noul = 1.1; },
91
- b => { b.answers.message_0.noul = -1; }, b => { b.answers.message_0.type = 'score'; }, b => { b.answers.message_0.extra = true; },
92
- b => { delete b.usage; }, b => { b.usage.input_tokens = -1; }, b => { b.usage.output_tokens = 1.1; }, b => { b.secret = 'raw'; }];
93
- for (const mutate of variants) { const invalid = body(); mutate(invalid); assert.equal(applyJevCorrection(ctx, options(() => spawned(invalid))), ctx.baseline); }
94
- for (const result of [{ status: 0, stdout: '{broken' }, { status: 1, stdout: 'private' }, { status: null, error: { code: 'ETIMEDOUT' } }, { status: 0, stdout: 'x'.repeat(65537) }]) {
95
- assert.equal(applyJevCorrection(ctx, options(() => result)), ctx.baseline);
96
- }
97
- assert.equal(applyJevCorrection(ctx, options(() => { throw null; })), ctx.baseline);
98
- });
99
- test('raw and normalized credential/generated text excluded; private context is a boundary', t => {
100
- const ctx = setup(t);
101
- for (const text of ['API_KEY="abcd1234"', 'API_KEY="abcd1234"', 'apikey_abcd12345678', '[HEADLESS MODE] execute', '## Automated Dispatch Context', '<system-reminder>injected</system-reminder>', '[Request interrupted by user]', 'For each numbered message, output a JSON array']) assert.equal(safeText(text), null);
102
- assert.equal(safeText('Please continue TASK_38'), 'Please continue TASK_38');
103
- ctx.lines[0] = '[12:00:00][Agent] API_KEY="abcd1234"';
104
- const batch = buildBatch(ctx.lines, ctx.userMessages); assert.deepEqual(batch[0].context, []);
105
- ctx.lines[1] = '[12:00:01][User] API_KEY="abcd1234"'; ctx.userMessages[0].text = 'API_KEY="abcd1234"';
106
- assert.deepEqual(buildBatch(ctx.lines, ctx.userMessages).map(x => x.idx), [1]);
107
- });
108
- test('state excludes future messages, tool/thinking lines and instructions contain no user data', t => {
109
- const ctx = setup(t), batch = buildBatch(ctx.lines, ctx.userMessages);
110
- const early = makeRequest(batch[0]);
111
- assert.equal(JSON.stringify(early).includes(ctx.userMessages[1].text), false);
112
- assert.equal(early.questions.message_0.instructions.includes(ctx.userMessages[0].text), false);
113
- assert.deepEqual(early.state.preceding_context, [{ role: 'assistant', text: 'I will change production.' }]);
114
- ctx.lines[0] = '[12:00:00][Agent][Read] private file'; assert.deepEqual(buildBatch(ctx.lines, ctx.userMessages)[0].context, []);
115
- ctx.lines[0] = '[12:00:00][Thinking] hidden reasoning'; assert.deepEqual(buildBatch(ctx.lines, ctx.userMessages)[0].context, []);
116
- ctx.userMessages[0].text = 'different identity'; assert.deepEqual(buildBatch(ctx.lines, ctx.userMessages).map(x => x.idx), [1]);
117
- });
118
- test('only most recent eight eligible messages and at most 32KB are sent', () => {
119
- const lines = Array.from({ length: 30 }, (_, i) => `[12:00:00][User] Message ${i} ` + 'x'.repeat(3000));
120
- const messages = lines.map((line, idx) => ({ idx, lineIndex: idx, text: line.split('[User] ')[1] }));
121
- const batch = buildBatch(lines, messages);
122
- assert.ok(batch.length > 0 && batch.length <= 8); assert.equal(batch.at(-1).idx, 29);
123
- assert.ok(Buffer.byteLength(JSON.stringify(makeBatchRequest(batch))) <= 32768);
124
- });
125
- test('typed Noul request fixed endpoint and redirect rejection; no network without valid key', async () => {
126
- const request = makeRequest({ idx: 0, message: 'test correction', context: [] }); let calls = 0;
127
- const fetchImpl = async (url, options) => {
128
- calls++; assert.equal(url, helper.ENDPOINT); assert.equal(options.redirect, 'error'); assert.equal(options.method, 'POST');
129
- assert.equal(options.headers.Authorization, `Bearer ${KEY}`);
130
- return new Response(JSON.stringify(body(['message_0'])));
131
- };
132
- assert.equal((await requestJev(request, { key: '', fetchImpl })).status, 'missing_key'); assert.equal(calls, 0);
133
- assert.equal((await requestJev(request, { key: KEY, fetchImpl })).status, 'ok'); assert.equal(calls, 1);
134
- });
135
- test('401/429/529 differentiated; malformed JSON and oversize streamed body fail safely', async () => {
136
- const request = makeRequest({ idx: 0, message: 'test correction', context: [] });
137
- for (const status of [401, 429, 529]) assert.equal((await requestJev(request, { key: KEY, fetchImpl: async () => new Response('private body', { status }) })).status, `http_${status}`);
138
- for (const text of ['{broken', 'x'.repeat(65537)]) {
139
- const result = await requestJev(request, { key: KEY, fetchImpl: async () => new Response(text) });
140
- assert.deepEqual(result, { status: 'invalid_response' });
141
- }
142
- });
143
- test('deadline covers stalled fetch AND stalled body, even if mock ignores abort', async () => {
144
- const request = makeRequest({ idx: 0, message: 'test correction', context: [] });
145
- for (const fetchImpl of [() => new Promise(() => {}), async () => new Response(new ReadableStream({ start() {} }))]) {
146
- const start = Date.now(); const result = await requestJev(request, { key: KEY, deadlineMs: 25, fetchImpl });
147
- assert.deepEqual(result, { status: 'timeout' }); assert.ok(Date.now() - start < 1500);
148
- }
149
- });
150
- test('parallel isolated calls bounded to eight, all-or-none failure, aggregate usage', async t => {
151
- const ctx = setup(t), packet = makeBatchRequest(buildBatch(ctx.lines, ctx.userMessages)); let calls = 0;
152
- const fetchImpl = async (_, options) => {
153
- calls++; const r = JSON.parse(options.body); const id = Object.keys(r.questions)[0];
154
- assert.equal(Object.keys(r.questions).length, 1);
155
- if (id === 'message_0') assert.equal(JSON.stringify(r).includes(ctx.userMessages[1].text), false);
156
- return new Response(JSON.stringify(body([id])));
157
- };
158
- const result = await requestBatch(packet, { key: KEY, fetchImpl });
159
- assert.equal(result.status, 'ok'); assert.equal(calls, 2); assert.deepEqual(result.body.usage, { input_tokens: 20, output_tokens: 4 });
160
- assert.equal((await requestBatch(packet, { key: KEY, fetchImpl: async () => new Response('', { status: 429 }) })).status, 'http_429');
161
- assert.equal((await requestBatch({ ...packet, requests: Array(9).fill(packet.requests[0]) }, { key: KEY, fetchImpl })).status, 'invalid_response');
162
- const start = Date.now();
163
- assert.equal((await requestBatch(packet, { key: KEY, deadlineMs: 30, fetchImpl: () => new Promise(() => {}) })).status, 'timeout');
164
- assert.ok(Date.now() - start < 500, 'parallel calls share the deadline, not sequential timeouts');
165
- });
166
- test('bounded metadata-only telemetry and logging failure cannot break decisions', t => {
167
- const ctx = setup(t), deps = options(() => spawned());
168
- for (let i = 0; i < 160; i++) applyJevCorrection(ctx, deps);
169
- const file = path.join(ctx.projectPath, '.kenaz', 'jev', 'decisions.jsonl'), text = fs.readFileSync(file, 'utf8');
170
- assert.ok(Buffer.byteLength(text) <= 65536);
171
- for (const privateText of [KEY, ctx.projectPath, ...ctx.userMessages.map(x => x.text), 'Existing English']) assert.equal(text.includes(privateText), false);
172
- for (const line of text.trim().split('\n')) {
173
- const row = JSON.parse(line); assert.equal(row.mode, 'active'); assert.equal(row.status, 'applied');
174
- assert.ok(row.decisions.every(x => /^[a-f0-9]{64}$/.test(x.message_id)));
175
- }
176
- fs.rmSync(path.dirname(file), { recursive: true }); fs.writeFileSync(path.dirname(file), 'obstruction');
177
- assert.ok(applyJevCorrection(ctx, deps)[0].labels.includes('correction'));
178
- });
@@ -1,232 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Formation Log Reader
4
- *
5
- * 讀取 Formation log 檔案的尾端/頭端/錯誤行
6
- * 用途:讓 Ansuz 按需讀取 log,避免載入完整 log 爆 context
7
- *
8
- * Usage:
9
- * node .formation/tools/log-reader.js --log <path> --tail 50
10
- * node .formation/tools/log-reader.js --task TASK_XXX --tail 50
11
- * node .formation/tools/log-reader.js --latest unit --tail 30
12
- * node .formation/tools/log-reader.js --log <path> --errors
13
- *
14
- * Options:
15
- * --log <path> 直接讀指定 log 檔
16
- * --task TASK_XXX 在 .formation/logs/ 下搜尋包含 TASK_XXX 的最新 log
17
- * --latest <formation> 讀指定陣型目錄下最新的 log
18
- * --tail N 只輸出最後 N 行(預設 50)
19
- * --head N 只輸出前 N 行
20
- * --errors 只輸出包含 ERROR/FAILED/❌ 的行
21
- */
22
-
23
- const fs = require('fs');
24
- const path = require('path');
25
- const { LOG_DIR, getLogDir } = require('./utils');
26
-
27
- // ─────────────────────────────────────────
28
- // 尋找 log 檔案
29
- // ─────────────────────────────────────────
30
-
31
- /**
32
- * 搜尋包含 taskId 的最新 log 檔案
33
- * @param {string} taskId - TASK_XXX
34
- * @param {string} [projectPath] - 專案路徑(多專案支援)
35
- * @returns {string|null}
36
- */
37
- function findTaskLog(taskId, projectPath) {
38
- const logDir = projectPath ? getLogDir(projectPath) : LOG_DIR;
39
- const formations = ['unit', 'solo', 'squad', 'legion', 'misc'];
40
- let candidates = [];
41
-
42
- for (const formation of formations) {
43
- const dir = path.join(logDir, formation);
44
- if (!fs.existsSync(dir)) continue;
45
-
46
- const files = fs.readdirSync(dir)
47
- .filter(f => f.endsWith('.log'))
48
- .sort((a, b) => {
49
- const aErr = a.endsWith('.err.log') ? 1 : 0;
50
- const bErr = b.endsWith('.err.log') ? 1 : 0;
51
- return aErr - bErr;
52
- });
53
- for (const file of files) {
54
- const filePath = path.join(dir, file);
55
- try {
56
- const content = fs.readFileSync(filePath, 'utf-8');
57
- if (content.includes(taskId)) {
58
- const stats = fs.statSync(filePath);
59
- candidates.push({ path: filePath, mtime: stats.mtime });
60
- }
61
- } catch (e) {
62
- // skip unreadable files
63
- }
64
- }
65
- }
66
-
67
- if (candidates.length === 0) return null;
68
-
69
- // 回傳最新的
70
- candidates.sort((a, b) => b.mtime - a.mtime);
71
- return candidates[0].path;
72
- }
73
-
74
- /**
75
- * 取得指定 formation 的最新 log
76
- * @param {string} formation - unit / solo / squad / legion
77
- * @param {string} [projectPath] - 專案路徑(多專案支援)
78
- * @returns {string|null}
79
- */
80
- function findLatestLog(formation, projectPath) {
81
- const logDir = projectPath ? getLogDir(projectPath) : LOG_DIR;
82
- const dir = path.join(logDir, formation);
83
- if (!fs.existsSync(dir)) return null;
84
-
85
- const files = fs.readdirSync(dir)
86
- .filter(f => f.endsWith('.log'))
87
- .sort((a, b) => {
88
- const aErr = a.endsWith('.err.log') ? 1 : 0;
89
- const bErr = b.endsWith('.err.log') ? 1 : 0;
90
- return aErr - bErr;
91
- })
92
- .map(f => {
93
- const filePath = path.join(dir, f);
94
- const stats = fs.statSync(filePath);
95
- return { path: filePath, mtime: stats.mtime };
96
- });
97
-
98
- if (files.length === 0) return null;
99
-
100
- files.sort((a, b) => b.mtime - a.mtime);
101
- return files[0].path;
102
- }
103
-
104
- // ─────────────────────────────────────────
105
- // 讀取與過濾
106
- // ─────────────────────────────────────────
107
-
108
- /**
109
- * 讀取 log 並根據選項過濾
110
- * @param {string} logPath
111
- * @param {object} opts
112
- * @param {number} [opts.tail] - 最後 N 行
113
- * @param {number} [opts.head] - 前 N 行
114
- * @param {boolean} [opts.errors] - 只顯示錯誤
115
- */
116
- function readLog(logPath, opts = {}) {
117
- const { tail, head, errors } = opts;
118
-
119
- if (!fs.existsSync(logPath)) {
120
- console.error(`❌ Log file not found: ${logPath}`);
121
- process.exit(1);
122
- }
123
-
124
- const content = fs.readFileSync(logPath, 'utf-8');
125
- let lines = content.split('\n');
126
-
127
- // 過濾錯誤行
128
- if (errors) {
129
- // TASK_1712: Added REFUSED to surface injection-refusal runs in --errors filter
130
- const errorKeywords = ['ERROR', 'FAILED', 'FAIL', 'REFUSED', '❌', 'exit 1', 'Exit Code: 1'];
131
- lines = lines.filter(line => {
132
- const upper = line.toUpperCase();
133
- return errorKeywords.some(kw => upper.includes(kw.toUpperCase()));
134
- });
135
- }
136
-
137
- // 取前/後 N 行
138
- if (head) {
139
- lines = lines.slice(0, head);
140
- } else if (tail) {
141
- lines = lines.slice(-tail);
142
- }
143
-
144
- console.log(`─── Log: ${logPath} ───`);
145
- if (tail) console.log(`─── Last ${tail} lines ───`);
146
- if (head) console.log(`─── First ${head} lines ───`);
147
- if (errors) console.log(`─── Error lines only ───`);
148
- console.log('');
149
-
150
- console.log(lines.join('\n'));
151
- }
152
-
153
- // ─────────────────────────────────────────
154
- // CLI
155
- // ─────────────────────────────────────────
156
-
157
- if (require.main === module) {
158
- const args = process.argv.slice(2);
159
-
160
- if (args.includes('--help') || args.includes('-h')) {
161
- console.log(`
162
- ⚔️ Formation Log Reader
163
-
164
- 讀取 Formation log 檔案的尾端/頭端/錯誤行
165
-
166
- Usage:
167
- node .formation/tools/log-reader.js --log <path> --tail 50
168
- node .formation/tools/log-reader.js --task TASK_XXX --tail 50
169
- node .formation/tools/log-reader.js --latest unit --tail 30
170
-
171
- Options:
172
- --log <path> 直接讀指定 log 檔
173
- --task TASK_XXX 在 .formation/logs/ 下搜尋包含 TASK_XXX 的最新 log
174
- --latest <formation> 讀指定陣型目錄下最新的 log
175
- --tail N 只輸出最後 N 行(預設 50)
176
- --head N 只輸出前 N 行
177
- --errors 只輸出包含 ERROR/FAILED/❌ 的行
178
-
179
- Examples:
180
- node .formation/tools/log-reader.js --log .formation/logs/unit/do_abc123.log --tail 30
181
- node .formation/tools/log-reader.js --task TASK_248 --errors
182
- node .formation/tools/log-reader.js --latest squad --tail 50
183
- `);
184
- process.exit(0);
185
- }
186
-
187
- const getArg = (flag) => {
188
- for (let i = 0; i < args.length; i++) {
189
- if (args[i].startsWith(`${flag}=`)) return args[i].split('=').slice(1).join('=');
190
- if (args[i] === flag && args[i + 1]) return args[i + 1];
191
- }
192
- return null;
193
- };
194
-
195
- const logPath = getArg('--log');
196
- const taskId = getArg('--task');
197
- const latest = getArg('--latest');
198
- const projectPath = getArg('--project-path');
199
- const tail = parseInt(getArg('--tail') || '50', 10);
200
- const head = parseInt(getArg('--head') || '0', 10);
201
- const errors = args.includes('--errors');
202
-
203
- let resolvedPath = null;
204
-
205
- if (logPath) {
206
- resolvedPath = logPath;
207
- } else if (taskId) {
208
- resolvedPath = findTaskLog(taskId, projectPath);
209
- if (!resolvedPath) {
210
- console.error(`❌ No log found for task: ${taskId}`);
211
- process.exit(1);
212
- }
213
- } else if (latest) {
214
- resolvedPath = findLatestLog(latest, projectPath);
215
- if (!resolvedPath) {
216
- console.error(`❌ No log found in formation: ${latest}`);
217
- process.exit(1);
218
- }
219
- } else {
220
- console.error('❌ Must specify one of: --log, --task, --latest');
221
- process.exit(1);
222
- }
223
-
224
- const opts = {};
225
- if (head > 0) opts.head = head;
226
- else if (tail > 0) opts.tail = tail;
227
- if (errors) opts.errors = true;
228
-
229
- readLog(resolvedPath, opts);
230
- }
231
-
232
- module.exports = { findTaskLog, findLatestLog, readLog };
@@ -1,162 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * revert-daemon-state.js
4
- *
5
- * On-demand cleanup for daemon-drift on the user branch between task merges.
6
- *
7
- * The post-complete merge pipeline already auto-reverts daemon-managed paths
8
- * via .kenaz/specialist/daemon-manifest.yaml + isDaemonManagedPath() inside
9
- * post-complete.js (worktree merge step). But that only fires DURING a task
10
- * merge. Between sessions, daemons keep writing to those files and
11
- * `git status` shows them as modified — pure noise on the user branch.
12
- *
13
- * This CLI uses the same manifest as the merge pipeline, but runs ad-hoc:
14
- * 1. Load .kenaz/specialist/daemon-manifest.yaml
15
- * 2. For every enrolled state_files entry + every file matching a static_paths
16
- * directory entry, check `git status --porcelain` for modification
17
- * 3. Run `git checkout HEAD -- <path>` to revert each
18
- *
19
- * Untracked files are left alone. Files that are not enrolled in the manifest
20
- * are left alone. The CLI is idempotent and never touches scope_paths or
21
- * non-daemon files.
22
- *
23
- * Usage:
24
- * node .formation/tools/revert-daemon-state.js # do it
25
- * node .formation/tools/revert-daemon-state.js --dry # show plan only
26
- * node .formation/tools/revert-daemon-state.js --quiet # only summary line
27
- *
28
- * Exit code: 0 on success (even if nothing reverted), 1 on manifest load
29
- * failure or git command failure.
30
- */
31
-
32
- 'use strict';
33
-
34
- const fs = require('fs');
35
- const path = require('path');
36
- const { execSync, spawnSync } = require('child_process');
37
-
38
- const ROOT = path.resolve(__dirname, '..', '..');
39
- const MANIFEST = path.join(ROOT, '.kenaz', 'specialist', 'daemon-manifest.yaml');
40
-
41
- const argv = process.argv.slice(2);
42
- const DRY = argv.includes('--dry') || argv.includes('--dry-run');
43
- const QUIET = argv.includes('--quiet');
44
-
45
- function log(...args) {
46
- if (!QUIET) console.log(...args);
47
- }
48
-
49
- function loadYaml(filePath) {
50
- let yaml;
51
- try {
52
- yaml = require('js-yaml');
53
- } catch {
54
- const candidates = [
55
- path.resolve(__dirname, '../../.vendor/js-yaml.cjs'),
56
- path.resolve(__dirname, '.vendor/js-yaml.cjs'),
57
- path.resolve(__dirname, '..', '.vendor', 'js-yaml.cjs'),
58
- ];
59
- for (const c of candidates) {
60
- try { yaml = require(c); break; } catch {}
61
- }
62
- }
63
- if (!yaml) throw new Error('js-yaml not available — check .formation/.vendor/');
64
- return yaml.load(fs.readFileSync(filePath, 'utf8'));
65
- }
66
-
67
- function loadManifest() {
68
- if (!fs.existsSync(MANIFEST)) {
69
- throw new Error(`daemon-manifest.yaml not found at ${MANIFEST}`);
70
- }
71
- const raw = loadYaml(MANIFEST);
72
- return {
73
- stateFiles: Array.isArray(raw?.state_files) ? raw.state_files : [],
74
- staticPaths: Array.isArray(raw?.static_paths) ? raw.static_paths : [],
75
- };
76
- }
77
-
78
- function normalizeRepoPath(p) {
79
- return String(p || '')
80
- .replace(/\\/g, '/')
81
- .replace(/^\.\//, '')
82
- .replace(/\/+/g, '/');
83
- }
84
-
85
- function listModifiedTracked() {
86
- const out = execSync('git status --porcelain --untracked-files=no', {
87
- cwd: ROOT, encoding: 'utf8', windowsHide: true,
88
- });
89
- const modified = [];
90
- for (const line of out.split(/\r?\n/)) {
91
- if (!line) continue;
92
- const xy = line.slice(0, 2);
93
- const rel = normalizeRepoPath(line.slice(3).trim());
94
- if (xy.includes('M') || xy.includes('A') || xy.includes('D') || xy.includes('R')) {
95
- modified.push(rel);
96
- }
97
- }
98
- return modified;
99
- }
100
-
101
- function isManagedByManifest(relPath, manifest) {
102
- const norm = normalizeRepoPath(relPath);
103
- if (!norm) return false;
104
- if (manifest.stateFiles.includes(norm)) return true;
105
- for (const sp of manifest.staticPaths) {
106
- const spn = normalizeRepoPath(sp);
107
- if (spn === norm) return true;
108
- if (spn.endsWith('/') && norm.startsWith(spn)) return true;
109
- }
110
- return false;
111
- }
112
-
113
- function gitCheckoutHead(paths) {
114
- if (paths.length === 0) return { ok: true, stderr: '' };
115
- // Use spawnSync with --pathspec-file via stdin to avoid command-line length limits
116
- const args = ['checkout', 'HEAD', '--', ...paths];
117
- const r = spawnSync('git', args, { cwd: ROOT, encoding: 'utf8', windowsHide: true });
118
- return { ok: r.status === 0, stderr: r.stderr || '' };
119
- }
120
-
121
- function main() {
122
- let manifest;
123
- try { manifest = loadManifest(); }
124
- catch (e) {
125
- console.error(`✗ ${e.message}`);
126
- process.exit(1);
127
- }
128
-
129
- const modified = listModifiedTracked();
130
- const managed = modified.filter(p => isManagedByManifest(p, manifest));
131
- const unmanaged = modified.filter(p => !isManagedByManifest(p, manifest));
132
-
133
- if (managed.length === 0) {
134
- log(`✓ No daemon-managed drift in working tree (${modified.length} other modified file(s) untouched).`);
135
- return;
136
- }
137
-
138
- log(`Daemon-managed drift detected (${managed.length} file(s)):`);
139
- for (const p of managed) log(` ~ ${p}`);
140
-
141
- if (unmanaged.length > 0 && !QUIET) {
142
- log('');
143
- log(`Non-daemon modifications (left alone):`);
144
- for (const p of unmanaged) log(` ${p}`);
145
- }
146
-
147
- if (DRY) {
148
- log('');
149
- log('[--dry] No changes made. Re-run without --dry to revert.');
150
- return;
151
- }
152
-
153
- log('');
154
- const result = gitCheckoutHead(managed);
155
- if (!result.ok) {
156
- console.error(`✗ git checkout failed:\n${result.stderr.trim()}`);
157
- process.exit(1);
158
- }
159
- console.log(`✓ Reverted ${managed.length} daemon-managed file(s) to HEAD.`);
160
- }
161
-
162
- main();