kenaz 0.3.22 → 0.3.24

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 (474) hide show
  1. package/core/.claude/hooks/_user-scope.js +1 -1
  2. package/core/.claude/hooks/core-resolve.js +1 -1
  3. package/core/.claude/hooks/worktree-create.js +11 -29
  4. package/core/.claude/hooks/worktree-remove.js +12 -38
  5. package/core/.collaboration/core/reconcile.js +16 -1
  6. package/core/.collaboration/core/task-2467-lifecycle.test.js +63 -0
  7. package/core/.collaboration/core/task-api.js +37 -7
  8. package/core/.formation/bifrost/launch.js +1 -1
  9. package/core/.formation/tools/dispatch-detail/worktree-subagent-mode.md +6 -1
  10. package/core/.formation/tools/kenaz-stats.js +1 -1
  11. package/core/.formation/tools/post-complete/git-merge.js +1 -1
  12. package/core/.formation/tools/prompt.js +1 -1
  13. package/core/.formation/tools/utils.js +5 -5
  14. package/core/.formation/tools/worktree-reclaim.js +73 -2
  15. package/core/.formation/tools/worktree-reclaim.test.js +113 -0
  16. package/core/.kenaz/specialist/ansuz_rules.yaml +7 -51
  17. package/core/.kenaz/specialist/ansuz_session_handoff.schema.json +2 -6
  18. package/core/.rule/general/project-self-containment.yaml +2 -2
  19. package/core/.specialist/Amelia/README.md +1 -1
  20. package/core/.specialist/Amelia/rule.yaml +1 -1
  21. package/core/.specialist/Ansuz/RULES.md +6 -2
  22. package/core/.specialist/Ansuz/concepts/commitment_layer.yaml +1 -1
  23. package/core/.specialist/Ansuz/concepts/evolvable_guardrails.yaml +1 -1
  24. package/core/.specialist/Ansuz/knowledge.yaml +1 -3
  25. package/core/.specialist/tools/__tests__/task-2409-lessons.test.js +10 -0
  26. package/core/.specialist/tools/__tests__/task-2427-harvest.test.js +25 -0
  27. package/core/.specialist/tools/ansuz-boot-fast.js +1 -1
  28. package/core/.specialist/tools/failure-detector.js +4 -4
  29. package/core/.specialist/tools/handoff-doc.js +1 -1
  30. package/core/.specialist/tools/lessons.js +2 -2
  31. package/core/CLAUDE.md +5 -5
  32. package/core/KENAZ_CORE_VERSION +1 -1
  33. package/core/dashboard/scripts/install-kenaz-cli.js +56 -30
  34. package/core/dev/scripts/check-file-size.js +1 -1
  35. package/core/dev/scripts/ci-feedback.js +1 -1
  36. package/core/dev/scripts/gc-agent-worktrees.js +13 -12
  37. package/core/dev/scripts/kenaz-session.js +3 -3
  38. package/core/dev/scripts/peer-identity-e2e.js +6 -4
  39. package/core/dev/scripts/run-rust-tests.js +2 -2
  40. package/core/dev/scripts/skill-routing-replay.js +3 -3
  41. package/core/dev/scripts/task1961/selftest.js +2 -2
  42. package/core/dev/scripts/windows-hide-guard.test.js +112 -0
  43. package/core/plugins/kenaz/guidance.md +1 -0
  44. package/core/plugins/kenaz/hooks/core-resolve.js +1 -1
  45. package/core/plugins/kenaz/hooks/hooks.json +9 -0
  46. package/core/plugins/kenaz/hooks/kenaz-hook.js +58 -4
  47. package/core/plugins/kenaz/hooks/worktree-guard.js +121 -0
  48. package/core/plugins/kenaz/hooks/worktree-guard.test.js +75 -0
  49. package/core/plugins/kenaz/scripts/kenaz.test.js +72 -5
  50. package/core/plugins/kenaz-peer/hooks/register.test.ts +14 -2
  51. package/core/plugins/kenaz-peer/hooks/register.ts +6 -1
  52. package/lib/cli.js +9 -5
  53. package/package.json +6 -6
  54. package/vendor/install-kenaz-cli.js +56 -30
  55. package/core/.kenaz/designs/METAPLASTICITY_CONFIDENCE_DESIGN.md +0 -537
  56. package/core/.kenaz/designs/REFLEX_INITIATOR_DESIGN.md +0 -501
  57. package/core/.kenaz/designs/TASK_1385_handoff_mcp_design.md +0 -426
  58. package/core/.kenaz/designs/TASK_932_hippocampus_consolidation.md +0 -103
  59. package/core/.kenaz/designs/TASK_934_efe_signal_engine.md +0 -97
  60. package/core/.kenaz/designs/TASK_935_self_evolution_framework.md +0 -154
  61. package/core/.kenaz/designs/VISION_cognitive_architecture_roadmap.md +0 -159
  62. package/core/.kenaz/designs/metaplasticity_simulation_results.json +0 -696
  63. package/core/.kenaz/main-memory/README.md +0 -230
  64. package/core/.kenaz/main-memory/kenaz/cortex/001_cortex_overview.md +0 -168
  65. package/core/.kenaz/main-memory/kenaz/cortex/001_rag_engine_overview.md +0 -30
  66. package/core/.kenaz/main-memory/kenaz/memory-system/001_three_tier_architecture.md +0 -361
  67. package/core/.kenaz/main-memory/kenaz/pipeline/001_task_execution_flow.md +0 -117
  68. package/core/.kenaz/main-memory/kenaz/pipeline/001_task_granularity.md +0 -154
  69. package/core/.kenaz/main-memory/kenaz/pipeline/002_team_priority.md +0 -51
  70. package/core/.kenaz/main-memory/kenaz/pipeline/003_feature_id_system.md +0 -46
  71. package/core/.kenaz/main-memory/kenaz/rules/001_gen_007_self_containment.md +0 -108
  72. package/core/.kenaz/main-memory/kenaz/rules/001_rule_priority_system.md +0 -121
  73. package/core/.kenaz/main-memory/kenaz/rules/002_agt_006_pre_check.md +0 -0
  74. package/core/.kenaz/main-memory/kenaz/rules/003_ppl_002_task_archival.md +0 -48
  75. package/core/.kenaz/main-memory/kenaz/system/001_dual_track_task_system.md +0 -197
  76. package/core/.kenaz/main-memory/knowledge/patterns/001_json_bom_issue.md +0 -78
  77. package/core/.kenaz/main-memory/knowledge/patterns/001_leader_worker_pattern.md +0 -0
  78. package/core/.kenaz/main-memory/knowledge/patterns/002_scope_path_conflict.md +0 -115
  79. package/core/.kenaz/main-memory/knowledge/patterns/002_task_dependency_resolution.md +0 -223
  80. package/core/.kenaz/main-memory/knowledge/patterns/003_question_protocol.md +0 -242
  81. package/core/.kenaz/main-memory/knowledge/patterns/004_user_insight_value.md +0 -111
  82. package/core/.kenaz/main-memory/knowledge/patterns/005_file_lock_pattern.md +0 -274
  83. package/core/.kenaz/main-memory/knowledge/references/001_ppl_rules.md +0 -28
  84. package/core/.kenaz/main-memory/knowledge/solutions/001_json_bom_issue.md +0 -137
  85. package/core/.kenaz/main-memory/knowledge/solutions/001_team_invocation.md +0 -0
  86. package/core/.kenaz/main-memory/knowledge/solutions/002_passive_monitoring.md +0 -0
  87. package/core/.kenaz/main-memory/knowledge/solutions/003_windows_file_race_condition.md +0 -239
  88. package/core/.kenaz/main-memory/registry.json +0 -326
  89. package/core/.kenaz/main-memory/version.yaml +0 -58
  90. package/core/.kenaz/specialist/memory_guard_fired.json +0 -1
  91. package/core/.kenaz/specialist/memory_guard_trigger_cache.json +0 -1
  92. package/core/.kenaz/specialist/memory_source_priority.yaml +0 -260
  93. package/core/.kenaz/specialist/prompt_1775.txt +0 -317
  94. package/core/.kenaz/specialist/prompt_1776.txt +0 -326
  95. package/core/.kenaz/specialist/prompt_1791.txt +0 -320
  96. package/core/.kenaz/specialist/prompt_1792.txt +0 -320
  97. package/core/.kenaz/specialist/prompt_1795.txt +0 -281
  98. package/core/.kenaz/specialist/prompt_1813.txt +0 -332
  99. package/core/.kenaz/specialist/prompt_1814.txt +0 -401
  100. package/core/.kenaz/specialist/prompt_1815.txt +0 -394
  101. package/core/.kenaz/specialist/prompt_1816.txt +0 -437
  102. package/core/.kenaz/specialist/prompt_1818.txt +0 -361
  103. package/core/.kenaz/specialist/prompt_1819.txt +0 -421
  104. package/core/.kenaz/specialist/prompt_1821.txt +0 -345
  105. package/core/.kenaz/specialist/prompt_1822.txt +0 -313
  106. package/core/.kenaz/specialist/prompt_1824.txt +0 -348
  107. package/core/.kenaz/specialist/prompt_1826.txt +0 -388
  108. package/core/.kenaz/specialist/rune_efe_salience_gap.md +0 -21
  109. package/core/.kenaz/specialist/task1825_update.json +0 -43
  110. package/core/.kenaz/specialist/taskgen/consolidation_i.json +0 -38
  111. package/core/.kenaz/specialist/taskgen/csharp_a.json +0 -44
  112. package/core/.kenaz/specialist/taskgen/csharp_b.json +0 -40
  113. package/core/.kenaz/specialist/taskgen/embedding_e.json +0 -34
  114. package/core/.kenaz/specialist/taskgen/hygiene_fg.json +0 -39
  115. package/core/.kenaz/specialist/taskgen/pathology_h.json +0 -36
  116. package/core/.kenaz/specialist/taskgen/unity_noise_d.json +0 -38
  117. package/core/.kenaz/specialist/taskgen/visibility_c.json +0 -38
  118. package/core/.specialist/Ansuz/decisions/ADR-requirement-graph-layer.md +0 -390
  119. package/core/.specialist/Ansuz/self_model_seed.backup.json +0 -100
  120. package/core/.specialist/ansuz_session_handoff.json +0 -96
  121. package/core/dev/ALAYA_FIELD_FEEDBACK_DESIGN.md +0 -126
  122. package/core/dev/ANSUZ_SCAFFOLD_DIET_2026-09-20.md +0 -231
  123. package/core/dev/ANSUZ_STARTUP_INJECTION_REVIEW.md +0 -355
  124. package/core/dev/ANSUZ_WORKFLOW_MODERNIZATION.md +0 -143
  125. package/core/dev/CORTEX_META_GRAPH_ASSESSMENT.md +0 -99
  126. package/core/dev/FREYA_DOWNSTREAM_BUGS_2026-09-19.md +0 -44
  127. package/core/dev/GLOBAL_MEMORY_IDENTITY_CONSOLIDATION.md +0 -263
  128. package/core/dev/GUARD_EFFECTIVENESS_DESIGN.md +0 -180
  129. package/core/dev/HEALTH_GATE_VARIANCE_ASSESSMENT.md +0 -271
  130. package/core/dev/HOOK_DIET_2026-09-21.md +0 -126
  131. package/core/dev/JEV_INTEGRATION_PLAN.md +0 -189
  132. package/core/dev/KENAZ_AGENT_CONNECT_v1_SPEC.md +0 -139
  133. package/core/dev/MOBILE_DESIGN_SPEC.md +0 -569
  134. package/core/dev/MULTI_ANSUZ_SPEC.md +0 -136
  135. package/core/dev/MUNINN_RETIREMENT.md +0 -115
  136. package/core/dev/PHASE3_ATTRIBUTION_POPULATION_DIAGNOSIS.md +0 -211
  137. package/core/dev/PHASE3_P3-2B_TASKLEVEL_PROBE.md +0 -83
  138. package/core/dev/PHASE3_P3-2_POPULATION_DISJOINTNESS.md +0 -83
  139. package/core/dev/PHASE3_P3-2_REMEASURE_REPORT.md +0 -231
  140. package/core/dev/PREDICTION_GROUNDING_DESIGN.md +0 -376
  141. package/core/dev/PRODUCT_SPEC.md +0 -317
  142. package/core/dev/PROJECT_REGISTRY_DUPLICATE_ASSESSMENT.md +0 -86
  143. package/core/dev/STARTUP_TIMELINE_TASK_1995.md +0 -181
  144. package/core/dev/SYNAPSE_WORKER_PER_PROJECT.md +0 -881
  145. package/core/dev/TASK_1680_P3-3_DISPATCH_SPEC.md +0 -96
  146. package/core/dev/TASK_1684_CALIBRATION_IMPACT_ANALYSIS.md +0 -170
  147. package/core/dev/TASK_1684_FORK_A_GOODHART_DESIGN.md +0 -171
  148. package/core/dev/TASK_1684_P3_2_REMEASURE_VALIDATION.md +0 -262
  149. package/core/dev/TASK_1903_SIGNAL_AUC_MEASUREMENT.md +0 -207
  150. package/core/dev/TASK_1904_BRANCH_INTEGRITY_AUDIT.md +0 -146
  151. package/core/dev/ansuz-eval/README.md +0 -38
  152. package/core/dev/ansuz-eval/build-fixtures.js +0 -87
  153. package/core/dev/ansuz-eval/grade.js +0 -96
  154. package/core/dev/ansuz-eval/grader.test.js +0 -117
  155. package/core/dev/ansuz-eval/tasks.md +0 -32
  156. package/core/dev/archive/ansuz/BOOT_FULL.md +0 -141
  157. package/core/dev/archive/ansuz/agents/ansuz-boot.md +0 -176
  158. package/core/dev/archive/ansuz/designs/alaya-passive-surfacing.md +0 -84
  159. package/core/dev/archive/ansuz/designs/cc_memory_indexing.md +0 -307
  160. package/core/dev/archive/ansuz/designs/check_guard.md +0 -322
  161. package/core/dev/archive/ansuz/designs/consequence_loop.md +0 -227
  162. package/core/dev/archive/ansuz/designs/mcp_kuzudb_lock_architecture.md +0 -312
  163. package/core/dev/archive/ansuz/designs/phase0_git_enrichment.md +0 -278
  164. package/core/dev/archive/ansuz/designs/refactor_mcp_tools_synapse.md +0 -490
  165. package/core/dev/archive/ansuz/designs/semantic_markdown_extraction.md +0 -167
  166. package/core/dev/archive/ansuz/designs/task_1372_prompt_injects_into.md +0 -193
  167. package/core/dev/archive/ansuz/designs/thought_stack.md +0 -286
  168. package/core/dev/archive/ansuz/investigations/reachability_unified_api_2026-04-11.md +0 -330
  169. package/core/dev/archive/ansuz/investigations/synapse_orphans_indexing_bug_2026-04-11.md +0 -352
  170. package/core/dev/archive/ansuz/investigations/synapse_orphans_reindex_verification_2026-04-11.md +0 -48
  171. package/core/dev/archive/ansuz/investigations/synapse_orphans_verification_2026-04-11.md +0 -170
  172. package/core/dev/archive/ansuz/legacy/kernel.yaml +0 -399
  173. package/core/dev/archive/ansuz/legacy/phases/phase_0.yaml +0 -418
  174. package/core/dev/archive/ansuz/legacy/phases/phase_1.yaml +0 -376
  175. package/core/dev/archive/ansuz/legacy/phases/phase_10.yaml +0 -35
  176. package/core/dev/archive/ansuz/legacy/phases/phase_11.yaml +0 -582
  177. package/core/dev/archive/ansuz/legacy/phases/phase_2.yaml +0 -94
  178. package/core/dev/archive/ansuz/legacy/phases/phase_3.yaml +0 -274
  179. package/core/dev/archive/ansuz/legacy/phases/phase_4.yaml +0 -67
  180. package/core/dev/archive/ansuz/legacy/phases/phase_5.yaml +0 -32
  181. package/core/dev/archive/ansuz/legacy/phases/phase_6.yaml +0 -91
  182. package/core/dev/archive/ansuz/legacy/phases/phase_7.yaml +0 -58
  183. package/core/dev/archive/ansuz/legacy/phases/phase_8.yaml +0 -146
  184. package/core/dev/archive/ansuz/legacy/phases/phase_9.yaml +0 -424
  185. package/core/dev/archive/ansuz/specs/INDEX_bifrost_hook_parity.yaml +0 -92
  186. package/core/dev/archive/ansuz/specs/active-inference-formation.yaml +0 -453
  187. package/core/dev/archive/ansuz/specs/brief_TASK_1228_userpromptsubmit.yaml +0 -191
  188. package/core/dev/archive/ansuz/specs/brief_TASK_1229_pretooluse_posttooluse.yaml +0 -250
  189. package/core/dev/archive/ansuz/specs/brief_TASK_1230_sessionstart_stop.yaml +0 -301
  190. package/core/dev/archive/ansuz/specs/brief_TASK_1231_verification.yaml +0 -272
  191. package/core/dev/archive/skills/feature_agent/SKILL.md +0 -289
  192. package/core/dev/design/PHASE4_DESIGN.md +0 -559
  193. package/core/dev/design/dashboard_docs_integration_PLAN.md +0 -388
  194. package/core/dev/design/matrix_format_ABBREVIATIONS.md +0 -655
  195. package/core/dev/design/matrix_format_DESIGN_SPEC.md +0 -601
  196. package/core/dev/design/matrix_format_DISCUSSION_SUMMARY.md +0 -484
  197. package/core/dev/design/matrix_format_EXAMPLE_memory.matrix +0 -13
  198. package/core/dev/design/matrix_format_EXAMPLE_project_status.matrix +0 -9
  199. package/core/dev/design/matrix_format_EXAMPLE_tasks.matrix +0 -14
  200. package/core/dev/design/matrix_format_SYNTAX_BNF.md +0 -754
  201. package/core/dev/design/matrix_format_TOKEN_COMPARISON.md +0 -484
  202. package/core/dev/design/matrix_v2_COGNITIVE_DESIGN.md +0 -503
  203. package/core/dev/design/matrix_v2_DISCUSSION_SUMMARY.md +0 -414
  204. package/core/dev/design/matrix_v2_EXAMPLE.matrix +0 -67
  205. package/core/dev/designs/EXPANDABLE_CARD_DESIGN_SPEC.md +0 -509
  206. package/core/dev/jev-eval/ACTIVE_CORRECTION.md +0 -52
  207. package/core/dev/jev-eval/ANNOTATION_GUIDE.md +0 -68
  208. package/core/dev/jev-eval/BASELINE_COMPARISON.md +0 -45
  209. package/core/dev/jev-eval/CONTEXT_REVIEW.md +0 -31
  210. package/core/dev/jev-eval/EVALUATION_STATUS.md +0 -39
  211. package/core/dev/jev-eval/HISTORICAL_CORPUS.md +0 -33
  212. package/core/dev/jev-eval/PACKAGING_VERIFICATION.md +0 -42
  213. package/core/dev/jev-eval/README.md +0 -101
  214. package/core/dev/jev-eval/THALAMUS_RANKING.md +0 -58
  215. package/core/dev/jev-eval/VALIDATION_PROGRESS.md +0 -54
  216. package/core/dev/jev-eval/cli.mjs +0 -50
  217. package/core/dev/jev-eval/context.mjs +0 -183
  218. package/core/dev/jev-eval/corpus.mjs +0 -186
  219. package/core/dev/jev-eval/fixtures/conversation-review.seed.jsonl +0 -6
  220. package/core/dev/jev-eval/fixtures/synthetic.jsonl +0 -11
  221. package/core/dev/jev-eval/metrics.mjs +0 -67
  222. package/core/dev/jev-eval/muninn-baseline.mjs +0 -119
  223. package/core/dev/jev-eval/providers.mjs +0 -95
  224. package/core/dev/jev-eval/reports/annotation-pilot-2026-09-20.json +0 -32
  225. package/core/dev/jev-eval/reports/context-review-2026-09-20.json +0 -48
  226. package/core/dev/jev-eval/reports/conversation-review.pending.json +0 -151
  227. package/core/dev/jev-eval/reports/history-corpus-2026-09-20.json +0 -52
  228. package/core/dev/jev-eval/reports/length-probe-2026-09-20.json +0 -133
  229. package/core/dev/jev-eval/reports/live-smoke-2026-09-20.json +0 -616
  230. package/core/dev/jev-eval/reports/muninn-baseline-2026-09-20.json +0 -52
  231. package/core/dev/jev-eval/reports/resilience-2026-09-20.json +0 -520
  232. package/core/dev/jev-eval/reports/rules-baseline.json +0 -197
  233. package/core/dev/jev-eval/reports/synthetic-review.pending.json +0 -357
  234. package/core/dev/jev-eval/resilience.mjs +0 -71
  235. package/core/dev/jev-eval/review.mjs +0 -78
  236. package/core/dev/jev-eval/schema.mjs +0 -87
  237. package/core/dev/jev-eval/test/context.test.mjs +0 -95
  238. package/core/dev/jev-eval/test/corpus.test.mjs +0 -102
  239. package/core/dev/jev-eval/test/eval.test.mjs +0 -146
  240. package/core/dev/jev-eval/test/muninn-baseline.test.mjs +0 -71
  241. package/core/dev/jev-eval/test/resilience.test.mjs +0 -72
  242. package/core/dev/jev-eval/test/review.test.mjs +0 -61
  243. package/core/dev/pipeline/PHASE3_PLANNING_SUMMARY.md +0 -338
  244. package/core/dev/pipeline/PROGRESS.md +0 -113
  245. package/core/dev/pipeline/PROGRESS_template.md +0 -860
  246. package/core/dev/pipeline/QA_REPORT_F008.md +0 -431
  247. package/core/dev/pipeline/QA_REPORT_LOCAL_CLAUDE_DIAGNOSIS.md +0 -583
  248. package/core/dev/pipeline/README.md +0 -210
  249. package/core/dev/pipeline/WORKFLOW_GUIDE.md +0 -824
  250. package/core/dev/pipeline/archived/TASK_015_tauri_init.yaml +0 -53
  251. package/core/dev/pipeline/archived/TASK_016_tauri_commands.yaml +0 -54
  252. package/core/dev/pipeline/archived/TASK_017_rust_pty.yaml +0 -54
  253. package/core/dev/pipeline/archived/TASK_018_tauri_bundle.yaml +0 -53
  254. package/core/dev/pipeline/archived/TASK_019_release_workflow.yaml +0 -56
  255. package/core/dev/pipeline/archived/TASK_020_update_ui.yaml +0 -54
  256. package/core/dev/pipeline/archived/TASK_021_update_notification_ui.yaml +0 -55
  257. package/core/dev/pipeline/archived/TASK_022_remove_node_pty.yaml +0 -65
  258. package/core/dev/pipeline/archived/TASK_023_api_routes_migration.yaml +0 -86
  259. package/core/dev/pipeline/archived/TASK_024_feature_id_system.yaml +0 -51
  260. package/core/dev/pipeline/archived/TASK_025_executable_acceptance.yaml +0 -66
  261. package/core/dev/pipeline/archived/TASK_026_spec_versioning.yaml +0 -56
  262. package/core/dev/pipeline/archived/TASK_027_drift_detection.yaml +0 -60
  263. package/core/dev/pipeline/archived/TASK_028_tauri_pty_manager.yaml +0 -60
  264. package/core/dev/pipeline/archived/TASK_029_tauri_pty_commands.yaml +0 -62
  265. package/core/dev/pipeline/archived/TASK_030_frontend_session_adapter.yaml +0 -54
  266. package/core/dev/pipeline/archived/TASK_031_terminal_tauri_events.yaml +0 -56
  267. package/core/dev/pipeline/archived/TASK_041_scheduler_data_models.yaml +0 -54
  268. package/core/dev/pipeline/archived/TASK_042_path_lock_manager.yaml +0 -53
  269. package/core/dev/pipeline/archived/TASK_043_process_manager.yaml +0 -57
  270. package/core/dev/pipeline/archived/TASK_044_git_integration.yaml +0 -85
  271. package/core/dev/pipeline/archived/TASK_045_task_queue_manager.yaml +0 -54
  272. package/core/dev/pipeline/archived/TASK_046_scheduler_dispatcher.yaml +0 -60
  273. package/core/dev/pipeline/archived/TASK_047_tauri_scheduler_commands.yaml +0 -55
  274. package/core/dev/pipeline/archived/TASK_048_realtime_status_push.yaml +0 -92
  275. package/core/dev/pipeline/archived/TASK_049_frontend_scheduler_integration.yaml +0 -58
  276. package/core/dev/pipeline/archived/TASK_050_error_recovery.yaml +0 -56
  277. package/core/dev/pipeline/archived/TASK_051_optimization_proposals_backend.yaml +0 -53
  278. package/core/dev/pipeline/archived/TASK_052_optimization_proposals_ui.yaml +0 -58
  279. package/core/dev/pipeline/archived/TASK_053_optimization_proposals_diff_view.yaml +0 -54
  280. package/core/dev/pipeline/archived/TASK_054_multi_project_scheduler_state.yaml +0 -76
  281. package/core/dev/pipeline/archived/TASK_055_scheduler_api_project_scope.yaml +0 -64
  282. package/core/dev/pipeline/archived/TASK_056_frontend_scheduler_project_scope.yaml +0 -62
  283. package/core/dev/pipeline/archived/TASK_057_scheduler_module_structure.yaml +0 -54
  284. package/core/dev/pipeline/archived/TASK_058_scheduler_models_extract.yaml +0 -51
  285. package/core/dev/pipeline/archived/TASK_059_scheduler_core_extract.yaml +0 -51
  286. package/core/dev/pipeline/archived/TASK_060_scheduler_commands_extract.yaml +0 -51
  287. package/core/dev/pipeline/archived/TASK_061_scheduler_specialized_commands.yaml +0 -53
  288. package/core/dev/pipeline/archived/TASK_062_process_manager_module_structure.yaml +0 -56
  289. package/core/dev/pipeline/archived/TASK_063_process_manager_core_extract.yaml +0 -56
  290. package/core/dev/pipeline/archived/TASK_064_recovery_module_structure.yaml +0 -57
  291. package/core/dev/pipeline/archived/TASK_065_recovery_core_extract.yaml +0 -56
  292. package/core/dev/pipeline/archived/TASK_066_self_enhancement_scheduler_models.yaml +0 -60
  293. package/core/dev/pipeline/archived/TASK_067_agents_section_quick_actions.yaml +0 -53
  294. package/core/dev/pipeline/archived/TASK_067_self_enhancement_scheduler_core.yaml +0 -65
  295. package/core/dev/pipeline/archived/TASK_068_agent_workflow_rule_enhancement.yaml +0 -46
  296. package/core/dev/pipeline/archived/TASK_068_self_enhancement_tauri_commands.yaml +0 -61
  297. package/core/dev/pipeline/archived/TASK_069_agent_wizard_responsive.yaml +0 -46
  298. package/core/dev/pipeline/archived/TASK_069_self_enhancement_ui.yaml +0 -62
  299. package/core/dev/pipeline/archived/TASK_070_preview_panel_redesign.yaml +0 -62
  300. package/core/dev/pipeline/archived/TASK_070_self_enhancement_integration.yaml +0 -57
  301. package/core/dev/pipeline/archived/TASK_071_preview_panel_qa.yaml +0 -98
  302. package/core/dev/pipeline/archived/TASK_071_single_agent_config.yaml +0 -57
  303. package/core/dev/pipeline/archived/TASK_072_preview_modal_esc_fix.yaml +0 -71
  304. package/core/dev/pipeline/archived/TASK_072_product_review_module.yaml +0 -57
  305. package/core/dev/pipeline/archived/TASK_073_agents_page_component_refactor.yaml +0 -68
  306. package/core/dev/pipeline/archived/TASK_073_rename_single_agent.yaml +0 -64
  307. package/core/dev/pipeline/archived/TASK_074_preview_mode_ui_diagnosis.yaml +0 -71
  308. package/core/dev/pipeline/archived/TASK_074_single_agent_ui_toggle.yaml +0 -56
  309. package/core/dev/pipeline/archived/TASK_075_agents_page_component_refactor.yaml +0 -69
  310. package/core/dev/pipeline/archived/TASK_075_single_agent_integration_test.yaml +0 -75
  311. package/core/dev/pipeline/archived/TASK_076_preview_mode_ui_diagnosis.yaml +0 -70
  312. package/core/dev/pipeline/archived/TASK_076_single_agent_continuous_mode.yaml +0 -65
  313. package/core/dev/pipeline/archived/TASK_077_failure_directory_structure.yaml +0 -51
  314. package/core/dev/pipeline/archived/TASK_077_single_agent_typescript_types.yaml +0 -59
  315. package/core/dev/pipeline/archived/TASK_078_fail_001_agent_no_output.yaml +0 -53
  316. package/core/dev/pipeline/archived/TASK_078_single_agent_ui_simplify.yaml +0 -74
  317. package/core/dev/pipeline/archived/TASK_079_dashboard_rwd_responsive.yaml +0 -63
  318. package/core/dev/pipeline/archived/TASK_079_fail_002_json_bom.yaml +0 -56
  319. package/core/dev/pipeline/archived/TASK_080_fail_003_queue_pollution.yaml +0 -56
  320. package/core/dev/pipeline/archived/TASK_080_http_server_module.yaml +0 -55
  321. package/core/dev/pipeline/archived/TASK_081_failure_logging_tools.yaml +0 -57
  322. package/core/dev/pipeline/archived/TASK_081_http_api_routes.yaml +0 -62
  323. package/core/dev/pipeline/archived/TASK_082_frontend_api_adapter.yaml +0 -51
  324. package/core/dev/pipeline/archived/TASK_082_integrate_failure_to_workflow.yaml +0 -60
  325. package/core/dev/pipeline/archived/TASK_083_cleanup_nextjs_api.yaml +0 -48
  326. package/core/dev/pipeline/archived/TASK_083_task_queue_cleanup.yaml +0 -67
  327. package/core/dev/pipeline/archived/TASK_084_rust_dead_code_cleanup.yaml +0 -66
  328. package/core/dev/pipeline/archived/TASK_084_scheduler_sync_logic_fix.yaml +0 -68
  329. package/core/dev/pipeline/archived/TASK_085_http_api_web_mode_fixes.yaml +0 -46
  330. package/core/dev/pipeline/archived/TASK_085_memory_consolidation_0204_0205.yaml +0 -98
  331. package/core/dev/pipeline/archived/TASK_086_collapsible_preview_panel.yaml +0 -161
  332. package/core/dev/pipeline/archived/TASK_086_web_mode_feature_parity.yaml +0 -62
  333. package/core/dev/pipeline/archived/TASK_087_manual_memory_archival.yaml +0 -163
  334. package/core/dev/pipeline/archived/TASK_087_mobile_http_control.yaml +0 -68
  335. package/core/dev/pipeline/archived/TASK_088_fail_003_to_ppl_002_rule.yaml +0 -63
  336. package/core/dev/pipeline/archived/TASK_088_mobile_http_qa.yaml +0 -121
  337. package/core/dev/pipeline/archived/TASK_089_agent_collaboration_topic.yaml +0 -60
  338. package/core/dev/pipeline/archived/TASK_089_web_mode_monitor_fix.yaml +0 -58
  339. package/core/dev/pipeline/archived/TASK_090_cli_detection_fix.yaml +0 -61
  340. package/core/dev/pipeline/archived/TASK_090_ui_ux_lessons_topic.yaml +0 -63
  341. package/core/dev/pipeline/archived/TASK_091_expandable_card_design.yaml +0 -56
  342. package/core/dev/pipeline/archived/TASK_091_move_agent_section_components.yaml +0 -65
  343. package/core/dev/pipeline/archived/TASK_092_expandable_card_component.yaml +0 -60
  344. package/core/dev/pipeline/archived/TASK_092_refactor_agent_create_wizard.yaml +0 -84
  345. package/core/dev/pipeline/archived/TASK_093_taskcard_detail_integration.yaml +0 -57
  346. package/core/dev/pipeline/archived/TASK_093_update_barrel_exports_test.yaml +0 -84
  347. package/core/dev/pipeline/archived/TASK_094_ai_agent_generation_enhancement.yaml +0 -115
  348. package/core/dev/pipeline/archived/TASK_094_proposalcard_detail_integration.yaml +0 -55
  349. package/core/dev/pipeline/archived/TASK_095_preview_fixes.yaml +0 -129
  350. package/core/dev/pipeline/archived/TASK_095_single_agent_task_selector.yaml +0 -60
  351. package/core/dev/pipeline/archived/TASK_096_agents_page_ux_improvements.yaml +0 -163
  352. package/core/dev/pipeline/archived/TASK_096_single_agent_status_sync.yaml +0 -60
  353. package/core/dev/pipeline/archived/TASK_097_local_claude_error_logging.yaml +0 -59
  354. package/core/dev/pipeline/archived/TASK_097_single_agent_monitor_events.yaml +0 -59
  355. package/core/dev/pipeline/archived/TASK_098_product_manager_team_phase2.yaml +0 -60
  356. package/core/dev/pipeline/archived/TASK_098_single_agent_refactor_test.yaml +0 -58
  357. package/core/dev/pipeline/archived/TASK_099_backend_team_creation.yaml +0 -258
  358. package/core/dev/pipeline/archived/TASK_100_frontend_team_creation.yaml +0 -61
  359. package/core/dev/pipeline/archived/TASK_101_orchestrator_system.yaml +0 -403
  360. package/core/dev/pipeline/archived/TASK_102_designer_sre_teams.yaml +0 -90
  361. package/core/dev/pipeline/archived/TASK_103_integration_testing.yaml +0 -86
  362. package/core/dev/pipeline/archived/TASK_128_integration_testing.yaml +0 -83
  363. package/core/dev/pipeline/archived/TASK_134_cortex_v2_phase3_file_watcher.yaml +0 -65
  364. package/core/dev/pipeline/archived/TASK_134_team_http_api.yaml +0 -96
  365. package/core/dev/pipeline/archived/TASK_135_cortex_v2_phase3_git_monitor.yaml +0 -63
  366. package/core/dev/pipeline/archived/TASK_136_cortex_v2_phase3_change_analyzer.yaml +0 -69
  367. package/core/dev/pipeline/archived/TASK_137_cortex_v2_phase3_cache_invalidator.yaml +0 -67
  368. package/core/dev/pipeline/archived/TASK_137_team_orchestrator_integration.yaml +0 -93
  369. package/core/dev/pipeline/archived/TASK_138_cortex_v2_phase3_distributed_cache.yaml +0 -68
  370. package/core/dev/pipeline/archived/TASK_138_matrix_folder_structure.yaml +0 -61
  371. package/core/dev/pipeline/archived/TASK_139_cortex_v2_phase3_cache_prewarming.yaml +0 -65
  372. package/core/dev/pipeline/archived/TASK_146_unified_documentation.yaml +0 -141
  373. package/core/dev/pipeline/archived/TASK_147_pipeline_execution_rules.yaml +0 -76
  374. package/core/dev/pipeline/archived/TASK_148_update_claude_md.yaml +0 -77
  375. package/core/dev/pipeline/archived/TASK_149_fix_nextjs_mdx_serialization.yaml +0 -63
  376. package/core/dev/pipeline/archived/TASK_149_update_team_docs.yaml +0 -77
  377. package/core/dev/pipeline/archived/TASK_150_pipeline_workflow_guide.yaml +0 -82
  378. package/core/dev/pipeline/archived/TASK_164_fix_smart_context_switch.yaml +0 -49
  379. package/core/dev/pipeline/archived/TASK_165_ctags_symbol_index.yaml +0 -53
  380. package/core/dev/pipeline/archived/TASK_166_symbol_search_mcp_tool.yaml +0 -48
  381. package/core/dev/pipeline/archived/TASK_167_llm_module_summary.yaml +0 -55
  382. package/core/dev/pipeline/archived/TASK_168_map_reduce_context.yaml +0 -51
  383. package/core/dev/pipeline/archived/TASK_169_v2_integration_testing.yaml +0 -52
  384. package/core/dev/pipeline/backups/archive_2026-02-04T22-07-22/TASK_QUEUE_backup.json +0 -95
  385. package/core/dev/pipeline/docs/multi-agent-coordination.md +0 -446
  386. package/core/dev/pipeline/docs/overview.md +0 -406
  387. package/core/dev/pipeline/docs/task-management.md +0 -412
  388. package/core/dev/pipeline/docs/workflows.md +0 -32
  389. package/core/dev/pipeline/orchestrator/schemas/task_queue_schema.json +0 -58
  390. package/core/dev/pipeline/orchestrator/schemas/task_schema.json +0 -139
  391. package/core/dev/pipeline/plans/PLAN_task_cli_refactor.md +0 -281
  392. package/core/dev/pipeline/test_results/TASK_TEST_PARALLEL_002_result.txt +0 -27
  393. package/core/dev/plans/ANSUZ_SLIM_PLAN.md +0 -68
  394. package/core/dev/plans/CLI_FIRST_INSTALL_FLOW.md +0 -120
  395. package/core/dev/plans/FORMATION_RETIREMENT_PLAN.md +0 -313
  396. package/core/dev/plans/KUZU_REPLACEMENT_PLAN.md +0 -126
  397. package/core/dev/scripts/CRASH_DIAGNOSIS.md +0 -47
  398. package/core/dev/scripts/README.md +0 -142
  399. package/core/dev/scripts/RUN_ONCE.bat +0 -40
  400. package/core/dev/scripts/START_DEV_AGENT.bat +0 -63
  401. package/core/dev/scripts/START_MULTI_AGENT.bat +0 -80
  402. package/core/dev/scripts/dev_agent_scheduler.ps1 +0 -536
  403. package/core/dev/scripts/init_git.ps1 +0 -396
  404. package/core/dev/scripts/init_git.sh +0 -337
  405. package/core/dev/scripts/init_project.ps1 +0 -851
  406. package/core/dev/scripts/init_project.sh +0 -477
  407. package/core/dev/scripts/multi_agent_scheduler.ps1 +0 -2021
  408. package/core/dev/scripts/multi_agent_scheduler.sh +0 -1344
  409. package/core/dev/scripts/run_once.sh +0 -47
  410. package/core/dev/scripts/setup_rag.ps1 +0 -304
  411. package/core/dev/scripts/setup_rag.sh +0 -230
  412. package/core/dev/scripts/start_dev_agent.sh +0 -137
  413. package/core/dev/scripts/start_multi_agent.sh +0 -41
  414. package/core/dev/scripts/sync_task_queue.ps1 +0 -505
  415. package/core/dev/scripts/sync_task_queue.sh +0 -392
  416. package/core/dev/specs/agent-connect/PROTOCOL.md +0 -177
  417. package/core/dev/specs/agent-connect/SDK_GUIDE.md +0 -915
  418. package/core/dev/specs/agent-connect/examples/minimal-site/README.md +0 -137
  419. package/core/dev/specs/agent-connect/examples/minimal-site/package.json +0 -12
  420. package/core/dev/specs/agent-connect/examples/minimal-site/public/index.html +0 -116
  421. package/core/dev/specs/agent-connect/examples/minimal-site/public/install-redirect.js +0 -73
  422. package/core/dev/specs/agent-connect/examples/minimal-site/server.js +0 -516
  423. package/core/dev/specs/agent-connect/examples/minimal-site/test/smoke.test.mjs +0 -263
  424. package/core/dev/specs/agent-connect/history/DEFECT_REPORT_kenaz-agent-hub_2026-09-09_v0.4-empty-prompt-no-first-turn.md +0 -77
  425. package/core/dev/specs/agent-connect/history/DEFECT_REPORT_kenaz-agent-hub_2026-09-09_v0.4-prompt-mojibake.md +0 -90
  426. package/core/dev/specs/agent-connect/history/FEATURE_REQUEST_kenaz-agent-hub_2026-09-07.md +0 -61
  427. package/core/dev/specs/agent-connect/history/FEATURE_REQUEST_kenaz-agent-hub_2026-09-08_relay-v1-conformance.md +0 -76
  428. package/core/dev/specs/agent-connect/history/FEATURE_REQUEST_kenaz-agent-hub_2026-09-09_v0.4-session-channel.md +0 -87
  429. package/core/dev/specs/agent-connect/history/FLOWPIX_REPLY_agent-hub_2026-09-08_relay-v1-answers.md +0 -68
  430. package/core/dev/specs/agent-connect/history/FLOWPIX_bridge_CONTRACT.md +0 -642
  431. package/core/dev/specs/agent-connect/history/FLOWPIX_spikes_relay_spike_relay.mjs +0 -244
  432. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-07.md +0 -77
  433. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-08_direction-change-v0.3.md +0 -44
  434. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-08_relay-v1-answers-ack.md +0 -37
  435. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-08_relay-v1-conformance.md +0 -56
  436. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_annotations-install-coldstart.md +0 -44
  437. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_empty-prompt-first-turn.md +0 -56
  438. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_prompt-mojibake-fixed.md +0 -48
  439. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_session-channel.md +0 -57
  440. package/core/dev/specs/agent-connect/history/PROTOCOL_v0.3_snapshot.md +0 -379
  441. package/core/dev/specs/agent-connect/history/README.md +0 -47
  442. package/core/dev/specs/peer/CODEX_INTERACTIVE_PUSH.md +0 -65
  443. package/core/dev/specs/peer/CODEX_MANAGED_DAEMON.md +0 -54
  444. package/core/dev/specs/peer/CODEX_PEER_PULL_SPIKE.md +0 -54
  445. package/core/dev/specs/peer/MODS_SPIKE.md +0 -133
  446. package/core/dev/specs/peer/PER_PROJECT_ADDRESSING.md +0 -143
  447. package/core/dev/specs/peer/SWARM_PROTOCOLS.md +0 -256
  448. package/core/dev/specs/peer/codex-hook-shim-peer.test.js +0 -113
  449. package/core/dev/specs/peer/codex-push-launcher.test.js +0 -142
  450. package/core/dev/specs/peer/setup-codex-hooks.test.js +0 -60
  451. package/core/dev/specs/peer-ansuz/DELIVERY_SPIKE.md +0 -397
  452. package/core/dev/specs/peer-ansuz/DESIGN.md +0 -109
  453. package/core/dev/specs/peer-ansuz/spike/claude_poke.js +0 -129
  454. package/core/dev/specs/peer-ansuz/spike/claude_session_start_hook.js +0 -37
  455. package/core/dev/specs/peer-ansuz/spike/claude_settings_hook.json +0 -14
  456. package/core/dev/specs/peer-ansuz/spike/codex_appserver_client.js +0 -105
  457. package/core/dev/specs/peer-ansuz/spike/codex_appserver_query.js +0 -29
  458. package/core/dev/specs/peer-ansuz/spike/extract_timeline.js +0 -26
  459. package/core/dev/specs/synapse/SYMBOL_IDENTITY.md +0 -305
  460. package/core/dev/spikes/A4-cypher-varlen.md +0 -176
  461. package/core/dev/spikes/bloat-rounds.sh +0 -25
  462. package/core/dev/spikes/mods/clean-claude.js +0 -9
  463. package/core/dev/spikes/mods/drive-probe.js +0 -29
  464. package/core/dev/spikes/mods/e2e-peer.js +0 -71
  465. package/core/dev/spikes/mods/evidence/e2e-peer-control.json +0 -17
  466. package/core/dev/spikes/mods/evidence/e2e-peer-mod.json +0 -17
  467. package/core/dev/spikes/mods/evidence/probe-006a6e65-d807-4bc1-b648-fd7d1edfe0b4.jsonl +0 -4
  468. package/core/dev/spikes/mods/evidence/probe-cebdf1f7-f9c4-47a8-83cd-7c0786177404.jsonl +0 -12
  469. package/core/dev/spikes/mods/evidence/probe-eb21147d-10ce-4c32-93ed-37ca37d88d5a.jsonl +0 -11
  470. package/core/dev/spikes/mods/evidence/stream-cebdf1f7.jsonl +0 -18
  471. package/core/dev/spikes/mods/kenaz-mod-probe/.claude-plugin/plugin.json +0 -1
  472. package/core/dev/spikes/mods/kenaz-mod-probe/hooks/hooks.json +0 -1
  473. package/core/dev/spikes/mods/kenaz-mod-probe/hooks/register.ts +0 -65
  474. package/core/dev/spikes/mods/kenaz-mod-probe/tsconfig.json +0 -3
