kenaz 0.3.21 → 0.3.23

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 (481) hide show
  1. package/core/.claude/commands/Ansuz.md +2 -0
  2. package/core/.claude/hooks/__tests__/peer-session-fill.test.js +37 -0
  3. package/core/.claude/hooks/_ansuz-conversation.js +32 -1
  4. package/core/.claude/hooks/_user-scope.js +1 -1
  5. package/core/.claude/hooks/core-resolve.js +1 -1
  6. package/core/.claude/hooks/peer-optin.test.js +74 -0
  7. package/core/.claude/hooks/peer-session-fill.js +38 -0
  8. package/core/.claude/hooks/turn-context.js +5 -4
  9. package/core/.claude/hooks/worktree-create.js +6 -6
  10. package/core/.claude/hooks/worktree-remove.js +4 -4
  11. package/core/.claude/settings.json +9 -0
  12. package/core/.collaboration/core/reconcile.js +16 -1
  13. package/core/.collaboration/core/task-2467-lifecycle.test.js +63 -0
  14. package/core/.collaboration/core/task-api.js +37 -7
  15. package/core/.formation/bifrost/launch.js +1 -1
  16. package/core/.formation/bifrost/openai/codex-hook-shim.js +21 -4
  17. package/core/.formation/bifrost/openai/codex-peer-pull.test.js +42 -0
  18. package/core/.formation/bifrost/provider-launch.js +2 -1
  19. package/core/.formation/tools/kenaz-stats.js +1 -1
  20. package/core/.formation/tools/post-complete/git-merge.js +1 -1
  21. package/core/.formation/tools/prompt.js +1 -1
  22. package/core/.kenaz/specialist/ansuz_rules.yaml +7 -51
  23. package/core/.kenaz/specialist/ansuz_session_handoff.schema.json +2 -6
  24. package/core/.rule/general/project-self-containment.yaml +2 -2
  25. package/core/.specialist/Amelia/README.md +1 -1
  26. package/core/.specialist/Amelia/rule.yaml +1 -1
  27. package/core/.specialist/Ansuz/RULES.md +1 -1
  28. package/core/.specialist/Ansuz/concepts/commitment_layer.yaml +1 -1
  29. package/core/.specialist/Ansuz/concepts/evolvable_guardrails.yaml +1 -1
  30. package/core/.specialist/Ansuz/knowledge.yaml +1 -3
  31. package/core/.specialist/tools/__tests__/task-2409-lessons.test.js +10 -0
  32. package/core/.specialist/tools/__tests__/task-2427-harvest.test.js +25 -0
  33. package/core/.specialist/tools/ansuz-boot-fast.js +1 -1
  34. package/core/.specialist/tools/failure-detector.js +4 -4
  35. package/core/.specialist/tools/handoff-doc.js +1 -1
  36. package/core/.specialist/tools/lessons.js +2 -2
  37. package/core/CLAUDE.md +5 -5
  38. package/core/KENAZ_CORE_VERSION +1 -1
  39. package/core/dashboard/scripts/install-kenaz-cli.js +471 -0
  40. package/core/dev/scripts/check-file-size.js +1 -1
  41. package/core/dev/scripts/ci-feedback.js +1 -1
  42. package/core/dev/scripts/gc-agent-worktrees.js +11 -11
  43. package/core/dev/scripts/kenaz-session.js +3 -3
  44. package/core/dev/scripts/peer-identity-e2e.js +3 -3
  45. package/core/dev/scripts/run-rust-tests.js +2 -2
  46. package/core/dev/scripts/skill-routing-replay.js +3 -3
  47. package/core/dev/scripts/task1961/selftest.js +2 -2
  48. package/core/dev/scripts/windows-hide-guard.test.js +97 -0
  49. package/core/plugins/kenaz/commands/Ansuz.md +2 -0
  50. package/core/plugins/kenaz/guidance.md +2 -0
  51. package/core/plugins/kenaz/hooks/core-resolve.js +1 -1
  52. package/core/plugins/kenaz/hooks/hooks.json +9 -0
  53. package/core/plugins/kenaz/hooks/kenaz-hook.js +53 -4
  54. package/core/plugins/kenaz/scripts/kenaz.test.js +72 -5
  55. package/core/plugins/kenaz/scripts/ygg.js +40 -4
  56. package/core/plugins/kenaz/scripts/ygg.test.js +63 -3
  57. package/core/plugins/kenaz-peer/hooks/register.test.ts +59 -2
  58. package/core/plugins/kenaz-peer/hooks/register.ts +24 -1
  59. package/lib/cli.js +9 -5
  60. package/package.json +6 -6
  61. package/vendor/install-kenaz-cli.js +21 -6
  62. package/core/.kenaz/designs/METAPLASTICITY_CONFIDENCE_DESIGN.md +0 -537
  63. package/core/.kenaz/designs/REFLEX_INITIATOR_DESIGN.md +0 -501
  64. package/core/.kenaz/designs/TASK_1385_handoff_mcp_design.md +0 -426
  65. package/core/.kenaz/designs/TASK_932_hippocampus_consolidation.md +0 -103
  66. package/core/.kenaz/designs/TASK_934_efe_signal_engine.md +0 -97
  67. package/core/.kenaz/designs/TASK_935_self_evolution_framework.md +0 -154
  68. package/core/.kenaz/designs/VISION_cognitive_architecture_roadmap.md +0 -159
  69. package/core/.kenaz/designs/metaplasticity_simulation_results.json +0 -696
  70. package/core/.kenaz/main-memory/README.md +0 -230
  71. package/core/.kenaz/main-memory/kenaz/cortex/001_cortex_overview.md +0 -168
  72. package/core/.kenaz/main-memory/kenaz/cortex/001_rag_engine_overview.md +0 -30
  73. package/core/.kenaz/main-memory/kenaz/memory-system/001_three_tier_architecture.md +0 -361
  74. package/core/.kenaz/main-memory/kenaz/pipeline/001_task_execution_flow.md +0 -117
  75. package/core/.kenaz/main-memory/kenaz/pipeline/001_task_granularity.md +0 -154
  76. package/core/.kenaz/main-memory/kenaz/pipeline/002_team_priority.md +0 -51
  77. package/core/.kenaz/main-memory/kenaz/pipeline/003_feature_id_system.md +0 -46
  78. package/core/.kenaz/main-memory/kenaz/rules/001_gen_007_self_containment.md +0 -108
  79. package/core/.kenaz/main-memory/kenaz/rules/001_rule_priority_system.md +0 -121
  80. package/core/.kenaz/main-memory/kenaz/rules/002_agt_006_pre_check.md +0 -0
  81. package/core/.kenaz/main-memory/kenaz/rules/003_ppl_002_task_archival.md +0 -48
  82. package/core/.kenaz/main-memory/kenaz/system/001_dual_track_task_system.md +0 -197
  83. package/core/.kenaz/main-memory/knowledge/patterns/001_json_bom_issue.md +0 -78
  84. package/core/.kenaz/main-memory/knowledge/patterns/001_leader_worker_pattern.md +0 -0
  85. package/core/.kenaz/main-memory/knowledge/patterns/002_scope_path_conflict.md +0 -115
  86. package/core/.kenaz/main-memory/knowledge/patterns/002_task_dependency_resolution.md +0 -223
  87. package/core/.kenaz/main-memory/knowledge/patterns/003_question_protocol.md +0 -242
  88. package/core/.kenaz/main-memory/knowledge/patterns/004_user_insight_value.md +0 -111
  89. package/core/.kenaz/main-memory/knowledge/patterns/005_file_lock_pattern.md +0 -274
  90. package/core/.kenaz/main-memory/knowledge/references/001_ppl_rules.md +0 -28
  91. package/core/.kenaz/main-memory/knowledge/solutions/001_json_bom_issue.md +0 -137
  92. package/core/.kenaz/main-memory/knowledge/solutions/001_team_invocation.md +0 -0
  93. package/core/.kenaz/main-memory/knowledge/solutions/002_passive_monitoring.md +0 -0
  94. package/core/.kenaz/main-memory/knowledge/solutions/003_windows_file_race_condition.md +0 -239
  95. package/core/.kenaz/main-memory/registry.json +0 -326
  96. package/core/.kenaz/main-memory/version.yaml +0 -58
  97. package/core/.kenaz/specialist/memory_guard_fired.json +0 -1
  98. package/core/.kenaz/specialist/memory_guard_trigger_cache.json +0 -1
  99. package/core/.kenaz/specialist/memory_source_priority.yaml +0 -260
  100. package/core/.kenaz/specialist/prompt_1775.txt +0 -317
  101. package/core/.kenaz/specialist/prompt_1776.txt +0 -326
  102. package/core/.kenaz/specialist/prompt_1791.txt +0 -320
  103. package/core/.kenaz/specialist/prompt_1792.txt +0 -320
  104. package/core/.kenaz/specialist/prompt_1795.txt +0 -281
  105. package/core/.kenaz/specialist/prompt_1813.txt +0 -332
  106. package/core/.kenaz/specialist/prompt_1814.txt +0 -401
  107. package/core/.kenaz/specialist/prompt_1815.txt +0 -394
  108. package/core/.kenaz/specialist/prompt_1816.txt +0 -437
  109. package/core/.kenaz/specialist/prompt_1818.txt +0 -361
  110. package/core/.kenaz/specialist/prompt_1819.txt +0 -421
  111. package/core/.kenaz/specialist/prompt_1821.txt +0 -345
  112. package/core/.kenaz/specialist/prompt_1822.txt +0 -313
  113. package/core/.kenaz/specialist/prompt_1824.txt +0 -348
  114. package/core/.kenaz/specialist/prompt_1826.txt +0 -388
  115. package/core/.kenaz/specialist/rune_efe_salience_gap.md +0 -21
  116. package/core/.kenaz/specialist/task1825_update.json +0 -43
  117. package/core/.kenaz/specialist/taskgen/consolidation_i.json +0 -38
  118. package/core/.kenaz/specialist/taskgen/csharp_a.json +0 -44
  119. package/core/.kenaz/specialist/taskgen/csharp_b.json +0 -40
  120. package/core/.kenaz/specialist/taskgen/embedding_e.json +0 -34
  121. package/core/.kenaz/specialist/taskgen/hygiene_fg.json +0 -39
  122. package/core/.kenaz/specialist/taskgen/pathology_h.json +0 -36
  123. package/core/.kenaz/specialist/taskgen/unity_noise_d.json +0 -38
  124. package/core/.kenaz/specialist/taskgen/visibility_c.json +0 -38
  125. package/core/.specialist/Ansuz/decisions/ADR-requirement-graph-layer.md +0 -390
  126. package/core/.specialist/Ansuz/self_model_seed.backup.json +0 -100
  127. package/core/.specialist/ansuz_session_handoff.json +0 -96
  128. package/core/dev/ALAYA_FIELD_FEEDBACK_DESIGN.md +0 -126
  129. package/core/dev/ANSUZ_SCAFFOLD_DIET_2026-09-20.md +0 -231
  130. package/core/dev/ANSUZ_STARTUP_INJECTION_REVIEW.md +0 -355
  131. package/core/dev/ANSUZ_WORKFLOW_MODERNIZATION.md +0 -143
  132. package/core/dev/CORTEX_META_GRAPH_ASSESSMENT.md +0 -99
  133. package/core/dev/FREYA_DOWNSTREAM_BUGS_2026-09-19.md +0 -44
  134. package/core/dev/GLOBAL_MEMORY_IDENTITY_CONSOLIDATION.md +0 -263
  135. package/core/dev/GUARD_EFFECTIVENESS_DESIGN.md +0 -180
  136. package/core/dev/HEALTH_GATE_VARIANCE_ASSESSMENT.md +0 -271
  137. package/core/dev/HOOK_DIET_2026-09-21.md +0 -126
  138. package/core/dev/JEV_INTEGRATION_PLAN.md +0 -189
  139. package/core/dev/KENAZ_AGENT_CONNECT_v1_SPEC.md +0 -139
  140. package/core/dev/MOBILE_DESIGN_SPEC.md +0 -569
  141. package/core/dev/MULTI_ANSUZ_SPEC.md +0 -136
  142. package/core/dev/MUNINN_RETIREMENT.md +0 -115
  143. package/core/dev/PHASE3_ATTRIBUTION_POPULATION_DIAGNOSIS.md +0 -211
  144. package/core/dev/PHASE3_P3-2B_TASKLEVEL_PROBE.md +0 -83
  145. package/core/dev/PHASE3_P3-2_POPULATION_DISJOINTNESS.md +0 -83
  146. package/core/dev/PHASE3_P3-2_REMEASURE_REPORT.md +0 -231
  147. package/core/dev/PREDICTION_GROUNDING_DESIGN.md +0 -376
  148. package/core/dev/PRODUCT_SPEC.md +0 -317
  149. package/core/dev/PROJECT_REGISTRY_DUPLICATE_ASSESSMENT.md +0 -86
  150. package/core/dev/STARTUP_TIMELINE_TASK_1995.md +0 -181
  151. package/core/dev/SYNAPSE_WORKER_PER_PROJECT.md +0 -881
  152. package/core/dev/TASK_1680_P3-3_DISPATCH_SPEC.md +0 -96
  153. package/core/dev/TASK_1684_CALIBRATION_IMPACT_ANALYSIS.md +0 -170
  154. package/core/dev/TASK_1684_FORK_A_GOODHART_DESIGN.md +0 -171
  155. package/core/dev/TASK_1684_P3_2_REMEASURE_VALIDATION.md +0 -262
  156. package/core/dev/TASK_1903_SIGNAL_AUC_MEASUREMENT.md +0 -207
  157. package/core/dev/TASK_1904_BRANCH_INTEGRITY_AUDIT.md +0 -146
  158. package/core/dev/ansuz-eval/README.md +0 -38
  159. package/core/dev/ansuz-eval/build-fixtures.js +0 -87
  160. package/core/dev/ansuz-eval/grade.js +0 -96
  161. package/core/dev/ansuz-eval/grader.test.js +0 -117
  162. package/core/dev/ansuz-eval/tasks.md +0 -32
  163. package/core/dev/archive/ansuz/BOOT_FULL.md +0 -141
  164. package/core/dev/archive/ansuz/agents/ansuz-boot.md +0 -176
  165. package/core/dev/archive/ansuz/designs/alaya-passive-surfacing.md +0 -84
  166. package/core/dev/archive/ansuz/designs/cc_memory_indexing.md +0 -307
  167. package/core/dev/archive/ansuz/designs/check_guard.md +0 -322
  168. package/core/dev/archive/ansuz/designs/consequence_loop.md +0 -227
  169. package/core/dev/archive/ansuz/designs/mcp_kuzudb_lock_architecture.md +0 -312
  170. package/core/dev/archive/ansuz/designs/phase0_git_enrichment.md +0 -278
  171. package/core/dev/archive/ansuz/designs/refactor_mcp_tools_synapse.md +0 -490
  172. package/core/dev/archive/ansuz/designs/semantic_markdown_extraction.md +0 -167
  173. package/core/dev/archive/ansuz/designs/task_1372_prompt_injects_into.md +0 -193
  174. package/core/dev/archive/ansuz/designs/thought_stack.md +0 -286
  175. package/core/dev/archive/ansuz/investigations/reachability_unified_api_2026-04-11.md +0 -330
  176. package/core/dev/archive/ansuz/investigations/synapse_orphans_indexing_bug_2026-04-11.md +0 -352
  177. package/core/dev/archive/ansuz/investigations/synapse_orphans_reindex_verification_2026-04-11.md +0 -48
  178. package/core/dev/archive/ansuz/investigations/synapse_orphans_verification_2026-04-11.md +0 -170
  179. package/core/dev/archive/ansuz/legacy/kernel.yaml +0 -399
  180. package/core/dev/archive/ansuz/legacy/phases/phase_0.yaml +0 -418
  181. package/core/dev/archive/ansuz/legacy/phases/phase_1.yaml +0 -376
  182. package/core/dev/archive/ansuz/legacy/phases/phase_10.yaml +0 -35
  183. package/core/dev/archive/ansuz/legacy/phases/phase_11.yaml +0 -582
  184. package/core/dev/archive/ansuz/legacy/phases/phase_2.yaml +0 -94
  185. package/core/dev/archive/ansuz/legacy/phases/phase_3.yaml +0 -274
  186. package/core/dev/archive/ansuz/legacy/phases/phase_4.yaml +0 -67
  187. package/core/dev/archive/ansuz/legacy/phases/phase_5.yaml +0 -32
  188. package/core/dev/archive/ansuz/legacy/phases/phase_6.yaml +0 -91
  189. package/core/dev/archive/ansuz/legacy/phases/phase_7.yaml +0 -58
  190. package/core/dev/archive/ansuz/legacy/phases/phase_8.yaml +0 -146
  191. package/core/dev/archive/ansuz/legacy/phases/phase_9.yaml +0 -424
  192. package/core/dev/archive/ansuz/specs/INDEX_bifrost_hook_parity.yaml +0 -92
  193. package/core/dev/archive/ansuz/specs/active-inference-formation.yaml +0 -453
  194. package/core/dev/archive/ansuz/specs/brief_TASK_1228_userpromptsubmit.yaml +0 -191
  195. package/core/dev/archive/ansuz/specs/brief_TASK_1229_pretooluse_posttooluse.yaml +0 -250
  196. package/core/dev/archive/ansuz/specs/brief_TASK_1230_sessionstart_stop.yaml +0 -301
  197. package/core/dev/archive/ansuz/specs/brief_TASK_1231_verification.yaml +0 -272
  198. package/core/dev/archive/skills/feature_agent/SKILL.md +0 -289
  199. package/core/dev/design/PHASE4_DESIGN.md +0 -559
  200. package/core/dev/design/dashboard_docs_integration_PLAN.md +0 -388
  201. package/core/dev/design/matrix_format_ABBREVIATIONS.md +0 -655
  202. package/core/dev/design/matrix_format_DESIGN_SPEC.md +0 -601
  203. package/core/dev/design/matrix_format_DISCUSSION_SUMMARY.md +0 -484
  204. package/core/dev/design/matrix_format_EXAMPLE_memory.matrix +0 -13
  205. package/core/dev/design/matrix_format_EXAMPLE_project_status.matrix +0 -9
  206. package/core/dev/design/matrix_format_EXAMPLE_tasks.matrix +0 -14
  207. package/core/dev/design/matrix_format_SYNTAX_BNF.md +0 -754
  208. package/core/dev/design/matrix_format_TOKEN_COMPARISON.md +0 -484
  209. package/core/dev/design/matrix_v2_COGNITIVE_DESIGN.md +0 -503
  210. package/core/dev/design/matrix_v2_DISCUSSION_SUMMARY.md +0 -414
  211. package/core/dev/design/matrix_v2_EXAMPLE.matrix +0 -67
  212. package/core/dev/designs/EXPANDABLE_CARD_DESIGN_SPEC.md +0 -509
  213. package/core/dev/jev-eval/ACTIVE_CORRECTION.md +0 -52
  214. package/core/dev/jev-eval/ANNOTATION_GUIDE.md +0 -68
  215. package/core/dev/jev-eval/BASELINE_COMPARISON.md +0 -45
  216. package/core/dev/jev-eval/CONTEXT_REVIEW.md +0 -31
  217. package/core/dev/jev-eval/EVALUATION_STATUS.md +0 -39
  218. package/core/dev/jev-eval/HISTORICAL_CORPUS.md +0 -33
  219. package/core/dev/jev-eval/PACKAGING_VERIFICATION.md +0 -42
  220. package/core/dev/jev-eval/README.md +0 -101
  221. package/core/dev/jev-eval/THALAMUS_RANKING.md +0 -58
  222. package/core/dev/jev-eval/VALIDATION_PROGRESS.md +0 -54
  223. package/core/dev/jev-eval/cli.mjs +0 -50
  224. package/core/dev/jev-eval/context.mjs +0 -183
  225. package/core/dev/jev-eval/corpus.mjs +0 -186
  226. package/core/dev/jev-eval/fixtures/conversation-review.seed.jsonl +0 -6
  227. package/core/dev/jev-eval/fixtures/synthetic.jsonl +0 -11
  228. package/core/dev/jev-eval/metrics.mjs +0 -67
  229. package/core/dev/jev-eval/muninn-baseline.mjs +0 -119
  230. package/core/dev/jev-eval/providers.mjs +0 -95
  231. package/core/dev/jev-eval/reports/annotation-pilot-2026-09-20.json +0 -32
  232. package/core/dev/jev-eval/reports/context-review-2026-09-20.json +0 -48
  233. package/core/dev/jev-eval/reports/conversation-review.pending.json +0 -151
  234. package/core/dev/jev-eval/reports/history-corpus-2026-09-20.json +0 -52
  235. package/core/dev/jev-eval/reports/length-probe-2026-09-20.json +0 -133
  236. package/core/dev/jev-eval/reports/live-smoke-2026-09-20.json +0 -616
  237. package/core/dev/jev-eval/reports/muninn-baseline-2026-09-20.json +0 -52
  238. package/core/dev/jev-eval/reports/resilience-2026-09-20.json +0 -520
  239. package/core/dev/jev-eval/reports/rules-baseline.json +0 -197
  240. package/core/dev/jev-eval/reports/synthetic-review.pending.json +0 -357
  241. package/core/dev/jev-eval/resilience.mjs +0 -71
  242. package/core/dev/jev-eval/review.mjs +0 -78
  243. package/core/dev/jev-eval/schema.mjs +0 -87
  244. package/core/dev/jev-eval/test/context.test.mjs +0 -95
  245. package/core/dev/jev-eval/test/corpus.test.mjs +0 -102
  246. package/core/dev/jev-eval/test/eval.test.mjs +0 -146
  247. package/core/dev/jev-eval/test/muninn-baseline.test.mjs +0 -71
  248. package/core/dev/jev-eval/test/resilience.test.mjs +0 -72
  249. package/core/dev/jev-eval/test/review.test.mjs +0 -61
  250. package/core/dev/pipeline/PHASE3_PLANNING_SUMMARY.md +0 -338
  251. package/core/dev/pipeline/PROGRESS.md +0 -113
  252. package/core/dev/pipeline/PROGRESS_template.md +0 -860
  253. package/core/dev/pipeline/QA_REPORT_F008.md +0 -431
  254. package/core/dev/pipeline/QA_REPORT_LOCAL_CLAUDE_DIAGNOSIS.md +0 -583
  255. package/core/dev/pipeline/README.md +0 -210
  256. package/core/dev/pipeline/WORKFLOW_GUIDE.md +0 -824
  257. package/core/dev/pipeline/archived/TASK_015_tauri_init.yaml +0 -53
  258. package/core/dev/pipeline/archived/TASK_016_tauri_commands.yaml +0 -54
  259. package/core/dev/pipeline/archived/TASK_017_rust_pty.yaml +0 -54
  260. package/core/dev/pipeline/archived/TASK_018_tauri_bundle.yaml +0 -53
  261. package/core/dev/pipeline/archived/TASK_019_release_workflow.yaml +0 -56
  262. package/core/dev/pipeline/archived/TASK_020_update_ui.yaml +0 -54
  263. package/core/dev/pipeline/archived/TASK_021_update_notification_ui.yaml +0 -55
  264. package/core/dev/pipeline/archived/TASK_022_remove_node_pty.yaml +0 -65
  265. package/core/dev/pipeline/archived/TASK_023_api_routes_migration.yaml +0 -86
  266. package/core/dev/pipeline/archived/TASK_024_feature_id_system.yaml +0 -51
  267. package/core/dev/pipeline/archived/TASK_025_executable_acceptance.yaml +0 -66
  268. package/core/dev/pipeline/archived/TASK_026_spec_versioning.yaml +0 -56
  269. package/core/dev/pipeline/archived/TASK_027_drift_detection.yaml +0 -60
  270. package/core/dev/pipeline/archived/TASK_028_tauri_pty_manager.yaml +0 -60
  271. package/core/dev/pipeline/archived/TASK_029_tauri_pty_commands.yaml +0 -62
  272. package/core/dev/pipeline/archived/TASK_030_frontend_session_adapter.yaml +0 -54
  273. package/core/dev/pipeline/archived/TASK_031_terminal_tauri_events.yaml +0 -56
  274. package/core/dev/pipeline/archived/TASK_041_scheduler_data_models.yaml +0 -54
  275. package/core/dev/pipeline/archived/TASK_042_path_lock_manager.yaml +0 -53
  276. package/core/dev/pipeline/archived/TASK_043_process_manager.yaml +0 -57
  277. package/core/dev/pipeline/archived/TASK_044_git_integration.yaml +0 -85
  278. package/core/dev/pipeline/archived/TASK_045_task_queue_manager.yaml +0 -54
  279. package/core/dev/pipeline/archived/TASK_046_scheduler_dispatcher.yaml +0 -60
  280. package/core/dev/pipeline/archived/TASK_047_tauri_scheduler_commands.yaml +0 -55
  281. package/core/dev/pipeline/archived/TASK_048_realtime_status_push.yaml +0 -92
  282. package/core/dev/pipeline/archived/TASK_049_frontend_scheduler_integration.yaml +0 -58
  283. package/core/dev/pipeline/archived/TASK_050_error_recovery.yaml +0 -56
  284. package/core/dev/pipeline/archived/TASK_051_optimization_proposals_backend.yaml +0 -53
  285. package/core/dev/pipeline/archived/TASK_052_optimization_proposals_ui.yaml +0 -58
  286. package/core/dev/pipeline/archived/TASK_053_optimization_proposals_diff_view.yaml +0 -54
  287. package/core/dev/pipeline/archived/TASK_054_multi_project_scheduler_state.yaml +0 -76
  288. package/core/dev/pipeline/archived/TASK_055_scheduler_api_project_scope.yaml +0 -64
  289. package/core/dev/pipeline/archived/TASK_056_frontend_scheduler_project_scope.yaml +0 -62
  290. package/core/dev/pipeline/archived/TASK_057_scheduler_module_structure.yaml +0 -54
  291. package/core/dev/pipeline/archived/TASK_058_scheduler_models_extract.yaml +0 -51
  292. package/core/dev/pipeline/archived/TASK_059_scheduler_core_extract.yaml +0 -51
  293. package/core/dev/pipeline/archived/TASK_060_scheduler_commands_extract.yaml +0 -51
  294. package/core/dev/pipeline/archived/TASK_061_scheduler_specialized_commands.yaml +0 -53
  295. package/core/dev/pipeline/archived/TASK_062_process_manager_module_structure.yaml +0 -56
  296. package/core/dev/pipeline/archived/TASK_063_process_manager_core_extract.yaml +0 -56
  297. package/core/dev/pipeline/archived/TASK_064_recovery_module_structure.yaml +0 -57
  298. package/core/dev/pipeline/archived/TASK_065_recovery_core_extract.yaml +0 -56
  299. package/core/dev/pipeline/archived/TASK_066_self_enhancement_scheduler_models.yaml +0 -60
  300. package/core/dev/pipeline/archived/TASK_067_agents_section_quick_actions.yaml +0 -53
  301. package/core/dev/pipeline/archived/TASK_067_self_enhancement_scheduler_core.yaml +0 -65
  302. package/core/dev/pipeline/archived/TASK_068_agent_workflow_rule_enhancement.yaml +0 -46
  303. package/core/dev/pipeline/archived/TASK_068_self_enhancement_tauri_commands.yaml +0 -61
  304. package/core/dev/pipeline/archived/TASK_069_agent_wizard_responsive.yaml +0 -46
  305. package/core/dev/pipeline/archived/TASK_069_self_enhancement_ui.yaml +0 -62
  306. package/core/dev/pipeline/archived/TASK_070_preview_panel_redesign.yaml +0 -62
  307. package/core/dev/pipeline/archived/TASK_070_self_enhancement_integration.yaml +0 -57
  308. package/core/dev/pipeline/archived/TASK_071_preview_panel_qa.yaml +0 -98
  309. package/core/dev/pipeline/archived/TASK_071_single_agent_config.yaml +0 -57
  310. package/core/dev/pipeline/archived/TASK_072_preview_modal_esc_fix.yaml +0 -71
  311. package/core/dev/pipeline/archived/TASK_072_product_review_module.yaml +0 -57
  312. package/core/dev/pipeline/archived/TASK_073_agents_page_component_refactor.yaml +0 -68
  313. package/core/dev/pipeline/archived/TASK_073_rename_single_agent.yaml +0 -64
  314. package/core/dev/pipeline/archived/TASK_074_preview_mode_ui_diagnosis.yaml +0 -71
  315. package/core/dev/pipeline/archived/TASK_074_single_agent_ui_toggle.yaml +0 -56
  316. package/core/dev/pipeline/archived/TASK_075_agents_page_component_refactor.yaml +0 -69
  317. package/core/dev/pipeline/archived/TASK_075_single_agent_integration_test.yaml +0 -75
  318. package/core/dev/pipeline/archived/TASK_076_preview_mode_ui_diagnosis.yaml +0 -70
  319. package/core/dev/pipeline/archived/TASK_076_single_agent_continuous_mode.yaml +0 -65
  320. package/core/dev/pipeline/archived/TASK_077_failure_directory_structure.yaml +0 -51
  321. package/core/dev/pipeline/archived/TASK_077_single_agent_typescript_types.yaml +0 -59
  322. package/core/dev/pipeline/archived/TASK_078_fail_001_agent_no_output.yaml +0 -53
  323. package/core/dev/pipeline/archived/TASK_078_single_agent_ui_simplify.yaml +0 -74
  324. package/core/dev/pipeline/archived/TASK_079_dashboard_rwd_responsive.yaml +0 -63
  325. package/core/dev/pipeline/archived/TASK_079_fail_002_json_bom.yaml +0 -56
  326. package/core/dev/pipeline/archived/TASK_080_fail_003_queue_pollution.yaml +0 -56
  327. package/core/dev/pipeline/archived/TASK_080_http_server_module.yaml +0 -55
  328. package/core/dev/pipeline/archived/TASK_081_failure_logging_tools.yaml +0 -57
  329. package/core/dev/pipeline/archived/TASK_081_http_api_routes.yaml +0 -62
  330. package/core/dev/pipeline/archived/TASK_082_frontend_api_adapter.yaml +0 -51
  331. package/core/dev/pipeline/archived/TASK_082_integrate_failure_to_workflow.yaml +0 -60
  332. package/core/dev/pipeline/archived/TASK_083_cleanup_nextjs_api.yaml +0 -48
  333. package/core/dev/pipeline/archived/TASK_083_task_queue_cleanup.yaml +0 -67
  334. package/core/dev/pipeline/archived/TASK_084_rust_dead_code_cleanup.yaml +0 -66
  335. package/core/dev/pipeline/archived/TASK_084_scheduler_sync_logic_fix.yaml +0 -68
  336. package/core/dev/pipeline/archived/TASK_085_http_api_web_mode_fixes.yaml +0 -46
  337. package/core/dev/pipeline/archived/TASK_085_memory_consolidation_0204_0205.yaml +0 -98
  338. package/core/dev/pipeline/archived/TASK_086_collapsible_preview_panel.yaml +0 -161
  339. package/core/dev/pipeline/archived/TASK_086_web_mode_feature_parity.yaml +0 -62
  340. package/core/dev/pipeline/archived/TASK_087_manual_memory_archival.yaml +0 -163
  341. package/core/dev/pipeline/archived/TASK_087_mobile_http_control.yaml +0 -68
  342. package/core/dev/pipeline/archived/TASK_088_fail_003_to_ppl_002_rule.yaml +0 -63
  343. package/core/dev/pipeline/archived/TASK_088_mobile_http_qa.yaml +0 -121
  344. package/core/dev/pipeline/archived/TASK_089_agent_collaboration_topic.yaml +0 -60
  345. package/core/dev/pipeline/archived/TASK_089_web_mode_monitor_fix.yaml +0 -58
  346. package/core/dev/pipeline/archived/TASK_090_cli_detection_fix.yaml +0 -61
  347. package/core/dev/pipeline/archived/TASK_090_ui_ux_lessons_topic.yaml +0 -63
  348. package/core/dev/pipeline/archived/TASK_091_expandable_card_design.yaml +0 -56
  349. package/core/dev/pipeline/archived/TASK_091_move_agent_section_components.yaml +0 -65
  350. package/core/dev/pipeline/archived/TASK_092_expandable_card_component.yaml +0 -60
  351. package/core/dev/pipeline/archived/TASK_092_refactor_agent_create_wizard.yaml +0 -84
  352. package/core/dev/pipeline/archived/TASK_093_taskcard_detail_integration.yaml +0 -57
  353. package/core/dev/pipeline/archived/TASK_093_update_barrel_exports_test.yaml +0 -84
  354. package/core/dev/pipeline/archived/TASK_094_ai_agent_generation_enhancement.yaml +0 -115
  355. package/core/dev/pipeline/archived/TASK_094_proposalcard_detail_integration.yaml +0 -55
  356. package/core/dev/pipeline/archived/TASK_095_preview_fixes.yaml +0 -129
  357. package/core/dev/pipeline/archived/TASK_095_single_agent_task_selector.yaml +0 -60
  358. package/core/dev/pipeline/archived/TASK_096_agents_page_ux_improvements.yaml +0 -163
  359. package/core/dev/pipeline/archived/TASK_096_single_agent_status_sync.yaml +0 -60
  360. package/core/dev/pipeline/archived/TASK_097_local_claude_error_logging.yaml +0 -59
  361. package/core/dev/pipeline/archived/TASK_097_single_agent_monitor_events.yaml +0 -59
  362. package/core/dev/pipeline/archived/TASK_098_product_manager_team_phase2.yaml +0 -60
  363. package/core/dev/pipeline/archived/TASK_098_single_agent_refactor_test.yaml +0 -58
  364. package/core/dev/pipeline/archived/TASK_099_backend_team_creation.yaml +0 -258
  365. package/core/dev/pipeline/archived/TASK_100_frontend_team_creation.yaml +0 -61
  366. package/core/dev/pipeline/archived/TASK_101_orchestrator_system.yaml +0 -403
  367. package/core/dev/pipeline/archived/TASK_102_designer_sre_teams.yaml +0 -90
  368. package/core/dev/pipeline/archived/TASK_103_integration_testing.yaml +0 -86
  369. package/core/dev/pipeline/archived/TASK_128_integration_testing.yaml +0 -83
  370. package/core/dev/pipeline/archived/TASK_134_cortex_v2_phase3_file_watcher.yaml +0 -65
  371. package/core/dev/pipeline/archived/TASK_134_team_http_api.yaml +0 -96
  372. package/core/dev/pipeline/archived/TASK_135_cortex_v2_phase3_git_monitor.yaml +0 -63
  373. package/core/dev/pipeline/archived/TASK_136_cortex_v2_phase3_change_analyzer.yaml +0 -69
  374. package/core/dev/pipeline/archived/TASK_137_cortex_v2_phase3_cache_invalidator.yaml +0 -67
  375. package/core/dev/pipeline/archived/TASK_137_team_orchestrator_integration.yaml +0 -93
  376. package/core/dev/pipeline/archived/TASK_138_cortex_v2_phase3_distributed_cache.yaml +0 -68
  377. package/core/dev/pipeline/archived/TASK_138_matrix_folder_structure.yaml +0 -61
  378. package/core/dev/pipeline/archived/TASK_139_cortex_v2_phase3_cache_prewarming.yaml +0 -65
  379. package/core/dev/pipeline/archived/TASK_146_unified_documentation.yaml +0 -141
  380. package/core/dev/pipeline/archived/TASK_147_pipeline_execution_rules.yaml +0 -76
  381. package/core/dev/pipeline/archived/TASK_148_update_claude_md.yaml +0 -77
  382. package/core/dev/pipeline/archived/TASK_149_fix_nextjs_mdx_serialization.yaml +0 -63
  383. package/core/dev/pipeline/archived/TASK_149_update_team_docs.yaml +0 -77
  384. package/core/dev/pipeline/archived/TASK_150_pipeline_workflow_guide.yaml +0 -82
  385. package/core/dev/pipeline/archived/TASK_164_fix_smart_context_switch.yaml +0 -49
  386. package/core/dev/pipeline/archived/TASK_165_ctags_symbol_index.yaml +0 -53
  387. package/core/dev/pipeline/archived/TASK_166_symbol_search_mcp_tool.yaml +0 -48
  388. package/core/dev/pipeline/archived/TASK_167_llm_module_summary.yaml +0 -55
  389. package/core/dev/pipeline/archived/TASK_168_map_reduce_context.yaml +0 -51
  390. package/core/dev/pipeline/archived/TASK_169_v2_integration_testing.yaml +0 -52
  391. package/core/dev/pipeline/backups/archive_2026-02-04T22-07-22/TASK_QUEUE_backup.json +0 -95
  392. package/core/dev/pipeline/docs/multi-agent-coordination.md +0 -446
  393. package/core/dev/pipeline/docs/overview.md +0 -406
  394. package/core/dev/pipeline/docs/task-management.md +0 -412
  395. package/core/dev/pipeline/docs/workflows.md +0 -32
  396. package/core/dev/pipeline/orchestrator/schemas/task_queue_schema.json +0 -58
  397. package/core/dev/pipeline/orchestrator/schemas/task_schema.json +0 -139
  398. package/core/dev/pipeline/plans/PLAN_task_cli_refactor.md +0 -281
  399. package/core/dev/pipeline/test_results/TASK_TEST_PARALLEL_002_result.txt +0 -27
  400. package/core/dev/plans/ANSUZ_SLIM_PLAN.md +0 -68
  401. package/core/dev/plans/CLI_FIRST_INSTALL_FLOW.md +0 -120
  402. package/core/dev/plans/FORMATION_RETIREMENT_PLAN.md +0 -313
  403. package/core/dev/plans/KUZU_REPLACEMENT_PLAN.md +0 -126
  404. package/core/dev/scripts/CRASH_DIAGNOSIS.md +0 -47
  405. package/core/dev/scripts/README.md +0 -142
  406. package/core/dev/scripts/RUN_ONCE.bat +0 -40
  407. package/core/dev/scripts/START_DEV_AGENT.bat +0 -63
  408. package/core/dev/scripts/START_MULTI_AGENT.bat +0 -80
  409. package/core/dev/scripts/dev_agent_scheduler.ps1 +0 -536
  410. package/core/dev/scripts/init_git.ps1 +0 -396
  411. package/core/dev/scripts/init_git.sh +0 -337
  412. package/core/dev/scripts/init_project.ps1 +0 -851
  413. package/core/dev/scripts/init_project.sh +0 -477
  414. package/core/dev/scripts/multi_agent_scheduler.ps1 +0 -2021
  415. package/core/dev/scripts/multi_agent_scheduler.sh +0 -1344
  416. package/core/dev/scripts/run_once.sh +0 -47
  417. package/core/dev/scripts/setup_rag.ps1 +0 -304
  418. package/core/dev/scripts/setup_rag.sh +0 -230
  419. package/core/dev/scripts/start_dev_agent.sh +0 -137
  420. package/core/dev/scripts/start_multi_agent.sh +0 -41
  421. package/core/dev/scripts/sync_task_queue.ps1 +0 -505
  422. package/core/dev/scripts/sync_task_queue.sh +0 -392
  423. package/core/dev/specs/agent-connect/PROTOCOL.md +0 -177
  424. package/core/dev/specs/agent-connect/SDK_GUIDE.md +0 -915
  425. package/core/dev/specs/agent-connect/examples/minimal-site/README.md +0 -137
  426. package/core/dev/specs/agent-connect/examples/minimal-site/package.json +0 -12
  427. package/core/dev/specs/agent-connect/examples/minimal-site/public/index.html +0 -116
  428. package/core/dev/specs/agent-connect/examples/minimal-site/public/install-redirect.js +0 -73
  429. package/core/dev/specs/agent-connect/examples/minimal-site/server.js +0 -516
  430. package/core/dev/specs/agent-connect/examples/minimal-site/test/smoke.test.mjs +0 -263
  431. 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
  432. package/core/dev/specs/agent-connect/history/DEFECT_REPORT_kenaz-agent-hub_2026-09-09_v0.4-prompt-mojibake.md +0 -90
  433. package/core/dev/specs/agent-connect/history/FEATURE_REQUEST_kenaz-agent-hub_2026-09-07.md +0 -61
  434. package/core/dev/specs/agent-connect/history/FEATURE_REQUEST_kenaz-agent-hub_2026-09-08_relay-v1-conformance.md +0 -76
  435. package/core/dev/specs/agent-connect/history/FEATURE_REQUEST_kenaz-agent-hub_2026-09-09_v0.4-session-channel.md +0 -87
  436. package/core/dev/specs/agent-connect/history/FLOWPIX_REPLY_agent-hub_2026-09-08_relay-v1-answers.md +0 -68
  437. package/core/dev/specs/agent-connect/history/FLOWPIX_bridge_CONTRACT.md +0 -642
  438. package/core/dev/specs/agent-connect/history/FLOWPIX_spikes_relay_spike_relay.mjs +0 -244
  439. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-07.md +0 -77
  440. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-08_direction-change-v0.3.md +0 -44
  441. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-08_relay-v1-answers-ack.md +0 -37
  442. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-08_relay-v1-conformance.md +0 -56
  443. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_annotations-install-coldstart.md +0 -44
  444. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_empty-prompt-first-turn.md +0 -56
  445. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_prompt-mojibake-fixed.md +0 -48
  446. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_session-channel.md +0 -57
  447. package/core/dev/specs/agent-connect/history/PROTOCOL_v0.3_snapshot.md +0 -379
  448. package/core/dev/specs/agent-connect/history/README.md +0 -47
  449. package/core/dev/specs/peer/CODEX_INTERACTIVE_PUSH.md +0 -65
  450. package/core/dev/specs/peer/CODEX_MANAGED_DAEMON.md +0 -54
  451. package/core/dev/specs/peer/CODEX_PEER_PULL_SPIKE.md +0 -54
  452. package/core/dev/specs/peer/MODS_SPIKE.md +0 -133
  453. package/core/dev/specs/peer/PER_PROJECT_ADDRESSING.md +0 -143
  454. package/core/dev/specs/peer/SWARM_PROTOCOLS.md +0 -256
  455. package/core/dev/specs/peer/codex-hook-shim-peer.test.js +0 -113
  456. package/core/dev/specs/peer/codex-push-launcher.test.js +0 -142
  457. package/core/dev/specs/peer/setup-codex-hooks.test.js +0 -60
  458. package/core/dev/specs/peer-ansuz/DELIVERY_SPIKE.md +0 -397
  459. package/core/dev/specs/peer-ansuz/DESIGN.md +0 -109
  460. package/core/dev/specs/peer-ansuz/spike/claude_poke.js +0 -129
  461. package/core/dev/specs/peer-ansuz/spike/claude_session_start_hook.js +0 -37
  462. package/core/dev/specs/peer-ansuz/spike/claude_settings_hook.json +0 -14
  463. package/core/dev/specs/peer-ansuz/spike/codex_appserver_client.js +0 -105
  464. package/core/dev/specs/peer-ansuz/spike/codex_appserver_query.js +0 -29
  465. package/core/dev/specs/peer-ansuz/spike/extract_timeline.js +0 -26
  466. package/core/dev/specs/synapse/SYMBOL_IDENTITY.md +0 -305
  467. package/core/dev/spikes/A4-cypher-varlen.md +0 -176
  468. package/core/dev/spikes/bloat-rounds.sh +0 -25
  469. package/core/dev/spikes/mods/clean-claude.js +0 -9
  470. package/core/dev/spikes/mods/drive-probe.js +0 -29
  471. package/core/dev/spikes/mods/e2e-peer.js +0 -71
  472. package/core/dev/spikes/mods/evidence/e2e-peer-control.json +0 -17
  473. package/core/dev/spikes/mods/evidence/e2e-peer-mod.json +0 -17
  474. package/core/dev/spikes/mods/evidence/probe-006a6e65-d807-4bc1-b648-fd7d1edfe0b4.jsonl +0 -4
  475. package/core/dev/spikes/mods/evidence/probe-cebdf1f7-f9c4-47a8-83cd-7c0786177404.jsonl +0 -12
  476. package/core/dev/spikes/mods/evidence/probe-eb21147d-10ce-4c32-93ed-37ca37d88d5a.jsonl +0 -11
  477. package/core/dev/spikes/mods/evidence/stream-cebdf1f7.jsonl +0 -18
  478. package/core/dev/spikes/mods/kenaz-mod-probe/.claude-plugin/plugin.json +0 -1
  479. package/core/dev/spikes/mods/kenaz-mod-probe/hooks/hooks.json +0 -1
  480. package/core/dev/spikes/mods/kenaz-mod-probe/hooks/register.ts +0 -65
  481. package/core/dev/spikes/mods/kenaz-mod-probe/tsconfig.json +0 -3
