kenaz 0.3.22 → 0.3.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (474) hide show
  1. package/core/.claude/hooks/_user-scope.js +1 -1
  2. package/core/.claude/hooks/core-resolve.js +1 -1
  3. package/core/.claude/hooks/worktree-create.js +11 -29
  4. package/core/.claude/hooks/worktree-remove.js +12 -38
  5. package/core/.collaboration/core/reconcile.js +16 -1
  6. package/core/.collaboration/core/task-2467-lifecycle.test.js +63 -0
  7. package/core/.collaboration/core/task-api.js +37 -7
  8. package/core/.formation/bifrost/launch.js +1 -1
  9. package/core/.formation/tools/dispatch-detail/worktree-subagent-mode.md +6 -1
  10. package/core/.formation/tools/kenaz-stats.js +1 -1
  11. package/core/.formation/tools/post-complete/git-merge.js +1 -1
  12. package/core/.formation/tools/prompt.js +1 -1
  13. package/core/.formation/tools/utils.js +5 -5
  14. package/core/.formation/tools/worktree-reclaim.js +73 -2
  15. package/core/.formation/tools/worktree-reclaim.test.js +113 -0
  16. package/core/.kenaz/specialist/ansuz_rules.yaml +7 -51
  17. package/core/.kenaz/specialist/ansuz_session_handoff.schema.json +2 -6
  18. package/core/.rule/general/project-self-containment.yaml +2 -2
  19. package/core/.specialist/Amelia/README.md +1 -1
  20. package/core/.specialist/Amelia/rule.yaml +1 -1
  21. package/core/.specialist/Ansuz/RULES.md +6 -2
  22. package/core/.specialist/Ansuz/concepts/commitment_layer.yaml +1 -1
  23. package/core/.specialist/Ansuz/concepts/evolvable_guardrails.yaml +1 -1
  24. package/core/.specialist/Ansuz/knowledge.yaml +1 -3
  25. package/core/.specialist/tools/__tests__/task-2409-lessons.test.js +10 -0
  26. package/core/.specialist/tools/__tests__/task-2427-harvest.test.js +25 -0
  27. package/core/.specialist/tools/ansuz-boot-fast.js +1 -1
  28. package/core/.specialist/tools/failure-detector.js +4 -4
  29. package/core/.specialist/tools/handoff-doc.js +1 -1
  30. package/core/.specialist/tools/lessons.js +2 -2
  31. package/core/CLAUDE.md +5 -5
  32. package/core/KENAZ_CORE_VERSION +1 -1
  33. package/core/dashboard/scripts/install-kenaz-cli.js +56 -30
  34. package/core/dev/scripts/check-file-size.js +1 -1
  35. package/core/dev/scripts/ci-feedback.js +1 -1
  36. package/core/dev/scripts/gc-agent-worktrees.js +13 -12
  37. package/core/dev/scripts/kenaz-session.js +3 -3
  38. package/core/dev/scripts/peer-identity-e2e.js +6 -4
  39. package/core/dev/scripts/run-rust-tests.js +2 -2
  40. package/core/dev/scripts/skill-routing-replay.js +3 -3
  41. package/core/dev/scripts/task1961/selftest.js +2 -2
  42. package/core/dev/scripts/windows-hide-guard.test.js +112 -0
  43. package/core/plugins/kenaz/guidance.md +1 -0
  44. package/core/plugins/kenaz/hooks/core-resolve.js +1 -1
  45. package/core/plugins/kenaz/hooks/hooks.json +9 -0
  46. package/core/plugins/kenaz/hooks/kenaz-hook.js +58 -4
  47. package/core/plugins/kenaz/hooks/worktree-guard.js +121 -0
  48. package/core/plugins/kenaz/hooks/worktree-guard.test.js +75 -0
  49. package/core/plugins/kenaz/scripts/kenaz.test.js +72 -5
  50. package/core/plugins/kenaz-peer/hooks/register.test.ts +14 -2
  51. package/core/plugins/kenaz-peer/hooks/register.ts +6 -1
  52. package/lib/cli.js +9 -5
  53. package/package.json +6 -6
  54. package/vendor/install-kenaz-cli.js +56 -30
  55. package/core/.kenaz/designs/METAPLASTICITY_CONFIDENCE_DESIGN.md +0 -537
  56. package/core/.kenaz/designs/REFLEX_INITIATOR_DESIGN.md +0 -501
  57. package/core/.kenaz/designs/TASK_1385_handoff_mcp_design.md +0 -426
  58. package/core/.kenaz/designs/TASK_932_hippocampus_consolidation.md +0 -103
  59. package/core/.kenaz/designs/TASK_934_efe_signal_engine.md +0 -97
  60. package/core/.kenaz/designs/TASK_935_self_evolution_framework.md +0 -154
  61. package/core/.kenaz/designs/VISION_cognitive_architecture_roadmap.md +0 -159
  62. package/core/.kenaz/designs/metaplasticity_simulation_results.json +0 -696
  63. package/core/.kenaz/main-memory/README.md +0 -230
  64. package/core/.kenaz/main-memory/kenaz/cortex/001_cortex_overview.md +0 -168
  65. package/core/.kenaz/main-memory/kenaz/cortex/001_rag_engine_overview.md +0 -30
  66. package/core/.kenaz/main-memory/kenaz/memory-system/001_three_tier_architecture.md +0 -361
  67. package/core/.kenaz/main-memory/kenaz/pipeline/001_task_execution_flow.md +0 -117
  68. package/core/.kenaz/main-memory/kenaz/pipeline/001_task_granularity.md +0 -154
  69. package/core/.kenaz/main-memory/kenaz/pipeline/002_team_priority.md +0 -51
  70. package/core/.kenaz/main-memory/kenaz/pipeline/003_feature_id_system.md +0 -46
  71. package/core/.kenaz/main-memory/kenaz/rules/001_gen_007_self_containment.md +0 -108
  72. package/core/.kenaz/main-memory/kenaz/rules/001_rule_priority_system.md +0 -121
  73. package/core/.kenaz/main-memory/kenaz/rules/002_agt_006_pre_check.md +0 -0
  74. package/core/.kenaz/main-memory/kenaz/rules/003_ppl_002_task_archival.md +0 -48
  75. package/core/.kenaz/main-memory/kenaz/system/001_dual_track_task_system.md +0 -197
  76. package/core/.kenaz/main-memory/knowledge/patterns/001_json_bom_issue.md +0 -78
  77. package/core/.kenaz/main-memory/knowledge/patterns/001_leader_worker_pattern.md +0 -0
  78. package/core/.kenaz/main-memory/knowledge/patterns/002_scope_path_conflict.md +0 -115
  79. package/core/.kenaz/main-memory/knowledge/patterns/002_task_dependency_resolution.md +0 -223
  80. package/core/.kenaz/main-memory/knowledge/patterns/003_question_protocol.md +0 -242
  81. package/core/.kenaz/main-memory/knowledge/patterns/004_user_insight_value.md +0 -111
  82. package/core/.kenaz/main-memory/knowledge/patterns/005_file_lock_pattern.md +0 -274
  83. package/core/.kenaz/main-memory/knowledge/references/001_ppl_rules.md +0 -28
  84. package/core/.kenaz/main-memory/knowledge/solutions/001_json_bom_issue.md +0 -137
  85. package/core/.kenaz/main-memory/knowledge/solutions/001_team_invocation.md +0 -0
  86. package/core/.kenaz/main-memory/knowledge/solutions/002_passive_monitoring.md +0 -0
  87. package/core/.kenaz/main-memory/knowledge/solutions/003_windows_file_race_condition.md +0 -239
  88. package/core/.kenaz/main-memory/registry.json +0 -326
  89. package/core/.kenaz/main-memory/version.yaml +0 -58
  90. package/core/.kenaz/specialist/memory_guard_fired.json +0 -1
  91. package/core/.kenaz/specialist/memory_guard_trigger_cache.json +0 -1
  92. package/core/.kenaz/specialist/memory_source_priority.yaml +0 -260
  93. package/core/.kenaz/specialist/prompt_1775.txt +0 -317
  94. package/core/.kenaz/specialist/prompt_1776.txt +0 -326
  95. package/core/.kenaz/specialist/prompt_1791.txt +0 -320
  96. package/core/.kenaz/specialist/prompt_1792.txt +0 -320
  97. package/core/.kenaz/specialist/prompt_1795.txt +0 -281
  98. package/core/.kenaz/specialist/prompt_1813.txt +0 -332
  99. package/core/.kenaz/specialist/prompt_1814.txt +0 -401
  100. package/core/.kenaz/specialist/prompt_1815.txt +0 -394
  101. package/core/.kenaz/specialist/prompt_1816.txt +0 -437
  102. package/core/.kenaz/specialist/prompt_1818.txt +0 -361
  103. package/core/.kenaz/specialist/prompt_1819.txt +0 -421
  104. package/core/.kenaz/specialist/prompt_1821.txt +0 -345
  105. package/core/.kenaz/specialist/prompt_1822.txt +0 -313
  106. package/core/.kenaz/specialist/prompt_1824.txt +0 -348
  107. package/core/.kenaz/specialist/prompt_1826.txt +0 -388
  108. package/core/.kenaz/specialist/rune_efe_salience_gap.md +0 -21
  109. package/core/.kenaz/specialist/task1825_update.json +0 -43
  110. package/core/.kenaz/specialist/taskgen/consolidation_i.json +0 -38
  111. package/core/.kenaz/specialist/taskgen/csharp_a.json +0 -44
  112. package/core/.kenaz/specialist/taskgen/csharp_b.json +0 -40
  113. package/core/.kenaz/specialist/taskgen/embedding_e.json +0 -34
  114. package/core/.kenaz/specialist/taskgen/hygiene_fg.json +0 -39
  115. package/core/.kenaz/specialist/taskgen/pathology_h.json +0 -36
  116. package/core/.kenaz/specialist/taskgen/unity_noise_d.json +0 -38
  117. package/core/.kenaz/specialist/taskgen/visibility_c.json +0 -38
  118. package/core/.specialist/Ansuz/decisions/ADR-requirement-graph-layer.md +0 -390
  119. package/core/.specialist/Ansuz/self_model_seed.backup.json +0 -100
  120. package/core/.specialist/ansuz_session_handoff.json +0 -96
  121. package/core/dev/ALAYA_FIELD_FEEDBACK_DESIGN.md +0 -126
  122. package/core/dev/ANSUZ_SCAFFOLD_DIET_2026-09-20.md +0 -231
  123. package/core/dev/ANSUZ_STARTUP_INJECTION_REVIEW.md +0 -355
  124. package/core/dev/ANSUZ_WORKFLOW_MODERNIZATION.md +0 -143
  125. package/core/dev/CORTEX_META_GRAPH_ASSESSMENT.md +0 -99
  126. package/core/dev/FREYA_DOWNSTREAM_BUGS_2026-09-19.md +0 -44
  127. package/core/dev/GLOBAL_MEMORY_IDENTITY_CONSOLIDATION.md +0 -263
  128. package/core/dev/GUARD_EFFECTIVENESS_DESIGN.md +0 -180
  129. package/core/dev/HEALTH_GATE_VARIANCE_ASSESSMENT.md +0 -271
  130. package/core/dev/HOOK_DIET_2026-09-21.md +0 -126
  131. package/core/dev/JEV_INTEGRATION_PLAN.md +0 -189
  132. package/core/dev/KENAZ_AGENT_CONNECT_v1_SPEC.md +0 -139
  133. package/core/dev/MOBILE_DESIGN_SPEC.md +0 -569
  134. package/core/dev/MULTI_ANSUZ_SPEC.md +0 -136
  135. package/core/dev/MUNINN_RETIREMENT.md +0 -115
  136. package/core/dev/PHASE3_ATTRIBUTION_POPULATION_DIAGNOSIS.md +0 -211
  137. package/core/dev/PHASE3_P3-2B_TASKLEVEL_PROBE.md +0 -83
  138. package/core/dev/PHASE3_P3-2_POPULATION_DISJOINTNESS.md +0 -83
  139. package/core/dev/PHASE3_P3-2_REMEASURE_REPORT.md +0 -231
  140. package/core/dev/PREDICTION_GROUNDING_DESIGN.md +0 -376
  141. package/core/dev/PRODUCT_SPEC.md +0 -317
  142. package/core/dev/PROJECT_REGISTRY_DUPLICATE_ASSESSMENT.md +0 -86
  143. package/core/dev/STARTUP_TIMELINE_TASK_1995.md +0 -181
  144. package/core/dev/SYNAPSE_WORKER_PER_PROJECT.md +0 -881
  145. package/core/dev/TASK_1680_P3-3_DISPATCH_SPEC.md +0 -96
  146. package/core/dev/TASK_1684_CALIBRATION_IMPACT_ANALYSIS.md +0 -170
  147. package/core/dev/TASK_1684_FORK_A_GOODHART_DESIGN.md +0 -171
  148. package/core/dev/TASK_1684_P3_2_REMEASURE_VALIDATION.md +0 -262
  149. package/core/dev/TASK_1903_SIGNAL_AUC_MEASUREMENT.md +0 -207
  150. package/core/dev/TASK_1904_BRANCH_INTEGRITY_AUDIT.md +0 -146
  151. package/core/dev/ansuz-eval/README.md +0 -38
  152. package/core/dev/ansuz-eval/build-fixtures.js +0 -87
  153. package/core/dev/ansuz-eval/grade.js +0 -96
  154. package/core/dev/ansuz-eval/grader.test.js +0 -117
  155. package/core/dev/ansuz-eval/tasks.md +0 -32
  156. package/core/dev/archive/ansuz/BOOT_FULL.md +0 -141
  157. package/core/dev/archive/ansuz/agents/ansuz-boot.md +0 -176
  158. package/core/dev/archive/ansuz/designs/alaya-passive-surfacing.md +0 -84
  159. package/core/dev/archive/ansuz/designs/cc_memory_indexing.md +0 -307
  160. package/core/dev/archive/ansuz/designs/check_guard.md +0 -322
  161. package/core/dev/archive/ansuz/designs/consequence_loop.md +0 -227
  162. package/core/dev/archive/ansuz/designs/mcp_kuzudb_lock_architecture.md +0 -312
  163. package/core/dev/archive/ansuz/designs/phase0_git_enrichment.md +0 -278
  164. package/core/dev/archive/ansuz/designs/refactor_mcp_tools_synapse.md +0 -490
  165. package/core/dev/archive/ansuz/designs/semantic_markdown_extraction.md +0 -167
  166. package/core/dev/archive/ansuz/designs/task_1372_prompt_injects_into.md +0 -193
  167. package/core/dev/archive/ansuz/designs/thought_stack.md +0 -286
  168. package/core/dev/archive/ansuz/investigations/reachability_unified_api_2026-04-11.md +0 -330
  169. package/core/dev/archive/ansuz/investigations/synapse_orphans_indexing_bug_2026-04-11.md +0 -352
  170. package/core/dev/archive/ansuz/investigations/synapse_orphans_reindex_verification_2026-04-11.md +0 -48
  171. package/core/dev/archive/ansuz/investigations/synapse_orphans_verification_2026-04-11.md +0 -170
  172. package/core/dev/archive/ansuz/legacy/kernel.yaml +0 -399
  173. package/core/dev/archive/ansuz/legacy/phases/phase_0.yaml +0 -418
  174. package/core/dev/archive/ansuz/legacy/phases/phase_1.yaml +0 -376
  175. package/core/dev/archive/ansuz/legacy/phases/phase_10.yaml +0 -35
  176. package/core/dev/archive/ansuz/legacy/phases/phase_11.yaml +0 -582
  177. package/core/dev/archive/ansuz/legacy/phases/phase_2.yaml +0 -94
  178. package/core/dev/archive/ansuz/legacy/phases/phase_3.yaml +0 -274
  179. package/core/dev/archive/ansuz/legacy/phases/phase_4.yaml +0 -67
  180. package/core/dev/archive/ansuz/legacy/phases/phase_5.yaml +0 -32
  181. package/core/dev/archive/ansuz/legacy/phases/phase_6.yaml +0 -91
  182. package/core/dev/archive/ansuz/legacy/phases/phase_7.yaml +0 -58
  183. package/core/dev/archive/ansuz/legacy/phases/phase_8.yaml +0 -146
  184. package/core/dev/archive/ansuz/legacy/phases/phase_9.yaml +0 -424
  185. package/core/dev/archive/ansuz/specs/INDEX_bifrost_hook_parity.yaml +0 -92
  186. package/core/dev/archive/ansuz/specs/active-inference-formation.yaml +0 -453
  187. package/core/dev/archive/ansuz/specs/brief_TASK_1228_userpromptsubmit.yaml +0 -191
  188. package/core/dev/archive/ansuz/specs/brief_TASK_1229_pretooluse_posttooluse.yaml +0 -250
  189. package/core/dev/archive/ansuz/specs/brief_TASK_1230_sessionstart_stop.yaml +0 -301
  190. package/core/dev/archive/ansuz/specs/brief_TASK_1231_verification.yaml +0 -272
  191. package/core/dev/archive/skills/feature_agent/SKILL.md +0 -289
  192. package/core/dev/design/PHASE4_DESIGN.md +0 -559
  193. package/core/dev/design/dashboard_docs_integration_PLAN.md +0 -388
  194. package/core/dev/design/matrix_format_ABBREVIATIONS.md +0 -655
  195. package/core/dev/design/matrix_format_DESIGN_SPEC.md +0 -601
  196. package/core/dev/design/matrix_format_DISCUSSION_SUMMARY.md +0 -484
  197. package/core/dev/design/matrix_format_EXAMPLE_memory.matrix +0 -13
  198. package/core/dev/design/matrix_format_EXAMPLE_project_status.matrix +0 -9
  199. package/core/dev/design/matrix_format_EXAMPLE_tasks.matrix +0 -14
  200. package/core/dev/design/matrix_format_SYNTAX_BNF.md +0 -754
  201. package/core/dev/design/matrix_format_TOKEN_COMPARISON.md +0 -484
  202. package/core/dev/design/matrix_v2_COGNITIVE_DESIGN.md +0 -503
  203. package/core/dev/design/matrix_v2_DISCUSSION_SUMMARY.md +0 -414
  204. package/core/dev/design/matrix_v2_EXAMPLE.matrix +0 -67
  205. package/core/dev/designs/EXPANDABLE_CARD_DESIGN_SPEC.md +0 -509
  206. package/core/dev/jev-eval/ACTIVE_CORRECTION.md +0 -52
  207. package/core/dev/jev-eval/ANNOTATION_GUIDE.md +0 -68
  208. package/core/dev/jev-eval/BASELINE_COMPARISON.md +0 -45
  209. package/core/dev/jev-eval/CONTEXT_REVIEW.md +0 -31
  210. package/core/dev/jev-eval/EVALUATION_STATUS.md +0 -39
  211. package/core/dev/jev-eval/HISTORICAL_CORPUS.md +0 -33
  212. package/core/dev/jev-eval/PACKAGING_VERIFICATION.md +0 -42
  213. package/core/dev/jev-eval/README.md +0 -101
  214. package/core/dev/jev-eval/THALAMUS_RANKING.md +0 -58
  215. package/core/dev/jev-eval/VALIDATION_PROGRESS.md +0 -54
  216. package/core/dev/jev-eval/cli.mjs +0 -50
  217. package/core/dev/jev-eval/context.mjs +0 -183
  218. package/core/dev/jev-eval/corpus.mjs +0 -186
  219. package/core/dev/jev-eval/fixtures/conversation-review.seed.jsonl +0 -6
  220. package/core/dev/jev-eval/fixtures/synthetic.jsonl +0 -11
  221. package/core/dev/jev-eval/metrics.mjs +0 -67
  222. package/core/dev/jev-eval/muninn-baseline.mjs +0 -119
  223. package/core/dev/jev-eval/providers.mjs +0 -95
  224. package/core/dev/jev-eval/reports/annotation-pilot-2026-09-20.json +0 -32
  225. package/core/dev/jev-eval/reports/context-review-2026-09-20.json +0 -48
  226. package/core/dev/jev-eval/reports/conversation-review.pending.json +0 -151
  227. package/core/dev/jev-eval/reports/history-corpus-2026-09-20.json +0 -52
  228. package/core/dev/jev-eval/reports/length-probe-2026-09-20.json +0 -133
  229. package/core/dev/jev-eval/reports/live-smoke-2026-09-20.json +0 -616
  230. package/core/dev/jev-eval/reports/muninn-baseline-2026-09-20.json +0 -52
  231. package/core/dev/jev-eval/reports/resilience-2026-09-20.json +0 -520
  232. package/core/dev/jev-eval/reports/rules-baseline.json +0 -197
  233. package/core/dev/jev-eval/reports/synthetic-review.pending.json +0 -357
  234. package/core/dev/jev-eval/resilience.mjs +0 -71
  235. package/core/dev/jev-eval/review.mjs +0 -78
  236. package/core/dev/jev-eval/schema.mjs +0 -87
  237. package/core/dev/jev-eval/test/context.test.mjs +0 -95
  238. package/core/dev/jev-eval/test/corpus.test.mjs +0 -102
  239. package/core/dev/jev-eval/test/eval.test.mjs +0 -146
  240. package/core/dev/jev-eval/test/muninn-baseline.test.mjs +0 -71
  241. package/core/dev/jev-eval/test/resilience.test.mjs +0 -72
  242. package/core/dev/jev-eval/test/review.test.mjs +0 -61
  243. package/core/dev/pipeline/PHASE3_PLANNING_SUMMARY.md +0 -338
  244. package/core/dev/pipeline/PROGRESS.md +0 -113
  245. package/core/dev/pipeline/PROGRESS_template.md +0 -860
  246. package/core/dev/pipeline/QA_REPORT_F008.md +0 -431
  247. package/core/dev/pipeline/QA_REPORT_LOCAL_CLAUDE_DIAGNOSIS.md +0 -583
  248. package/core/dev/pipeline/README.md +0 -210
  249. package/core/dev/pipeline/WORKFLOW_GUIDE.md +0 -824
  250. package/core/dev/pipeline/archived/TASK_015_tauri_init.yaml +0 -53
  251. package/core/dev/pipeline/archived/TASK_016_tauri_commands.yaml +0 -54
  252. package/core/dev/pipeline/archived/TASK_017_rust_pty.yaml +0 -54
  253. package/core/dev/pipeline/archived/TASK_018_tauri_bundle.yaml +0 -53
  254. package/core/dev/pipeline/archived/TASK_019_release_workflow.yaml +0 -56
  255. package/core/dev/pipeline/archived/TASK_020_update_ui.yaml +0 -54
  256. package/core/dev/pipeline/archived/TASK_021_update_notification_ui.yaml +0 -55
  257. package/core/dev/pipeline/archived/TASK_022_remove_node_pty.yaml +0 -65
  258. package/core/dev/pipeline/archived/TASK_023_api_routes_migration.yaml +0 -86
  259. package/core/dev/pipeline/archived/TASK_024_feature_id_system.yaml +0 -51
  260. package/core/dev/pipeline/archived/TASK_025_executable_acceptance.yaml +0 -66
  261. package/core/dev/pipeline/archived/TASK_026_spec_versioning.yaml +0 -56
  262. package/core/dev/pipeline/archived/TASK_027_drift_detection.yaml +0 -60
  263. package/core/dev/pipeline/archived/TASK_028_tauri_pty_manager.yaml +0 -60
  264. package/core/dev/pipeline/archived/TASK_029_tauri_pty_commands.yaml +0 -62
  265. package/core/dev/pipeline/archived/TASK_030_frontend_session_adapter.yaml +0 -54
  266. package/core/dev/pipeline/archived/TASK_031_terminal_tauri_events.yaml +0 -56
  267. package/core/dev/pipeline/archived/TASK_041_scheduler_data_models.yaml +0 -54
  268. package/core/dev/pipeline/archived/TASK_042_path_lock_manager.yaml +0 -53
  269. package/core/dev/pipeline/archived/TASK_043_process_manager.yaml +0 -57
  270. package/core/dev/pipeline/archived/TASK_044_git_integration.yaml +0 -85
  271. package/core/dev/pipeline/archived/TASK_045_task_queue_manager.yaml +0 -54
  272. package/core/dev/pipeline/archived/TASK_046_scheduler_dispatcher.yaml +0 -60
  273. package/core/dev/pipeline/archived/TASK_047_tauri_scheduler_commands.yaml +0 -55
  274. package/core/dev/pipeline/archived/TASK_048_realtime_status_push.yaml +0 -92
  275. package/core/dev/pipeline/archived/TASK_049_frontend_scheduler_integration.yaml +0 -58
  276. package/core/dev/pipeline/archived/TASK_050_error_recovery.yaml +0 -56
  277. package/core/dev/pipeline/archived/TASK_051_optimization_proposals_backend.yaml +0 -53
  278. package/core/dev/pipeline/archived/TASK_052_optimization_proposals_ui.yaml +0 -58
  279. package/core/dev/pipeline/archived/TASK_053_optimization_proposals_diff_view.yaml +0 -54
  280. package/core/dev/pipeline/archived/TASK_054_multi_project_scheduler_state.yaml +0 -76
  281. package/core/dev/pipeline/archived/TASK_055_scheduler_api_project_scope.yaml +0 -64
  282. package/core/dev/pipeline/archived/TASK_056_frontend_scheduler_project_scope.yaml +0 -62
  283. package/core/dev/pipeline/archived/TASK_057_scheduler_module_structure.yaml +0 -54
  284. package/core/dev/pipeline/archived/TASK_058_scheduler_models_extract.yaml +0 -51
  285. package/core/dev/pipeline/archived/TASK_059_scheduler_core_extract.yaml +0 -51
  286. package/core/dev/pipeline/archived/TASK_060_scheduler_commands_extract.yaml +0 -51
  287. package/core/dev/pipeline/archived/TASK_061_scheduler_specialized_commands.yaml +0 -53
  288. package/core/dev/pipeline/archived/TASK_062_process_manager_module_structure.yaml +0 -56
  289. package/core/dev/pipeline/archived/TASK_063_process_manager_core_extract.yaml +0 -56
  290. package/core/dev/pipeline/archived/TASK_064_recovery_module_structure.yaml +0 -57
  291. package/core/dev/pipeline/archived/TASK_065_recovery_core_extract.yaml +0 -56
  292. package/core/dev/pipeline/archived/TASK_066_self_enhancement_scheduler_models.yaml +0 -60
  293. package/core/dev/pipeline/archived/TASK_067_agents_section_quick_actions.yaml +0 -53
  294. package/core/dev/pipeline/archived/TASK_067_self_enhancement_scheduler_core.yaml +0 -65
  295. package/core/dev/pipeline/archived/TASK_068_agent_workflow_rule_enhancement.yaml +0 -46
  296. package/core/dev/pipeline/archived/TASK_068_self_enhancement_tauri_commands.yaml +0 -61
  297. package/core/dev/pipeline/archived/TASK_069_agent_wizard_responsive.yaml +0 -46
  298. package/core/dev/pipeline/archived/TASK_069_self_enhancement_ui.yaml +0 -62
  299. package/core/dev/pipeline/archived/TASK_070_preview_panel_redesign.yaml +0 -62
  300. package/core/dev/pipeline/archived/TASK_070_self_enhancement_integration.yaml +0 -57
  301. package/core/dev/pipeline/archived/TASK_071_preview_panel_qa.yaml +0 -98
  302. package/core/dev/pipeline/archived/TASK_071_single_agent_config.yaml +0 -57
  303. package/core/dev/pipeline/archived/TASK_072_preview_modal_esc_fix.yaml +0 -71
  304. package/core/dev/pipeline/archived/TASK_072_product_review_module.yaml +0 -57
  305. package/core/dev/pipeline/archived/TASK_073_agents_page_component_refactor.yaml +0 -68
  306. package/core/dev/pipeline/archived/TASK_073_rename_single_agent.yaml +0 -64
  307. package/core/dev/pipeline/archived/TASK_074_preview_mode_ui_diagnosis.yaml +0 -71
  308. package/core/dev/pipeline/archived/TASK_074_single_agent_ui_toggle.yaml +0 -56
  309. package/core/dev/pipeline/archived/TASK_075_agents_page_component_refactor.yaml +0 -69
  310. package/core/dev/pipeline/archived/TASK_075_single_agent_integration_test.yaml +0 -75
  311. package/core/dev/pipeline/archived/TASK_076_preview_mode_ui_diagnosis.yaml +0 -70
  312. package/core/dev/pipeline/archived/TASK_076_single_agent_continuous_mode.yaml +0 -65
  313. package/core/dev/pipeline/archived/TASK_077_failure_directory_structure.yaml +0 -51
  314. package/core/dev/pipeline/archived/TASK_077_single_agent_typescript_types.yaml +0 -59
  315. package/core/dev/pipeline/archived/TASK_078_fail_001_agent_no_output.yaml +0 -53
  316. package/core/dev/pipeline/archived/TASK_078_single_agent_ui_simplify.yaml +0 -74
  317. package/core/dev/pipeline/archived/TASK_079_dashboard_rwd_responsive.yaml +0 -63
  318. package/core/dev/pipeline/archived/TASK_079_fail_002_json_bom.yaml +0 -56
  319. package/core/dev/pipeline/archived/TASK_080_fail_003_queue_pollution.yaml +0 -56
  320. package/core/dev/pipeline/archived/TASK_080_http_server_module.yaml +0 -55
  321. package/core/dev/pipeline/archived/TASK_081_failure_logging_tools.yaml +0 -57
  322. package/core/dev/pipeline/archived/TASK_081_http_api_routes.yaml +0 -62
  323. package/core/dev/pipeline/archived/TASK_082_frontend_api_adapter.yaml +0 -51
  324. package/core/dev/pipeline/archived/TASK_082_integrate_failure_to_workflow.yaml +0 -60
  325. package/core/dev/pipeline/archived/TASK_083_cleanup_nextjs_api.yaml +0 -48
  326. package/core/dev/pipeline/archived/TASK_083_task_queue_cleanup.yaml +0 -67
  327. package/core/dev/pipeline/archived/TASK_084_rust_dead_code_cleanup.yaml +0 -66
  328. package/core/dev/pipeline/archived/TASK_084_scheduler_sync_logic_fix.yaml +0 -68
  329. package/core/dev/pipeline/archived/TASK_085_http_api_web_mode_fixes.yaml +0 -46
  330. package/core/dev/pipeline/archived/TASK_085_memory_consolidation_0204_0205.yaml +0 -98
  331. package/core/dev/pipeline/archived/TASK_086_collapsible_preview_panel.yaml +0 -161
  332. package/core/dev/pipeline/archived/TASK_086_web_mode_feature_parity.yaml +0 -62
  333. package/core/dev/pipeline/archived/TASK_087_manual_memory_archival.yaml +0 -163
  334. package/core/dev/pipeline/archived/TASK_087_mobile_http_control.yaml +0 -68
  335. package/core/dev/pipeline/archived/TASK_088_fail_003_to_ppl_002_rule.yaml +0 -63
  336. package/core/dev/pipeline/archived/TASK_088_mobile_http_qa.yaml +0 -121
  337. package/core/dev/pipeline/archived/TASK_089_agent_collaboration_topic.yaml +0 -60
  338. package/core/dev/pipeline/archived/TASK_089_web_mode_monitor_fix.yaml +0 -58
  339. package/core/dev/pipeline/archived/TASK_090_cli_detection_fix.yaml +0 -61
  340. package/core/dev/pipeline/archived/TASK_090_ui_ux_lessons_topic.yaml +0 -63
  341. package/core/dev/pipeline/archived/TASK_091_expandable_card_design.yaml +0 -56
  342. package/core/dev/pipeline/archived/TASK_091_move_agent_section_components.yaml +0 -65
  343. package/core/dev/pipeline/archived/TASK_092_expandable_card_component.yaml +0 -60
  344. package/core/dev/pipeline/archived/TASK_092_refactor_agent_create_wizard.yaml +0 -84
  345. package/core/dev/pipeline/archived/TASK_093_taskcard_detail_integration.yaml +0 -57
  346. package/core/dev/pipeline/archived/TASK_093_update_barrel_exports_test.yaml +0 -84
  347. package/core/dev/pipeline/archived/TASK_094_ai_agent_generation_enhancement.yaml +0 -115
  348. package/core/dev/pipeline/archived/TASK_094_proposalcard_detail_integration.yaml +0 -55
  349. package/core/dev/pipeline/archived/TASK_095_preview_fixes.yaml +0 -129
  350. package/core/dev/pipeline/archived/TASK_095_single_agent_task_selector.yaml +0 -60
  351. package/core/dev/pipeline/archived/TASK_096_agents_page_ux_improvements.yaml +0 -163
  352. package/core/dev/pipeline/archived/TASK_096_single_agent_status_sync.yaml +0 -60
  353. package/core/dev/pipeline/archived/TASK_097_local_claude_error_logging.yaml +0 -59
  354. package/core/dev/pipeline/archived/TASK_097_single_agent_monitor_events.yaml +0 -59
  355. package/core/dev/pipeline/archived/TASK_098_product_manager_team_phase2.yaml +0 -60
  356. package/core/dev/pipeline/archived/TASK_098_single_agent_refactor_test.yaml +0 -58
  357. package/core/dev/pipeline/archived/TASK_099_backend_team_creation.yaml +0 -258
  358. package/core/dev/pipeline/archived/TASK_100_frontend_team_creation.yaml +0 -61
  359. package/core/dev/pipeline/archived/TASK_101_orchestrator_system.yaml +0 -403
  360. package/core/dev/pipeline/archived/TASK_102_designer_sre_teams.yaml +0 -90
  361. package/core/dev/pipeline/archived/TASK_103_integration_testing.yaml +0 -86
  362. package/core/dev/pipeline/archived/TASK_128_integration_testing.yaml +0 -83
  363. package/core/dev/pipeline/archived/TASK_134_cortex_v2_phase3_file_watcher.yaml +0 -65
  364. package/core/dev/pipeline/archived/TASK_134_team_http_api.yaml +0 -96
  365. package/core/dev/pipeline/archived/TASK_135_cortex_v2_phase3_git_monitor.yaml +0 -63
  366. package/core/dev/pipeline/archived/TASK_136_cortex_v2_phase3_change_analyzer.yaml +0 -69
  367. package/core/dev/pipeline/archived/TASK_137_cortex_v2_phase3_cache_invalidator.yaml +0 -67
  368. package/core/dev/pipeline/archived/TASK_137_team_orchestrator_integration.yaml +0 -93
  369. package/core/dev/pipeline/archived/TASK_138_cortex_v2_phase3_distributed_cache.yaml +0 -68
  370. package/core/dev/pipeline/archived/TASK_138_matrix_folder_structure.yaml +0 -61
  371. package/core/dev/pipeline/archived/TASK_139_cortex_v2_phase3_cache_prewarming.yaml +0 -65
  372. package/core/dev/pipeline/archived/TASK_146_unified_documentation.yaml +0 -141
  373. package/core/dev/pipeline/archived/TASK_147_pipeline_execution_rules.yaml +0 -76
  374. package/core/dev/pipeline/archived/TASK_148_update_claude_md.yaml +0 -77
  375. package/core/dev/pipeline/archived/TASK_149_fix_nextjs_mdx_serialization.yaml +0 -63
  376. package/core/dev/pipeline/archived/TASK_149_update_team_docs.yaml +0 -77
  377. package/core/dev/pipeline/archived/TASK_150_pipeline_workflow_guide.yaml +0 -82
  378. package/core/dev/pipeline/archived/TASK_164_fix_smart_context_switch.yaml +0 -49
  379. package/core/dev/pipeline/archived/TASK_165_ctags_symbol_index.yaml +0 -53
  380. package/core/dev/pipeline/archived/TASK_166_symbol_search_mcp_tool.yaml +0 -48
  381. package/core/dev/pipeline/archived/TASK_167_llm_module_summary.yaml +0 -55
  382. package/core/dev/pipeline/archived/TASK_168_map_reduce_context.yaml +0 -51
  383. package/core/dev/pipeline/archived/TASK_169_v2_integration_testing.yaml +0 -52
  384. package/core/dev/pipeline/backups/archive_2026-02-04T22-07-22/TASK_QUEUE_backup.json +0 -95
  385. package/core/dev/pipeline/docs/multi-agent-coordination.md +0 -446
  386. package/core/dev/pipeline/docs/overview.md +0 -406
  387. package/core/dev/pipeline/docs/task-management.md +0 -412
  388. package/core/dev/pipeline/docs/workflows.md +0 -32
  389. package/core/dev/pipeline/orchestrator/schemas/task_queue_schema.json +0 -58
  390. package/core/dev/pipeline/orchestrator/schemas/task_schema.json +0 -139
  391. package/core/dev/pipeline/plans/PLAN_task_cli_refactor.md +0 -281
  392. package/core/dev/pipeline/test_results/TASK_TEST_PARALLEL_002_result.txt +0 -27
  393. package/core/dev/plans/ANSUZ_SLIM_PLAN.md +0 -68
  394. package/core/dev/plans/CLI_FIRST_INSTALL_FLOW.md +0 -120
  395. package/core/dev/plans/FORMATION_RETIREMENT_PLAN.md +0 -313
  396. package/core/dev/plans/KUZU_REPLACEMENT_PLAN.md +0 -126
  397. package/core/dev/scripts/CRASH_DIAGNOSIS.md +0 -47
  398. package/core/dev/scripts/README.md +0 -142
  399. package/core/dev/scripts/RUN_ONCE.bat +0 -40
  400. package/core/dev/scripts/START_DEV_AGENT.bat +0 -63
  401. package/core/dev/scripts/START_MULTI_AGENT.bat +0 -80
  402. package/core/dev/scripts/dev_agent_scheduler.ps1 +0 -536
  403. package/core/dev/scripts/init_git.ps1 +0 -396
  404. package/core/dev/scripts/init_git.sh +0 -337
  405. package/core/dev/scripts/init_project.ps1 +0 -851
  406. package/core/dev/scripts/init_project.sh +0 -477
  407. package/core/dev/scripts/multi_agent_scheduler.ps1 +0 -2021
  408. package/core/dev/scripts/multi_agent_scheduler.sh +0 -1344
  409. package/core/dev/scripts/run_once.sh +0 -47
  410. package/core/dev/scripts/setup_rag.ps1 +0 -304
  411. package/core/dev/scripts/setup_rag.sh +0 -230
  412. package/core/dev/scripts/start_dev_agent.sh +0 -137
  413. package/core/dev/scripts/start_multi_agent.sh +0 -41
  414. package/core/dev/scripts/sync_task_queue.ps1 +0 -505
  415. package/core/dev/scripts/sync_task_queue.sh +0 -392
  416. package/core/dev/specs/agent-connect/PROTOCOL.md +0 -177
  417. package/core/dev/specs/agent-connect/SDK_GUIDE.md +0 -915
  418. package/core/dev/specs/agent-connect/examples/minimal-site/README.md +0 -137
  419. package/core/dev/specs/agent-connect/examples/minimal-site/package.json +0 -12
  420. package/core/dev/specs/agent-connect/examples/minimal-site/public/index.html +0 -116
  421. package/core/dev/specs/agent-connect/examples/minimal-site/public/install-redirect.js +0 -73
  422. package/core/dev/specs/agent-connect/examples/minimal-site/server.js +0 -516
  423. package/core/dev/specs/agent-connect/examples/minimal-site/test/smoke.test.mjs +0 -263
  424. package/core/dev/specs/agent-connect/history/DEFECT_REPORT_kenaz-agent-hub_2026-09-09_v0.4-empty-prompt-no-first-turn.md +0 -77
  425. package/core/dev/specs/agent-connect/history/DEFECT_REPORT_kenaz-agent-hub_2026-09-09_v0.4-prompt-mojibake.md +0 -90
  426. package/core/dev/specs/agent-connect/history/FEATURE_REQUEST_kenaz-agent-hub_2026-09-07.md +0 -61
  427. package/core/dev/specs/agent-connect/history/FEATURE_REQUEST_kenaz-agent-hub_2026-09-08_relay-v1-conformance.md +0 -76
  428. package/core/dev/specs/agent-connect/history/FEATURE_REQUEST_kenaz-agent-hub_2026-09-09_v0.4-session-channel.md +0 -87
  429. package/core/dev/specs/agent-connect/history/FLOWPIX_REPLY_agent-hub_2026-09-08_relay-v1-answers.md +0 -68
  430. package/core/dev/specs/agent-connect/history/FLOWPIX_bridge_CONTRACT.md +0 -642
  431. package/core/dev/specs/agent-connect/history/FLOWPIX_spikes_relay_spike_relay.mjs +0 -244
  432. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-07.md +0 -77
  433. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-08_direction-change-v0.3.md +0 -44
  434. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-08_relay-v1-answers-ack.md +0 -37
  435. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-08_relay-v1-conformance.md +0 -56
  436. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_annotations-install-coldstart.md +0 -44
  437. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_empty-prompt-first-turn.md +0 -56
  438. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_prompt-mojibake-fixed.md +0 -48
  439. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_session-channel.md +0 -57
  440. package/core/dev/specs/agent-connect/history/PROTOCOL_v0.3_snapshot.md +0 -379
  441. package/core/dev/specs/agent-connect/history/README.md +0 -47
  442. package/core/dev/specs/peer/CODEX_INTERACTIVE_PUSH.md +0 -65
  443. package/core/dev/specs/peer/CODEX_MANAGED_DAEMON.md +0 -54
  444. package/core/dev/specs/peer/CODEX_PEER_PULL_SPIKE.md +0 -54
  445. package/core/dev/specs/peer/MODS_SPIKE.md +0 -133
  446. package/core/dev/specs/peer/PER_PROJECT_ADDRESSING.md +0 -143
  447. package/core/dev/specs/peer/SWARM_PROTOCOLS.md +0 -256
  448. package/core/dev/specs/peer/codex-hook-shim-peer.test.js +0 -113
  449. package/core/dev/specs/peer/codex-push-launcher.test.js +0 -142
  450. package/core/dev/specs/peer/setup-codex-hooks.test.js +0 -60
  451. package/core/dev/specs/peer-ansuz/DELIVERY_SPIKE.md +0 -397
  452. package/core/dev/specs/peer-ansuz/DESIGN.md +0 -109
  453. package/core/dev/specs/peer-ansuz/spike/claude_poke.js +0 -129
  454. package/core/dev/specs/peer-ansuz/spike/claude_session_start_hook.js +0 -37
  455. package/core/dev/specs/peer-ansuz/spike/claude_settings_hook.json +0 -14
  456. package/core/dev/specs/peer-ansuz/spike/codex_appserver_client.js +0 -105
  457. package/core/dev/specs/peer-ansuz/spike/codex_appserver_query.js +0 -29
  458. package/core/dev/specs/peer-ansuz/spike/extract_timeline.js +0 -26
  459. package/core/dev/specs/synapse/SYMBOL_IDENTITY.md +0 -305
  460. package/core/dev/spikes/A4-cypher-varlen.md +0 -176
  461. package/core/dev/spikes/bloat-rounds.sh +0 -25
  462. package/core/dev/spikes/mods/clean-claude.js +0 -9
  463. package/core/dev/spikes/mods/drive-probe.js +0 -29
  464. package/core/dev/spikes/mods/e2e-peer.js +0 -71
  465. package/core/dev/spikes/mods/evidence/e2e-peer-control.json +0 -17
  466. package/core/dev/spikes/mods/evidence/e2e-peer-mod.json +0 -17
  467. package/core/dev/spikes/mods/evidence/probe-006a6e65-d807-4bc1-b648-fd7d1edfe0b4.jsonl +0 -4
  468. package/core/dev/spikes/mods/evidence/probe-cebdf1f7-f9c4-47a8-83cd-7c0786177404.jsonl +0 -12
  469. package/core/dev/spikes/mods/evidence/probe-eb21147d-10ce-4c32-93ed-37ca37d88d5a.jsonl +0 -11
  470. package/core/dev/spikes/mods/evidence/stream-cebdf1f7.jsonl +0 -18
  471. package/core/dev/spikes/mods/kenaz-mod-probe/.claude-plugin/plugin.json +0 -1
  472. package/core/dev/spikes/mods/kenaz-mod-probe/hooks/hooks.json +0 -1
  473. package/core/dev/spikes/mods/kenaz-mod-probe/hooks/register.ts +0 -65
  474. package/core/dev/spikes/mods/kenaz-mod-probe/tsconfig.json +0 -3
@@ -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