@@ -13,7 +13,8 @@ const fs = require('fs');
13
13
  const path = require('path');
14
14
  const net = require('net');
15
15
  const http = require('http');
16
- const { spawnSync } = require('child_process');
16
+ const os = require('os');
17
+ const { spawn, spawnSync } = require('child_process');
17
18
  const { resolveMode, allows, projectDir } = require('./mode');
18
19
  const { isSdkSession } = require('./sdk-gate');
19
20
 
@@ -34,6 +35,7 @@ const HOOKS = {
34
35
  'memory-guard': { kind: 'script', file: 'memory-guard.js', call: 'main', minMode: 'full' },
35
36
  'vendor-agent-guard': { kind: 'script', file: 'vendor-agent-guard.js', call: 'main', minMode: 'assist' },
36
37
  'peer-session-fill': { kind: 'script', file: 'peer-session-fill.js', call: 'main', minMode: 'assist' },
38
+ 'worktree-guard': { kind: 'inline', file: 'worktree-guard.js', minMode: 'assist' }, // TASK_2485: runs from the plugin itself, needs no core
37
39
  'task-bridge': { kind: 'script', file: 'task-bridge.js', minMode: 'assist' },
38
40
  };
39
41
 
@@ -49,6 +51,42 @@ function backendUp(cb) {
49
51
  s.on('error', () => done(false));
50
52
  }
