kenaz 0.3.17 → 0.3.19

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 (316) 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/hooks/synapse-first-investigation.js +15 -0
  7. package/core/.claude/skills/architect_agent/SKILL.md +11 -92
  8. package/core/.claude/skills/assessment_agent/SKILL.md +0 -1
  9. package/core/.claude/skills/backend_engineer/SKILL.md +3 -6
  10. package/core/.claude/skills/code_reviewer/SKILL.md +1 -1
  11. package/core/.claude/skills/code_reviewer/patterns.yaml +1 -1
  12. package/core/.claude/skills/designer/SKILL.md +3 -6
  13. package/core/.claude/skills/dev_agent/SKILL.md +30 -491
  14. package/core/.claude/skills/developer/SKILL.md +3 -6
  15. package/core/.claude/skills/feature_agent/SKILL.md +3 -17
  16. package/core/.claude/skills/product_manager/SKILL.md +29 -1064
  17. package/core/.claude/skills/qa_engineer/SKILL.md +12 -17
  18. package/core/.claude/skills/spec_optimizer/SKILL.md +25 -275
  19. package/core/.claude/skills/sre_agent/SKILL.md +3 -6
  20. package/core/.collaboration/README.md +2 -3
  21. package/core/.collaboration/core/task-api.js +5 -138
  22. package/core/.collaboration/docs/CLI.md +0 -2
  23. package/core/.failure/INDEX.yaml +6 -40
  24. package/core/.failure/agent-execution/FAIL-013-search-cwd-drift-and-case-mismatch.yaml +1 -1
  25. package/core/.failure/tools/README.md +9 -227
  26. package/core/.formation/bifrost/exec.js +29 -4
  27. package/core/.formation/bifrost/launch.js +1 -6
  28. package/core/.formation/bifrost/launch.test.js +1 -1
  29. package/core/.formation/bifrost/provider-launch.js +18 -11
  30. package/core/.formation/bifrost/provider-launch.test.js +26 -2
  31. package/core/.formation/bifrost/shared/ansuz-boot-policy.js +3 -3
  32. package/core/.formation/bifrost/shared/ansuz-boot-policy.test.js +1 -2
  33. package/core/.formation/tools/__tests__/dispatch-cwd-project.test.js +42 -0
  34. package/core/.formation/tools/__tests__/m1-hmap-convid.test.js +1 -124
  35. package/core/.formation/tools/__tests__/subagent-executor.test.js +3 -2
  36. package/core/.formation/tools/dispatch.js +15 -2
  37. package/core/.formation/tools/loader.js +17 -140
  38. package/core/.formation/tools/post-complete.js +0 -31
  39. package/core/.rule/INDEX.yaml +0 -18
  40. package/core/.rule/general/agent-workflow.yaml +14 -164
  41. package/core/.rule/general/project-self-containment.yaml +8 -19
  42. package/core/.rule/general/rust-verify-target.yaml +6 -5
  43. package/core/.rule/general/synapse-code-intelligence.yaml +3 -3
  44. package/core/.specialist/Amelia/capability.yaml +12 -12
  45. package/core/.specialist/Amelia/workflow.yaml +2 -2
  46. package/core/.specialist/Ansuz/SYSTEM_DOC.md +20 -578
  47. package/core/.specialist/Ansuz/cognitive_principles.yaml +2 -3
  48. package/core/.specialist/Ansuz/concepts/boot_rules_summary.yaml +0 -1
  49. package/core/.specialist/Ansuz/concepts/deep_knowledge_pointers.yaml +1 -2
  50. package/core/.specialist/Ansuz/core.yaml +6 -108
  51. package/core/.specialist/Ansuz/guards/lesson_guards.yaml +0 -3
  52. package/core/.specialist/Ansuz/identity_contract.yaml +0 -1
  53. package/core/.specialist/Ansuz/knowledge.yaml +0 -4
  54. package/core/.specialist/Ansuz/rule.yaml +0 -1
  55. package/core/.specialist/Ansuz/tools/handoff-session-identity.test.js +6 -150
  56. package/core/.specialist/tests/runtime-discovery/README.md +1 -1
  57. package/core/.specialist/tools/__tests__/task-2374-usage-counter.test.js +1 -12
  58. package/core/.specialist/tools/prompt-files.test.js +1 -0
  59. package/core/.specialist/tools/task-bridge.js +1 -66
  60. package/core/.system/README.md +11 -552
  61. package/core/.system/collaboration/README.md +10 -174
  62. package/core/CLAUDE.md +1 -6
  63. package/core/KENAZ_CORE_VERSION +1 -1
  64. package/core/dev/scripts/js-yaml-resolution.test.js +1 -1
  65. package/core/dev/scripts/run-rust-tests.js +30 -46
  66. package/core/dev/scripts/run-rust-tests.test.js +17 -0
  67. package/core/dev/scripts/rust-verify-worktree.js +4 -4
  68. package/core/dev/scripts/verify-target-dir.js +6 -6
  69. package/core/plugins/kenaz/INVENTORY.md +8 -8
  70. package/core/plugins/kenaz/commands/architect.md +1 -2
  71. package/core/plugins/kenaz/commands/spec.md +1 -1
  72. package/core/plugins/kenaz/commands//347/224/242/345/223/201.md +1 -1
  73. package/core/plugins/kenaz/guidance.md +1 -1
  74. package/core/plugins/kenaz/scripts/sync.js +1 -1
  75. package/core/plugins/kenaz/scripts/ygg.js +6 -0
  76. package/core/plugins/kenaz/skills/architect_agent/SKILL.md +11 -92
  77. package/core/plugins/kenaz/skills/assessment_agent/SKILL.md +0 -1
  78. package/core/plugins/kenaz/skills/backend_engineer/SKILL.md +3 -6
  79. package/core/plugins/kenaz/skills/code_reviewer/SKILL.md +1 -1
  80. package/core/plugins/kenaz/skills/code_reviewer/patterns.yaml +1 -1
  81. package/core/plugins/kenaz/skills/designer/SKILL.md +3 -6
  82. package/core/plugins/kenaz/skills/dev_agent/SKILL.md +30 -491
  83. package/core/plugins/kenaz/skills/developer/SKILL.md +3 -6
  84. package/core/plugins/kenaz/skills/feature_agent/SKILL.md +3 -17
  85. package/core/plugins/kenaz/skills/product_manager/SKILL.md +29 -1064
  86. package/core/plugins/kenaz/skills/qa_engineer/SKILL.md +12 -17
  87. package/core/plugins/kenaz/skills/spec_optimizer/SKILL.md +25 -275
  88. package/core/plugins/kenaz/skills/sre_agent/SKILL.md +3 -6
  89. package/package.json +6 -6
  90. package/core/.claude/commands/archive.md +0 -24
  91. package/core/.claude/commands/init.md +0 -112
  92. package/core/.claude/commands/legacy_dev.md +0 -18
  93. package/core/.claude/commands/product-review.md +0 -131
  94. package/core/.claude/commands/strategy.md +0 -141
  95. package/core/.claude/commands/sunny.md +0 -1
  96. package/core/.claude/commands//347/224/242/345/223/201/346/252/242/350/246/226.md +0 -129
  97. package/core/.claude/commands//351/200/262/345/272/246.md +0 -15
  98. package/core/.claude/hooks/__tests__/substrate.test.js +0 -122
  99. package/core/.claude/hooks/_substrate-paths.js +0 -95
  100. package/core/.claude/hooks/context-check.js +0 -51
  101. package/core/.claude/hooks/fatigue-check.js +0 -52
  102. package/core/.claude/hooks/handoff-snapshot-on-commit.js +0 -154
  103. package/core/.claude/hooks/handoff-snapshot-on-question.js +0 -158
  104. package/core/.claude/hooks/handoff-staleness.js +0 -197
  105. package/core/.claude/hooks/jev-thalamus-context.js +0 -17
  106. package/core/.claude/hooks/jev-thalamus-context.test.js +0 -41
  107. package/core/.claude/hooks/lease-release.js +0 -119
  108. package/core/.claude/hooks/lease-touch.js +0 -96
  109. package/core/.claude/hooks/reflex-feedback.js +0 -5
  110. package/core/.claude/hooks/session-init.ps1 +0 -49
  111. package/core/.claude/hooks/sound-event.js +0 -70
  112. package/core/.claude/hooks/sound-event.sh +0 -37
  113. package/core/.claude/hooks/stream-delta.js +0 -169
  114. package/core/.claude/no-hooks.settings.json +0 -3
  115. package/core/.claude/skills/legacy_dev/SKILL.md +0 -202
  116. package/core/.claude/skills/sunny/SKILL.md +0 -74
  117. package/core/.collaboration/cli/commands/assign.js +0 -39
  118. package/core/.collaboration/cli/commands/claim.js +0 -33
  119. package/core/.collaboration/cli/commands/complete.js +0 -44
  120. package/core/.collaboration/cli/commands/create.js +0 -110
  121. package/core/.collaboration/cli/commands/get.js +0 -83
  122. package/core/.collaboration/cli/commands/index.js +0 -52
  123. package/core/.collaboration/cli/commands/list.js +0 -51
  124. package/core/.collaboration/cli/commands/lock.js +0 -45
  125. package/core/.collaboration/cli/commands/rebuild.js +0 -39
  126. package/core/.collaboration/cli/commands/search.js +0 -61
  127. package/core/.collaboration/cli/commands/stats.js +0 -61
  128. package/core/.collaboration/cli/commands/transfer.js +0 -41
  129. package/core/.collaboration/cli/commands/unlock.js +0 -48
  130. package/core/.collaboration/cli/formatters/help-formatter.js +0 -70
  131. package/core/.collaboration/cli/formatters/index.js +0 -7
  132. package/core/.collaboration/cli/task-cli.js +0 -46
  133. package/core/.collaboration/cli/utils/arg-parser.js +0 -74
  134. package/core/.collaboration/cli/utils/git-user.js +0 -25
  135. package/core/.collaboration/cli/utils/index.js +0 -9
  136. package/core/.collaboration/cli/utils/output.js +0 -10
  137. package/core/.collaboration/config/default.yaml +0 -189
  138. package/core/.collaboration/core/conflict-resolver.js +0 -461
  139. package/core/.collaboration/core/conflict-resolver.test.js +0 -389
  140. package/core/.collaboration/core/migrate-legacy.js +0 -260
  141. package/core/.collaboration/docs/API.md +0 -787
  142. package/core/.collaboration/docs/ARCHITECTURE.md +0 -596
  143. package/core/.collaboration/docs/FAQ.md +0 -695
  144. package/core/.collaboration/docs/MIGRATION.md +0 -804
  145. package/core/.collaboration/docs/examples/README.md +0 -320
  146. package/core/.collaboration/docs/examples/advanced-queries.js +0 -261
  147. package/core/.collaboration/docs/examples/basic-usage.js +0 -184
  148. package/core/.collaboration/docs/examples/team-workflow.js +0 -352
  149. package/core/.failure/agent-execution/FAIL-001-agent-no-output.yaml +0 -391
  150. package/core/.failure/agent-execution/FAIL-007-pm-lead-wrong-team-invocation.yaml +0 -0
  151. package/core/.failure/agent-execution/FAIL-010-phase0-poem-format-skipped.yaml +0 -28
  152. package/core/.failure/agent-execution/FAIL-010-skipping-cognitive-checkpoint-after-verification.yaml +0 -59
  153. package/core/.failure/agent-execution/FAIL-012-grep-shortcut-during-investigation.yaml +0 -85
  154. package/core/.failure/architecture/FAIL-006-python-version-compatibility.yaml +0 -445
  155. package/core/.failure/pipeline/FAIL-003-queue-pollution.yaml +0 -335
  156. package/core/.failure/pipeline/README.md +0 -95
  157. package/core/.failure/retired/FAIL-009-skipping-synapse-pulse-before-code-change.yaml +0 -49
  158. package/core/.failure/tools/USAGE_GUIDE.md +0 -323
  159. package/core/.failure/tools/check_failures.ps1 +0 -387
  160. package/core/.failure/tools/log_failure.ps1 +0 -474
  161. package/core/.formation/.episode-input.json +0 -10
  162. package/core/.formation/.merge-lock +0 -1
  163. package/core/.formation/lead.yaml +0 -118
  164. package/core/.formation/legacy.bak/designer.yaml +0 -57
  165. package/core/.formation/legacy.bak/pm.yaml +0 -57
  166. package/core/.formation/legacy.bak/qa.yaml +0 -57
  167. package/core/.formation/legacy.bak/review.yaml +0 -62
  168. package/core/.formation/legacy.bak/scheduler.yaml +0 -129
  169. package/core/.formation/legacy.bak/sre.yaml +0 -57
  170. package/core/.formation/role-map.yaml +0 -274
  171. package/core/.formation/roles/_shared/modules/code_review.yaml +0 -98
  172. package/core/.formation/roles/_shared/modules/security.yaml +0 -103
  173. package/core/.formation/roles/_shared/modules/testing.yaml +0 -14
  174. package/core/.formation/roles/backend/role.yaml +0 -93
  175. package/core/.formation/roles/code_reviewer/role.yaml +0 -102
  176. package/core/.formation/roles/database_optimizer/role.yaml +0 -107
  177. package/core/.formation/roles/designer/role.yaml +0 -66
  178. package/core/.formation/roles/developer/role.yaml +0 -75
  179. package/core/.formation/roles/frontend/role.yaml +0 -134
  180. package/core/.formation/roles/incident_response/role.yaml +0 -89
  181. package/core/.formation/roles/qa/role.yaml +0 -89
  182. package/core/.formation/roles/security/role.yaml +0 -87
  183. package/core/.formation/roles/sre/role.yaml +0 -66
  184. package/core/.formation/skills/coordinator.yaml +0 -52
  185. package/core/.formation/solo/diagnosis.yaml +0 -78
  186. package/core/.formation/solo/strategy.yaml +0 -121
  187. package/core/.formation/tests/hello.txt +0 -2
  188. package/core/.formation/tools/coordinator.js +0 -350
  189. package/core/.formation/tools/jev-correction.js +0 -214
  190. package/core/.formation/tools/jev-correction.test.js +0 -178
  191. package/core/.formation/tools/log-reader.js +0 -232
  192. package/core/.formation/tools/revert-daemon-state.js +0 -162
  193. package/core/.formation/tools/test-drift.js +0 -148
  194. package/core/.formation/unit/heimdall.yaml +0 -96
  195. package/core/.formation/unit/plan.yaml +0 -67
  196. package/core/.formation/unit/think.yaml +0 -58
  197. package/core/.kenaz/MUNINN_SNAPSHOT9_EPISODE.json +0 -32
  198. package/core/.kenaz/MUNINN_SNAPSHOT9_RUNE.json +0 -23
  199. package/core/.kenaz/MUNINN_SNAPSHOT9_SUMMARY.md +0 -89
  200. package/core/.kenaz/ash_TASK_1428-20260507.json +0 -14
  201. package/core/.kenaz/muninn_episode_write.ps1 +0 -17
  202. package/core/.kenaz/muninn_snapshot11_rune_candidates.md +0 -63
  203. package/core/.kenaz/muninn_snapshot1_rune_candidates.md +0 -49
  204. package/core/.kenaz/runes_TASK_1428.json +0 -57
  205. package/core/.kenaz/tmp_heimdall_proposal_8d3e392.json +0 -13
  206. package/core/.kenaz/tmp_props.json +0 -1
  207. package/core/.kenaz/tmp_sounddrop_t1_prompt.txt +0 -371
  208. package/core/.rule/MECHANIZED.md +0 -61
  209. package/core/.rule/general/cortex-memory-recall.yaml +0 -446
  210. package/core/.rule/general/pipeline.yaml +0 -246
  211. package/core/.rule/general/sunny-access-control.yaml +0 -60
  212. package/core/.rule/general/system-invariants.yaml +0 -231
  213. package/core/.rule/pipeline/PPL-002-completed-task-archival.yaml +0 -528
  214. package/core/.rule/pipeline/auto-update.yaml +0 -282
  215. package/core/.rule/pipeline/task-execution.yaml +0 -365
  216. package/core/.specialist/Ansuz/concepts/phase_protocol.yaml +0 -65
  217. package/core/.specialist/Ansuz/experiments/boot_ablation_replay.js +0 -197
  218. package/core/.specialist/Ansuz/tools/bootstrap-anchors.js +0 -289
  219. package/core/.specialist/Ansuz/workflow.yaml +0 -1225
  220. package/core/.specialist/experiments/rg_benchmark.js +0 -523
  221. package/core/.specialist/experiments/rg_benchmark_results.json +0 -27
  222. package/core/.specialist/tools/jev-optional-context.js +0 -107
  223. package/core/.specialist/tools/jev-optional-context.test.js +0 -152
  224. package/core/.specialist/tools/memory-action-log.js +0 -839
  225. package/core/.specialist/tools/phase-gate.js +0 -3534
  226. package/core/.specialist/tools/phase-gate.test.js +0 -85
  227. package/core/.specialist/tools/precompute-runner.js +0 -444
  228. package/core/.specialist/tools/rule-engine.js +0 -621
  229. package/core/.specialist/tools/task-bridge-jev.test.js +0 -170
  230. package/core/.synapse/memory-shared.json.sync +0 -1
  231. package/core/.system/agent-skills/README.md +0 -724
  232. package/core/.system/cli-tools/README.md +0 -724
  233. package/core/.system/cortex/MODULES.md +0 -1046
  234. package/core/.system/dashboard/FRONTEND.md +0 -812
  235. package/core/.system/dashboard/README.md +0 -737
  236. package/core/.system/failure/README.md +0 -723
  237. package/core/.system/formation/LEGACY_SKILLS.md +0 -974
  238. package/core/.system/formation/POST_COMPLETE.md +0 -602
  239. package/core/.system/formation/README.md +0 -1094
  240. package/core/.system/formation/TOOLS_REFERENCE.md +0 -1145
  241. package/core/.system/kenaz/README.md +0 -787
  242. package/core/.system/memory/README.md +0 -719
  243. package/core/.system/pipeline/README.md +0 -712
  244. package/core/.system/rule/README.md +0 -794
  245. package/core/.system/sunny/README.md +0 -476
  246. package/core/.system/sunny/RULES.json +0 -89
  247. package/core/.system/sunny/knowledge/INDEX.md +0 -37
  248. package/core/.system/sunny/knowledge/agent-teams-api.md +0 -0
  249. package/core/.system/sunny/knowledge/ansuz-specialist.md +0 -500
  250. package/core/.system/sunny/knowledge/claude-cli-spawn.md +0 -177
  251. package/core/.system/sunny/knowledge/collaboration-api.md +0 -925
  252. package/core/.system/sunny/teammates/README.md +0 -107
  253. package/core/.system/sunny/teammates/how_to_use.yaml +0 -101
  254. package/core/.system/sunny/teammates/tools/headless/launcher.js +0 -318
  255. package/core/.system/sunny/teammates/tools/powershell/launcher.js +0 -241
  256. package/core/.system/sunny/teammates/tools/powershell/start.bat +0 -50
  257. package/core/.system/sunny/teammates/tools/utils/env.js +0 -96
  258. package/core/.system/sunny/teammates/tools/utils/format-output.js +0 -329
  259. package/core/.system/sunny/tools.json +0 -101
  260. package/core/dev/scripts/cleanup-queue.js +0 -184
  261. package/core/dev/scripts/cleanup_queue.js +0 -86
  262. package/core/dev/scripts/legacy/README.md +0 -39
  263. package/core/dev/scripts/legacy/dev_agent_scheduler.ps1.bak +0 -536
  264. package/core/dev/scripts/legacy/multi_agent_scheduler.ps1.bak +0 -1978
  265. package/core/dev/scripts/matrix/CLI_README.md +0 -214
  266. package/core/dev/scripts/matrix/README.md +0 -310
  267. package/core/dev/scripts/matrix/package-lock.json +0 -4266
  268. package/core/dev/scripts/matrix/package.json +0 -55
  269. package/core/dev/scripts/matrix/src/abbreviations.ts +0 -295
  270. package/core/dev/scripts/matrix/src/cli/commands/convert.ts +0 -211
  271. package/core/dev/scripts/matrix/src/cli/commands/create.ts +0 -95
  272. package/core/dev/scripts/matrix/src/cli/commands/delete.ts +0 -102
  273. package/core/dev/scripts/matrix/src/cli/commands/list-tags.ts.wip +0 -140
  274. package/core/dev/scripts/matrix/src/cli/commands/manage-tags.ts.wip +0 -173
  275. package/core/dev/scripts/matrix/src/cli/commands/query.ts +0 -261
  276. package/core/dev/scripts/matrix/src/cli/commands/read.ts +0 -77
  277. package/core/dev/scripts/matrix/src/cli/commands/stats.ts.wip +0 -168
  278. package/core/dev/scripts/matrix/src/cli/commands/tokens.ts.wip +0 -126
  279. package/core/dev/scripts/matrix/src/cli/commands/update.ts +0 -147
  280. package/core/dev/scripts/matrix/src/cli/commands/validate.ts +0 -275
  281. package/core/dev/scripts/matrix/src/cli/index.ts +0 -350
  282. package/core/dev/scripts/matrix/src/cli/utils/file-handler.ts +0 -72
  283. package/core/dev/scripts/matrix/src/cli/utils/logger.ts +0 -65
  284. package/core/dev/scripts/matrix/src/index.ts +0 -62
  285. package/core/dev/scripts/matrix/src/indexer/tag-indexer.ts +0 -165
  286. package/core/dev/scripts/matrix/src/parser.ts +0 -281
  287. package/core/dev/scripts/matrix/src/serializer.ts +0 -151
  288. package/core/dev/scripts/matrix/src/validator.ts +0 -301
  289. package/core/dev/scripts/matrix/tests/abbreviations.test.ts +0 -122
  290. package/core/dev/scripts/matrix/tests/cli.test.ts +0 -177
  291. package/core/dev/scripts/matrix/tests/convert.test.ts +0 -143
  292. package/core/dev/scripts/matrix/tests/parser.test.ts +0 -203
  293. package/core/dev/scripts/matrix/tests/query.test.ts +0 -85
  294. package/core/dev/scripts/matrix/tests/serializer.test.ts +0 -197
  295. package/core/dev/scripts/matrix/tests/validate.test.ts +0 -141
  296. package/core/dev/scripts/matrix/tests/validator.test.ts +0 -167
  297. package/core/dev/scripts/matrix/tsconfig.json +0 -20
  298. package/core/dev/scripts/matrix/types/index.d.ts +0 -111
  299. package/core/dev/scripts/matrix/types/index.d.ts.map +0 -1
  300. package/core/dev/scripts/matrix/types/index.js +0 -8
  301. package/core/dev/scripts/matrix/types/index.js.map +0 -1
  302. package/core/dev/scripts/matrix/types/index.ts +0 -124
  303. package/core/dev/scripts/memory-usage-report.js +0 -152
  304. package/core/dev/scripts/probe/ansuz-scaffold-ablation.js +0 -579
  305. package/core/dev/scripts/probe/ansuz-scaffold-ablation.test.js +0 -244
  306. package/core/dev/scripts/probe/hook-latency-probe.js +0 -315
  307. package/core/dev/scripts/probe/hook-latency-probe.test.js +0 -105
  308. package/core/dev/scripts/probe/prediction-signal-auc.js +0 -483
  309. package/core/dev/scripts/probe/prediction-signal-auc.test.js +0 -200
  310. package/core/dev/scripts/test-pty-ws-tunnel.js +0 -229
  311. package/core/dev/scripts/validate_pipeline.js +0 -197
  312. package/core/dev/spikes/task2145-evidence-20261004/backend-log-excerpt.txt +0 -56
  313. package/core/dev/spikes/task2145-evidence-20261004/graph.shadow +0 -0
  314. package/core/dev/spikes/task2145-evidence-20261004/graph.wal +0 -0
  315. package/core/dev/spikes/task2145-evidence-20261004/graph_corrupt_suspect.marker +0 -1
  316. package/core/plugins/kenaz/commands/strategy.md +0 -141
