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
@@ -1,1344 +0,0 @@
1
- #!/usr/bin/env bash
2
- # ============================================================
3
- # Multi-Agent Parallel Scheduler (macOS/Linux version)
4
- # ============================================================
5
- # Equivalent of multi_agent_scheduler.ps1
6
- # Compatible with bash 3.2+ (macOS default)
7
- #
8
- # Launches multiple Claude Agents in parallel for task execution
9
- # - Auto-assigns non-conflicting tasks to multiple agents
10
- # - Uses path locking to prevent conflicts
11
- # - Each agent works on an independent branch
12
- # ============================================================
13
-
14
- set -uo pipefail
15
-
16
- # --- Default Parameters ---
17
- MAX_AGENTS=3
18
- POLL_INTERVAL=30
19
- TASK_TIMEOUT=60
20
- DRY_RUN=false
21
- SINGLE_RUN=false
22
- WORKING_DIRECTORY=""
23
- STANDALONE=false
24
-
25
- # --- Parse Arguments ---
26
- while [ $# -gt 0 ]; do
27
- case "$1" in
28
- --max-agents) MAX_AGENTS="$2"; shift 2 ;;
29
- --poll-interval) POLL_INTERVAL="$2"; shift 2 ;;
30
- --task-timeout) TASK_TIMEOUT="$2"; shift 2 ;;
31
- --dry-run) DRY_RUN=true; shift ;;
32
- --single-run) SINGLE_RUN=true; shift ;;
33
- --working-directory|--wd) WORKING_DIRECTORY="$2"; shift 2 ;;
34
- --standalone|-s) STANDALONE=true; shift ;;
35
- --nopause) shift ;;
36
- *) shift ;;
37
- esac
38
- done
39
-
40
- # Use KENAZ_PROJECT_PATH env var if WorkingDirectory not specified
41
- if [ -z "$WORKING_DIRECTORY" ]; then
42
- if [ -n "${KENAZ_PROJECT_PATH:-}" ]; then
43
- WORKING_DIRECTORY="$KENAZ_PROJECT_PATH"
44
- else
45
- WORKING_DIRECTORY="$(pwd)"
46
- fi
47
- fi
48
-
49
- # --- File Paths ---
50
- LOG_DIR="$WORKING_DIRECTORY/dev/pipeline/logs"
51
- LOG_FILE="$LOG_DIR/multi_agent_$(date +%Y-%m-%d).log"
52
- TASK_QUEUE_FILE="$WORKING_DIRECTORY/dev/pipeline/TASK_QUEUE.json"
53
- LOCK_STATE_FILE="$WORKING_DIRECTORY/dev/pipeline/LOCK_STATE.json"
54
- AGENT_STATE_FILE="$WORKING_DIRECTORY/dev/pipeline/AGENT_STATE.json"
55
- HEARTBEAT_FILE="$WORKING_DIRECTORY/dev/pipeline/DASHBOARD_HEARTBEAT.json"
56
- STARTUP_LOG="$WORKING_DIRECTORY/multi_agent_startup.log"
57
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
58
-
59
- # Ensure log directory exists
60
- mkdir -p "$LOG_DIR"
61
-
62
- # --- Agent tracking via temp directory (bash 3.2 compatible) ---
63
- # Each agent gets a directory: $TRACKER_DIR/<agent_id>/
64
- # With files: pid, task_id, branch, start_time, log_file, agent_type
65
- TRACKER_DIR=$(mktemp -d /tmp/kenaz_agents.XXXXXX)
66
-
67
- get_active_agent_ids() {
68
- # List all tracked agent IDs
69
- if [ -d "$TRACKER_DIR" ]; then
70
- ls "$TRACKER_DIR" 2>/dev/null || true
71
- fi
72
- }
73
-
74
- get_active_count() {
75
- local count=0
76
- for d in "$TRACKER_DIR"/*/; do
77
- [ -d "$d" ] && count=$((count + 1))
78
- done
79
- echo "$count"
80
- }
81
-
82
- track_agent() {
83
- local agent_id="$1" pid="$2" task_id="$3" branch="$4" agent_type="$5" log_file="$6" task_title="${7:-}"
84
- local dir="$TRACKER_DIR/$agent_id"
85
- mkdir -p "$dir"
86
- echo "$pid" > "$dir/pid"
87
- echo "$task_id" > "$dir/task_id"
88
- echo "$branch" > "$dir/branch"
89
- echo "$(date +%s)" > "$dir/start_time"
90
- echo "$log_file" > "$dir/log_file"
91
- echo "$agent_type" > "$dir/agent_type"
92
- echo "$task_title" > "$dir/task_title"
93
- }
94
-
95
- untrack_agent() {
96
- local agent_id="$1"
97
- rm -rf "$TRACKER_DIR/$agent_id"
98
- }
99
-
100
- agent_get() {
101
- local agent_id="$1" field="$2"
102
- cat "$TRACKER_DIR/$agent_id/$field" 2>/dev/null || echo ""
103
- }
104
-
105
- is_task_running() {
106
- local task_id="$1"
107
- for d in "$TRACKER_DIR"/*/; do
108
- [ -d "$d" ] || continue
109
- local running_task
110
- running_task=$(cat "$d/task_id" 2>/dev/null || echo "")
111
- if [ "$running_task" = "$task_id" ]; then
112
- return 0
113
- fi
114
- done
115
- return 1
116
- }
117
-
118
- # ============================================================
119
- # Utility Functions
120
- # ============================================================
121
-
122
- log_msg() {
123
- local msg="$1"
124
- local level="${2:-INFO}"
125
- local timestamp
126
- timestamp=$(date "+%Y-%m-%d %H:%M:%S")
127
- local log_line="[$timestamp] [$level] $msg"
128
-
129
- case "$level" in
130
- ERROR) printf '\033[31m%s\033[0m\n' "$log_line" ;;
131
- WARN) printf '\033[33m%s\033[0m\n' "$log_line" ;;
132
- SUCCESS) printf '\033[32m%s\033[0m\n' "$log_line" ;;
133
- *) echo "$log_line" ;;
134
- esac
135
-
136
- echo "$log_line" >> "$LOG_FILE" 2>/dev/null || true
137
- }
138
-
139
- debug_log() {
140
- local timestamp
141
- timestamp=$(date "+%Y-%m-%d %H:%M:%S")
142
- echo "[$timestamp] [${2:-INFO}] $1" >> "$STARTUP_LOG" 2>/dev/null || true
143
- }
144
-
145
- # ============================================================
146
- # Agent Type Detection
147
- # ============================================================
148
-
149
- get_agent_type() {
150
- local task_title="$1"
151
- local explicit_type="${2:-}"
152
-
153
- if [ -n "$explicit_type" ]; then
154
- echo "$explicit_type"
155
- return
156
- fi
157
-
158
- local title_lower
159
- title_lower=$(echo "$task_title" | tr '[:upper:]' '[:lower:]')
160
-
161
- # Keyword matching
162
- for kw in ui ux layout style design css theme color visual icon; do
163
- case "$title_lower" in *"$kw"*) echo "designer"; return ;; esac
164
- done
165
- for kw in api database backend endpoint server sql migration supabase postgres; do
166
- case "$title_lower" in *"$kw"*) echo "backend"; return ;; esac
167
- done
168
- for kw in test qa quality e2e spec coverage; do
169
- case "$title_lower" in *"$kw"*) echo "qa"; return ;; esac
170
- done
171
- for kw in deploy ci/cd monitoring infrastructure docker kubernetes devops; do
172
- case "$title_lower" in *"$kw"*) echo "sre"; return ;; esac
173
- done
174
- for kw in component react frontend tsx jsx hook state page dashboard; do
175
- case "$title_lower" in *"$kw"*) echo "developer"; return ;; esac
176
- done
177
-
178
- echo "dev"
179
- }
180
-
181
- get_display_name() {
182
- case "$1" in
183
- developer) echo "Frontend Developer" ;;
184
- backend) echo "Backend Engineer" ;;
185
- designer) echo "UI/UX Designer" ;;
186
- qa) echo "QA Engineer" ;;
187
- sre) echo "SRE Agent" ;;
188
- frontend) echo "Frontend Agent" ;;
189
- architect) echo "Architect" ;;
190
- *) echo "Dev Agent" ;;
191
- esac
192
- }
193
-
194
- get_dashboard_type() {
195
- case "$1" in
196
- developer) echo "developer" ;;
197
- backend) echo "backend_engineer" ;;
198
- designer) echo "designer" ;;
199
- qa) echo "qa_engineer" ;;
200
- sre) echo "sre_agent" ;;
201
- frontend) echo "frontend_agent" ;;
202
- architect) echo "architect_agent" ;;
203
- *) echo "dev_agent" ;;
204
- esac
205
- }
206
-
207
- # ============================================================
208
- # State Management (via Python for reliable JSON ops)
209
- # ============================================================
210
-
211
- save_lock_state() {
212
- local content="$1"
213
- python3 -c "
214
- import json
215
- from datetime import datetime
216
- data = json.loads(r'''$content''')
217
- data['last_updated'] = datetime.now().isoformat()
218
- with open('$LOCK_STATE_FILE', 'w', encoding='utf-8') as f:
219
- json.dump(data, f, indent=2, ensure_ascii=False)
220
- " 2>/dev/null || true
221
- }
222
-
223
- save_agent_state() {
224
- local content="$1"
225
- python3 -c "
226
- import json
227
- from datetime import datetime
228
- data = json.loads(r'''$content''')
229
- data['last_updated'] = datetime.now().isoformat()
230
- with open('$AGENT_STATE_FILE', 'w', encoding='utf-8') as f:
231
- json.dump(data, f, indent=2, ensure_ascii=False)
232
- " 2>/dev/null || true
233
- }
234
-
235
- add_agent_to_state() {
236
- local agent_id="$1"
237
- local task_id="$2"
238
- local task_title="$3"
239
- local branch="$4"
240
- local agent_type="$5"
241
- local dashboard_type
242
- dashboard_type=$(get_dashboard_type "$agent_type")
243
-
244
- python3 << PYEOF
245
- import json
246
- from datetime import datetime
247
-
248
- state_file = '$AGENT_STATE_FILE'
249
- try:
250
- with open(state_file, 'r', encoding='utf-8') as f:
251
- state = json.load(f)
252
- except (FileNotFoundError, json.JSONDecodeError):
253
- state = {'agents': []}
254
-
255
- state['agents'] = [a for a in state.get('agents', []) if a.get('id') != '$agent_id']
256
- state['agents'].append({
257
- 'id': '$agent_id',
258
- 'type': '$dashboard_type',
259
- 'status': 'working',
260
- 'current_task': '$task_id',
261
- 'current_operation': $(python3 -c "import json; print(json.dumps('$task_title'))"),
262
- 'branch': '$branch',
263
- 'started_at': datetime.now().isoformat(),
264
- 'task_id': '$task_id',
265
- 'task_title': $(python3 -c "import json; print(json.dumps('$task_title'))"),
266
- })
267
- state['last_updated'] = datetime.now().isoformat()
268
-
269
- with open(state_file, 'w', encoding='utf-8') as f:
270
- json.dump(state, f, indent=2, ensure_ascii=False)
271
- PYEOF
272
-
273
- local display_name
274
- display_name=$(get_display_name "$agent_type")
275
- log_msg "Added agent $agent_id ($display_name) to AGENT_STATE.json (task: $task_id)"
276
- }
277
-
278
- remove_agent_from_state() {
279
- local agent_id="$1"
280
- python3 -c "
281
- import json
282
- from datetime import datetime
283
- try:
284
- with open('$AGENT_STATE_FILE', 'r', encoding='utf-8') as f:
285
- state = json.load(f)
286
- state['agents'] = [a for a in state.get('agents', []) if a.get('id') != '$agent_id']
287
- state['last_updated'] = datetime.now().isoformat()
288
- with open('$AGENT_STATE_FILE', 'w', encoding='utf-8') as f:
289
- json.dump(state, f, indent=2, ensure_ascii=False)
290
- except Exception:
291
- pass
292
- " 2>/dev/null || true
293
- log_msg "Removed agent $agent_id from AGENT_STATE.json"
294
- }
295
-
296
- # ============================================================
297
- # Lock Management
298
- # ============================================================
299
-
300
- add_path_locks() {
301
- local agent_id="$1"
302
- local task_id="$2"
303
- shift 2
304
- # Remaining args are paths, build a JSON array
305
- local paths_json
306
- paths_json=$(python3 -c "import json,sys; print(json.dumps(sys.argv[1:]))" "$@")
307
-
308
- python3 << PYEOF
309
- import json
310
- from datetime import datetime
311
-
312
- lock_file = '$LOCK_STATE_FILE'
313
- try:
314
- with open(lock_file, 'r', encoding='utf-8') as f:
315
- state = json.load(f)
316
- except (FileNotFoundError, json.JSONDecodeError):
317
- state = {'locks': []}
318
-
319
- paths = json.loads('$paths_json')
320
- for path in paths:
321
- state['locks'].append({
322
- 'path': path,
323
- 'agent_id': '$agent_id',
324
- 'task_id': '$task_id',
325
- 'lock_type': 'directory' if path.endswith('/') else 'file',
326
- 'acquired_at': datetime.now().isoformat(),
327
- })
328
-
329
- state['last_updated'] = datetime.now().isoformat()
330
- with open(lock_file, 'w', encoding='utf-8') as f:
331
- json.dump(state, f, indent=2, ensure_ascii=False)
332
- PYEOF
333
- log_msg "Acquired locks for $agent_id on $# paths"
334
- }
335
-
336
- remove_agent_locks() {
337
- local agent_id="$1"
338
- python3 -c "
339
- import json
340
- from datetime import datetime
341
- try:
342
- with open('$LOCK_STATE_FILE', 'r', encoding='utf-8') as f:
343
- state = json.load(f)
344
- state['locks'] = [l for l in state.get('locks', []) if l.get('agent_id') != '$agent_id']
345
- state['last_updated'] = datetime.now().isoformat()
346
- with open('$LOCK_STATE_FILE', 'w', encoding='utf-8') as f:
347
- json.dump(state, f, indent=2, ensure_ascii=False)
348
- except Exception:
349
- pass
350
- " 2>/dev/null || true
351
- log_msg "Released locks for $agent_id"
352
- }
353
-
354
- # ============================================================
355
- # Task Queue Operations
356
- # ============================================================
357
-
358
- update_task_status() {
359
- local task_id="$1"
360
- local status="$2"
361
- local agent_id="${3:-}"
362
- local branch="${4:-}"
363
-
364
- python3 << PYEOF
365
- import json
366
- from datetime import datetime
367
-
368
- try:
369
- with open('$TASK_QUEUE_FILE', 'r', encoding='utf-8') as f:
370
- queue = json.load(f)
371
- except (FileNotFoundError, json.JSONDecodeError):
372
- exit(0)
373
-
374
- for task in queue.get('tasks', []):
375
- if task['id'] == '$task_id':
376
- task['status'] = '$status'
377
- if '$status' == 'in_progress':
378
- task['started_at'] = datetime.now().isoformat()
379
- if '$agent_id':
380
- task['assigned_agent'] = '$agent_id'
381
- if '$branch':
382
- task['branch'] = '$branch'
383
- task.pop('resume_branch', None)
384
- elif '$status' == 'completed':
385
- task['completed_at'] = datetime.now().isoformat()
386
- break
387
-
388
- queue['last_updated'] = datetime.now().isoformat()
389
- with open('$TASK_QUEUE_FILE', 'w', encoding='utf-8') as f:
390
- json.dump(queue, f, indent=2, ensure_ascii=False)
391
- PYEOF
392
- }
393
-
394
- move_task_to_completed() {
395
- local task_id="$1"
396
- local tasks_dir="$WORKING_DIRECTORY/dev/pipeline/tasks"
397
- local completed_dir="$WORKING_DIRECTORY/dev/pipeline/completed"
398
-
399
- mkdir -p "$completed_dir"
400
-
401
- # Move task file
402
- for f in "$tasks_dir"/${task_id}_*.yaml "$tasks_dir"/${task_id}_*.yml "$tasks_dir"/${task_id}_*.md; do
403
- if [ -f "$f" ]; then
404
- mv "$f" "$completed_dir/"
405
- log_msg "Moved task file to completed: $(basename "$f")"
406
- break
407
- fi
408
- done
409
-
410
- # Remove from TASK_QUEUE.json
411
- python3 << PYEOF
412
- import json
413
- from datetime import datetime
414
-
415
- try:
416
- with open('$TASK_QUEUE_FILE', 'r', encoding='utf-8') as f:
417
- queue = json.load(f)
418
-
419
- before = len(queue.get('tasks', []))
420
- queue['tasks'] = [t for t in queue['tasks'] if t['id'] != '$task_id']
421
- after = len(queue['tasks'])
422
-
423
- if before != after:
424
- stats = queue.get('statistics', {})
425
- stats['total'] = len(queue['tasks'])
426
- stats['pending'] = sum(1 for t in queue['tasks'] if t.get('status') == 'pending')
427
- stats['in_progress'] = sum(1 for t in queue['tasks'] if t.get('status') == 'in_progress')
428
- stats['blocked'] = sum(1 for t in queue['tasks'] if t.get('status') == 'blocked')
429
- stats['completed'] = 0
430
- stats['cancelled'] = sum(1 for t in queue['tasks'] if t.get('status') == 'cancelled')
431
- queue['statistics'] = stats
432
- queue['last_updated'] = datetime.now().isoformat()
433
-
434
- with open('$TASK_QUEUE_FILE', 'w', encoding='utf-8') as f:
435
- json.dump(queue, f, indent=2, ensure_ascii=False)
436
- except Exception:
437
- pass
438
- PYEOF
439
- log_msg "Removed $task_id from TASK_QUEUE.json"
440
- }
441
-
442
- # ============================================================
443
- # Progress File Update (ported from PowerShell Update-ProgressFile)
444
- # ============================================================
445
-
446
- update_progress_file() {
447
- local task_id="$1"
448
- local task_title="$2"
449
- local action="$3"
450
- local progress_file="$WORKING_DIRECTORY/dev/pipeline/PROGRESS.md"
451
-
452
- [ -f "$progress_file" ] || return 0
453
-
454
- TASK_QUEUE_FILE="$TASK_QUEUE_FILE" python3 << PYEOF "$progress_file" "$task_id" "$task_title" "$action"
455
- import re, os, json, sys
456
- from datetime import datetime
457
-
458
- progress_file = sys.argv[1]
459
- task_id = sys.argv[2]
460
- task_title = sys.argv[3]
461
- action = sys.argv[4]
462
-
463
- try:
464
- with open(progress_file, 'r', encoding='utf-8') as f:
465
- content = f.read()
466
- except Exception:
467
- sys.exit(0)
468
-
469
- timestamp = datetime.now().strftime('%Y-%m-%d %H:%M')
470
-
471
- # Update Last Update section
472
- content = re.sub(r'(## Last Update\n-.*?Time.*?:)[^\n]*', rf'\1 {timestamp}', content)
473
- content = re.sub(r'(## Last Update\n.*?Agent.*?:)[^\n]*', r'\1 Multi-Agent Scheduler', content)
474
- content = re.sub(r'(## Last Update\n.*?Session.*?:)[^\n]*', rf'\1 {task_id} {action}', content)
475
-
476
- # Update statistics from current queue
477
- queue_file = os.environ.get('TASK_QUEUE_FILE', '')
478
- try:
479
- with open(queue_file, 'r', encoding='utf-8') as f:
480
- queue = json.load(f)
481
- tasks = queue.get('tasks', [])
482
- total = len(tasks)
483
- completed = sum(1 for t in tasks if t.get('status') == 'completed')
484
- in_progress = sum(1 for t in tasks if t.get('status') == 'in_progress')
485
- pending = sum(1 for t in tasks if t.get('status') == 'pending')
486
- blocked = sum(1 for t in tasks if t.get('status') == 'blocked')
487
-
488
- # Also count completed/ directory
489
- completed_dir = os.path.join(os.path.dirname(queue_file), 'completed')
490
- if os.path.isdir(completed_dir):
491
- completed += sum(1 for f in os.listdir(completed_dir) if re.match(r'TASK_\d+', f))
492
- total += sum(1 for f in os.listdir(completed_dir) if re.match(r'TASK_\d+', f))
493
-
494
- c_pct = round(completed / total * 100) if total > 0 else 0
495
- i_pct = round(in_progress / total * 100) if total > 0 else 0
496
- p_pct = round(pending / total * 100) if total > 0 else 0
497
- b_pct = round(blocked / total * 100) if total > 0 else 0
498
-
499
- stats_block = f"""Total Tasks: {total}
500
- Completed: {completed} ({c_pct}%)
501
- In Progress: {in_progress} ({i_pct}%)
502
- Pending: {pending} ({p_pct}%)
503
- Blocked: {blocked} ({b_pct}%)"""
504
-
505
- content = re.sub(
506
- r'(### Overall Progress\n```\n).*?(```)',
507
- rf'\1{stats_block}\n\2',
508
- content,
509
- flags=re.DOTALL
510
- )
511
- except Exception:
512
- pass
513
-
514
- # Add to change history
515
- date_str = datetime.now().strftime('%Y-%m-%d')
516
- history_entry = f"| {date_str} | {action} | {task_id} - {task_title} |"
517
- # Insert after the header row of the history table
518
- content = re.sub(
519
- r'(\| Date \| Action \| Details \|\n\|[-| ]+\|)\n',
520
- rf'\1\n{history_entry}\n',
521
- content
522
- )
523
-
524
- with open(progress_file, 'w', encoding='utf-8') as f:
525
- f.write(content)
526
- PYEOF
527
-
528
- log_msg "Updated PROGRESS.md ($task_id: $action)"
529
- }
530
-
531
- # Get ready tasks (pending, deps met, sorted by priority) — outputs JSON lines
532
- get_ready_tasks() {
533
- TASK_QUEUE_FILE="$TASK_QUEUE_FILE" WORKING_DIRECTORY="$WORKING_DIRECTORY" python3 << 'PYEOF'
534
- import json, os, re, sys
535
-
536
- queue_file = os.environ.get('TASK_QUEUE_FILE', '')
537
- working_dir = os.environ.get('WORKING_DIRECTORY', '')
538
-
539
- try:
540
- with open(queue_file, 'r', encoding='utf-8') as f:
541
- queue = json.load(f)
542
- except (FileNotFoundError, json.JSONDecodeError):
543
- sys.exit(0)
544
-
545
- completed_ids = set()
546
- for task in queue.get('tasks', []):
547
- if task.get('status') == 'completed':
548
- completed_ids.add(task['id'])
549
-
550
- completed_dir = os.path.join(working_dir, 'dev/pipeline/completed')
551
- if os.path.isdir(completed_dir):
552
- for f in os.listdir(completed_dir):
553
- m = re.match(r'^(TASK_\d+)', f)
554
- if m:
555
- completed_ids.add(m.group(1))
556
-
557
- ready = []
558
- for task in queue.get('tasks', []):
559
- if task.get('status') != 'pending':
560
- continue
561
- deps = task.get('dependencies', [])
562
- if all(d in completed_ids for d in deps):
563
- ready.append(task)
564
-
565
- priority_order = {'P0': 0, 'P1': 1, 'P2': 2, 'P3': 3}
566
- ready.sort(key=lambda t: priority_order.get(t.get('priority', 'P2'), 2))
567
-
568
- for task in ready:
569
- print(json.dumps(task))
570
- PYEOF
571
- }
572
-
573
- # Check path conflict against current locks
574
- check_path_conflict() {
575
- local scope_paths_json="$1"
576
- python3 -c "
577
- import json, sys
578
-
579
- try:
580
- with open('$LOCK_STATE_FILE', 'r', encoding='utf-8') as f:
581
- state = json.load(f)
582
- except (FileNotFoundError, json.JSONDecodeError):
583
- print('NO_CONFLICT')
584
- sys.exit(0)
585
-
586
- requested = json.loads('''$scope_paths_json''')
587
- locks = state.get('locks', [])
588
-
589
- for req_path in requested:
590
- for lock in locks:
591
- lock_path = lock.get('path', '')
592
- if req_path.startswith(lock_path) or lock_path.startswith(req_path) or req_path == lock_path:
593
- print(f\"CONFLICT:{lock.get('agent_id', '')}:{lock_path}:{lock.get('task_id', '')}\")
594
- sys.exit(0)
595
-
596
- print('NO_CONFLICT')
597
- " 2>/dev/null || echo "NO_CONFLICT"
598
- }
599
-
600
- # ============================================================
601
- # Heartbeat Check
602
- # ============================================================
603
-
604
- check_heartbeat() {
605
- if [ "$STANDALONE" = "true" ]; then
606
- echo "ALIVE"
607
- return
608
- fi
609
-
610
- if [ ! -f "$HEARTBEAT_FILE" ]; then
611
- echo "ALIVE"
612
- return
613
- fi
614
-
615
- python3 -c "
616
- import json, sys
617
- from datetime import datetime
618
-
619
- try:
620
- with open('$HEARTBEAT_FILE', 'r', encoding='utf-8') as f:
621
- hb = json.load(f)
622
-
623
- if hb.get('status') == 'closing':
624
- print('CLOSING')
625
- sys.exit(0)
626
-
627
- if hb.get('timestamp'):
628
- ts = hb['timestamp']
629
- # Handle various ISO format variants
630
- for fmt in ['%Y-%m-%dT%H:%M:%S.%f', '%Y-%m-%dT%H:%M:%S', '%Y-%m-%dT%H:%M:%S%z']:
631
- try:
632
- last = datetime.strptime(ts.split('+')[0].split('Z')[0], fmt.replace('%z',''))
633
- break
634
- except ValueError:
635
- continue
636
- else:
637
- print('ALIVE')
638
- sys.exit(0)
639
- elapsed = (datetime.now() - last).total_seconds()
640
- if elapsed > 120:
641
- print(f'TIMEOUT:{int(elapsed)}')
642
- sys.exit(0)
643
-
644
- print('ALIVE')
645
- except Exception:
646
- print('ALIVE')
647
- " 2>/dev/null || echo "ALIVE"
648
- }
649
-
650
- # ============================================================
651
- # Agent Success Detection
652
- # ============================================================
653
-
654
- test_agent_success() {
655
- local exit_code="$1"
656
- local log_file="$2"
657
- local branch="$3"
658
- local task_id="$4"
659
-
660
- # Exit code 0 = always success
661
- if [ "$exit_code" = "0" ]; then
662
- echo "SUCCESS:Exit code 0"
663
- return
664
- fi
665
-
666
- # Check for commits in branch
667
- if [ -n "$branch" ]; then
668
- local commits_ahead="0"
669
- if cd "$WORKING_DIRECTORY" 2>/dev/null; then
670
- if git rev-parse --verify "$branch" >/dev/null 2>&1; then
671
- local main_branch="main"
672
- git rev-parse --verify main >/dev/null 2>&1 || main_branch="master"
673
- commits_ahead=$(git rev-list --count "${main_branch}..${branch}" 2>/dev/null || echo "0")
674
- if [ "$commits_ahead" -gt 0 ] 2>/dev/null; then
675
- local commit_msgs
676
- commit_msgs=$(git log --oneline "${main_branch}..${branch}" 2>/dev/null || echo "")
677
- if echo "$commit_msgs" | grep -q "$task_id"; then
678
- echo "SUCCESS:Branch has $commits_ahead commit(s) with $task_id"
679
- return
680
- fi
681
- fi
682
- fi
683
- fi
684
- fi
685
-
686
- # Check log file for success patterns
687
- if [ -n "$log_file" ] && [ -f "$log_file" ]; then
688
- if grep -qE "Status:\s*SUCCESS|completed\s+successfully|\[SUCCESS\].*completed" "$log_file" 2>/dev/null; then
689
- echo "SUCCESS:Log matches success pattern"
690
- return
691
- fi
692
- if grep -qE "FATAL\s+ERROR|Build\s+failed|Compilation\s+error" "$log_file" 2>/dev/null; then
693
- echo "FAIL:Log matches failure pattern"
694
- return
695
- fi
696
- fi
697
-
698
- echo "FAIL:Exit code $exit_code"
699
- }
700
-
701
- # ============================================================
702
- # Process Management
703
- # ============================================================
704
-
705
- kill_process_tree() {
706
- local pid="$1"
707
- # Try to kill the process group first
708
- kill -TERM -- -"$pid" 2>/dev/null || kill -TERM "$pid" 2>/dev/null || true
709
- sleep 1
710
- kill -9 -- -"$pid" 2>/dev/null || kill -9 "$pid" 2>/dev/null || true
711
- log_msg "Terminated process tree for PID $pid"
712
- }
713
-
714
- generate_agent_id() {
715
- echo "agent_$(date +%H%M%S)_$(head -c 4 /dev/urandom | od -An -tx1 | tr -d ' \n' | head -c 4)"
716
- }
717
-
718
- # ============================================================
719
- # Start Agent Worker
720
- # ============================================================
721
-
722
- start_agent_worker() {
723
- local agent_id="$1"
724
- local task_id="$2"
725
- local task_title="$3"
726
- local agent_type="$4"
727
- shift 4
728
- local scope_paths_args=("$@")
729
-
730
- local display_name
731
- display_name=$(get_display_name "$agent_type")
732
- log_msg "Starting $display_name ($agent_id) for task $task_id" "SUCCESS"
733
-
734
- if [ "$DRY_RUN" = "true" ]; then
735
- log_msg "[DRY RUN] Would start: claude -p '/agent-worker --task $task_id --agent $agent_id'" "WARN"
736
- return 1
737
- fi
738
-
739
- # Check for resumable branch
740
- local resume_branch=""
741
- resume_branch=$(python3 -c "
742
- import json
743
- try:
744
- with open('$TASK_QUEUE_FILE', 'r') as f:
745
- q = json.load(f)
746
- for t in q.get('tasks', []):
747
- if t['id'] == '$task_id' and t.get('resume_branch'):
748
- print(t['resume_branch'])
749
- break
750
- except Exception:
751
- pass
752
- " 2>/dev/null)
753
-
754
- # Determine branch name
755
- local branch_name
756
- if [ -n "$resume_branch" ]; then
757
- branch_name="$resume_branch"
758
- log_msg "Resuming task from existing branch: $resume_branch"
759
- else
760
- branch_name="task-$(echo "$task_id" | tr '[:upper:]' '[:lower:]')-$agent_id"
761
- fi
762
-
763
- # Setup git branch
764
- (
765
- cd "$WORKING_DIRECTORY" || exit 1
766
- if [ -n "$resume_branch" ]; then
767
- git checkout "$resume_branch" 2>/dev/null || {
768
- log_msg "Failed to checkout resume branch, creating new one" "WARN"
769
- branch_name="task-$(echo "$task_id" | tr '[:upper:]' '[:lower:]')-$agent_id"
770
- git checkout main 2>/dev/null || git checkout master 2>/dev/null
771
- git checkout -b "$branch_name" 2>/dev/null
772
- }
773
- else
774
- local current_branch
775
- current_branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
776
- if [ "$current_branch" != "main" ] && [ "$current_branch" != "master" ]; then
777
- git checkout main 2>/dev/null || git checkout master 2>/dev/null
778
- fi
779
- git checkout -b "$branch_name" 2>/dev/null
780
- fi
781
- )
782
-
783
- # Create agent log file
784
- local agent_log="$LOG_DIR/agent_${agent_id}.log"
785
- local agent_err="$LOG_DIR/agent_${agent_id}.err"
786
- local prompt="/agent-worker --task $task_id --agent $agent_id --branch $branch_name"
787
-
788
- # Launch claude agent in background (must run from project root so .claude/commands/ is found)
789
- (cd "$WORKING_DIRECTORY" && exec claude --dangerously-skip-permissions -p "$prompt") \
790
- > "$agent_log" 2> "$agent_err" &
791
- local pid=$!
792
-
793
- log_msg "Agent $agent_id started (PID: $pid)"
794
- log_msg "Agent log: $agent_log"
795
-
796
- # Store tracking info
797
- track_agent "$agent_id" "$pid" "$task_id" "$branch_name" "$agent_type" "$agent_log" "$task_title"
798
-
799
- return 0
800
- }
801
-
802
- # ============================================================
803
- # Backup Task Files
804
- # ============================================================
805
-
806
- backup_task_files() {
807
- local tasks_dir="$WORKING_DIRECTORY/dev/pipeline/tasks"
808
- local backup_dir="$WORKING_DIRECTORY/dev/pipeline/backups"
809
-
810
- if [ ! -d "$tasks_dir" ]; then
811
- log_msg "Tasks directory not found, skipping backup" "WARN"
812
- return
813
- fi
814
-
815
- local file_count
816
- file_count=$(find "$tasks_dir" -maxdepth 1 -type f 2>/dev/null | wc -l | tr -d ' ')
817
- if [ "$file_count" -eq 0 ]; then
818
- log_msg "No task files to backup"
819
- return
820
- fi
821
-
822
- local timestamp
823
- timestamp=$(date +%Y%m%d_%H%M%S)
824
- local backup_path="$backup_dir/tasks_$timestamp"
825
-
826
- mkdir -p "$backup_dir"
827
- cp -r "$tasks_dir" "$backup_path"
828
- log_msg "Backed up $file_count task file(s) to: $backup_path" "SUCCESS"
829
-
830
- # Clean up old backups (keep last 5)
831
- ls -dt "$backup_dir"/tasks_* 2>/dev/null | tail -n +6 | while read -r old; do
832
- rm -rf "$old"
833
- log_msg "Removed old backup: $(basename "$old")"
834
- done
835
- }
836
-
837
- # ============================================================
838
- # Clear Stale State
839
- # ============================================================
840
-
841
- clear_stale_state() {
842
- log_msg "Cleaning stale state from previous sessions..."
843
-
844
- # Clear locks
845
- if [ -f "$LOCK_STATE_FILE" ]; then
846
- local lock_count
847
- lock_count=$(python3 -c "
848
- import json
849
- try:
850
- with open('$LOCK_STATE_FILE', 'r') as f:
851
- data = json.load(f)
852
- print(len(data.get('locks', [])))
853
- except Exception:
854
- print(0)
855
- " 2>/dev/null)
856
- if [ "${lock_count:-0}" -gt 0 ] 2>/dev/null; then
857
- log_msg "Found $lock_count stale lock(s) from previous session" "WARN"
858
- fi
859
- fi
860
- save_lock_state '{"locks": []}'
861
-
862
- # Clear agents
863
- if [ -f "$AGENT_STATE_FILE" ]; then
864
- local agent_count
865
- agent_count=$(python3 -c "
866
- import json
867
- try:
868
- with open('$AGENT_STATE_FILE', 'r') as f:
869
- data = json.load(f)
870
- print(len(data.get('agents', [])))
871
- except Exception:
872
- print(0)
873
- " 2>/dev/null)
874
- if [ "${agent_count:-0}" -gt 0 ] 2>/dev/null; then
875
- log_msg "Found $agent_count stale agent(s) from previous session" "WARN"
876
- fi
877
- fi
878
- save_agent_state '{"agents": []}'
879
-
880
- # Reset in_progress tasks to pending
881
- if [ -f "$TASK_QUEUE_FILE" ]; then
882
- WORKING_DIRECTORY="$WORKING_DIRECTORY" python3 << 'PYEOF'
883
- import json, os, subprocess
884
- from datetime import datetime
885
-
886
- queue_file = os.environ.get('TASK_QUEUE_FILE', '')
887
- working_dir = os.environ.get('WORKING_DIRECTORY', '')
888
-
889
- try:
890
- with open(queue_file, 'r', encoding='utf-8') as f:
891
- queue = json.load(f)
892
- except (FileNotFoundError, json.JSONDecodeError):
893
- exit(0)
894
-
895
- changed = False
896
- for task in queue.get('tasks', []):
897
- if task.get('status') == 'in_progress':
898
- branch = task.get('branch', '')
899
- has_progress = False
900
-
901
- if branch:
902
- try:
903
- result = subprocess.run(
904
- ['git', 'rev-list', '--count', f'main..{branch}'],
905
- capture_output=True, text=True, cwd=working_dir
906
- )
907
- if result.returncode == 0 and int(result.stdout.strip()) > 0:
908
- has_progress = True
909
- except Exception:
910
- pass
911
-
912
- task['status'] = 'pending'
913
- task.pop('assigned_agent', None)
914
- task.pop('started_at', None)
915
-
916
- if has_progress:
917
- task['resume_branch'] = branch
918
- task.pop('branch', None)
919
- else:
920
- task.pop('branch', None)
921
- task.pop('resume_branch', None)
922
-
923
- changed = True
924
-
925
- if changed:
926
- queue['last_updated'] = datetime.now().isoformat()
927
- with open(queue_file, 'w', encoding='utf-8') as f:
928
- json.dump(queue, f, indent=2, ensure_ascii=False)
929
- PYEOF
930
- fi
931
-
932
- log_msg "Stale state cleanup completed" "SUCCESS"
933
- }
934
-
935
- # ============================================================
936
- # Cleanup on Exit
937
- # ============================================================
938
-
939
- cleanup() {
940
- log_msg "Shutting down scheduler..."
941
-
942
- # Terminate all active agents
943
- for agent_id in $(get_active_agent_ids); do
944
- local pid
945
- pid=$(agent_get "$agent_id" "pid")
946
- if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
947
- log_msg "Terminating agent $agent_id (PID: $pid)"
948
- kill_process_tree "$pid"
949
- fi
950
- remove_agent_locks "$agent_id"
951
- remove_agent_from_state "$agent_id"
952
- done
953
-
954
- # Update AGENT_STATE.json
955
- save_agent_state '{"agents": [], "scheduler": {"status": "stopped", "stopped_at": "'"$(date -u +%Y-%m-%dT%H:%M:%S)"'"}}'
956
- log_msg "Scheduler stopped"
957
-
958
- # Cleanup tracker directory
959
- rm -rf "$TRACKER_DIR"
960
- }
961
-
962
- trap cleanup EXIT INT TERM
963
-
964
- # ============================================================
965
- # Main
966
- # ============================================================
967
-
968
- clear
969
- echo ""
970
- echo "============================================================"
971
- echo " Multi-Agent Parallel Scheduler"
972
- echo "============================================================"
973
- echo " Max Parallel Agents: $MAX_AGENTS"
974
- echo " Poll Interval: ${POLL_INTERVAL}s"
975
- echo " Task Timeout: ${TASK_TIMEOUT}min"
976
- echo " Working Dir: $WORKING_DIRECTORY"
977
- [ "$DRY_RUN" = "true" ] && echo " Mode: DRY RUN"
978
- [ "$STANDALONE" = "true" ] && echo " Mode: STANDALONE (heartbeat ignored)"
979
- echo "============================================================"
980
- echo ""
981
-
982
- # Write startup debug log
983
- cat > "$STARTUP_LOG" << EOF
984
- === Multi-Agent Scheduler Startup ===
985
- Time: $(date "+%Y-%m-%d %H:%M:%S")
986
- WorkingDirectory: $WORKING_DIRECTORY
987
- Script Directory: $SCRIPT_DIR
988
- Shell: ${SHELL:-bash}
989
- OS: $(uname -s) $(uname -r)
990
- Standalone: $STANDALONE
991
- MaxAgents: $MAX_AGENTS
992
- PollIntervalSeconds: $POLL_INTERVAL
993
- TaskTimeoutMinutes: $TASK_TIMEOUT
994
- === Execution Log ===
995
- EOF
996
-
997
- # --- Prerequisite Checks ---
998
- echo "[CHECK] Running prerequisite checks..."
999
-
1000
- if ! command -v claude >/dev/null 2>&1; then
1001
- echo ""
1002
- echo "============================================================"
1003
- echo " ERROR: Claude CLI not found!"
1004
- echo "============================================================"
1005
- echo ""
1006
- echo " To install:"
1007
- echo " npm install -g @anthropic-ai/claude-code"
1008
- echo ""
1009
- exit 1
1010
- fi
1011
- echo " [OK] Claude CLI found"
1012
-
1013
- if ! command -v python3 >/dev/null 2>&1; then
1014
- echo " [ERROR] python3 not found (required for JSON operations)"
1015
- exit 1
1016
- fi
1017
- echo " [OK] python3 found"
1018
-
1019
- if [ ! -d "$WORKING_DIRECTORY" ]; then
1020
- echo " [ERROR] Working directory not found: $WORKING_DIRECTORY"
1021
- exit 1
1022
- fi
1023
- echo " [OK] Working directory exists"
1024
-
1025
- if [ ! -d "$WORKING_DIRECTORY/dev/pipeline" ]; then
1026
- echo " [ERROR] Pipeline directory not found. Run Initialize Project first."
1027
- exit 1
1028
- fi
1029
- echo " [OK] Pipeline directory exists"
1030
-
1031
- if [ ! -f "$TASK_QUEUE_FILE" ]; then
1032
- echo " [WARN] Task queue not found, will be created by sync"
1033
- fi
1034
-
1035
- echo "[CHECK] Prerequisites passed"
1036
- echo ""
1037
-
1038
- # --- Standalone: remove old heartbeat ---
1039
- if [ "$STANDALONE" = "true" ] && [ -f "$HEARTBEAT_FILE" ]; then
1040
- rm -f "$HEARTBEAT_FILE"
1041
- echo "[STANDALONE] Removed old heartbeat file"
1042
- fi
1043
-
1044
- # --- Auto-sync task queue ---
1045
- echo "[SYNC] Syncing task queue from task files..."
1046
- SYNC_SCRIPT="$SCRIPT_DIR/sync_task_queue.sh"
1047
- if [ -x "$SYNC_SCRIPT" ]; then
1048
- "$SYNC_SCRIPT" --wd "$WORKING_DIRECTORY" --quiet || true
1049
- echo "[SYNC] Task queue synced successfully"
1050
- else
1051
- echo "[SYNC] sync_task_queue.sh not found or not executable, skipping"
1052
- fi
1053
- echo ""
1054
-
1055
- log_msg "Multi-Agent Scheduler started (MaxAgents=$MAX_AGENTS)"
1056
-
1057
- # Backup task files
1058
- backup_task_files
1059
-
1060
- # Clean stale state
1061
- export TASK_QUEUE_FILE WORKING_DIRECTORY
1062
- clear_stale_state
1063
-
1064
- # Check for pending tasks
1065
- PENDING_INFO=$(python3 -c "
1066
- import json
1067
- try:
1068
- with open('$TASK_QUEUE_FILE', 'r') as f:
1069
- q = json.load(f)
1070
- pending = [t for t in q.get('tasks', []) if t.get('status') == 'pending']
1071
- total = len(q.get('tasks', []))
1072
- print(f'{len(pending)}:{total}')
1073
- except Exception:
1074
- print('0:0')
1075
- " 2>/dev/null)
1076
-
1077
- PENDING="${PENDING_INFO%%:*}"
1078
- TOTAL="${PENDING_INFO##*:}"
1079
-
1080
- if [ "$PENDING" -eq 0 ] 2>/dev/null; then
1081
- echo ""
1082
- echo "============================================================"
1083
- echo " No pending tasks found!"
1084
- echo "============================================================"
1085
- echo " Total: $TOTAL Pending: 0"
1086
- echo ""
1087
- if [ "$SINGLE_RUN" = "true" ]; then
1088
- log_msg "No pending tasks (SingleRun mode)"
1089
- exit 0
1090
- fi
1091
- log_msg "No pending tasks. Scheduler will wait for new tasks..."
1092
- else
1093
- log_msg "Found $PENDING pending task(s) out of $TOTAL total" "SUCCESS"
1094
- fi
1095
-
1096
- # Set scheduler status to running
1097
- save_agent_state '{"agents": [], "scheduler": {"status": "running", "max_agents": '"$MAX_AGENTS"', "started_at": "'"$(date -u +%Y-%m-%dT%H:%M:%S)"'"}}'
1098
- log_msg "Scheduler status set to 'running' in AGENT_STATE.json"
1099
-
1100
- # Sync counter
1101
- SYNC_COUNTER=0
1102
- SYNC_INTERVAL=5
1103
-
1104
- # ============================================================
1105
- # Main Loop
1106
- # ============================================================
1107
-
1108
- while true; do
1109
- # Check if scheduler was stopped via API
1110
- local_status=$(python3 -c "
1111
- import json
1112
- try:
1113
- with open('$AGENT_STATE_FILE', 'r') as f:
1114
- s = json.load(f)
1115
- print(s.get('scheduler', {}).get('status', 'running'))
1116
- except Exception:
1117
- print('running')
1118
- " 2>/dev/null)
1119
-
1120
- if [ "$local_status" = "stopped" ]; then
1121
- log_msg "Scheduler stop requested via API - shutting down..." "WARN"
1122
- exit 0
1123
- fi
1124
-
1125
- # Check heartbeat
1126
- hb_status=$(check_heartbeat)
1127
- if [ "$hb_status" = "CLOSING" ]; then
1128
- log_msg "Dashboard explicitly closed. Exiting." "WARN"
1129
- exit 0
1130
- fi
1131
- case "$hb_status" in
1132
- TIMEOUT:*)
1133
- log_msg "Dashboard heartbeat timeout. Exiting." "WARN"
1134
- exit 0
1135
- ;;
1136
- esac
1137
-
1138
- # Periodic sync
1139
- SYNC_COUNTER=$((SYNC_COUNTER + 1))
1140
- active_count=$(get_active_count)
1141
- if [ $SYNC_COUNTER -ge $SYNC_INTERVAL ] || [ "$active_count" -eq 0 ]; then
1142
- SYNC_COUNTER=0
1143
- if [ -x "$SYNC_SCRIPT" ]; then
1144
- "$SYNC_SCRIPT" --wd "$WORKING_DIRECTORY" --quiet 2>/dev/null || true
1145
- fi
1146
- fi
1147
-
1148
- # Check completed agents
1149
- for agent_id in $(get_active_agent_ids); do
1150
- pid=$(agent_get "$agent_id" "pid")
1151
- task_id=$(agent_get "$agent_id" "task_id")
1152
- branch=$(agent_get "$agent_id" "branch")
1153
- start_time=$(agent_get "$agent_id" "start_time")
1154
- agent_log=$(agent_get "$agent_id" "log_file")
1155
-
1156
- if [ -z "$pid" ]; then
1157
- untrack_agent "$agent_id"
1158
- continue
1159
- fi
1160
-
1161
- if ! kill -0 "$pid" 2>/dev/null; then
1162
- # Process has exited
1163
- wait "$pid" 2>/dev/null
1164
- exit_code=$?
1165
- now=$(date +%s)
1166
- duration_min=$(( (now - start_time) / 60 ))
1167
-
1168
- result=$(test_agent_success "$exit_code" "$agent_log" "$branch" "$task_id")
1169
-
1170
- case "$result" in
1171
- SUCCESS:*)
1172
- reason="${result#SUCCESS:}"
1173
- log_msg "Agent $agent_id completed task $task_id successfully (${duration_min}min) - $reason" "SUCCESS"
1174
-
1175
- # Get task title before moving (from tracker)
1176
- task_title=$(agent_get "$agent_id" "task_title")
1177
-
1178
- update_task_status "$task_id" "completed"
1179
- move_task_to_completed "$task_id"
1180
-
1181
- # Update PROGRESS.md
1182
- update_progress_file "$task_id" "$task_title" "Completed"
1183
-
1184
- # Merge branch to main
1185
- (
1186
- cd "$WORKING_DIRECTORY" || exit 1
1187
- git checkout main 2>/dev/null || git checkout master 2>/dev/null
1188
- git merge "$branch" -m "Merge $task_id: Completed by $agent_id" 2>/dev/null || true
1189
- git branch -d "$branch" 2>/dev/null || true
1190
- ) && log_msg "Merged branch $branch to main" "SUCCESS"
1191
- ;;
1192
- *)
1193
- reason="${result#FAIL:}"
1194
- log_msg "Agent $agent_id failed task $task_id after ${duration_min}min - $reason" "ERROR"
1195
-
1196
- # Check for partial work
1197
- has_partial=false
1198
- if [ -n "$branch" ]; then
1199
- partial_check=$(
1200
- cd "$WORKING_DIRECTORY" 2>/dev/null || exit 0
1201
- if git rev-parse --verify "$branch" >/dev/null 2>&1; then
1202
- main_branch="main"
1203
- git rev-parse --verify main >/dev/null 2>&1 || main_branch="master"
1204
- ahead=$(git rev-list --count "${main_branch}..${branch}" 2>/dev/null || echo "0")
1205
- [ "$ahead" -gt 0 ] 2>/dev/null && echo "PARTIAL"
1206
- fi
1207
- )
1208
- [ "$partial_check" = "PARTIAL" ] && has_partial=true
1209
- fi
1210
-
1211
- if [ "$has_partial" = "true" ]; then
1212
- log_msg "Branch $branch has commits - marking for resume"
1213
- python3 -c "
1214
- import json
1215
- from datetime import datetime
1216
- try:
1217
- with open('$TASK_QUEUE_FILE', 'r') as f:
1218
- q = json.load(f)
1219
- for t in q.get('tasks', []):
1220
- if t['id'] == '$task_id':
1221
- t['status'] = 'pending'
1222
- t['resume_branch'] = '$branch'
1223
- t.pop('assigned_agent', None)
1224
- break
1225
- q['last_updated'] = datetime.now().isoformat()
1226
- with open('$TASK_QUEUE_FILE', 'w') as f:
1227
- json.dump(q, f, indent=2, ensure_ascii=False)
1228
- except Exception:
1229
- pass
1230
- " 2>/dev/null
1231
- else
1232
- update_task_status "$task_id" "pending"
1233
- fi
1234
- ;;
1235
- esac
1236
-
1237
- remove_agent_locks "$agent_id"
1238
- remove_agent_from_state "$agent_id"
1239
- untrack_agent "$agent_id"
1240
- else
1241
- # Check timeout
1242
- now=$(date +%s)
1243
- elapsed_min=$(( (now - start_time) / 60 ))
1244
- if [ $elapsed_min -gt $TASK_TIMEOUT ] 2>/dev/null; then
1245
- log_msg "Agent $agent_id timed out on task $task_id (PID: $pid)" "WARN"
1246
- kill_process_tree "$pid"
1247
- remove_agent_locks "$agent_id"
1248
- remove_agent_from_state "$agent_id"
1249
- update_task_status "$task_id" "pending"
1250
- untrack_agent "$agent_id"
1251
- fi
1252
- fi
1253
- done
1254
-
1255
- # Start new agents if slots available
1256
- active_count=$(get_active_count)
1257
- available_slots=$(( MAX_AGENTS - active_count ))
1258
-
1259
- if [ $available_slots -gt 0 ]; then
1260
- get_ready_tasks | while IFS= read -r task_json; do
1261
- [ -z "$task_json" ] && continue
1262
-
1263
- # Re-check available slots (may have changed in this loop iteration)
1264
- current_active=$(get_active_count)
1265
- current_available=$(( MAX_AGENTS - current_active ))
1266
- [ $current_available -le 0 ] && break
1267
-
1268
- task_id=$(echo "$task_json" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
1269
- task_title=$(echo "$task_json" | python3 -c "import sys,json; print(json.load(sys.stdin)['title'])")
1270
- scope_paths_json=$(echo "$task_json" | python3 -c "import sys,json; t=json.load(sys.stdin); print(json.dumps(t.get('scope_paths', t.get('scope', {}).get('paths', ['src/']))))")
1271
- agent_type_explicit=$(echo "$task_json" | python3 -c "import sys,json; print(json.load(sys.stdin).get('agent_type', ''))")
1272
-
1273
- # Skip already running tasks
1274
- if is_task_running "$task_id"; then
1275
- continue
1276
- fi
1277
-
1278
- # Check path conflict
1279
- conflict_result=$(check_path_conflict "$scope_paths_json")
1280
- if [ "$conflict_result" != "NO_CONFLICT" ]; then
1281
- conflict_info="${conflict_result#CONFLICT:}"
1282
- log_msg "Task $task_id conflicts with $conflict_info" "WARN"
1283
- continue
1284
- fi
1285
-
1286
- # Read scope paths into args
1287
- scope_paths_args=()
1288
- while IFS= read -r p; do
1289
- scope_paths_args+=("$p")
1290
- done < <(echo "$scope_paths_json" | python3 -c "import sys,json; [print(p) for p in json.load(sys.stdin)]")
1291
-
1292
- # Determine agent type
1293
- agent_type=$(get_agent_type "$task_title" "$agent_type_explicit")
1294
-
1295
- # Generate agent ID
1296
- agent_id=$(generate_agent_id)
1297
-
1298
- # Start agent
1299
- if start_agent_worker "$agent_id" "$task_id" "$task_title" "$agent_type" "${scope_paths_args[@]}"; then
1300
- branch=$(agent_get "$agent_id" "branch")
1301
-
1302
- # Add locks
1303
- add_path_locks "$agent_id" "$task_id" "${scope_paths_args[@]}"
1304
-
1305
- # Update task status
1306
- update_task_status "$task_id" "in_progress" "$agent_id" "$branch"
1307
-
1308
- # Update AGENT_STATE.json
1309
- add_agent_to_state "$agent_id" "$task_id" "$task_title" "$branch" "$agent_type"
1310
-
1311
- display_name=$(get_display_name "$agent_type")
1312
- log_msg "Launched $display_name ($agent_id) for $task_id: $task_title"
1313
- fi
1314
- done
1315
- fi
1316
-
1317
- # Display status line
1318
- timestamp=$(date "+%H:%M:%S")
1319
- active_count=$(get_active_count)
1320
- status_line="[$timestamp] Agents: ${active_count}/$MAX_AGENTS"
1321
-
1322
- if [ "$active_count" -gt 0 ]; then
1323
- agent_info=""
1324
- for agent_id in $(get_active_agent_ids); do
1325
- start_time=$(agent_get "$agent_id" "start_time")
1326
- task_id=$(agent_get "$agent_id" "task_id")
1327
- now=$(date +%s)
1328
- elapsed_min=$(( (now - start_time) / 60 ))
1329
- agent_info="$agent_info ${task_id}(${elapsed_min}min)"
1330
- done
1331
- status_line="$status_line |$agent_info"
1332
- else
1333
- status_line="$status_line | Waiting for tasks..."
1334
- fi
1335
- printf '\033[36m%s\033[0m\n' "$status_line"
1336
-
1337
- # Single run check
1338
- if [ "$SINGLE_RUN" = "true" ] && [ "$active_count" -eq 0 ]; then
1339
- log_msg "Single run completed, no active agents"
1340
- break
1341
- fi
1342
-
1343
- sleep "$POLL_INTERVAL"
1344
- done