51
53
 
54
+ // TASK_2468: after a reboot nothing has started kenaz-server yet (the plugin MCP is a static http URL).
55
+ // Start the installed binary detached, the way the installer does; never by process name, and only
56
+ // called after the port probe failed (a second server is never started over an answering one).
57
+ function startServer(dir) {
58
+ try {
59
+ const home = os.homedir();
60
+ const meta = JSON.parse(fs.readFileSync(path.join(home, '.kenaz', 'install.json'), 'utf8'));
61
+ const bin = meta && meta.serverBin;
62
+ if (!bin || !fs.existsSync(bin)) return false;
63
+ const core = coreDir(dir);
64
+ const env = Object.assign({}, process.env, core ? { KENAZ_SOURCE_DIR: core } : {});
65
+ const opts = { env, detached: true, stdio: 'ignore', windowsHide: true };
66
+ const viaNode = /\.js$/.test(bin); // a script (tests) runs under node; the real server is a binary
67
+ let child;
68
+ if (process.platform === 'win32') {
69
+ const args = core ? ['--source-dir', core] : []; // TASK_2478: no console, core dir as an argument
70
+ child = viaNode ? spawn(process.execPath, [bin, ...args], opts) : spawn(bin, args, opts);
71
+ } else {
72
+ const log = path.join(home, '.kenaz', 'kenaz-server.log');
73
+ const sq = (v) => "'" + String(v).replace(/'/g, "'\\''") + "'";
74
+ const cmd = 'if command -v setsid >/dev/null 2>&1; then S=setsid; else S=; fi; $S nohup ' +
75
+ (viaNode ? sq(process.execPath) + ' ' : '') + sq(bin) + ' >> ' + sq(log) + ' 2>&1 < /dev/null &';
76
+ child = spawn('sh', ['-c', cmd], opts);
77
+ }
78
+ child.on('error', () => {});
79
+ child.unref();
80
+ return true;
81
+ } catch (_) { return false; }
82
+ }
83
+
84
+ function waitForBackend(ms, cb) {
85
+ const end = Date.now() + ms;
86
+ const tick = () => backendUp((ok) => { if (ok || Date.now() >= end) return cb(ok); setTimeout(tick, 150); });
87
+ tick();
88
+ }
89
+
52
90
  function post(body, cb) {
53
91
  const r = http.request({ hostname: HOST, port: PORT, path: '/api/rust/agent-flow/hook', method: 'POST',
54
92
  headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) }, timeout: 3000 },
@@ -75,7 +113,7 @@ function run(spec, stdin, dir) {
75
113
  const stdio = ['pipe', 'inherit', 'ignore'];
76
114
  if (spec.kind === 'core-script') {
77
115
  const target = path.join(core, spec.rel);
78
- if (fs.existsSync(target)) spawnSync(process.execPath, [target, ...(spec.args || [])], { cwd: dir, env, input: stdin, stdio, timeout: 10000 });
116
+ if (fs.existsSync(target)) spawnSync(process.execPath, [target, ...(spec.args || [])], { cwd: dir, env, input: stdin, stdio, timeout: 10000, windowsHide: true });
79
117
  return;
80
118
  }
81
119
  const file = path.join(core, '.claude', 'hooks', spec.file);
@@ -83,7 +121,7 @@ function run(spec, stdin, dir) {
83
121
  // Same shape as the core's own `node -e "chdir; require(hook)"` wrappers (require.main stays undefined).
84
122
  const code = 'process.chdir(process.env.CLAUDE_PROJECT_DIR);const m=require(process.argv[1]);' +
85
123
  (spec.call ? 'm[process.argv[2]]();' : '');
86
- spawnSync(process.execPath, ['-e', code, file, spec.call || ''], { cwd: dir, env, input: stdin, stdio, timeout: 10000 });
124
+ spawnSync(process.execPath, ['-e', code, file, spec.call || ''], { cwd: dir, env, input: stdin, stdio, timeout: 10000, windowsHide: true });
87
125
  }
88
126
 
89
127
  function main() {
@@ -103,9 +141,25 @@ function main() {
103
141
  if (spec.kind === 'session-start') {
104
142
  return post(JSON.stringify({ hook_event_name: 'SessionStart', session_id: process.env.SESSION_ID || 'unknown', project_path: dir }), () => {});
105
143
  }
144
+ if (spec.kind === 'inline') {
145
+ const out = require('./' + spec.file).decide(JSON.parse(stdin || '{}'));
146
+ if (out) process.stdout.write(JSON.stringify(out));
147
+ return;
148
+ }
106
149
  run(spec, stdin, dir);
107
150
  };
108
- if (spec.backend) backendUp((ok) => { if (ok) go(); }); else go();
151
+ if (!spec.backend) return go();
152
+ backendUp((ok) => {
153
+ if (ok) return go();
154
+ if (spec.kind !== 'session-start') return;
155
+ const finish = (up) => {
156
+ if (up) go();
157
+ process.stdout.write(up
158
+ ? 'kenaz-server was not running; the Kenaz hook started it on ' + HOST + ':' + PORT + '. If the kenaz MCP tools (kenaz-dashboard) show as failed, ask the user to run /mcp to reconnect them (they connected before the server was up).\n'
159
+ : 'kenaz-server is not running on ' + HOST + ':' + PORT + ', so the kenaz MCP tools are unavailable. Ask the user to run `! npx kenaz install` (registers the boot service and starts it), then /mcp to reconnect kenaz-dashboard.\n');
160
+ };
161
+ if (startServer(dir)) waitForBackend(3000, finish); else finish(false);
162
+ });
109
163
  }
110
164
 
111
165
  process.on('uncaughtException', () => process.exit(0));
@@ -0,0 +1,121 @@
1
+ 'use strict';
2
+ // PreToolUse(Bash): deny `git worktree remove`, `rm -r`, `rmdir /s` and `Remove-Item -Recurse` aimed at a
3
+ // directory that contains a symlink/junction (any name, any depth). On Windows `git worktree remove --force`
4
+ // walks THROUGH junctions and empties their targets: field report 2026-10-20 lost node_modules, backend/.env
5
+ // and tracked files of the MAIN repo. Directories without links pass. Fails open on any error or timeout.
6
+ // Safe path: node <core>/.formation/tools/worktree-reclaim.js remove <dir> (unlinks every link first).
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+
10
+ const MAX_MS = 2500;
11
+
12
+ // Quote-aware split into commands (on && || ; | newline), each a token list.
13
+ function commands(line) {
14
+ const out = []; let tok = ''; let cur = []; let q = null;
15
+ const endTok = () => { if (tok) cur.push(tok); tok = ''; };
16
+ const endCmd = () => { endTok(); if (cur.length) out.push(cur); cur = []; };
17
+ for (let i = 0; i < line.length; i++) {
18
+ const c = line[i];
19
+ if (q) { if (c === q) q = null; else tok += c; continue; }
20
+ if (c === '"' || c === "'") { q = c; continue; }
21
+ if (c === '\\' && /[ "']/.test(line[i + 1] || '') && process.platform !== 'win32') { tok += line[++i]; continue; }
22
+ if (/\s/.test(c) && c !== '\n') { endTok(); continue; }
23
+ if (c === '\n' || c === ';' || c === '|' || c === '&') { endCmd(); continue; }
24
+ tok += c;
25
+ }
26
+ endCmd();
27
+ return out;
28
+ }
29
+
30
+ // Directory arguments of a removal command, or [] when the command is not a recursive removal.
31
+ function removalTargets(t) {
32
+ const base = (s) => s.replace(/^.*[\\/]/, '').replace(/\.exe$/i, '').toLowerCase();
33
+ const i = t.findIndex((x) => ['git', 'rm', 'rmdir', 'rd', 'remove-item', 'ri', 'del'].includes(base(x)));
34
+ if (i < 0) return [];
35
+ const name = base(t[i]); const a = t.slice(i + 1);
36
+ if (name === 'git') {
37
+ const k = a.indexOf('worktree');
38
+ return k >= 0 && a[k + 1] === 'remove' ? a.slice(k + 2).filter((x) => !x.startsWith('-')) : [];
39
+ }
40
+ if (name === 'rm') return a.some((x) => /^-[a-z]*[rR]/.test(x) || x === '--recursive') ? a.filter((x) => !x.startsWith('-')) : [];
41
+ if (name === 'rmdir' || name === 'rd') return a.some((x) => /^\/s$/i.test(x)) ? a.filter((x) => !x.startsWith('/')) : [];
42
+ // PowerShell: Remove-Item / ri / del with -Recurse
43
+ if (!a.some((x) => /^-r(ecurse)?$/i.test(x))) return [];
44
+ const out = []; const valued = /^-(path|literalpath|include|exclude|filter|credential)$/i;
45
+ for (let j = 0; j < a.length; j++) {
46
+ if (/^-(path|literalpath)$/i.test(a[j]) && a[j + 1]) { out.push(a[++j]); continue; }
47
+ if (valued.test(a[j])) { j++; continue; }
48
+ if (!a[j].startsWith('-')) out.push(a[j]);
49
+ }
50
+ return out;
51
+ }
52
+
53
+ function resolveDir(arg, cwd) {
54
+ let p = arg;
55
+ if (/[*?]/.test(p)) return null;
56
+ const m = /^\/([a-zA-Z])\/(.*)$/.exec(p); // Git Bash /c/Users/...
57
+ if (m && process.platform === 'win32') p = m[1].toUpperCase() + ':/' + m[2];
58
+ return path.resolve(cwd || process.cwd(), p);
59
+ }
60
+
61
+ // First symlink/junction found under dir (lstat walk, never follows), or null.
62
+ function findLink(dir, deadline) {
63
+ const stack = [dir];
64
+ while (stack.length) {
65
+ if (Date.now() > deadline) return null; // too big to prove: fail open
66
+ const d = stack.pop();
67
+ let names; try { names = fs.readdirSync(d); } catch { continue; }
68
+ for (const n of names) {
69
+ const p = path.join(d, n);
70
+ let st; try { st = fs.lstatSync(p); } catch { continue; }
71
+ if (st.isSymbolicLink()) return p;
72
+ if (st.isDirectory()) stack.push(p);
73
+ }
74
+ }
75
+ return null;
76
+ }
77
+
78
+ function coreHint(cwd) {
79
+ try { return require('./core-resolve').resolveCoreDir(cwd) || '<kenaz core>'; } catch (_) { return '<kenaz core>'; }
80
+ }
81
+
82
+ function decide(input) {
83
+ if (!input || input.tool_name !== 'Bash') return null;
84
+ const command = String((input.tool_input && input.tool_input.command) || '');
85
+ if (!/worktree|rm\b|rmdir|\brd\b|remove-item|\bri\b|\bdel\b/i.test(command)) return null;
86
+ const deadline = Date.now() + MAX_MS;
87
+ const cmds = commands(command);
88
+ // `powershell -Command "Remove-Item ..."` / `bash -c 'rm -rf ..'`: re-parse quoted tokens that hold a whole command
89
+ for (const t of [...cmds]) for (const tok of t) if (/\s/.test(tok)) cmds.push(...commands(tok));
90
+ for (const t of cmds) {
91
+ for (const arg of removalTargets(t)) {
92
+ const dir = resolveDir(arg, input.cwd);
93
+ if (!dir) continue;
94
+ let st; try { st = fs.lstatSync(dir); } catch { continue; }
95
+ if (!st.isDirectory()) continue; // a link itself, a file, or missing: removing it is safe
96
+ const link = findLink(dir, deadline);
97
+ if (!link) continue;
98
+ return {
99
+ hookSpecificOutput: {
100
+ hookEventName: 'PreToolUse',
101
+ permissionDecision: 'deny',
102
+ permissionDecisionReason: `Blocked: ${dir} contains a symlink/junction (${path.relative(dir, link)}). ` +
103
+ '`git worktree remove --force` follows junctions on Windows and empties their targets in the MAIN repo (node_modules, backend/.env, tracked files). ' +
104
+ 'Use the safe remover, which unlinks every link first and refuses if one survives: ' +
105
+ `node "${coreHint(input.cwd)}/.formation/tools/worktree-reclaim.js" remove "${dir}"`,
106
+ },
107
+ };
108
+ }
109
+ }
110
+ return null;
111
+ }
112
+
113
+ function main() {
114
+ try {
115
+ const out = decide(JSON.parse(fs.readFileSync(0, 'utf8') || '{}'));
116
+ if (out) process.stdout.write(JSON.stringify(out));
117
+ } catch (_) { /* fail open */ }
118
+ }
119
+
120
+ if (require.main === module) main();
121
+ module.exports = { decide, main, commands, removalTargets };
@@ -0,0 +1,75 @@
1
+ 'use strict';
2
+ // TASK_2485: the guard denies recursive removal of a dir that holds a junction/symlink, allows link-free dirs.
3
+ const test = require('node:test');
4
+ const assert = require('node:assert');
5
+ const fs = require('fs');
6
+ const os = require('os');
7
+ const path = require('path');
8
+ const { spawnSync } = require('child_process');
9
+ const { decide } = require('./worktree-guard');
10
+
11
+ function fixture() {
12
+ const root = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'wtguard-')));
13
+ const target = path.join(root, 'main'); fs.mkdirSync(target);
14
+ const withLink = path.join(root, 'wt-link'); fs.mkdirSync(path.join(withLink, 'a', 'b'), { recursive: true });
15
+ fs.symlinkSync(target, path.join(withLink, 'a', 'b', 'anything'), 'junction'); // not named node_modules, nested
16
+ const plain = path.join(root, 'wt-plain'); fs.mkdirSync(path.join(plain, 'a'), { recursive: true });
17
+ fs.writeFileSync(path.join(plain, 'a', 'f.txt'), 'x');
18
+ return { root, withLink, plain, target };
19
+ }
20
+ const bash = (command, cwd) => ({ tool_name: 'Bash', cwd, tool_input: { command } });
21
+ const denied = (r) => r && r.hookSpecificOutput.permissionDecision === 'deny';
22
+
23
+ test('denies git worktree remove / rm -rf / rmdir /s / Remove-Item -Recurse on a dir holding a junction', () => {
24
+ const f = fixture();
25
+ try {
26
+ const d = f.withLink; const fwd = d.replace(/\\/g, '/');
27
+ for (const cmd of [
28
+ `git worktree remove --force "${d}"`,
29
+ `git -C "${f.root}" worktree remove -f ${fwd}`,
30
+ `rm -rf "${fwd}"`,
31
+ `rm -fr ${fwd} && echo done`,
32
+ `cd ${f.root} && rm -r wt-link`,
33
+ `rmdir /s /q "${d}"`,
34
+ `cmd /c rmdir /s /q "${d}"`,
35
+ `Remove-Item -Recurse -Force "${d}"`,
36
+ `powershell -Command "Remove-Item -Path '${d}' -Recurse -Force"`,
37
+ ]) {
38
+ const r = decide(bash(cmd, f.root));
39
+ assert.ok(denied(r), `should deny: ${cmd}`);
40
+ assert.match(r.hookSpecificOutput.permissionDecisionReason, /worktree-reclaim\.js/);
41
+ }
42
+ } finally { fs.rmSync(f.root, { recursive: true, force: true }); }
43
+ });
44
+
45
+ test('same commands on a link-free dir, a missing dir, a link itself and unrelated commands pass (control)', () => {
46
+ const f = fixture();
47
+ try {
48
+ const p = f.plain;
49
+ for (const cmd of [
50
+ `git worktree remove --force "${p}"`, `rm -rf "${p.replace(/\\/g, '/')}"`, `rmdir /s /q "${p}"`, `Remove-Item -Recurse -Force "${p}"`,
51
+ `rm -rf ${path.join(f.root, 'nope')}`, `rm -f ${path.join(f.withLink, 'a', 'b', 'anything')}`, // a plain link/file removal is safe
52
+ `rm -rf ${f.withLink}/a/b/*`, // glob: cannot resolve, passes
53
+ `ls ${f.withLink}`, `git status`, `git worktree list`,
54
+ ]) {
55
+ assert.strictEqual(decide(bash(cmd, f.root)), null, `should pass: ${cmd}`);
56
+ }
57
+ assert.strictEqual(decide({ tool_name: 'Read', tool_input: { command: `rm -rf ${f.withLink}` } }), null);
58
+ } finally { fs.rmSync(f.root, { recursive: true, force: true }); }
59
+ });
60
+
61
+ test('through the plugin entry point: deny output for a junction dir, nothing for a plain dir; mode off disables', () => {
62
+ const f = fixture();
63
+ try {
64
+ const hook = path.join(__dirname, 'kenaz-hook.js');
65
+ const run = (cmd, env = {}) => spawnSync(process.execPath, [hook, 'worktree-guard'], {
66
+ cwd: f.root, encoding: 'utf8', input: JSON.stringify(bash(cmd, f.root)),
67
+ env: { ...process.env, CLAUDE_PROJECT_DIR: f.root, KENAZ_MODE: 'full', CLAUDE_CODE_ENTRYPOINT: 'cli', ...env },
68
+ });
69
+ const blocked = run(`rm -rf "${f.withLink}"`);
70
+ assert.strictEqual(blocked.status, 0);
71
+ assert.strictEqual(JSON.parse(blocked.stdout).hookSpecificOutput.permissionDecision, 'deny');
72
+ assert.strictEqual(run(`rm -rf "${f.plain}"`).stdout, '');
73
+ assert.strictEqual(run(`rm -rf "${f.withLink}"`, { KENAZ_MODE: 'off' }).stdout, '');
74
+ } finally { fs.rmSync(f.root, { recursive: true, force: true }); }
75
+ });
@@ -58,11 +58,14 @@ test('kenaz.yaml switch is honoured; env wins', () => {
58
58
  });
59
59
 
60
60
  test('backend down: no output, no stderr, exit 0', () => {
61
- for (const n of ['flow-post', 'session-start']) {
62
- const r = hook(n, proj(), { KENAZ_BACKEND_PORT: '1' });
63
- assert.strictEqual(r.status, 0);
64
- assert.strictEqual(r.stdout + r.stderr, '');
65
- }
61
+ const home = proj(); // temp HOME: session-start would otherwise start the real installed server (TASK_2468)
62
+ const env = { KENAZ_BACKEND_PORT: '1', HOME: home, USERPROFILE: home };
63
+ const r = hook('flow-post', proj(), env);
64
+ assert.strictEqual(r.status, 0);
65
+ assert.strictEqual(r.stdout + r.stderr, '');
66
+ const s = hook('session-start', proj(), env); // only session-start speaks: one line naming the fix
67
+ assert.strictEqual(s.stderr, '');
68
+ assert.match(s.stdout, /npx kenaz install/);
66
69
  });
67
70
 
68
71
  test('ygg status fixture: masked key, room, peers, mail (TASK_2366)', () => {
@@ -202,3 +205,67 @@ test('ygg create explains 429, 503, missing relay_url and unreachable relay (TAS
202
205
  await assert.rejects(createTeam(dir, '', 'project'), /cannot reach the relay at http:\/\/127\.0\.0\.1:1/);
203
206
  });
204
207
  });
