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