@@ -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,97 @@
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
+ // plugins/kenaz/hooks/core-resolve.js is generated (gitignored) from .claude/hooks/core-resolve.js
38
+ const isGenerated = (rel) => rel === 'plugins/kenaz/hooks/core-resolve.js';
39
+
40
+ function matchParen(src, open) {
41
+ let depth = 0, q = null;
42
+ for (let i = open; i < src.length; i++) {
43
+ const c = src[i];
44
+ if (q) { if (c === '\\') i++; else if (c === q) q = null; continue; }
45
+ if (c === '"' || c === "'" || c === '`') { q = c; continue; }
46
+ if (c === '(') depth++;
47
+ else if (c === ')' && --depth === 0) return i;
48
+ }
49
+ return src.length;
50
+ }
51
+
52
+ function scanJs(rel, src) {
53
+ if (!/child_process/.test(src)) return [];
54
+ const bad = [];
55
+ // blank block comments and whole-line // comments (offsets and line numbers preserved)
56
+ src = src.replace(/\/\*[\s\S]*?\*\//g, (c) => c.replace(/[^\n]/g, ' ')).replace(/^[ \t]*\/\/.*$/gm, (c) => ' '.repeat(c.length));
57
+ const re = /(?<![\w$.])(?:(?:cp|child_process|childProcess|proc)\.)?(spawn|spawnSync|exec|execSync|execFile|execFileSync)\s*\(/g;
58
+ let m;
59
+ while ((m = re.exec(src))) {
60
+ const open = m.index + m[0].length - 1;
61
+ const args = src.slice(open, matchParen(src, open) + 1);
62
+ if (/windowsHide/.test(args)) continue;
63
+ // options passed as a bare identifier: accept when that identifier is defined with windowsHide in the file
64
+ const last = args.slice(1, -1).split(',').pop().trim();
65
+ if (/^[A-Za-z_$][\w$]*$/.test(last) && new RegExp(`${last}\\s*=\\s*\\{[^;]*windowsHide`).test(src)) continue;
66
+ const line = src.slice(0, m.index).split('\n').length;
67
+ if (JS_ALLOW[`${rel}:${line}`]) continue;
68
+ bad.push(`${rel}:${line} ${m[1]}`);
69
+ }
70
+ return bad;
71
+ }
72
+
73
+ function scanRs(rel, src) {
74
+ if (RS_ALLOW[rel]) return [];
75
+ const cut = src.search(/#\[cfg\(test\)\]/);
76
+ const body = cut >= 0 ? src.slice(0, cut) : src;
77
+ const bad = [];
78
+ body.split('\n').forEach((ln, i) => {
79
+ if (/^\s*\/\//.test(ln)) return;
80
+ if (/Command::new\s*\(/.test(ln) && !/hidden_/.test(ln)) bad.push(`${rel}:${i + 1}`);
81
+ });
82
+ return bad;
83
+ }
84
+
85
+ test('Node: every child_process call passes windowsHide', () => {
86
+ const files = JS_DIRS.flatMap((d) => walk(d, ['.js', '.cjs', '.mjs'])).filter((f) => !isGenerated(f));
87
+ const bad = files.flatMap((f) => scanJs(f, fs.readFileSync(path.join(ROOT, f), 'utf8')));
88
+ console.log(`node violations: ${bad.length}`);
89
+ assert.deepStrictEqual(bad, []);
90
+ });
91
+
92
+ test('Rust: no raw Command::new in production code outside common/process.rs', () => {
93
+ const files = walk(RS_DIR, ['.rs']).filter((f) => !/(^|\/)tests?\.rs$|_tests?\.rs$|\/tests\//.test(f));
94
+ const bad = files.flatMap((f) => scanRs(f, fs.readFileSync(path.join(ROOT, f), 'utf8')));
95
+ console.log(`rust violations: ${bad.length}`);
96
+ assert.deepStrictEqual(bad, []);
97
+ });
@@ -5,6 +5,8 @@ ARGUMENTS 含 `[專案: X]` 或 `--project-path X` → PROJECT_PATH = X,下方
5
5
 
6
6
  你是 **Ansuz**,Kenaz 的 orchestrator:理解需求,自己動手或拆卡派給 subagent,合併前在真實路徑上驗證,然後回報。先查現況、確認 scope,再動手。
7
7
 
8
+ 用戶貼上房間 key 或要求加入/建立房間時,自己執行 `kenaz ygg join <key>` / `kenaz ygg create`(不要請用戶輸入),再轉述 status 區塊與「restart Claude Code」提示。
9
+
8
10
  ## Boot(一次 Bash)
9
11
  1. Turn Context 有 `[session] session_id=<id>` 就記住 `<id>`。
10
12
  2. `node "${CLAUDE_PLUGIN_ROOT}/hooks/core-resolve.js" .specialist/tools/ansuz-boot-fast.js`(有 `<id>` 加 `--conversation-id="<id>"`;有 PROJECT_PATH 加 `--project-path`)。
@@ -1,5 +1,7 @@
1
1
  [Kenaz plugin: mode full] Kenaz MCP tools (kenaz-dashboard) are available when kenaz-server runs on localhost:18080.
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
+ - 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.
4
6
  - Reply in the user's language. Commands: /Ansuz, /Amelia, /review, /security, /incident, /spec.
5
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
  }
@@ -51,6 +51,15 @@
51
51
  }
52
52
  ]
53
53
  },
54
+ {
55
+ "matcher": "mcp__.*kenaz_peer_send|Bash",
56
+ "hooks": [
57
+ {
58
+ "type": "command",
59
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/kenaz-hook.js\" peer-session-fill"
60
+ }
61
+ ]
62
+ },
54
63
  {
55
64
  "matcher": "Agent|Task",
56
65
  "hooks": [
@@ -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
 
@@ -33,6 +34,7 @@ const HOOKS = {
33
34
  'synapse-first': { kind: 'script', file: 'synapse-first-investigation.js', minMode: 'full' },
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' },
37
+ 'peer-session-fill': { kind: 'script', file: 'peer-session-fill.js', call: 'main', minMode: 'assist' },
36
38
  'task-bridge': { kind: 'script', file: 'task-bridge.js', minMode: 'assist' },
37
39
  };
38
40
 
@@ -48,6 +50,42 @@ function backendUp(cb) {
48
50
  s.on('error', () => done(false));
49
51
  }
50
52
 
53
+ // TASK_2468: after a reboot nothing has started kenaz-server yet (the plugin MCP is a static http URL).
54
+ // Start the installed binary detached, the way the installer does; never by process name, and only
55
+ // called after the port probe failed (a second server is never started over an answering one).
56
+ function startServer(dir) {
57
+ try {
58
+ const home = os.homedir();
59
+ const meta = JSON.parse(fs.readFileSync(path.join(home, '.kenaz', 'install.json'), 'utf8'));
60
+ const bin = meta && meta.serverBin;
61
+ if (!bin || !fs.existsSync(bin)) return false;
62
+ const vbs = path.join(home, '.kenaz', 'kenaz-server.vbs');
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
+ child = fs.existsSync(vbs) ? spawn('wscript.exe', [vbs], opts) : viaNode ? spawn(process.execPath, [bin], opts) : spawn(bin, [], opts);
70
+ } else {
71
+ const log = path.join(home, '.kenaz', 'kenaz-server.log');
72
+ const sq = (v) => "'" + String(v).replace(/'/g, "'\\''") + "'";
73
+ const cmd = 'if command -v setsid >/dev/null 2>&1; then S=setsid; else S=; fi; $S nohup ' +
74
+ (viaNode ? sq(process.execPath) + ' ' : '') + sq(bin) + ' >> ' + sq(log) + ' 2>&1 < /dev/null &';
75
+ child = spawn('sh', ['-c', cmd], opts);
76
+ }
77
+ child.on('error', () => {});
78
+ child.unref();
79
+ return true;
80
+ } catch (_) { return false; }
81
+ }
82
+
83
+ function waitForBackend(ms, cb) {
84
+ const end = Date.now() + ms;
85
+ const tick = () => backendUp((ok) => { if (ok || Date.now() >= end) return cb(ok); setTimeout(tick, 150); });
86
+ tick();
87
+ }
88
+
51
89
  function post(body, cb) {
52
90
  const r = http.request({ hostname: HOST, port: PORT, path: '/api/rust/agent-flow/hook', method: 'POST',
53
91
  headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) }, timeout: 3000 },
@@ -74,7 +112,7 @@ function run(spec, stdin, dir) {
74
112
  const stdio = ['pipe', 'inherit', 'ignore'];
75
113
  if (spec.kind === 'core-script') {
76
114
  const target = path.join(core, spec.rel);
77
- if (fs.existsSync(target)) spawnSync(process.execPath, [target, ...(spec.args || [])], { cwd: dir, env, input: stdin, stdio, timeout: 10000 });
115
+ if (fs.existsSync(target)) spawnSync(process.execPath, [target, ...(spec.args || [])], { cwd: dir, env, input: stdin, stdio, timeout: 10000, windowsHide: true });
78
116
  return;
79
117
  }
80
118
  const file = path.join(core, '.claude', 'hooks', spec.file);
@@ -82,7 +120,7 @@ function run(spec, stdin, dir) {
82
120
  // Same shape as the core's own `node -e "chdir; require(hook)"` wrappers (require.main stays undefined).
83
121
  const code = 'process.chdir(process.env.CLAUDE_PROJECT_DIR);const m=require(process.argv[1]);' +
84
122
  (spec.call ? 'm[process.argv[2]]();' : '');
85
- spawnSync(process.execPath, ['-e', code, file, spec.call || ''], { cwd: dir, env, input: stdin, stdio, timeout: 10000 });
123
+ spawnSync(process.execPath, ['-e', code, file, spec.call || ''], { cwd: dir, env, input: stdin, stdio, timeout: 10000, windowsHide: true });
86
124
  }
87
125
 
88
126
  function main() {
@@ -104,7 +142,18 @@ function main() {
104
142
  }
105
143
  run(spec, stdin, dir);
106
144
  };
107
- if (spec.backend) backendUp((ok) => { if (ok) go(); }); else go();
145
+ if (!spec.backend) return go();
146
+ backendUp((ok) => {
147
+ if (ok) return go();
148
+ if (spec.kind !== 'session-start') return;
149
+ const finish = (up) => {
150
+ if (up) go();
151
+ process.stdout.write(up
152
+ ? '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'
153
+ : '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');
154
+ };
155
+ if (startServer(dir)) waitForBackend(3000, finish); else finish(false);
156
+ });
108
157
  }
109
158
 
110
159
  process.on('uncaughtException', () => process.exit(0));
@@ -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
+ });
@@ -5,6 +5,8 @@
5
5
  // /api/yggdrasil/config + /api/peer/status (same per-project/global key rules as the Dashboard,
6
6
  // TASK_2321/2349). k-cli `ygg` shells out to this file - the one implementation.
7
7
  const path = require('path');
8
+ const fs = require('fs');
9
+ const os = require('os');
8
10
 
9
11
  const BASE = () => 'http://127.0.0.1:' + (process.env.KENAZ_HTTP_PORT || process.env.KENAZ_BACKEND_PORT || '18080');
10
12
 
@@ -86,6 +88,33 @@ function buildStatus(cfg, relay, peer) {
86
88
  };
87
89
  }
88
90
 
91
+ // TASK_2461: push needs the kenaz-peer plugin loaded by Claude Code (only in Ansuz sessions). join/create
92
+ // leave the node ready: register kenaz-peer in ~/.claude/settings.json when missing (same writer as the
93
+ // installer). Returns {state: 'ok'|'added'|'missing'|'skipped'|'error', note}. Never throws.
94
+ function loadInstaller() {
95
+ for (const p of ['../../../dashboard/scripts/install-kenaz-cli.js', '../../../packages/kenaz/vendor/install-kenaz-cli.js']) {
96
+ try { return require(path.join(__dirname, p)); } catch (e) { if (e.code !== 'MODULE_NOT_FOUND') throw e; }
97
+ }
98
+ return null;
99
+ }
100
+ function peerPlugin(home, register, version) {
101
+ try {
102
+ const inst = loadInstaller();
103
+ if (!inst) return { state: 'skipped', note: 'installer not found' };
104
+ const settings = path.join(home, '.claude', 'settings.json');
105
+ if (!fs.existsSync(path.join(home, '.claude'))) return { state: 'skipped', note: 'claude is not installed' };
106
+ const ver = version === undefined ? inst.claudeVersion() : version;
107
+ if (ver && inst.cmpVersion(ver, inst.MIN_CLI) < 0) return { state: 'skipped', note: 'claude ' + ver.join('.') + ' < ' + inst.MIN_CLI.join('.') + ' (run `claude update`)' };
108
+ const core = path.resolve(process.env.KENAZ_CORE_DIR || path.join(__dirname, '..', '..', '..'));
109
+ const dir = path.join(core, 'plugins', 'kenaz-peer');
110
+ const list = inst.entriesOf(inst.loadSettings(settings));
111
+ if (list.some((e) => inst.norm(e) === inst.norm(dir))) return { state: 'ok', note: 'kenaz-peer plugin is registered' };
112
+ if (!register || !fs.existsSync(dir)) return { state: 'missing', note: 'kenaz-peer plugin is not registered in ' + settings + (fs.existsSync(dir) ? ' (run `kenaz ygg join <key>` or `kenaz install`)' : ' (run `npx kenaz@latest install`)') };
113
+ inst.registerPlugin(settings, dir, false);
114
+ return { state: 'added', note: 'registered the kenaz-peer plugin in ' + settings + '; restart Claude Code (new session) for it to load, then run /Ansuz for idle push' };
115
+ } catch (e) { return { state: 'error', note: 'could not check the kenaz-peer plugin: ' + e.message }; }
116
+ }
117
+
89
118
  function renderStatus(s) {
90
119
  const L = [
91
120
  'Yggdrasil room: ' + s.room,
@@ -102,14 +131,19 @@ function renderStatus(s) {
102
131
  'Last poll: ' + (s.last_poll_at ? s.last_poll_at + (s.last_poll_ok === false ? ' (FAILED)' : ' (ok)') : 'none yet'),
103
132
  'Delivery: ' + s.delivery_mode + (s.sessions.length ? '' : ' (no live sessions)'),
104
133
  ];
105
- for (const x of s.sessions) L.push(' - ' + x.agent + ' ' + String(x.session_id).slice(0, 8) + ': ' + x.delivery_mode);
134
+ for (const x of s.sessions) L.push(' ' + (x.name || x.agent) + ' (' + String(x.session_id).slice(0, 8) + ') - ' + x.delivery_mode);
106
135
  if (s.created) {
107
136
  L.push('', 'New team key (shown once, save it): ' + s.created.key + (s.created.team_name ? ' [' + s.created.team_name + ']' : ''));
108
137
  L.push('share with teammates: kenaz ygg join ' + s.created.key);
109
138
  }
110
139
  if (s.same_name_warning) L.push('WARNING: ' + s.same_name_warning);
111
140
  if (s.room_warning) L.push('WARNING: ' + s.room_warning);
112
- if (s.delivery_note) L.push('Note: ' + s.delivery_note);
141
+ const pl = s.plugin;
142
+ if (pl && ['added', 'missing', 'error'].includes(pl.state)) L.push('Push plugin: ' + pl.note);
143
+ // The server cannot know whether the plugin is registered; when this machine knows it is, do not repeat "register it".
144
+ const stale = pl && (pl.state === 'ok' || pl.state === 'added') && /register the kenaz-peer plugin|may not be registered/.test(s.delivery_note || '');
145
+ if (stale) L.push('Note: No push channel yet: the kenaz-peer plugin is registered but only serves Ansuz sessions. Run /Ansuz or /kenaz:Ansuz in this session' + (pl.state === 'added' ? ' after restarting Claude Code' : '') + ' for idle push; until then messages arrive on your next prompt.');
146
+ else if (s.delivery_note) L.push('Note: ' + s.delivery_note);
113
147
  return L.join('\n');
114
148
  }
115
149
 
@@ -200,7 +234,7 @@ async function leave(dir) {
200
234
  }
201
235
 
202
236
  async function main(argv) {
203
- const rest = []; let dir = process.env.CLAUDE_PROJECT_DIR || process.cwd(); let scope = 'project'; let json = false; let name = '';
237
+ const rest = []; let dir = process.env.CLAUDE_PROJECT_DIR || process.cwd(); let scope = 'project'; let json = false; let name = ''; let home = os.homedir();
204
238
  for (let i = 0; i < argv.length; i++) {
205
239
  const a = argv[i];
206
240
  if (a === '--project-path' && argv[i + 1]) dir = argv[++i];
@@ -208,6 +242,7 @@ async function main(argv) {
208
242
  else if (a === '--global') scope = 'global';
209
243
  else if (a === '--project') scope = 'project';
210
244
  else if (a === '--json') json = true;
245
+ else if (a === '--home' && argv[i + 1]) home = argv[++i];
211
246
  else if (a === '--name' && argv[i + 1]) name = argv[++i];
212
247
  else if (a.startsWith('--name=')) name = a.slice(7);
213
248
  else rest.push(a);
@@ -221,6 +256,7 @@ async function main(argv) {
221
256
  else if (sub === 'leave') s = await leave(dir);
222
257
  else if (sub === 'status') s = await status(dir);
223
258
  else throw new Error('unknown ygg subcommand: ' + sub + ' (join <key> | create [--name N] | status | leave)');
259
+ s.plugin = peerPlugin(path.resolve(home), sub === 'join' || sub === 'create');
224
260
  } catch (e) {
225
261
  console.error('ygg: ' + e.message + (/fetch failed|timeout|abort/i.test(e.message) ? ' (is the Kenaz backend running on ' + BASE() + '?)' : ''));
226
262
  process.exit(1);
@@ -228,5 +264,5 @@ async function main(argv) {
228
264
  console.log(json ? JSON.stringify(s, null, 2) : renderStatus(s));
229
265
  }
230
266
 
231
- module.exports = { nodeIsOnline, maskKey, buildStatus, renderStatus, join, createTeam };
267
+ module.exports = { peerPlugin, nodeIsOnline, maskKey, buildStatus, renderStatus, join, createTeam };
232
268
  if (require.main === module) main(process.argv.slice(2));
@@ -29,10 +29,10 @@ async function withBackend(persist, fn) {
29
29
  try { return await fn(srv.address().port); } finally { srv.close(); }
30
30
  }
31
31
 
32
- function cli(port, dir) {
32
+ function cli(port, dir, home = fs.mkdtempSync(path.join(os.tmpdir(), 'ygg-home-'))) { // never the real ~/.claude
33
33
  return new Promise((resolve) => {
34
- const c = spawn(process.execPath, [YGG, 'join', 'ygk_abc', '--project-path', dir],
35
- { env: Object.assign({}, process.env, { KENAZ_HTTP_PORT: String(port) }) });
34
+ const c = spawn(process.execPath, [YGG, 'join', 'ygk_abc', '--project-path', dir].concat(['--home', home]),
35
+ { env: Object.assign({}, process.env, { KENAZ_HTTP_PORT: String(port), KENAZ_CORE_DIR: CORE }) });
36
36
  let out = ''; let err = '';
37
37
  c.stdout.on('data', (d) => { out += d; }); c.stderr.on('data', (d) => { err += d; });
38
38
  c.on('close', (code) => resolve({ code, out, err }));
@@ -70,3 +70,63 @@ test('join refuses when the backend reports no effective_project_key (nothing to
70
70
  assert.match(r.err, /cannot work out this project's room/);
71
71
  } finally { srv.close(); }
72
72
  });
73
+
74
+ // TASK_2461: join leaves the node push-ready (kenaz-peer registered), touching only the --home it is given.
75
+ // a temp core: the checkout may itself be a .kenaz-worktrees path, which the installer refuses to register
76
+ const CORE = fs.mkdtempSync(path.join(os.tmpdir(), 'ygg2461-core-'));
77
+ const CORE_PEER = path.join(CORE, 'plugins', 'kenaz-peer');
78
+ fs.mkdirSync(CORE_PEER, { recursive: true });
79
+ function tempHome(settings) {
80
+ const home = fs.mkdtempSync(path.join(os.tmpdir(), 'ygg2461-'));
81
+ fs.mkdirSync(path.join(home, '.claude'));
82
+ const f = path.join(home, '.claude', 'settings.json');
83
+ fs.writeFileSync(f, settings);
84
+ return { home, f };
85
+ }
86
+
87
+ test('join registers a missing kenaz-peer in the temp settings.json, names the restart, and is idempotent', async () => {
88
+ const { home, f } = tempHome(JSON.stringify({ env: { CLAUDE_CODE_PLUGIN_DIRS: '/other/plugin' } }));
89
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'ygg2461-'));
90
+ await withBackend(true, async (port) => {
91
+ const r = await cli(port, dir, home);
92
+ assert.strictEqual(r.code, 0, r.err);
93
+ assert.ok(JSON.parse(fs.readFileSync(f, 'utf8')).env.CLAUDE_CODE_PLUGIN_DIRS.split(path.delimiter).includes(CORE_PEER));
94
+ assert.match(r.out, /restart Claude Code/);
95
+ const after = fs.readFileSync(f, 'utf8');
96
+ const r2 = await cli(port, dir, home);
97
+ assert.strictEqual(r2.code, 0, r2.err);
98
+ assert.strictEqual(fs.readFileSync(f, 'utf8'), after);
99
+ assert.doesNotMatch(r2.out, /restart Claude Code/);
100
+ });
101
+ });
102
+
103
+ test('join leaves settings.json byte-identical when kenaz-peer is already registered', async () => {
104
+ const txt = JSON.stringify({ env: { CLAUDE_CODE_PLUGIN_DIRS: CORE_PEER } });
105
+ const { home, f } = tempHome(txt);
106
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'ygg2461-'));
107
+ await withBackend(true, async (port) => {
108
+ const r = await cli(port, dir, home);
109
+ assert.strictEqual(r.code, 0, r.err);
110
+ assert.strictEqual(fs.readFileSync(f, 'utf8'), txt);
111
+ });
112
+ });
113
+
114
+ test('rendered status: registered but not Ansuz never says to register the plugin; unregistered says what to do', () => {
115
+ const { renderStatus, buildStatus } = require('./ygg.js');
116
+ const base = buildStatus({ effective_project_key: 'r', node_name: 'n', enabled: true, collaboration_projects: ['r'] }, { connected: true, nodes: [] },
117
+ { delivery_mode: 'pull-on-prompt', delivery_note: 'No push channel. No kenaz-peer plugin heartbeat seen: register the kenaz-peer plugin, then run /Ansuz' });
118
+ const ok = renderStatus(Object.assign({}, base, { plugin: { state: 'ok', note: 'x' } }));
119
+ assert.doesNotMatch(ok, /register the kenaz-peer plugin/);
120
+ assert.match(ok, /only serves Ansuz sessions/);
121
+ const miss = renderStatus(Object.assign({}, base, { plugin: { state: 'missing', note: 'kenaz-peer plugin is not registered in S (run `kenaz ygg join <key>` or `kenaz install`)' } }));
122
+ assert.match(miss, /Push plugin:.*not registered/);
123
+ });
124
+
125
+ test('TASK_2463: rendered status shows each session as name (short id) - mode', () => {
126
+ const { renderStatus, buildStatus } = require('./ygg.js');
127
+ const st = buildStatus({ effective_project_key: 'r', node_name: 'n', enabled: true, collaboration_projects: ['r'] }, { connected: true, nodes: [] },
128
+ { delivery_mode: 'push', sessions: [{ session_id: 'abcdef123456', agent: 'claude', name: 'my-work', delivery_mode: 'push' }, { session_id: 'zzzzzzzz9999', agent: 'codex', delivery_mode: 'pull-on-prompt' }] });
129
+ const out = renderStatus(st);
130
+ assert.match(out, /^ {2}my-work \(abcdef12\) - push$/m);
131
+ assert.match(out, /^ {2}codex \(zzzzzzzz\) - pull-on-prompt$/m);
132
+ });
@@ -2,14 +2,17 @@ import { test, expect, mock } from 'claude-code/testing'
2
2
 
3
3
  const msg = { id: 'm1', framed: '[Peer message] hello' }
4
4
 
5
- function setup(on: any, rows: () => unknown[]) {
5
+ function setup(on: any, rows: () => unknown[], marker?: () => string | null) {
6
6
  const calls: string[] = []
7
7
  let delivered = false
8
8
  on('session.start', async (_$: any, e: any) => ({ cwd: e.cwd }))
9
9
  on('session.id', async () => ({ value: 'sess-1' }))
10
10
  on('session.cwd', async () => ({ value: '/tmp/proj' }))
11
11
  on('session.messages', async () => ({ value: rows() }))
12
- on('fs.read', async () => ({ deny: 'no pin' }))
12
+ on('fs.read', async (_$: any, e: any) => {
13
+ const m = marker?.()
14
+ return String(e.path ?? e.file ?? '').endsWith('/sess-1.json') && m ? { value: m } : { deny: 'no pin' }
15
+ })
13
16
  on('http.fetch', async (_$: any, e: any) => {
14
17
  const url = String(e.url)
15
18
  calls.push(`${e.init?.method ?? 'GET'} ${url}`)
@@ -144,3 +147,57 @@ test('plugin-namespaced /kenaz:Ansuz also activates delivery', async ($, on) =>
144
147
  expect(calls[0]).toContain('POST http://127.0.0.1:18080/api/peer/mod-heartbeat')
145
148
  expect(submits.length).toBe(1)
146
149
  })
150
+
151
+ // TASK_2465: collaboration opt-in (marker written by peer-session-fill.js, or KENAZ_PEER_OPTIN=1 from kenaz launch).
152
+ const PLAIN = [{ role: 'user', content: 'hello there' }]
153
+ const MARKER_ENV = { CLAUDE_CODE_ENTRYPOINT: 'cli', KENAZ_PEER_OPTIN_DIR: '/m' }
154
+
155
+ test('TASK_2465 privacy: plain session without opt-in never heartbeats, peeks or submits', async ($, on) => {
156
+ const clock = mock.clock(on)
157
+ mock.env(on, MARKER_ENV)
158
+ const { calls, submits } = setup(on, () => PLAIN, () => null)
159
+ await $.session.start(START)
160
+ await clock.advance(15_000)
161
+ expect(calls.length).toBe(0)
162
+ expect(submits.length).toBe(0)
163
+ })
164
+
165
+ test('TASK_2465: opt-in marker makes a plain session heartbeat and receive push', async ($, on) => {
166
+ const clock = mock.clock(on)
167
+ mock.env(on, MARKER_ENV)
168
+ const { calls, submits } = setup(on, () => PLAIN, () => JSON.stringify({ ts: Date.now() }))
169
+ await $.session.start(START)
170
+ await clock.advance(5_000)
171
+ await clock.advance(5_000)
172
+ expect(calls[0]).toContain('POST http://127.0.0.1:18080/api/peer/mod-heartbeat')
173
+ expect(submits.length).toBe(1)
174
+ })
175
+
176
+ test('TASK_2465: an expired marker is not an opt-in', async ($, on) => {
177
+ const clock = mock.clock(on)
178
+ mock.env(on, MARKER_ENV)
179
+ const { calls, submits } = setup(on, () => PLAIN, () => JSON.stringify({ ts: Date.now() - 25 * 3600 * 1000 }))
180
+ await $.session.start(START)
181
+ await clock.advance(15_000)
182
+ expect(calls.length).toBe(0)
183
+ expect(submits.length).toBe(0)
184
+ })
185
+
186
+ test('TASK_2465: KENAZ_PEER_OPTIN=1 does not opt in a claude -p worker (sdk-cli)', async ($, on) => {
187
+ const clock = mock.clock(on)
188
+ mock.env(on, { CLAUDE_CODE_ENTRYPOINT: 'sdk-cli', KENAZ_PEER_OPTIN: '1' })
189
+ const { calls } = setup(on, () => PLAIN)
190
+ await $.session.start(START)
191
+ await clock.advance(15_000)
192
+ expect(calls.length).toBe(0)
193
+ })
194
+
195
+ test('TASK_2465: KENAZ_PEER_OPTIN=1 (kenaz launch) opts a plain session in', async ($, on) => {
196
+ const clock = mock.clock(on)
197
+ mock.env(on, { CLAUDE_CODE_ENTRYPOINT: 'cli', KENAZ_PEER_OPTIN: '1' })
198
+ const { calls } = setup(on, () => PLAIN)
199
+ await $.session.start(START)
200
+ await clock.advance(5_000)
201
+ await clock.advance(5_000)
202
+ expect(calls[0]).toContain('POST http://127.0.0.1:18080/api/peer/mod-heartbeat')
203
+ })