208
+
209
+ // TASK_2468: SessionStart starts the installed server when the port is closed (temp HOME, free port, fake server script).
210
+ async function freePort() {
211
+ const srv = require('net').createServer();
212
+ await new Promise((r) => srv.listen(0, '127.0.0.1', r));
213
+ const p = srv.address().port;
214
+ await new Promise((r) => srv.close(r));
215
+ return p;
216
+ }
217
+ function fakeHome(withBin) {
218
+ const home = fs.mkdtempSync(path.join(os.tmpdir(), 'kz-home-'));
219
+ fs.mkdirSync(path.join(home, '.kenaz'));
220
+ const bin = path.join(home, 'fake-server.js');
221
+ fs.writeFileSync(bin, "const http=require('http');require('fs').writeFileSync(process.env.PIDFILE,String(process.pid));" +
222
+ "http.createServer((q,r)=>{r.end('{}')}).listen(Number(process.env.KENAZ_BACKEND_PORT),'127.0.0.1');setTimeout(()=>process.exit(0),15000);");
223
+ if (withBin) fs.writeFileSync(path.join(home, '.kenaz', 'install.json'), JSON.stringify({ serverBin: bin }));
224
+ return { home, pidfile: path.join(home, 'pid') };
225
+ }
226
+ const isUp = (port) => new Promise((r) => { const s = require('net').connect({ host: '127.0.0.1', port }); s.on('connect', () => { s.destroy(); r(true); }); s.on('error', () => r(false)); });
227
+ const killPid = (f) => { try { process.kill(Number(fs.readFileSync(f, 'utf8'))); } catch (_) { /* never started */ } };
228
+ const hookAsync = (env) => new Promise((resolve) => {
229
+ const c = require('child_process').spawn(process.execPath, [HOOK, 'session-start'], { env: Object.assign({}, process.env, { CLAUDE_PROJECT_DIR: proj(), KENAZ_MODE: '', KENAZ_SOURCE_DIR: CORE }, env) });
230
+ let out = ''; c.stdout.on('data', (d) => { out += d; }); c.on('close', () => resolve(out)); c.stdin.end('{}');
231
+ });
232
+
233
+ test('TASK_2468: session-start with the port closed starts the installed server and says so', async () => {
234
+ const port = await freePort(); const f = fakeHome(true);
235
+ const env = { HOME: f.home, USERPROFILE: f.home, KENAZ_BACKEND_PORT: String(port), PIDFILE: f.pidfile };
236
+ try {
237
+ const out = await hookAsync(env);
238
+ assert.ok(await isUp(port), 'server came up');
239
+ assert.match(out, /started it/); assert.match(out, /\/mcp/);
240
+ } finally { killPid(f.pidfile); }
241
+ });
242
+
243
+ test('TASK_2468: no install.json -> one line naming `npx kenaz install` and /mcp; nothing spawned', async () => {
244
+ const port = await freePort(); const f = fakeHome(false);
245
+ const env = { HOME: f.home, USERPROFILE: f.home, KENAZ_BACKEND_PORT: String(port), PIDFILE: f.pidfile };
246
+ const out = await hookAsync(env);
247
+ assert.match(out, /npx kenaz install/); assert.match(out, /\/mcp/);
248
+ assert.strictEqual(out.trim().split('\n').length, 1);
249
+ assert.ok(!(await isUp(port)));
250
+ });
251
+
252
+ test('TASK_2468: KENAZ_MODE=off and sdk entrypoint -> no output, nothing spawned', async () => {
253
+ for (const extra of [{ KENAZ_MODE: 'off' }, { CLAUDE_CODE_ENTRYPOINT: 'sdk-ts' }]) {
254
+ const port = await freePort(); const f = fakeHome(true);
255
+ const env = Object.assign({ HOME: f.home, USERPROFILE: f.home, KENAZ_BACKEND_PORT: String(port), PIDFILE: f.pidfile }, extra);
256
+ try {
257
+ assert.strictEqual(await hookAsync(env), '');
258
+ assert.ok(!(await isUp(port)) && !fs.existsSync(f.pidfile));
259
+ } finally { killPid(f.pidfile); }
260
+ }
261
+ });
262
+
263
+ test('TASK_2468: port already answering -> nothing spawned, no extra line', async () => {
264
+ const port = await freePort(); const f = fakeHome(true);
265
+ const srv = require('http').createServer((q, r) => r.end('{}'));
266
+ await new Promise((r) => srv.listen(port, '127.0.0.1', r));
267
+ try {
268
+ const out = await hookAsync({ HOME: f.home, USERPROFILE: f.home, KENAZ_BACKEND_PORT: String(port), PIDFILE: f.pidfile });
269
+ assert.strictEqual(out, ''); assert.ok(!fs.existsSync(f.pidfile));
270
+ } finally { srv.close(); }
271
+ });
@@ -17,6 +17,7 @@ function setup(on: any, rows: () => unknown[], marker?: () => string | null) {
17
17
  const url = String(e.url)
18
18
  calls.push(`${e.init?.method ?? 'GET'} ${url}`)
19
19
  const reply = (o: unknown) => ({ value: { status: 200, ok: true, headers: {}, text: JSON.stringify(o) } })
20
+ if (url.includes('/api/health')) return healthOk ? reply({ status: 'ok' }) : { value: { status: 500, ok: false, headers: {}, text: '' } }
20
21
  if (url.includes('/pending')) return reply({ messages: delivered ? [] : [msg] })
21
22
  if (url.includes('/ack')) { delivered = true; return reply({ acked: ['m1'], already_delivered: [], unknown: [] }) }
22
23
  return reply({ ok: true })
@@ -54,7 +55,7 @@ test('heartbeat precedes submit, ack carries the submitted id, second cycle is e
54
55
  expect(calls.filter(c => c.includes('/ack')).length).toBe(1)
55
56
  })
