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
@@ -14,7 +14,7 @@ const fs = require('fs');
14
14
  const os = require('os');
15
15
  const path = require('path');
16
16
  const http = require('http');
17
- const { spawnSync } = require('child_process');
17
+ const { spawnSync, spawn } = require('child_process');
18
18
 
19
19
  const ENV_KEY = 'CLAUDE_CODE_PLUGIN_DIRS';
20
20
  const BACKUP = 'settings.json.bak-kenaz-peer'; // shared with the Rust path on purpose: one backup of the pristine file
@@ -22,6 +22,9 @@ const MIN_CLI = [2, 1, 287];
22
22
  const SEP = process.platform === 'win32' ? ';' : ':';
23
23
  const TASK_NAME = 'KenazServer';
24
24
  const LABEL = 'ai.kenaz.server';
25
+ const RUN_KEY = 'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run';
26
+ const BATTERY_PS = '$s = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -ExecutionTimeLimit ([TimeSpan]::Zero); Set-ScheduledTask -TaskName ' + TASK_NAME + ' -Settings $s';
27
+ const linuxUser = () => { try { return os.userInfo().username; } catch (_) { return process.env.USER || ''; } };
25
28
 
26
29
  const norm = (e) => {
27
30
  const s = String(e).trim().replace(/\\/g, '/').replace(/\/+$/, '');
@@ -113,9 +116,14 @@ function unregisterStatusline(file, dry) {
113
116
  // agent-flow curl/node posts) duplicate what plugins/kenaz/hooks/hooks.json now runs. Single owner = the plugin, so
114
117
  // once it is registered these are removed (first write backs up the pristine file to settings.json.bak-kenaz-peer).
115
118
  const DASH_HOOK = /_user-scope\.js|[\\/]\.claude[\\/]hooks[\\/][\w.-]+\.js|\/api\/rust\/agent-flow\/hook/;
119
+ // Field report 2026-10-19: Kenaz never wrote hooks into the user's own ~/.claude/hooks, so a hook there is the user's.
120
+ const HOME_HOOKS = /(^|["'\s])(~|\$\{?HOME\}?|%USERPROFILE%)[\\/]\.claude[\\/]hooks[\\/]/i;
121
+ const slashLower = (s) => s.replace(/\\/g, '/').toLowerCase();
116
122
  /** @returns number of hook commands retired */
117
123
  function retireDashboardHooks(file, dry) {
118
124
  if (!fs.existsSync(file)) return 0;
125
+ const homeHooks = slashLower(path.join(path.dirname(file), 'hooks')) + '/';
126
+ const isDash = (c) => DASH_HOOK.test(c) && !HOME_HOOKS.test(c) && !slashLower(c).includes(homeHooks);
119
127
  const v = loadSettings(file);
120
128
  if (!v.hooks || typeof v.hooks !== 'object' || Array.isArray(v.hooks)) return 0;
121
129
  let n = 0;
@@ -124,7 +132,7 @@ function retireDashboardHooks(file, dry) {
124
132
  const groups = [];
125
133
  for (const g of v.hooks[ev]) {
126
134
  if (!g || !Array.isArray(g.hooks)) { groups.push(g); continue; }
127
- const kept = g.hooks.filter((h) => !(h && typeof h.command === 'string' && DASH_HOOK.test(h.command)));
135
+ const kept = g.hooks.filter((h) => !(h && typeof h.command === 'string' && isDash(h.command)));
128
136
  n += g.hooks.length - kept.length;
129
137
  if (kept.length) groups.push(kept.length === g.hooks.length ? g : { ...g, hooks: kept });
130
138
  }
@@ -136,20 +144,22 @@ function retireDashboardHooks(file, dry) {
136
144
 
137
145
  function claudeVersion() {
138
146
  const r = process.platform === 'win32' // one string with shell (.cmd shim): args + shell:true is deprecated (DEP0190)
139
- ? spawnSync('claude --version', { encoding: 'utf8', shell: true, timeout: 15000 })
140
- : spawnSync('claude', ['--version'], { encoding: 'utf8', timeout: 15000 });
147
+ ? spawnSync('claude --version', { windowsHide: true, encoding: 'utf8', shell: true, timeout: 15000 })
148
+ : spawnSync('claude', ['--version'], { windowsHide: true, encoding: 'utf8', timeout: 15000 });
141
149
  return r.status === 0 ? parseVersion(r.stdout) : null;
142
150
  }
143
151
 
144
152
  // ---- service definitions (pure; the OS calls are in service* below) ----
145
153
  function launcherPaths(home) {
146
154
  const d = path.join(home, '.kenaz');
147
- return { dir: d, vbs: path.join(d, 'kenaz-server.vbs'), log: path.join(d, 'kenaz-server.log') };
155
+ return { dir: d, log: path.join(d, 'kenaz-server.log') };
148
156
  }
149
157
  const q = (s) => '"' + s + '"';
150
- function winVbs(bin, core) { // hidden window, env for task tools; server binds loopback by default
151
- return 'Set sh = WScript.CreateObject("WScript.Shell")\r\nsh.Environment("Process")("KENAZ_SOURCE_DIR") = "' + core + '"\r\n' +
152
- 'sh.Run """' + bin + '""", 0, False\r\n';
158
+ // TASK_2478: kenaz-server is a no-console binary on Windows and takes the core dir as an argument (no launcher script).
159
+ function winRunCmd(bin, core) { return q(bin) + ' --source-dir ' + q(core); }
160
+ // TASK_2478 migration: the old script-host launchers (antivirus flagged them); removed on install and uninstall.
161
+ function legacyLaunchers(home, roaming) {
162
+ return [path.join(home, '.kenaz', 'kenaz-server.vbs'), path.join(roaming, 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup', 'KenazServer.vbs')]; // legacy-vbs-cleanup
153
163
  }
154
164
  // launchd and systemd start the server with a bare PATH (/usr/bin:/bin...), so `node` from Homebrew,
155
165
  // nvm or /usr/local was not found and every MCP tool that runs a node script failed with
@@ -195,8 +205,7 @@ function servicePlan(home, bin, core, platform = process.platform, caps = { syst
195
205
  const L = launcherPaths(home);
196
206
  if (platform === 'win32') {
197
207
  const roaming = home === os.homedir() && process.env.APPDATA ? process.env.APPDATA : path.join(home, 'AppData', 'Roaming');
198
- const startup = path.join(roaming, 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup', 'KenazServer.vbs');
199
- return { kind: 'windows', files: [[L.vbs, winVbs(bin, core)]], fallbackFile: startup };
208
+ return { kind: 'windows', files: [], bin, core, runCmd: winRunCmd(bin, core), legacy: legacyLaunchers(home, roaming) };
200
209
  }
201
210
  if (platform === 'darwin') {
202
211
  const p = path.join(home, 'Library', 'LaunchAgents', LABEL + '.plist');
@@ -208,7 +217,7 @@ function servicePlan(home, bin, core, platform = process.platform, caps = { syst
208
217
  const p = path.join(home, '.config', 'systemd', 'user', 'kenaz-server.service');
209
218
  return { kind: 'systemd', files: [[p, systemdUnit(bin, core)]], unit: p };
210
219
  }
211
- const sh = (cmd, args, opts) => spawnSync(cmd, args, { encoding: 'utf8', ...(opts || {}) });
220
+ const sh = (cmd, args, opts) => spawnSync(cmd, args, { windowsHide: true, encoding: 'utf8', ...(opts || {}) });
212
221
 
213
222
  // crontab -l: null = no crontab binary; '' = binary present, no crontab yet. All through the injected `run`.
214
223
  function readCron(run) {
@@ -239,8 +248,7 @@ function restartHint(plan, uid = defaultUid()) {
239
248
  if (plan.kind === 'launchd') return 'launchctl kickstart -k gui/' + uid + '/' + LABEL;
240
249
  if (plan.kind === 'systemd') return 'systemctl --user restart kenaz-server';
241
250
  if (plan.kind === 'cron' || plan.kind === 'manual') return stopCmd(plan) + '; ' + detachedStartCmd(plan);
242
- // the launcher works for both the scheduled task and the Startup-folder fallback (no admin rights needed)
243
- return 'end kenaz-server.exe in Task Manager, then run: wscript.exe ' + q(plan.files && plan.files[0] ? plan.files[0][0] : 'kenaz-server.vbs');
251
+ return 'end kenaz-server.exe in Task Manager, then run: ' + plan.runCmd;
244
252
  }
245
253
  function serviceRestart(plan, dry, log, run = sh, uid = defaultUid()) {
246
254
  if (plan.kind === 'cron' || plan.kind === 'manual') { // no supervisor: start it (stopOwnServer freed the old one)
@@ -295,22 +303,28 @@ async function verifyRuntime(plan, expected, log, opts = {}) {
295
303
  return 'unreachable';
296
304
  }
297
305
 
298
- function serviceInstall(plan, dry, log, run = sh, uid) {
306
+ function serviceInstall(plan, dry, log, run = sh, uid, spawnFn = spawn) {
299
307
  const sh = run; // injectable for tests; shadows the module-level spawnSync wrapper inside this function
300
308
  for (const [f, body] of plan.files) { log('write ' + f); if (!dry) { fs.mkdirSync(path.dirname(f), { recursive: true }); fs.writeFileSync(f, body); } }
301
309
  if (plan.kind === 'windows') {
302
- const tr = 'wscript.exe ' + q(plan.files[0][0]);
303
- log('schtasks /Create /TN ' + TASK_NAME + ' /SC ONLOGON /TR ' + tr + ' /F (fallback: ' + plan.fallbackFile + ')');
310
+ const tr = plan.runCmd;
311
+ log('schtasks /Create /TN ' + TASK_NAME + ' /SC ONLOGON /TR ' + tr + ' /F (fallback: ' + RUN_KEY + '\\' + TASK_NAME + ')');
312
+ removeLegacy(plan, dry, log);
304
313
  if (dry) return;
305
314
  const r = sh('schtasks', ['/Create', '/TN', TASK_NAME, '/SC', 'ONLOGON', '/TR', tr, '/F']);
306
- if (r.status === 0) sh('schtasks', ['/Run', '/TN', TASK_NAME]);
307
- else { // ONLOGON tasks can need elevation: a Startup-folder launcher is the per-user equivalent
308
- fs.mkdirSync(path.dirname(plan.fallbackFile), { recursive: true });
309
- fs.copyFileSync(plan.files[0][0], plan.fallbackFile);
310
- sh('wscript.exe', [plan.files[0][0]]);
315
+ if (r.status === 0) {
316
+ // Task Scheduler defaults refuse to start on battery and stop the task when going on battery:
317
+ // a laptop unplugged at logon never got the server (TASK_2468). Re-running install fixes an old task.
318
+ const b = sh('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', BATTERY_PS]);
319
+ if (b.status !== 0) log('WARNING: could not set the task to run on battery (exit ' + b.status + '); on a laptop the server may not start unplugged. Run in PowerShell: ' + BATTERY_PS);
320
+ sh('schtasks', ['/Run', '/TN', TASK_NAME]);
321
+ } else { // ONLOGON tasks can need elevation: an HKCU Run value is the per-user equivalent
322
+ sh('reg', ['add', RUN_KEY, '/v', TASK_NAME, '/t', 'REG_SZ', '/d', plan.runCmd, '/f']);
323
+ const c = spawnFn(plan.bin, ['--source-dir', plan.core], { detached: true, stdio: 'ignore', windowsHide: true });
324
+ c.on('error', () => {}); c.unref();
311
325
  // schtasks' stderr is in the console's OEM code page (garbled when echoed); the usual cause is
312
- // missing admin rights for /SC ONLOGON. The Startup-folder launcher starts at logon the same way.
313
- log('schtasks needs administrator rights here (exit ' + r.status + '); installed the Startup-folder launcher instead (also starts at logon)');
326
+ // missing admin rights for /SC ONLOGON. The Run value starts the server at logon the same way.
327
+ log('schtasks needs administrator rights here (exit ' + r.status + '); registered the HKCU Run value instead (also starts at logon)');
314
328
  }
315
329
  } else if (plan.kind === 'launchd') {
316
330
  log('launchctl load -w ' + plan.unit); if (!dry) sh('launchctl', ['load', '-w', plan.unit]);
@@ -326,14 +340,23 @@ function serviceInstall(plan, dry, log, run = sh, uid) {
326
340
  } else {
327
341
  log('systemctl --user enable --now kenaz-server');
328
342
  if (!dry) { sh('systemctl', ['--user', 'daemon-reload']); sh('systemctl', ['--user', 'enable', '--now', 'kenaz-server']); }
343
+ // Without linger the user service starts only at login (headless boxes: never). Best effort.
344
+ const u = linuxUser();
345
+ log('loginctl enable-linger ' + u);
346
+ if (!dry && sh('loginctl', ['enable-linger', u]).status !== 0) log('WARNING: could not enable linger; the server starts at boot only after you log in. Run: loginctl enable-linger ' + u + ' (may need sudo)');
329
347
  serviceRestart(plan, dry, log, sh, uid);
330
348
  }
331
349
  }
350
+ function removeLegacy(plan, dry, log) {
351
+ for (const f of plan.legacy || []) if (fs.existsSync(f)) { log('remove ' + f + ' (old launcher)'); if (!dry) fs.rmSync(f, { force: true }); }
352
+ }
332
353
  function serviceUninstall(plan, dry, log, run = sh) {
333
354
  if (plan.kind === 'windows') {
334
355
  log('schtasks /End + /Delete /TN ' + TASK_NAME);
335
356
  if (!dry) { run('schtasks', ['/End', '/TN', TASK_NAME]); run('schtasks', ['/Delete', '/TN', TASK_NAME, '/F']); }
336
- if (fs.existsSync(plan.fallbackFile)) { log('remove ' + plan.fallbackFile); if (!dry) fs.rmSync(plan.fallbackFile, { force: true }); }
357
+ log('reg delete ' + RUN_KEY + ' /v ' + TASK_NAME);
358
+ if (!dry) run('reg', ['delete', RUN_KEY, '/v', TASK_NAME, '/f']); // not-found is fine
359
+ removeLegacy(plan, dry, log);
337
360
  } else if (plan.kind === 'launchd') {
338
361
  log('launchctl unload ' + plan.unit); if (!dry) run('launchctl', ['unload', '-w', plan.unit]);
339
362
  } else if (plan.kind === 'cron' || plan.kind === 'manual') {
@@ -347,7 +370,7 @@ function serviceUninstall(plan, dry, log, run = sh) {
347
370
  function serviceStatus(plan, run = sh) {
348
371
  if (plan.kind === 'cron') { const c = readCron(run); return c && c.includes(CRON_MARK) ? 'cron @reboot entry present' : 'not installed'; }
349
372
  if (plan.kind === 'manual') return 'manual (no systemd user session, no crontab)';
350
- if (plan.kind === 'windows') return run('schtasks', ['/Query', '/TN', TASK_NAME]).status === 0 ? 'scheduled task present' : (fs.existsSync(plan.fallbackFile) ? 'startup launcher present' : 'not installed');
373
+ if (plan.kind === 'windows') return run('schtasks', ['/Query', '/TN', TASK_NAME]).status === 0 ? 'scheduled task present' : (run('reg', ['query', RUN_KEY, '/v', TASK_NAME]).status === 0 ? 'Run key present' : 'not installed');
351
374
  if (plan.kind === 'systemd') return run('systemctl', ['--user', 'is-active', 'kenaz-server']).stdout.trim() || 'not installed';
352
375
  return fs.existsSync(plan.unit) ? 'plist present' : 'not installed';
353
376
  }
@@ -355,17 +378,20 @@ function serviceStatus(plan, run = sh) {
355
378
  /** Which mechanism keeps the server running on this machine (for `kenaz doctor`). Read-only, all via `run`. */
356
379
  function detectServiceMode(home, core, run = sh, platform = process.platform) {
357
380
  if (platform === 'win32') {
358
- const plan = servicePlan(home, '', core, 'win32');
359
381
  if (run('schtasks', ['/Query', '/TN', TASK_NAME]).status === 0) return { mode: 'windows task', detail: 'scheduled task ' + TASK_NAME };
360
- if (fs.existsSync(plan.fallbackFile)) return { mode: 'startup launcher', detail: plan.fallbackFile };
361
- return { mode: 'manual', detail: 'no scheduled task or Startup launcher; run `kenaz install`' };
382
+ if (run('reg', ['query', RUN_KEY, '/v', TASK_NAME]).status === 0) return { mode: 'run key', detail: RUN_KEY + '\\' + TASK_NAME };
383
+ return { mode: 'manual', detail: 'no scheduled task or Run key; run `kenaz install`' };
362
384
  }
363
385
  if (platform === 'darwin') {
364
386
  const p = servicePlan(home, '', core, 'darwin').unit;
365
387
  return fs.existsSync(p) ? { mode: 'launchd', detail: p } : { mode: 'manual', detail: 'no launchd agent; run `kenaz install`' };
366
388
  }
367
389
  const unit = servicePlan(home, '', core, 'linux').unit;
368
- if (fs.existsSync(unit) && probeLinux(run).systemd) return { mode: 'systemd', detail: unit };
390
+ if (fs.existsSync(unit) && probeLinux(run).systemd) {
391
+ const u = linuxUser();
392
+ const off = /Linger=no/.test(run('loginctl', ['show-user', u, '-p', 'Linger']).stdout || '');
393
+ return off ? { mode: 'systemd', detail: unit + '; linger is off, the server starts only after login: run loginctl enable-linger ' + u, warn: true } : { mode: 'systemd', detail: unit };
394
+ }
369
395
  const c = readCron(run);
370
396
  if (c && c.includes(CRON_MARK)) return { mode: 'cron', detail: '@reboot crontab entry (no systemd user session)' };
371
397
  return { mode: 'manual', detail: 'no systemd unit or cron entry; run `kenaz install`' };
@@ -453,4 +479,4 @@ function main(argv, out = console.log, getVersion = claudeVersion, deps = {}) {
453
479
  }
454
480
 
455
481
  if (require.main === module) process.exit(main(process.argv.slice(2)));
456
- module.exports = { main, verifyRuntime, healthOnce, serviceInstall, serviceRestart, restartHint, claudeVersion, loadSettings, entriesOf, norm, MIN_CLI, registerPlugin, unregisterPlugin, registerStatusline, unregisterStatusline, retireDashboardHooks, servicePlan, detectServiceMode, probeLinux, cronLine, CRON_MARK, winVbs, launchdPlist, systemdUnit, parseVersion, cmpVersion };
482
+ module.exports = { main, verifyRuntime, healthOnce, serviceInstall, serviceUninstall, serviceRestart, restartHint, claudeVersion, loadSettings, entriesOf, norm, MIN_CLI, registerPlugin, unregisterPlugin, registerStatusline, unregisterStatusline, retireDashboardHooks, servicePlan, detectServiceMode, probeLinux, cronLine, CRON_MARK, winRunCmd, RUN_KEY, launchdPlist, systemdUnit, parseVersion, cmpVersion };
@@ -103,7 +103,7 @@ function countLines(text) {
103
103
  }
104
104
 
105
105
  function git(args, cwd) {
106
- const result = spawnSync('git', args, { cwd, encoding: 'utf8' });
106
+ const result = spawnSync('git', args, { windowsHide: true, cwd, encoding: 'utf8' });
107
107
  return result;
108
108
  }
109
109
 
@@ -40,7 +40,7 @@ const TASK_API = path.join(ROOT, '.collaboration', 'core', 'task-api.js');
40
40
  // ─────────────────────────────────────────
41
41
 
42
42
  function runTaskApi(...args) {
43
- const result = spawnSync('node', [TASK_API, ...args], {
43
+ const result = spawnSync('node', [TASK_API, ...args], { windowsHide: true,
44
44
  encoding: 'utf8',
45
45
  timeout: 15000,
46
46
  cwd: ROOT,
@@ -72,11 +72,11 @@ const DRY_RUN = !process.argv.includes('--apply');
72
72
  // ─── Git helpers (GEN-008: dynamic root, never hardcoded) ────────────────────
73
73
 
74
74
  function gitRoot() {
75
- return execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();
75
+ return execSync('git rev-parse --show-toplevel', { windowsHide: true, encoding: 'utf8' }).trim();
76
76
  }
77
77
 
78
78
  function currentBranch() {
79
- return execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf8' }).trim();
79
+ return execSync('git rev-parse --abbrev-ref HEAD', { windowsHide: true, encoding: 'utf8' }).trim();
80
80
  }
81
81
 
82
82
  /**
@@ -84,7 +84,7 @@ function currentBranch() {
84
84
  * Uses exit code of `git merge-base --is-ancestor <commit> HEAD`.
85
85
  */
86
86
  function isAncestorOfHead(tipCommit) {
87
- const result = spawnSync('git', ['merge-base', '--is-ancestor', tipCommit, 'HEAD'], {
87
+ const result = spawnSync('git', ['merge-base', '--is-ancestor', tipCommit, 'HEAD'], { windowsHide: true,
88
88
  encoding: 'utf8',
89
89
  });
90
90
  return result.status === 0;
@@ -95,7 +95,7 @@ function isAncestorOfHead(tipCommit) {
95
95
  * Each entry: { path, head, branch, locked, lockReason }
96
96
  */
97
97
  function listWorktrees() {
98
- const raw = execSync('git worktree list --porcelain', { encoding: 'utf8' });
98
+ const raw = execSync('git worktree list --porcelain', { windowsHide: true, encoding: 'utf8' });
99
99
  const entries = [];
100
100
  let current = null;
101
101
 
@@ -199,7 +199,7 @@ function listUntrackedAgentDirs(root, trackedPaths) {
199
199
  function listDanglingAgentBranches(trackedBranches) {
200
200
  let raw = '';
201
201
  try {
202
- raw = execSync('git branch --list "worktree-agent-*" --format="%(refname:short)"', { encoding: 'utf8' });
202
+ raw = execSync('git branch --list "worktree-agent-*" --format="%(refname:short)"', { windowsHide: true, encoding: 'utf8' });
203
203
  } catch {
204
204
  return [];
205
205
  }
@@ -209,7 +209,7 @@ function listDanglingAgentBranches(trackedBranches) {
209
209
  const b = line.trim();
210
210
  if (!b || trackedSet.has(b)) continue;
211
211
  let tip = '';
212
- try { tip = execSync(`git rev-parse "${b}"`, { encoding: 'utf8' }).trim(); } catch { /* ignore */ }
212
+ try { tip = execSync(`git rev-parse "${b}"`, { windowsHide: true, encoding: 'utf8' }).trim(); } catch { /* ignore */ }
213
213
  out.push({ branch: b, tip, integrated: tip ? isAncestorOfHead(tip) : false });
214
214
  }
215
215
  return out;
@@ -354,7 +354,7 @@ function main() {
354
354
  // Unlock if locked (harness may have left lock even after pid is gone)
355
355
  if (wt.locked) {
356
356
  try {
357
- execSync(`git worktree unlock "${wt.path}"`, { encoding: 'utf8' });
357
+ execSync(`git worktree unlock "${wt.path}"`, { windowsHide: true, encoding: 'utf8' });
358
358
  } catch {
359
359
  // unlock may fail if git disagrees — proceed, remove --force handles it
360
360
  }
@@ -365,7 +365,8 @@ function main() {
365
365
  // checkout's node_modules). Reuse the hook's helper (never copy it). If it is
366
366
  // unavailable, refuse to remove rather than risk traversal.
367
367
  try {
368
- require(path.join(__dirname, '..', '..', '.claude', 'hooks', 'worktree-create.js')).unlinkNodeModulesLinks(wt.path);
368
+ const unl = require(path.join(__dirname, '..', '..', '.claude', 'hooks', 'worktree-create.js')).unlinkNodeModulesLinks(wt.path);
369
+ if (unl.failed.length) throw new Error('link(s) survive unlink: ' + unl.failed.slice(0, 3).join(', '));
369
370
  } catch (err) {
370
371
  console.log(` FAILED (node_modules unlink unavailable, not removing): ${err.message.trim()}`);
371
372
  failedCount++;
@@ -374,7 +375,7 @@ function main() {
374
375
 
375
376
  // Remove worktree (--force bypasses remaining lock metadata)
376
377
  try {
377
- execSync(`git worktree remove --force "${wt.path}"`, { encoding: 'utf8' });
378
+ execSync(`git worktree remove --force "${wt.path}"`, { windowsHide: true, encoding: 'utf8' });
378
379
  } catch (err) {
379
380
  console.log(` FAILED (worktree remove): ${err.message.trim()}`);
380
381
  failedCount++;
@@ -384,7 +385,7 @@ function main() {
384
385
  // Delete the branch (best-effort; branch may already be deleted or missing)
385
386
  if (wt.branch) {
386
387
  try {
387
- execSync(`git branch -D "${wt.branch}"`, { encoding: 'utf8' });
388
+ execSync(`git branch -D "${wt.branch}"`, { windowsHide: true, encoding: 'utf8' });
388
389
  } catch {
389
390
  // Branch may already be deleted — not an error
390
391
  }
@@ -396,7 +397,7 @@ function main() {
396
397
 
397
398
  // Prune stale worktree admin dirs (idempotent, always safe)
398
399
  try {
399
- execSync('git worktree prune', { encoding: 'utf8' });
400
+ execSync('git worktree prune', { windowsHide: true, encoding: 'utf8' });
400
401
  console.log('\n git worktree prune done');
401
402
  } catch (err) {
402
403
  console.log(`\n git worktree prune FAILED (non-fatal): ${err.message.trim()}`);
@@ -419,7 +420,7 @@ function main() {
419
420
  for (const b of danglingBranches) {
420
421
  if (!b.integrated) continue; // keep not-in-HEAD branches for salvage
421
422
  try {
422
- execSync(`git branch -D "${b.branch}"`, { encoding: 'utf8' });
423
+ execSync(`git branch -D "${b.branch}"`, { windowsHide: true, encoding: 'utf8' });
423
424
  danglingDeleted++;
424
425
  } catch { /* already gone — not an error */ }
425
426
  }
@@ -218,7 +218,7 @@ function parseCliArgs(argv) {
218
218
  function resolveExecutableWindows(whereFn) {
219
219
  whereFn = whereFn || function runWhere() {
220
220
  try {
221
- return cp.execSync('where claude', { encoding: 'utf8' });
221
+ return cp.execSync('where claude', { windowsHide: true, encoding: 'utf8' });
222
222
  } catch (e) {
223
223
  return '';
224
224
  }
@@ -263,13 +263,13 @@ function escapeCmdExe(exe) {
263
263
 
264
264
  function launch(exec, cwd, argv) {
265
265
  if (exec.useShell) {
266
- return cp.spawn(escapeCmdExe(exec.command), argv.map(escapeCmdArg), {
266
+ return cp.spawn(escapeCmdExe(exec.command), argv.map(escapeCmdArg), { windowsHide: true,
267
267
  cwd,
268
268
  stdio: 'inherit',
269
269
  shell: true,
270
270
  });
271
271
  }
272
- return cp.spawn(exec.command, argv, { cwd, stdio: 'inherit', shell: false });
272
+ return cp.spawn(exec.command, argv, { windowsHide: true, cwd, stdio: 'inherit', shell: false });
273
273
  }
274
274
 
275
275
  // ---- main ----
@@ -59,12 +59,12 @@ function start(name, exe, args, env, cwd) {
59
59
  }
60
60
  async function stop(p) {
61
61
  if (!p || p.exited) return;
62
- if (process.platform === 'win32') spawnSync('taskkill', ['/PID', String(p.pid), '/T', '/F'], { stdio: 'ignore' }); // our PID only
62
+ if (process.platform === 'win32') spawnSync('taskkill', ['/PID', String(p.pid), '/T', '/F'], { windowsHide: true, stdio: 'ignore' }); // our PID only
63
63
  else p.child.kill('SIGKILL');
64
64
  await until(`${p.name} exit`, () => p.exited, 15000, 100).catch(() => {});
65
65
  }
66
66
  function sh(cmd, args, env) {
67
- const r = spawnSync(cmd, args, { env: { ...process.env, ...env }, encoding: 'utf8' });
67
+ const r = spawnSync(cmd, args, { windowsHide: true, env: { ...process.env, ...env }, encoding: 'utf8' });
68
68
  return { code: r.status, out: `${r.stdout || ''}${r.stderr || ''}`.trim() };
69
69
  }
70
70
  function sqlite(file, readOnly = true) {
@@ -195,7 +195,9 @@ async function main() {
195
195
  const missing = Object.entries({ relay: BIN.relay, relayOld: BIN.relayOld, server: BIN.server, serverOldSrc: BIN.serverOldSrc }).filter(([, p]) => !fs.existsSync(p));
196
196
  if (missing.length) { console.error(`missing binaries: ${missing.map(([k, p]) => `${k}=${p}`).join(', ')}`); return 2; }
197
197
  for (const p of Object.values(PORT)) if (!(await portFree(p))) { console.error(`port ${p} busy; aborting`); return 2; }
198
- TMP = fs.mkdtempSync(path.join(os.tmpdir(), 'kenaz-peer-e2e-'));
198
+ // TASK_2480: not under os.tmpdir() - the server refuses to register (and prunes) projects in the OS temp dir
199
+ fs.mkdirSync(path.join(REPO, '.tmp'), { recursive: true });
200
+ TMP = fs.mkdtempSync(path.join(REPO, '.tmp', 'kenaz-peer-e2e-'));
199
201
  const runId = path.basename(TMP);
200
202
  console.log(`peer-identity-e2e: temp dir ${TMP}${CONTROL ? ' (control run: wrong fingerprint in scenario 3)' : ''}`);
201
203
  const gitBefore = gitState();
@@ -398,5 +400,5 @@ async function main() {
398
400
  return bad ? 1 : 0;
399
401
  }
400
402
 
401
- process.on('SIGINT', () => { for (const p of procs) if (!p.exited) { if (process.platform === 'win32') spawnSync('taskkill', ['/PID', String(p.pid), '/T', '/F'], { stdio: 'ignore' }); else p.child.kill('SIGKILL'); } process.exit(130); });
403
+ process.on('SIGINT', () => { for (const p of procs) if (!p.exited) { if (process.platform === 'win32') spawnSync('taskkill', ['/PID', String(p.pid), '/T', '/F'], { windowsHide: true, stdio: 'ignore' }); else p.child.kill('SIGKILL'); } process.exit(130); });
402
404
  main().then((c) => process.exit(c), (e) => { console.error(e); process.exit(1); });
@@ -142,7 +142,7 @@ function main() {
142
142
  const build = spawnSync(
143
143
  'cargo',
144
144
  ['test', '--lib', '--no-run', '--message-format=json'],
145
- { cwd: crateDir, encoding: 'utf8', shell: false, maxBuffer: 256 * 1024 * 1024, env }
145
+ { windowsHide: true, cwd: crateDir, encoding: 'utf8', shell: false, maxBuffer: 256 * 1024 * 1024, env }
146
146
  );
147
147
  if (build.status !== 0) {
148
148
  const compilerErrors = renderCompilerErrors(build.stdout);
@@ -180,7 +180,7 @@ function main() {
180
180
  }
181
181
 
182
182
  // 3. Run the artifact directly.
183
- const run = spawnSync(testExe, exeArgs, { stdio: 'inherit' });
183
+ const run = spawnSync(testExe, exeArgs, { windowsHide: true, stdio: 'inherit' });
184
184
  process.exit(run.status ?? 1);
185
185
  }
186
186
 
@@ -36,7 +36,7 @@ function evaluate(streamText, expected) {
36
36
  }
37
37
 
38
38
  function copyRepo(dest) {
39
- const files = execFileSync('git', ['ls-files', '-z'], { cwd: REPO, encoding: 'utf8', maxBuffer: 1 << 28 }).split('\0').filter(Boolean);
39
+ const files = execFileSync('git', ['ls-files', '-z'], { windowsHide: true, cwd: REPO, encoding: 'utf8', maxBuffer: 1 << 28 }).split('\0').filter(Boolean);
40
40
  for (const f of files) {
41
41
  const from = path.join(REPO, f);
42
42
  if (!fs.existsSync(from)) continue;
@@ -49,11 +49,11 @@ function runScenario(sc, opts) {
49
49
  const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'skill-replay-'));
50
50
  try {
51
51
  copyRepo(dir);
52
- execFileSync('git', ['init', '-q'], { cwd: dir });
52
+ execFileSync('git', ['init', '-q'], { windowsHide: true, cwd: dir });
53
53
  const prompt = (sc.prefix === undefined ? '/Ansuz ' : sc.prefix) + sc.message;
54
54
  // Prompt goes on stdin: with shell:true (needed on Windows) argv is concatenated unquoted, which split the message.
55
55
  const r = spawnSync('claude', ['-p', '--output-format', 'stream-json', '--verbose', '--max-turns', String(opts.maxTurns)],
56
- { cwd: dir, input: prompt, encoding: 'utf8', maxBuffer: 1 << 28, timeout: opts.timeoutMs, shell: process.platform === 'win32' });
56
+ { windowsHide: true, cwd: dir, input: prompt, encoding: 'utf8', maxBuffer: 1 << 28, timeout: opts.timeoutMs, shell: process.platform === 'win32' });
57
57
  const ev = evaluate(r.stdout || '', sc.expected);
58
58
  return { id: sc.id, expected: sc.expected, hit: ev.hit, calls: ev.calls, exit: r.status, error: r.error && r.error.message };
59
59
  } finally {
@@ -120,7 +120,7 @@ async function testSlowServe() {
120
120
  KENAZ_FIXTURE_SLOW_PHASE_MS: '4000',
121
121
  });
122
122
  const spawnedAt = Date.now();
123
- const child = spawn(process.execPath, [SLOW_SERVE], { env, stdio: ['ignore', 'pipe', 'pipe'] });
123
+ const child = spawn(process.execPath, [SLOW_SERVE], { windowsHide: true, env, stdio: ['ignore', 'pipe', 'pipe'] });
124
124
  spawnedPids.push(child.pid);
125
125
  let out = '';
126
126
  child.stdout.on('data', (d) => (out += d.toString()));
@@ -166,7 +166,7 @@ async function testSlowServe() {
166
166
 
167
167
  async function testNeverListens() {
168
168
  console.log('\n[selftest] never-listens.server.js');
169
- const child = spawn(process.execPath, [NEVER_LISTENS], { stdio: ['ignore', 'pipe', 'pipe'] });
169
+ const child = spawn(process.execPath, [NEVER_LISTENS], { windowsHide: true, stdio: ['ignore', 'pipe', 'pipe'] });
170
170
  spawnedPids.push(child.pid);
171
171
  let exited = false;
172
172
  child.on('exit', () => {
@@ -0,0 +1,112 @@
1
+ 'use strict';
2
+ // TASK_2474 guard: every child process Kenaz starts must be hidden on Windows.
3
+ // - Node: spawn/exec* calls in shipped JS must pass windowsHide (inline in the call, or on an options
4
+ // object defined in the same file). JS_ALLOW = intentionally visible terminals, with reasons.
5
+ // - Rust: Command::new in non-test Rust files outside common/process.rs must be hidden_command.
6
+ const test = require('node:test');
7
+ const assert = require('node:assert');
8
+ const fs = require('node:fs');
9
+ const path = require('node:path');
10
+
11
+ const ROOT = path.resolve(__dirname, '..', '..');
12
+ const JS_DIRS = ['.specialist/tools', '.formation', '.claude/hooks', 'plugins/kenaz/hooks', 'plugins/kenaz/scripts',
13
+ '.collaboration/core', 'packages/kenaz/lib', 'packages/kenaz/bin', 'dashboard/scripts', 'dev/scripts'];
14
+ const RS_DIR = 'dashboard/src-tauri/src';
15
+
16
+ // "relative/path.js:line" -> reason. Intentionally visible terminals only.
17
+ const JS_ALLOW = {
18
+ 'dev/scripts/task1961/selftest.js:132': 'false positive: "spawn (took ..." inside a template-string message, not a call',
19
+ };
20
+ // "relative/path.rs" -> reason (whole file may use raw Command::new outside #[cfg(test)]).
21
+ const RS_ALLOW = {
22
+ 'dashboard/src-tauri/src/common/process.rs': 'the hidden_command constructors themselves',
23
+ };
24
+
25
+ function walk(dir, exts, out = []) {
26
+ const abs = path.join(ROOT, dir);
27
+ if (!fs.existsSync(abs)) return out;
28
+ for (const e of fs.readdirSync(abs, { withFileTypes: true })) {
29
+ if (['node_modules', '.git', 'target', 'dist', 'fixtures'].includes(e.name)) continue;
30
+ const rel = dir + '/' + e.name;
31
+ if (e.isDirectory()) walk(rel, exts, out);
32
+ else if (exts.some((x) => e.name.endsWith(x)) && !/\.test\.[cm]?js$/.test(e.name)) out.push(rel);
33
+ }
34
+ return out;
35
+ }
36
+
37
+ // generated (gitignored) copies of scanned sources: core-resolve.js from .claude/hooks, packages/kenaz/vendor/ from
38
+ // dashboard/scripts by packages/kenaz/scripts/stage.js at pack time (a stale local copy must not fail the guard)
39
+ const isGenerated = (rel) => rel === 'plugins/kenaz/hooks/core-resolve.js' || rel.startsWith('packages/kenaz/vendor/');
40
+
41
+ function matchParen(src, open) {
42
+ let depth = 0, q = null;
43
+ for (let i = open; i < src.length; i++) {
44
+ const c = src[i];
45
+ if (q) { if (c === '\\') i++; else if (c === q) q = null; continue; }
46
+ if (c === '"' || c === "'" || c === '`') { q = c; continue; }
47
+ if (c === '(') depth++;
48
+ else if (c === ')' && --depth === 0) return i;
49
+ }
50
+ return src.length;
51
+ }
52
+
53
+ function scanJs(rel, src) {
54
+ if (!/child_process/.test(src)) return [];
55
+ const bad = [];
56
+ // blank block comments and whole-line // comments (offsets and line numbers preserved)
57
+ src = src.replace(/\/\*[\s\S]*?\*\//g, (c) => c.replace(/[^\n]/g, ' ')).replace(/^[ \t]*\/\/.*$/gm, (c) => ' '.repeat(c.length));
58
+ const re = /(?<![\w$.])(?:(?:cp|child_process|childProcess|proc)\.)?(spawn|spawnSync|exec|execSync|execFile|execFileSync)\s*\(/g;
59
+ let m;
60
+ while ((m = re.exec(src))) {
61
+ const open = m.index + m[0].length - 1;
62
+ const args = src.slice(open, matchParen(src, open) + 1);
63
+ if (/windowsHide/.test(args)) continue;
64
+ // options passed as a bare identifier: accept when that identifier is defined with windowsHide in the file
65
+ const last = args.slice(1, -1).split(',').pop().trim();
66
+ if (/^[A-Za-z_$][\w$]*$/.test(last) && new RegExp(`${last}\\s*=\\s*\\{[^;]*windowsHide`).test(src)) continue;
67
+ const line = src.slice(0, m.index).split('\n').length;
68
+ if (JS_ALLOW[`${rel}:${line}`]) continue;
69
+ bad.push(`${rel}:${line} ${m[1]}`);
70
+ }
71
+ return bad;
72
+ }
73
+
74
+ function scanRs(rel, src) {
75
+ if (RS_ALLOW[rel]) return [];
76
+ const cut = src.search(/#\[cfg\(test\)\]/);
77
+ const body = cut >= 0 ? src.slice(0, cut) : src;
78
+ const bad = [];
79
+ body.split('\n').forEach((ln, i) => {
80
+ if (/^\s*\/\//.test(ln)) return;
81
+ if (/Command::new\s*\(/.test(ln) && !/hidden_/.test(ln)) bad.push(`${rel}:${i + 1}`);
82
+ });
83
+ return bad;
84
+ }
85
+
86
+ test('Node: every child_process call passes windowsHide', () => {
87
+ const files = JS_DIRS.flatMap((d) => walk(d, ['.js', '.cjs', '.mjs'])).filter((f) => !isGenerated(f));
88
+ const bad = files.flatMap((f) => scanJs(f, fs.readFileSync(path.join(ROOT, f), 'utf8')));
89
+ console.log(`node violations: ${bad.length}`);
90
+ assert.deepStrictEqual(bad, []);
91
+ });
92
+
93
+ test('Rust: no raw Command::new in production code outside common/process.rs', () => {
94
+ const files = walk(RS_DIR, ['.rs']).filter((f) => !/(^|\/)tests?\.rs$|_tests?\.rs$|\/tests\//.test(f));
95
+ const bad = files.flatMap((f) => scanRs(f, fs.readFileSync(path.join(ROOT, f), 'utf8')));
96
+ console.log(`rust violations: ${bad.length}`);
97
+ assert.deepStrictEqual(bad, []);
98
+ });
99
+
100
+ // TASK_2478: no script-host autostart (antivirus flags schtasks ONLOGON + wscript + .vbs). The only allowed mentions
101
+ // are the migration cleanup of the old launcher files, marked `legacy-vbs-cleanup` on the same line.
102
+ test('Node: shipped JS neither runs wscript nor writes a .vbs (outside the marked migration cleanup)', () => {
103
+ const files = ['dashboard/scripts', 'packages/kenaz', 'plugins'].flatMap((d) => walk(d, ['.js', '.cjs', '.mjs'])).filter((f) => !isGenerated(f));
104
+ const bad = [];
105
+ for (const f of files) {
106
+ fs.readFileSync(path.join(ROOT, f), 'utf8').split('\n').forEach((ln, i) => {
107
+ if (/wscript|cscript|\.vbs\b/i.test(ln) && !ln.includes('legacy-vbs-cleanup')) bad.push(`${f}:${i + 1}`);
108
+ });
109
+ }
110
+ console.log(`script-host violations: ${bad.length}`);
111
+ assert.deepStrictEqual(bad, []);
112
+ });
@@ -2,5 +2,6 @@
2
2
  - Code navigation: kenaz_lsp_callers / kenaz_lsp_references / kenaz_lsp_definition / kenaz_lsp_symbols (always pass projectPath). Text search: Grep/Glob.
3
3
  - Collaboration: kenaz_peer_send / kenaz_peer_threads (other sessions, other machines, Codex), /kenaz ygg status|join.
4
4
  - Rooms: when the user pastes a room key or asks to join/create a room, run `kenaz ygg join <key>` / `kenaz ygg create` yourself (never ask them to type it), then relay the status block and any "restart Claude Code" note.
5
+ - Reporting a Kenaz problem or idea: call kenaz_wish_create (scope kenaz) yourself; it uploads to the Kenaz mother (Alaya) automatically, no user step. Claude Code's SendFeedback tool and /feedback go to Anthropic, never to Kenaz.
5
6
  - Reply in the user's language. Commands: /Ansuz, /Amelia, /review, /security, /incident, /spec.
6
7
  - Switch: /kenaz off | assist | full (or env KENAZ_MODE). off disables every Kenaz hook.
@@ -221,7 +221,7 @@ if (require.main === module) {
221
221
  if (!result) process.exit(0); // silent -- non-blocking hook
222
222
 
223
223
  try {
224
- execFileSync("node", [result.resolved, ...result.args], { stdio: "inherit" });
224
+ execFileSync("node", [result.resolved, ...result.args], { stdio: "inherit", windowsHide: true });
225
225
  } catch {
226
226
  // Hook errors should not block
227
227
  }
@@ -60,6 +60,15 @@
60
60
  }
61
61
  ]
62
62
  },
63
+ {
64
+ "matcher": "Bash",
65
+ "hooks": [
66
+ {
67
+ "type": "command",
68
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/kenaz-hook.js\" worktree-guard"
69
+ }
70
+ ]
71
+ },
63
72
  {
64
73
  "matcher": "Agent|Task",
65
74
  "hooks": [