@@ -1,85 +0,0 @@
1
- 'use strict';
2
- // phase-gate gate-shape tests (restored TASK_2340 after the Kuzu removal dropped the pulse/predicted_symbols/thalamus gates).
3
- // Everything runs against a temp --project-path; charts for the temp project land in the git-ignored .specialist/sessions/projects/.
4
- const test = require('node:test');
5
- const assert = require('node:assert/strict');
6
- const fs = require('node:fs');
7
- const os = require('node:os');
8
- const path = require('node:path');
9
-
10
- const proj = fs.mkdtempSync(path.join(os.tmpdir(), 'pg2340-'));
11
- fs.mkdirSync(path.join(proj, '.kenaz', 'specialist'), { recursive: true });
12
- process.argv.push('--project-path=' + proj); // read at module load by phase-gate
13
- const pg = require('./phase-gate');
14
-
15
- const coreRoot = path.resolve(__dirname, '../..');
16
- const taskId = 'TASK_PG2340_' + process.pid;
17
- const taskDir = path.join(coreRoot, '.kenaz', 'tasks', 'active');
18
- const taskFile = path.join(taskDir, taskId + '.yaml');
19
-
20
- // enterPhase/exitPhase print JSON; keep test output clean.
21
- function quiet(fn) {
22
- const log = console.log;
23
- console.log = () => {};
24
- try { return fn(); } finally { console.log = log; }
25
- }
26
-
27
- // enterPhase touches lesson_guards.yaml (injection bookkeeping); restore it so the suite leaves the tree clean.
28
- const guardsFile = path.join(coreRoot, '.specialist', 'Ansuz', 'guards', 'lesson_guards.yaml');
29
- const guardsBefore = fs.existsSync(guardsFile) ? fs.readFileSync(guardsFile) : null;
30
-
31
- test.before(() => {
32
- fs.mkdirSync(taskDir, { recursive: true });
33
- fs.writeFileSync(taskFile, `id: ${taskId}\ntitle: pg test\nscope_paths:\n - .specialist/tools/phase-gate.js\n`);
34
- });
35
- test.after(() => {
36
- if (guardsBefore) fs.writeFileSync(guardsFile, guardsBefore);
37
- fs.rmSync(taskFile, { force: true });
38
- try { fs.rmdirSync(taskDir); } catch { /* not empty or absent: leave tracked dirs alone */ }
39
- fs.rmSync(proj, { recursive: true, force: true });
40
- const sessions = path.join(coreRoot, '.specialist', 'sessions', 'projects');
41
- if (fs.existsSync(sessions)) {
42
- for (const d of fs.readdirSync(sessions)) {
43
- if (d.startsWith(path.basename(proj).toLowerCase())) fs.rmSync(path.join(sessions, d), { recursive: true, force: true });
44
- }
45
- }
46
- });
47
-
48
- test('the task fixture really declares scope_paths', () => {
49
- assert.deepEqual(pg.readTaskScopePaths(taskId), ['.specialist/tools/phase-gate.js']);
50
- });
51
-
52
- test('checklists no longer ask for removed tools (preamble, thalamus, pulse, search)', () => {
53
- const all = JSON.stringify(pg.PHASE_CHECKLISTS);
54
- for (const gone of ['synapse_preamble', 'preamble_loaded', 'Tier 2b', 'thalamus', 'synapse_pulse', 'synapse_search', 'synapse_impact']) {
55
- assert.equal(all.includes(gone), false, gone);
56
- }
57
- assert.ok(!pg.PHASE_CHECKLISTS[0].some(i => i.includes('cortex_recall') || i.includes('synapse_')));
58
- assert.ok(pg.PHASE_CHECKLISTS[2].some(i => i.includes('kenaz_lsp_callers')));
59
- assert.equal(JSON.stringify(pg.PHASE_CHECKLISTS).toLowerCase().includes('muninn'), false);
60
- });
61
-
62
- test('Phase 8 exit rule no longer requires predicted_symbols', () => {
63
- assert.equal(pg.PHASE_EXIT_RULES[8], undefined);
64
- assert.deepEqual(pg.PHASE_EXIT_RULES[1].required, ['ddx_hypotheses']);
65
- assert.deepEqual(pg.PHASE_EXIT_RULES[9].required, ['cognitive_checkpoint']);
66
- });
67
-
68
- test('Phase 3 enter is not blocked by a missing pulse log even when the task declares scope_paths', () => {
69
- const r = quiet(() => pg.enterPhase(3, taskId));
70
- assert.equal(r.blocked, false);
71
- assert.equal(r.block_reason, null);
72
- assert.equal(JSON.stringify(r.warnings).includes('pulse'), false);
73
- });
74
-
75
- test('Phase 8 enter no longer reports muninn / valence output', () => {
76
- const r = quiet(() => pg.enterPhase(8, taskId));
77
- assert.equal(r.blocked, false);
78
- assert.equal('valence' in r, false);
79
- assert.equal('muninn' in r, false);
80
- });
81
-
82
- test('Phase 8 exit passes with scope_paths and no predicted_symbols', () => {
83
- const r = quiet(() => pg.exitPhase(8, taskId, {}));
84
- assert.notEqual(r.blocked, true);
85
- });
@@ -1,444 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- /**
5
- * Precompute Runner — TASK_1162
6
- *
7
- * Executes safe, read-only named functions before phase entry and embeds
8
- * their output into blind-spot guard text. Eliminates "remember to check X"
9
- * compliance friction by making the result already present in instructions.
10
- *
11
- * Security model:
12
- * - execFileSync with argv array (never execSync + shell) — prevents shell injection
13
- * - env: SAFE_ENV (PATH-only) — drops GIT_EXEC_PATH, LD_PRELOAD, etc.
14
- * - Per-parameter regex validation BEFORE any execFileSync call
15
- * - File paths resolved within project root and rejected on escape
16
- * - Whitelist: 5 named functions only — gitShowStat, gitDiffStat, grepCount, wcLines, fileExists
17
- *
18
- * Budget:
19
- * - 3s total per phase enter (TOTAL_BUDGET_MS)
20
- * - 1s per command (PER_CMD_TIMEOUT_MS, enforced by execFileSync timeout option)
21
- * - Per-guard output capped at 200 chars (PER_GUARD_CAP)
22
- * - Total output capped at 4096 bytes (TOTAL_CAP)
23
- *
24
- * Kill switch:
25
- * KENAZ_PRECOMPUTE_DISABLE=1 → skip all precompute, fall back to text-only guard
26
- *
27
- * Guard YAML precompute field format:
28
- * precompute:
29
- * cmd: "gitShowStat" # one of 5 named functions
30
- * sha: "HEAD" # gitShowStat / gitDiffStat param
31
- * sha1: "HEAD~1" # gitDiffStat param
32
- * sha2: "HEAD" # gitDiffStat param
33
- * pattern: "TODO" # grepCount param (JS regex pattern)
34
- * file: "path/to/file" # grepCount / wcLines param (project-relative)
35
- * path: "path/to/check" # fileExists param (project-relative)
36
- * when: "always" # "always" | "never" | taskData key name
37
- * template: "Result: {{result}}" # {{result}} replaced with command output
38
- */
39
-
40
- const fs = require('fs');
41
- const path = require('path');
42
- const { execFileSync } = require('child_process');
43
-
44
- // ── Constants ───────────────────────────────────────────────
45
-
46
- const TOTAL_BUDGET_MS = 3000; // total per phase enter
47
- const PER_CMD_TIMEOUT_MS = 1000; // execFileSync timeout per command
48
- const PER_GUARD_CAP = 200; // max chars per guard output (truncated with …)
49
- const TOTAL_CAP = 4096; // max total chars across all guards per phase
50
- const MAX_BUFFER = 4096; // execFileSync maxBuffer
51
-
52
- // SHA validation: 7–40 lowercase hex chars (git short or full SHA)
53
- const SHA_RE = /^[0-9a-f]{7,40}$/;
54
-
55
- // Minimal safe environment — only PATH so git can be located.
56
- // Drops GIT_EXEC_PATH, GIT_SSH, GIT_TEMPLATE_DIR, LD_PRELOAD, etc.
57
- const SAFE_ENV = { PATH: process.env.PATH || process.env.Path || '' };
58
-
59
- // ── Kill switch ─────────────────────────────────────────────
60
-
61
- /**
62
- * Returns true if precompute is globally disabled via env var.
63
- * Evaluated lazily so tests can set the env var before calling runPrecompute.
64
- */
65
- function isDisabled() {
66
- return process.env.KENAZ_PRECOMPUTE_DISABLE === '1';
67
- }
68
-
69
- // ── Parameter validators ────────────────────────────────────
70
-
71
- /**
72
- * Validate a git SHA parameter.
73
- * @param {string} sha
74
- * @returns {string} validated sha
75
- * @throws {Error} if invalid
76
- */
77
- function validateSha(sha) {
78
- if (typeof sha !== 'string' || !SHA_RE.test(sha)) {
79
- throw new Error(`Invalid SHA "${sha}": must match /^[0-9a-f]{7,40}$/`);
80
- }
81
- return sha;
82
- }
83
-
84
- /**
85
- * Resolve and validate a file path within project root.
86
- * Rejects any path that escapes the project root (../ traversal).
87
- * @param {string} filePath - relative or absolute path
88
- * @param {string} projectRoot - absolute project root
89
- * @returns {string} validated absolute path
90
- * @throws {Error} if path escapes project root
91
- */
92
- function resolveFilePath(filePath, projectRoot) {
93
- if (typeof filePath !== 'string' || !filePath.trim()) {
94
- throw new Error('File path must be a non-empty string');
95
- }
96
- const abs = path.isAbsolute(filePath)
97
- ? filePath
98
- : path.resolve(projectRoot, filePath);
99
- const normalized = path.normalize(abs);
100
- const rootNormalized = path.normalize(projectRoot);
101
- // Must be within project root (starts with root + sep, or equals root)
102
- if (normalized !== rootNormalized &&
103
- !normalized.startsWith(rootNormalized + path.sep)) {
104
- throw new Error(`Path escape rejected: "${filePath}" resolves outside project root`);
105
- }
106
- return normalized;
107
- }
108
-
109
- // ── Named Function Library ──────────────────────────────────
110
- //
111
- // Each function validates its parameters, then either executes a read-only
112
- // git command via execFileSync (argv array, never shell) or reads files
113
- // using Node's fs module (grepCount, wcLines, fileExists — cross-platform,
114
- // no shell dependency).
115
-
116
- /**
117
- * Show stat for a single commit (files changed + insertions/deletions summary).
118
- * @param {string} sha - 7–40 hex git SHA
119
- * @param {string} projectRoot - absolute project root (cwd for git)
120
- * @returns {string} trimmed stdout
121
- */
122
- function gitShowStat(sha, projectRoot) {
123
- validateSha(sha);
124
- const result = execFileSync('git', ['show', '--stat', '--no-patch', sha], {
125
- env: SAFE_ENV,
126
- cwd: projectRoot,
127
- timeout: PER_CMD_TIMEOUT_MS,
128
- maxBuffer: MAX_BUFFER,
129
- encoding: 'utf8',
130
- windowsHide: true,
131
- });
132
- return result.trim();
133
- }
134
-
135
- /**
136
- * Diff stat between two commits (files changed summary).
137
- * @param {string} sha1 - base commit SHA
138
- * @param {string} sha2 - head commit SHA
139
- * @param {string} projectRoot - absolute project root
140
- * @returns {string} trimmed stdout
141
- */
142
- function gitDiffStat(sha1, sha2, projectRoot) {
143
- validateSha(sha1);
144
- validateSha(sha2);
145
- const result = execFileSync('git', ['diff', '--stat', sha1, sha2], {
146
- env: SAFE_ENV,
147
- cwd: projectRoot,
148
- timeout: PER_CMD_TIMEOUT_MS,
149
- maxBuffer: MAX_BUFFER,
150
- encoding: 'utf8',
151
- windowsHide: true,
152
- });
153
- return result.trim();
154
- }
155
-
156
- /**
157
- * Count lines matching a pattern in a file (pure Node — cross-platform).
158
- * Uses JavaScript RegExp — no grep binary required on Windows.
159
- * @param {string} pattern - JavaScript regex pattern string
160
- * @param {string} filePath - project-relative or absolute path
161
- * @param {string} projectRoot - absolute project root
162
- * @returns {string} match count as string
163
- */
164
- function grepCount(pattern, filePath, projectRoot) {
165
- if (typeof pattern !== 'string') throw new Error('pattern must be a string');
166
- const absPath = resolveFilePath(filePath, projectRoot);
167
- // Validate pattern compiles (throws SyntaxError on invalid regex)
168
- const re = new RegExp(pattern);
169
- const content = fs.readFileSync(absPath, 'utf8');
170
- const count = content.split('\n').filter(line => re.test(line)).length;
171
- return String(count);
172
- }
173
-
174
- /**
175
- * Count lines in a file (pure Node — cross-platform).
176
- * @param {string} filePath - project-relative or absolute path
177
- * @param {string} projectRoot - absolute project root
178
- * @returns {string} line count as string
179
- */
180
- function wcLines(filePath, projectRoot) {
181
- const absPath = resolveFilePath(filePath, projectRoot);
182
- const content = fs.readFileSync(absPath, 'utf8');
183
- // Split on \n — consistent with wc -l semantics (count \n occurrences)
184
- const count = content.split('\n').length - (content.endsWith('\n') ? 1 : 0);
185
- return String(count);
186
- }
187
-
188
- /**
189
- * Count commits between two refs: HEAD ahead of the given base ref.
190
- * Used by L-004 to detect stale worktree base (e.g. ahead origin/main by N commits).
191
- * @param {string} baseRef - base ref name (e.g. "origin/main", "main", "HEAD~10")
192
- * @param {string} projectRoot - absolute project root
193
- * @returns {string} "ahead {N} commits of {baseRef}" or "in sync with {baseRef}"
194
- */
195
- function gitCommitsAhead(baseRef, projectRoot) {
196
- // Only allow safe ref patterns: refs/, origin/x, local branch names, HEAD~N
197
- if (!/^[a-zA-Z0-9_./~-]{1,80}$/.test(baseRef)) {
198
- throw new Error(`Invalid baseRef "${baseRef}": must match /^[a-zA-Z0-9_./~-]{1,80}$/`);
199
- }
200
- let result;
201
- try {
202
- result = execFileSync('git', ['rev-list', '--count', `${baseRef}..HEAD`], {
203
- env: SAFE_ENV,
204
- cwd: projectRoot,
205
- timeout: PER_CMD_TIMEOUT_MS,
206
- maxBuffer: MAX_BUFFER,
207
- encoding: 'utf8',
208
- windowsHide: true,
209
- });
210
- } catch (e) {
211
- return `(unknown — ${baseRef} unreachable)`;
212
- }
213
- const n = parseInt(result.trim(), 10);
214
- if (!Number.isFinite(n)) return `(unknown count for ${baseRef})`;
215
- if (n === 0) return `in sync with ${baseRef}`;
216
- if (n > 50) return `⚠️ ahead ${n} commits of ${baseRef} — very stale base risk`;
217
- if (n > 10) return `ahead ${n} commits of ${baseRef} — stale base possible`;
218
- return `ahead ${n} commits of ${baseRef}`;
219
- }
220
-
221
- /**
222
- * Show recent commits touching a file (last 5).
223
- * Used by L-002 to surface what's recently changed in the file Ansuz is about to modify.
224
- * @param {string} filePath - project-relative path
225
- * @param {string} projectRoot - absolute project root
226
- * @returns {string} compact log lines
227
- */
228
- function gitLogShort(filePath, projectRoot) {
229
- const absPath = resolveFilePath(filePath, projectRoot);
230
- const relPath = path.relative(projectRoot, absPath);
231
- // Reject path traversal — relPath must not start with ..
232
- if (relPath.startsWith('..') || path.isAbsolute(relPath)) {
233
- throw new Error(`Path escape detected: ${filePath}`);
234
- }
235
- const result = execFileSync('git', ['log', '--oneline', '-5', '--', relPath], {
236
- env: SAFE_ENV,
237
- cwd: projectRoot,
238
- timeout: PER_CMD_TIMEOUT_MS,
239
- maxBuffer: MAX_BUFFER,
240
- encoding: 'utf8',
241
- windowsHide: true,
242
- });
243
- const lines = result.trim().split('\n').filter(Boolean);
244
- if (lines.length === 0) return `(no git history for ${relPath})`;
245
- return `${relPath}: last ${lines.length} commits — ${lines[0].substring(0, 60)}`;
246
- }
247
-
248
- /**
249
- * Check if a file exists within project root (pure Node — cross-platform).
250
- * @param {string} filePath - project-relative or absolute path
251
- * @param {string} projectRoot - absolute project root
252
- * @returns {string} "true" or "false"
253
- */
254
- function fileExists(filePath, projectRoot) {
255
- let absPath;
256
- try {
257
- absPath = resolveFilePath(filePath, projectRoot);
258
- } catch {
259
- return 'false'; // invalid/escaped path → treat as not-found
260
- }
261
- return fs.existsSync(absPath) ? 'true' : 'false';
262
- }
263
-
264
- // ── Template Rendering ──────────────────────────────────────
265
-
266
- /**
267
- * Render a template string, replacing {{result}} with the command output.
268
- * Truncates to PER_GUARD_CAP chars with ellipsis if needed.
269
- * @param {string} template
270
- * @param {string} result - raw command output
271
- * @returns {string} rendered and capped output
272
- */
273
- function renderTemplate(template, result) {
274
- const rendered = (template || '{{result}}').replace(/\{\{result\}\}/g, result);
275
- if (rendered.length > PER_GUARD_CAP) {
276
- return rendered.slice(0, PER_GUARD_CAP - 1) + '…';
277
- }
278
- return rendered;
279
- }
280
-
281
- // ── Single Guard Evaluator ──────────────────────────────────
282
-
283
- /**
284
- * Evaluate a single guard's precompute field.
285
- * Returns rendered string, or null if skipped (when=never or condition unmet).
286
- *
287
- * @param {object} guard - guard object with .precompute field
288
- * @param {object} taskData - phase data for when-condition evaluation
289
- * @param {string} projectRoot - absolute project root
290
- * @returns {string|null} rendered output or null
291
- */
292
- function evaluateGuard(guard, taskData, projectRoot) {
293
- const pc = guard.precompute;
294
- if (!pc || !pc.cmd) return null;
295
-
296
- // Evaluate when condition
297
- const when = (pc.when || 'always').trim();
298
- if (when === 'never') return null;
299
- if (when !== 'always') {
300
- // Treat as a taskData key name — run only if taskData[when] is truthy
301
- const safeData = taskData || {};
302
- if (!safeData[when]) return null;
303
- }
304
-
305
- let rawResult;
306
- try {
307
- const cmd = pc.cmd;
308
- switch (cmd) {
309
- case 'gitShowStat':
310
- rawResult = gitShowStat(pc.sha || 'HEAD', projectRoot);
311
- break;
312
-
313
- case 'gitDiffStat':
314
- rawResult = gitDiffStat(pc.sha1 || 'HEAD~1', pc.sha2 || 'HEAD', projectRoot);
315
- break;
316
-
317
- case 'grepCount':
318
- rawResult = grepCount(pc.pattern || '.', pc.file || '', projectRoot);
319
- break;
320
-
321
- case 'wcLines':
322
- rawResult = wcLines(pc.file || '', projectRoot);
323
- break;
324
-
325
- case 'fileExists':
326
- rawResult = fileExists(pc.path || pc.file || '', projectRoot);
327
- break;
328
-
329
- case 'gitCommitsAhead':
330
- rawResult = gitCommitsAhead(pc.baseRef || pc.ref || 'origin/main', projectRoot);
331
- break;
332
-
333
- case 'gitLogShort':
334
- rawResult = gitLogShort(pc.file || pc.path || '', projectRoot);
335
- break;
336
-
337
- default:
338
- return `[precompute: unknown cmd "${String(cmd).slice(0, 40)}"]`;
339
- }
340
- } catch (e) {
341
- // Surface error as result — guard still renders, just shows what went wrong
342
- return `[precompute error: ${String(e.message).slice(0, 150)}]`;
343
- }
344
-
345
- return renderTemplate(pc.template || '{{result}}', rawResult);
346
- }
347
-
348
- // ── Batch Runner ────────────────────────────────────────────
349
-
350
- /**
351
- * Run precompute for all guards that have a precompute field.
352
- * Mutates each matching guard object by adding a `precompute_result` field.
353
- *
354
- * Budget enforcement:
355
- * - Skips remaining guards if TOTAL_BUDGET_MS exceeded
356
- * - Skips remaining guards if TOTAL_CAP bytes exceeded
357
- * - Per-command timeout enforced by execFileSync timeout option (1s)
358
- *
359
- * Note: Uses synchronous execution (execFileSync). Promise.all is used
360
- * structurally for forward compatibility; true parallelism requires async
361
- * fs/child_process APIs which can be introduced in a follow-up.
362
- *
363
- * @param {Array<object>} guards - guard objects from readBlindSpotGuards
364
- * @param {object} taskData - current phase data (for when-condition evaluation)
365
- * @param {string} projectRoot - absolute project root path
366
- */
367
- function runPrecompute(guards, taskData, projectRoot) {
368
- // Kill switch: skip all precompute
369
- if (isDisabled()) {
370
- return;
371
- }
372
-
373
- if (!Array.isArray(guards) || guards.length === 0) return;
374
-
375
- const startMs = Date.now();
376
- let totalOutput = 0;
377
- let budgetExceeded = false;
378
-
379
- for (const guard of guards) {
380
- if (!guard.precompute) continue; // backward compat: guards without precompute unchanged
381
-
382
- // Budget gate: check elapsed time
383
- if (!budgetExceeded && (Date.now() - startMs) >= TOTAL_BUDGET_MS) {
384
- budgetExceeded = true;
385
- // Log warning to stderr (non-blocking — caller can inspect guard objects)
386
- process.stderr.write('[precompute] WARN: total budget (3s) exceeded — remaining guards skipped\n');
387
- }
388
-
389
- if (budgetExceeded) {
390
- guard.precompute_result = '[precompute: budget exceeded — skipped]';
391
- continue;
392
- }
393
-
394
- // Total output cap gate
395
- if (totalOutput >= TOTAL_CAP) {
396
- guard.precompute_result = '[precompute: total output cap (4096 bytes) reached — skipped]';
397
- continue;
398
- }
399
-
400
- const result = evaluateGuard(guard, taskData, projectRoot);
401
-
402
- if (result !== null && result !== undefined) {
403
- // Enforce total cap: trim result to fit remaining budget
404
- const remaining = TOTAL_CAP - totalOutput;
405
- if (result.length > remaining) {
406
- guard.precompute_result = result.slice(0, remaining - 1) + '…';
407
- totalOutput = TOTAL_CAP; // cap reached
408
- } else {
409
- guard.precompute_result = result;
410
- totalOutput += result.length;
411
- }
412
- }
413
- }
414
- }
415
-
416
- // ── Exports ─────────────────────────────────────────────────
417
-
418
- module.exports = {
419
- // Primary API
420
- runPrecompute,
421
-
422
- // Named functions (exported for unit testing)
423
- gitShowStat,
424
- gitDiffStat,
425
- grepCount,
426
- wcLines,
427
- fileExists,
428
- gitCommitsAhead,
429
- gitLogShort,
430
-
431
- // Validators (exported for unit testing)
432
- validateSha,
433
- resolveFilePath,
434
-
435
- // Helpers (exported for unit testing)
436
- renderTemplate,
437
- evaluateGuard,
438
-
439
- // Constants (exported for unit testing)
440
- TOTAL_BUDGET_MS,
441
- PER_CMD_TIMEOUT_MS,
442
- PER_GUARD_CAP,
443
- TOTAL_CAP,
444
- };