56
57
 
57
- function uiSetup(on: any, rows: unknown[], statusOk = true) {
58
+ function uiSetup(on: any, rows: unknown[], statusOk = true, healthOk = true) {
58
59
  const status: unknown[] = []
59
60
  const toasts: string[] = []
60
61
  on('session.start', async (_$: any, e: any) => ({ cwd: e.cwd }))
@@ -69,6 +70,7 @@ function uiSetup(on: any, rows: unknown[], statusOk = true) {
69
70
  if (url.includes('/pending')) return reply({ messages: delivered ? [] : [{ id: 'm1', framed: 'hi', from_node: 'node-b' }] })
70
71
  if (url.includes('/ack')) { delivered = true; return reply({ acked: ['m1'] }) }
71
72
  if (url.includes('/status')) return statusOk ? reply({ pending_count: 2, sessions: [{ delivery_mode: 'push' }, { delivery_mode: 'none' }] }) : { value: { status: 500, ok: false, headers: {}, text: '' } }
73
+ if (url.includes('/api/health')) return healthOk ? reply({ status: 'ok' }) : { value: { status: 503, ok: false, headers: {}, text: '' } }
72
74
  return reply({ ok: true })
73
75
  })
74
76
  on('prompt.submit', async (_$: any, e: any) => e)
@@ -90,13 +92,23 @@ test('Ansuz session: status line from /api/peer/status and a toast naming the se
90
92
 
91
93
  test('Ansuz session with the server down shows kenaz-server down', async ($, on) => {
92
94
  const clock = mock.clock(on)
93
- const { status } = uiSetup(on, [{ role: 'user', content: '# Ansuz -- Specialist Prompt' }], false)
95
+ const { status } = uiSetup(on, [{ role: 'user', content: '# Ansuz -- Specialist Prompt' }], false, false)
94
96
  await $.session.start(START)
95
97
  await clock.advance(5_000)
96
98
  await clock.advance(5_000)
97
99
  expect(status.some(s => String(s).includes('kenaz-server down'))).toBe(true)
98
100
  })
99
101
 
102
+ test('TASK_2480: /status failing while /api/health is up shows peer status slow, not down', async ($, on) => {
103
+ const clock = mock.clock(on)
104
+ const { status } = uiSetup(on, [{ role: 'user', content: '# Ansuz -- Specialist Prompt' }], false, true)
105
+ await $.session.start(START)
106
+ await clock.advance(5_000)
107
+ await clock.advance(5_000)
108
+ expect(status.some(s => String(s).includes('peer status slow'))).toBe(true)
109
+ expect(status.some(s => String(s).includes('kenaz-server down'))).toBe(false)
110
+ })
111
+
100
112
  test('control: non-Ansuz session gets no status and no toast', async ($, on) => {
101
113
  const clock = mock.clock(on)
102
114
  const { status, toasts } = uiSetup(on, [{ role: 'user', content: 'hello' }])
@@ -132,7 +132,12 @@ async function refreshStatus($: any): Promise<void> {
132
132
  try {
133
133
  const root = await project($)
134
134
  const st = await jget($, `${BACKEND}/api/peer/status?projectPath=${encodeURIComponent(root)}&limit=1`)
135
- if (!st || typeof st !== 'object') { await $.ui.status('Kenaz: kenaz-server down'); return }
135
+ if (!st || typeof st !== 'object') {
136
+ // TASK_2480: a failed /status is not "down": only a failed health probe says the server is down.
137
+ const alive = await jget($, `${BACKEND}/api/health`)
138
+ await $.ui.status(alive ? 'Kenaz: peer status slow' : 'Kenaz: kenaz-server down')
139
+ return
140
+ }
136
141
  const name = root.replace(/[\\/]+$/, '').split(/[\\/]/).pop() || root
137
142
  const sessions = Array.isArray(st.sessions) ? st.sessions.filter((s: any) => s?.delivery_mode !== 'none') : []
138
143
  const pending = Number(st.pending_count) || 0
package/lib/cli.js CHANGED
@@ -72,8 +72,8 @@ function platformServer() {
72
72
 
73
73
  function onPath(cmd) {
74
74
  const r = process.platform === 'win32' // one string with shell (.cmd shims); args + shell:true is deprecated (DEP0190)
75
- ? spawnSync(cmd + ' --version', { encoding: 'utf8', shell: true, timeout: 15000 })
76
- : spawnSync(cmd, ['--version'], { encoding: 'utf8', timeout: 15000 });
75
+ ? spawnSync(cmd + ' --version', { windowsHide: true, encoding: 'utf8', shell: true, timeout: 15000 })
76
+ : spawnSync(cmd, ['--version'], { windowsHide: true, encoding: 'utf8', timeout: 15000 });
77
77
  return r.status === 0;
78
78
  }
79
79
 
@@ -244,7 +244,7 @@ async function doctor(p, flags, out, deps = {}) {
244
244
 
245
245
  try { // TASK_2413: which mechanism restarts the server after a reboot (read-only; `deps.sh` / `deps.platform` for tests)
246
246
  const sm = installer().detectServiceMode(p.home, p.core, deps.sh, deps.platform);
247
- add('service mode', sm.mode === 'manual' ? 'skip' : 'ok', sm.mode + ' (' + sm.detail + ')');
247
+ add('service mode', sm.mode === 'manual' ? 'skip' : sm.warn ? 'warn' : 'ok', sm.mode + ' (' + sm.detail + ')');
248
248
  } catch (e) { add('service mode', 'skip', 'unknown: ' + e.message); }
249
249
  const d = dash.detect(p.home, deps.dashboard);
250
250
  if (!d.installed) add('dashboard', 'skip', 'no Kenaz Dashboard on this machine');
@@ -262,7 +262,11 @@ async function doctor(p, flags, out, deps = {}) {
262
262
  else {
263
263
  const d = { disabled: `off: ${upd.reason}`, error: `last check failed: ${upd.last_error}`, staged: `${upd.staged_version} staged, applies when idle`,
264
264
  applied: `${upd.applied_version} swapped in (previous ${upd.previous_version}), restart pending`, 'rolled-back': 'rolled back to the previous version' }[upd.state] || `${upd.state}, latest ${upd.latest_version || 'unknown'}`;
265
- add('self-update', upd.state === 'disabled' ? 'skip' : 'ok', `${d} [running ${upd.current_version}]`);
265
+ // A staged version not newer than the running one froze older servers' updater (checks stop while one is staged).
266
+ const num = (v) => String(v || '').split('.').map(Number);
267
+ const stale = upd.staged_version && num(upd.staged_version).reduce((c, x, i) => c || x - (num(upd.current_version)[i] || 0), 0) <= 0;
268
+ if (stale) add('self-update', 'warn', `${upd.staged_version} staged but running ${upd.current_version}: updater stuck; delete ${path.join(p.dir, 'update', 'status.json')} and restart kenaz-server`);
269
+ else add('self-update', upd.state === 'disabled' ? 'skip' : upd.state === 'error' ? 'warn' : 'ok', `${d} [running ${upd.current_version}]`);
266
270
  }
267
271
 
268
272
  const inst = installer();
@@ -313,7 +317,7 @@ function passthrough(argv, deps) {
313
317
  const script = argv[0] === 'ygg' ? 'ygg.js' : 'kenaz-mode.js';
314
318
  const args = argv[0] === 'ygg' ? argv.slice(1) : argv;
315
319
  const spawn = deps.spawnSync || require('child_process').spawnSync;
316
- const r = spawn(process.execPath, [path.join(core, 'plugins', 'kenaz', 'scripts', script), ...args], { stdio: 'inherit', cwd: process.cwd() });
320
+ const r = spawn(process.execPath, [path.join(core, 'plugins', 'kenaz', 'scripts', script), ...args], { windowsHide: true, stdio: 'inherit', cwd: process.cwd() });
317
321
  return r.status === null ? 1 : r.status;
318
322
  }
319
323
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kenaz",
3
- "version": "0.3.22",
3
+ "version": "0.3.24",
4
4
  "description": "Install Kenaz (plugin, hooks, kenaz-server) for Claude Code and Codex: npx kenaz install",
5
5
  "bin": {
6
6
  "kenaz": "bin/kenaz.js"
@@ -20,11 +20,11 @@
20
20
  "test": "node --test lib/cli.test.js"
21
21
  },
22
22
  "optionalDependencies": {
23
- "@kenazai/server-darwin-arm64": "0.3.22",
24
- "@kenazai/server-darwin-x64": "0.3.22",
25
- "@kenazai/server-linux-arm64": "0.3.22",
26
- "@kenazai/server-linux-x64": "0.3.22",
27
- "@kenazai/server-win32-x64": "0.3.22"
23
+ "@kenazai/server-darwin-arm64": "0.3.24",
24
+ "@kenazai/server-darwin-x64": "0.3.24",
25
+ "@kenazai/server-linux-arm64": "0.3.24",
26
+ "@kenazai/server-linux-x64": "0.3.24",
27
+ "@kenazai/server-win32-x64": "0.3.24"
28
28
  },
29
29
  "license": "UNLICENSED",
30
30
  "repository": {