swarmdo 1.58.15 → 1.58.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 (192) hide show
  1. package/.claude/agents/base-template-generator.md +1 -1
  2. package/.claude/agents/goal/code-goal-planner.md +1 -1
  3. package/.claude/helpers/agent-bridge-hook.cjs +174 -0
  4. package/.claude/helpers/hook-handler.cjs +34 -8
  5. package/.claude/settings.json +16 -0
  6. package/.claude/settings.local.json +7 -0
  7. package/README.md +2 -2
  8. package/package.json +1 -1
  9. package/v3/@swarmdo/cli/.claude/helpers/agent-bridge-hook.cjs +174 -0
  10. package/v3/@swarmdo/cli/.claude/helpers/auto-memory-hook.mjs +274 -27
  11. package/v3/@swarmdo/cli/.claude/helpers/hook-handler.cjs +150 -107
  12. package/v3/@swarmdo/cli/.claude/helpers/intelligence.cjs +196 -989
  13. package/v3/@swarmdo/cli/.claude/helpers/{memory.js → memory.cjs} +10 -9
  14. package/v3/@swarmdo/cli/.claude/helpers/router.cjs +88 -0
  15. package/v3/@swarmdo/cli/.claude/helpers/session.cjs +125 -0
  16. package/v3/@swarmdo/cli/.claude/settings.json +22 -10
  17. package/v3/@swarmdo/cli/dist/src/commands/config.js +5 -4
  18. package/v3/@swarmdo/cli/dist/src/init/executor.d.ts +15 -0
  19. package/v3/@swarmdo/cli/dist/src/init/executor.js +24 -1
  20. package/v3/@swarmdo/cli/dist/src/init/settings-generator.js +33 -5
  21. package/v3/@swarmdo/cli/dist/src/mcp-tools/agent-tools.js +1 -1
  22. package/v3/@swarmdo/cli/dist/src/mcp-tools/neural-tools.d.ts +1 -0
  23. package/v3/@swarmdo/cli/dist/src/mcp-tools/neural-tools.js +132 -78
  24. package/v3/@swarmdo/cli/package.json +1 -1
  25. package/v3/@swarmdo/cli-core/dist/src/index.js +1 -1
  26. package/v3/@swarmdo/codex/dist/cli.js +0 -0
  27. package/v3/@swarmdo/hooks/dist/cli/guidance-cli.js +0 -0
  28. package/v3/@swarmdo/hooks/dist/statusline/index.d.ts +3 -3
  29. package/v3/@swarmdo/hooks/dist/statusline/index.js +3 -3
  30. package/v3/@swarmdo/integration/dist/__tests__/agentic-flow-agent.test.js +1 -4
  31. package/v3/@swarmdo/neural/dist/flash-attention.d.ts +1 -1
  32. package/v3/@swarmdo/neural/dist/flash-attention.js +1 -1
  33. package/v3/@swarmdo/plugin-agent-federation/dist/plugin.js +1 -1
  34. package/v3/@swarmdo/plugin-agent-federation/dist/transport/midstream-aware-loader.js +2 -2
  35. package/v3/@swarmdo/plugin-iot-cognitum/dist/application/index.d.ts +2 -0
  36. package/v3/@swarmdo/plugin-iot-cognitum/dist/application/index.js +2 -0
  37. package/v3/@swarmdo/plugin-iot-cognitum/dist/application/iot-coordinator.d.ts +138 -0
  38. package/v3/@swarmdo/plugin-iot-cognitum/dist/application/iot-coordinator.js +418 -0
  39. package/v3/@swarmdo/plugin-iot-cognitum/dist/bin.d.ts +15 -0
  40. package/v3/@swarmdo/plugin-iot-cognitum/dist/bin.js +240 -0
  41. package/v3/@swarmdo/plugin-iot-cognitum/dist/cli-commands.d.ts +7 -0
  42. package/v3/@swarmdo/plugin-iot-cognitum/dist/cli-commands.js +508 -0
  43. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/device-agent.d.ts +54 -0
  44. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/device-agent.js +2 -0
  45. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/device-fleet.d.ts +46 -0
  46. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/device-fleet.js +2 -0
  47. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/device-trust-level.d.ts +18 -0
  48. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/device-trust-level.js +28 -0
  49. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/index.d.ts +5 -0
  50. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/index.js +2 -0
  51. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/telemetry.d.ts +35 -0
  52. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/telemetry.js +2 -0
  53. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/device-repository.d.ts +11 -0
  54. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/device-repository.js +2 -0
  55. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/fleet-repository.d.ts +9 -0
  56. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/fleet-repository.js +2 -0
  57. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/index.d.ts +5 -0
  58. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/index.js +2 -0
  59. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/telemetry-repository.d.ts +12 -0
  60. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/telemetry-repository.js +2 -0
  61. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/trust-history-repository.d.ts +19 -0
  62. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/trust-history-repository.js +2 -0
  63. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/anomaly-detection-service.d.ts +44 -0
  64. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/anomaly-detection-service.js +117 -0
  65. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/device-lifecycle-service.d.ts +70 -0
  66. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/device-lifecycle-service.js +194 -0
  67. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/firmware-orchestration-service.d.ts +69 -0
  68. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/firmware-orchestration-service.js +139 -0
  69. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/fleet-topology-service.d.ts +34 -0
  70. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/fleet-topology-service.js +101 -0
  71. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/index.d.ts +10 -0
  72. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/index.js +10 -0
  73. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/mesh-service.d.ts +64 -0
  74. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/mesh-service.js +70 -0
  75. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/sona-integration-service.d.ts +44 -0
  76. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/sona-integration-service.js +79 -0
  77. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/telemetry-ingestion-service.d.ts +37 -0
  78. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/telemetry-ingestion-service.js +39 -0
  79. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/telemetry-service.d.ts +67 -0
  80. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/telemetry-service.js +58 -0
  81. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/witness-verification-service.d.ts +45 -0
  82. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/witness-verification-service.js +63 -0
  83. package/v3/@swarmdo/plugin-iot-cognitum/dist/index.d.ts +26 -0
  84. package/v3/@swarmdo/plugin-iot-cognitum/dist/index.js +17 -0
  85. package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/agentdb-telemetry-repository.d.ts +51 -0
  86. package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/agentdb-telemetry-repository.js +110 -0
  87. package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/in-memory-device-repository.d.ts +13 -0
  88. package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/in-memory-device-repository.js +25 -0
  89. package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/in-memory-fleet-repository.d.ts +11 -0
  90. package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/in-memory-fleet-repository.js +19 -0
  91. package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/in-memory-trust-history-repository.d.ts +11 -0
  92. package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/in-memory-trust-history-repository.js +27 -0
  93. package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/index.d.ts +6 -0
  94. package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/index.js +6 -0
  95. package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/seed-client-factory.d.ts +41 -0
  96. package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/seed-client-factory.js +64 -0
  97. package/v3/@swarmdo/plugin-iot-cognitum/dist/mcp-tools.d.ts +8 -0
  98. package/v3/@swarmdo/plugin-iot-cognitum/dist/mcp-tools.js +703 -0
  99. package/v3/@swarmdo/plugin-iot-cognitum/dist/plugin.d.ts +23 -0
  100. package/v3/@swarmdo/plugin-iot-cognitum/dist/plugin.js +239 -0
  101. package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/anomaly-scan-worker.d.ts +17 -0
  102. package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/anomaly-scan-worker.js +42 -0
  103. package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/firmware-watch-worker.d.ts +18 -0
  104. package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/firmware-watch-worker.js +45 -0
  105. package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/health-probe-worker.d.ts +19 -0
  106. package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/health-probe-worker.js +50 -0
  107. package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/mesh-sync-worker.d.ts +19 -0
  108. package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/mesh-sync-worker.js +47 -0
  109. package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/telemetry-ingest-worker.d.ts +17 -0
  110. package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/telemetry-ingest-worker.js +40 -0
  111. package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/witness-audit-worker.d.ts +18 -0
  112. package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/witness-audit-worker.js +51 -0
  113. package/v3/@swarmdo/providers/dist/swarmvector-provider.d.ts +1 -1
  114. package/v3/@swarmdo/providers/dist/swarmvector-provider.js +1 -1
  115. package/v3/@swarmdo/security/dist/input-validator.d.ts +6 -6
  116. package/v3/@swarmdo/shared/dist/hooks/safety/git-commit.js +1 -1
  117. package/v3/@swarmdo/shared/dist/mcp/transport/http.js +1 -8
  118. package/v3/@swarmdo/testing/dist/fixtures/agent-fixtures.d.ts +214 -0
  119. package/v3/@swarmdo/testing/dist/fixtures/agent-fixtures.js +595 -0
  120. package/v3/@swarmdo/testing/dist/fixtures/agents.d.ts +76 -0
  121. package/v3/@swarmdo/testing/dist/fixtures/agents.js +158 -0
  122. package/v3/@swarmdo/testing/dist/fixtures/configurations.d.ts +157 -0
  123. package/v3/@swarmdo/testing/dist/fixtures/configurations.js +337 -0
  124. package/v3/@swarmdo/testing/dist/fixtures/index.d.ts +10 -0
  125. package/v3/@swarmdo/testing/dist/fixtures/index.js +17 -0
  126. package/v3/@swarmdo/testing/dist/fixtures/mcp-fixtures.d.ts +329 -0
  127. package/v3/@swarmdo/testing/dist/fixtures/mcp-fixtures.js +714 -0
  128. package/v3/@swarmdo/testing/dist/fixtures/memory-entries.d.ts +159 -0
  129. package/v3/@swarmdo/testing/dist/fixtures/memory-entries.js +262 -0
  130. package/v3/@swarmdo/testing/dist/fixtures/memory-fixtures.d.ts +290 -0
  131. package/v3/@swarmdo/testing/dist/fixtures/memory-fixtures.js +547 -0
  132. package/v3/@swarmdo/testing/dist/fixtures/swarm-fixtures.d.ts +289 -0
  133. package/v3/@swarmdo/testing/dist/fixtures/swarm-fixtures.js +534 -0
  134. package/v3/@swarmdo/testing/dist/fixtures/tasks.d.ts +106 -0
  135. package/v3/@swarmdo/testing/dist/fixtures/tasks.js +229 -0
  136. package/v3/@swarmdo/testing/dist/helpers/assertion-helpers.d.ts +213 -0
  137. package/v3/@swarmdo/testing/dist/helpers/assertion-helpers.js +435 -0
  138. package/v3/@swarmdo/testing/dist/helpers/assertions.d.ts +135 -0
  139. package/v3/@swarmdo/testing/dist/helpers/assertions.js +217 -0
  140. package/v3/@swarmdo/testing/dist/helpers/create-mock.d.ts +96 -0
  141. package/v3/@swarmdo/testing/dist/helpers/create-mock.js +164 -0
  142. package/v3/@swarmdo/testing/dist/helpers/index.d.ts +14 -0
  143. package/v3/@swarmdo/testing/dist/helpers/index.js +22 -0
  144. package/v3/@swarmdo/testing/dist/helpers/mock-factory.d.ts +323 -0
  145. package/v3/@swarmdo/testing/dist/helpers/mock-factory.js +350 -0
  146. package/v3/@swarmdo/testing/dist/helpers/setup-teardown.d.ts +271 -0
  147. package/v3/@swarmdo/testing/dist/helpers/setup-teardown.js +446 -0
  148. package/v3/@swarmdo/testing/dist/helpers/swarm-instance.d.ts +142 -0
  149. package/v3/@swarmdo/testing/dist/helpers/swarm-instance.js +205 -0
  150. package/v3/@swarmdo/testing/dist/helpers/test-application.d.ts +190 -0
  151. package/v3/@swarmdo/testing/dist/helpers/test-application.js +138 -0
  152. package/v3/@swarmdo/testing/dist/helpers/test-utils.d.ts +274 -0
  153. package/v3/@swarmdo/testing/dist/helpers/test-utils.js +456 -0
  154. package/v3/@swarmdo/testing/dist/index.d.ts +42 -0
  155. package/v3/@swarmdo/testing/dist/index.js +66 -0
  156. package/v3/@swarmdo/testing/dist/mocks/index.d.ts +8 -0
  157. package/v3/@swarmdo/testing/dist/mocks/index.js +10 -0
  158. package/v3/@swarmdo/testing/dist/mocks/mock-mcp-client.d.ts +206 -0
  159. package/v3/@swarmdo/testing/dist/mocks/mock-mcp-client.js +575 -0
  160. package/v3/@swarmdo/testing/dist/mocks/mock-services.d.ts +287 -0
  161. package/v3/@swarmdo/testing/dist/mocks/mock-services.js +563 -0
  162. package/v3/@swarmdo/testing/dist/regression/api-contract.d.ts +109 -0
  163. package/v3/@swarmdo/testing/dist/regression/api-contract.js +374 -0
  164. package/v3/@swarmdo/testing/dist/regression/index.d.ts +18 -0
  165. package/v3/@swarmdo/testing/dist/regression/index.js +18 -0
  166. package/v3/@swarmdo/testing/dist/regression/integration-regression.d.ts +67 -0
  167. package/v3/@swarmdo/testing/dist/regression/integration-regression.js +334 -0
  168. package/v3/@swarmdo/testing/dist/regression/performance-baseline.d.ts +106 -0
  169. package/v3/@swarmdo/testing/dist/regression/performance-baseline.js +268 -0
  170. package/v3/@swarmdo/testing/dist/regression/regression-runner.d.ts +124 -0
  171. package/v3/@swarmdo/testing/dist/regression/regression-runner.js +227 -0
  172. package/v3/@swarmdo/testing/dist/regression/security-regression.d.ts +73 -0
  173. package/v3/@swarmdo/testing/dist/regression/security-regression.js +258 -0
  174. package/v3/@swarmdo/testing/dist/setup.d.ts +43 -0
  175. package/v3/@swarmdo/testing/dist/setup.js +91 -0
  176. package/v3/@swarmdo/testing/dist/v2-compat/api-compat.test.d.ts +10 -0
  177. package/v3/@swarmdo/testing/dist/v2-compat/api-compat.test.js +433 -0
  178. package/v3/@swarmdo/testing/dist/v2-compat/cli-compat.test.d.ts +10 -0
  179. package/v3/@swarmdo/testing/dist/v2-compat/cli-compat.test.js +352 -0
  180. package/v3/@swarmdo/testing/dist/v2-compat/compatibility-validator.d.ts +206 -0
  181. package/v3/@swarmdo/testing/dist/v2-compat/compatibility-validator.js +839 -0
  182. package/v3/@swarmdo/testing/dist/v2-compat/hooks-compat.test.d.ts +10 -0
  183. package/v3/@swarmdo/testing/dist/v2-compat/hooks-compat.test.js +428 -0
  184. package/v3/@swarmdo/testing/dist/v2-compat/index.d.ts +38 -0
  185. package/v3/@swarmdo/testing/dist/v2-compat/index.js +41 -0
  186. package/v3/@swarmdo/testing/dist/v2-compat/mcp-compat.test.d.ts +10 -0
  187. package/v3/@swarmdo/testing/dist/v2-compat/mcp-compat.test.js +419 -0
  188. package/v3/@swarmdo/testing/dist/v2-compat/report-generator.d.ts +34 -0
  189. package/v3/@swarmdo/testing/dist/v2-compat/report-generator.js +372 -0
  190. package/v3/@swarmdo/cli/.claude/helpers/router.js +0 -105
  191. package/v3/@swarmdo/cli/.claude/helpers/session.js +0 -157
  192. package/v3/@swarmdo/cli/.claude/helpers/statusline.js +0 -352
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: base-template-generator
3
- description: Use this agent when you need to create foundational templates, boilerplate code, or starter configurations for new projects, components, or features. This agent excels at generating clean, well-structured base templates that follow best practices and can be easily customized. Examples: <example>Context: User needs to start a new React component and wants a solid foundation. user: 'I need to create a new user profile component' assistant: 'I'll use the base-template-generator agent to create a comprehensive React component template with proper structure, TypeScript definitions, and styling setup.' <commentary>Since the user needs a foundational template for a new component, use the base-template-generator agent to create a well-structured starting point.</commentary></example> <example>Context: User is setting up a new API endpoint and needs a template. user: 'Can you help me set up a new REST API endpoint for user management?' assistant: 'I'll use the base-template-generator agent to create a complete API endpoint template with proper error handling, validation, and documentation structure.' <commentary>The user needs a foundational template for an API endpoint, so use the base-template-generator agent to provide a comprehensive starting point.</commentary></example>
3
+ description: "Use this agent when you need to create foundational templates, boilerplate code, or starter configurations for new projects, components, or features. This agent excels at generating clean, well-structured base templates that follow best practices and can be easily customized. Examples: <example>Context: User needs to start a new React component and wants a solid foundation. user: 'I need to create a new user profile component' assistant: 'I'll use the base-template-generator agent to create a comprehensive React component template with proper structure, TypeScript definitions, and styling setup.' <commentary>Since the user needs a foundational template for a new component, use the base-template-generator agent to create a well-structured starting point.</commentary></example> <example>Context: User is setting up a new API endpoint and needs a template. user: 'Can you help me set up a new REST API endpoint for user management?' assistant: 'I'll use the base-template-generator agent to create a complete API endpoint template with proper error handling, validation, and documentation structure.' <commentary>The user needs a foundational template for an API endpoint, so use the base-template-generator agent to provide a comprehensive starting point.</commentary></example>"
4
4
  ---
5
5
 
6
6
  You are a Base Template Generator, an expert architect specializing in creating clean, well-structured foundational templates and boilerplate code. Your expertise lies in establishing solid starting points that follow industry best practices, maintain consistency, and provide clear extension paths.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: code-goal-planner
3
- description: Code-centric Goal-Oriented Action Planning specialist that creates intelligent plans for software development objectives. Excels at breaking down complex coding tasks into achievable milestones with clear success criteria. Examples: <example>Context: User needs to implement a new authentication system. user: 'I need to add OAuth2 authentication to our API' assistant: 'I'll use the code-goal-planner agent to create a comprehensive implementation plan with milestones for OAuth2 integration, including provider setup, token management, and security considerations.' <commentary>Since this is a complex feature implementation, the code-goal-planner will break it down into testable milestones.</commentary></example> <example>Context: User wants to improve application performance. user: 'Our app is slow, we need to optimize database queries' assistant: 'I'll use the code-goal-planner agent to develop a performance optimization plan with measurable targets for query optimization, including profiling, indexing strategies, and caching implementation.' <commentary>Performance optimization requires systematic planning with clear metrics, perfect for code-goal-planner.</commentary></example>
3
+ description: "Code-centric Goal-Oriented Action Planning specialist that creates intelligent plans for software development objectives. Excels at breaking down complex coding tasks into achievable milestones with clear success criteria. Examples: <example>Context: User needs to implement a new authentication system. user: 'I need to add OAuth2 authentication to our API' assistant: 'I'll use the code-goal-planner agent to create a comprehensive implementation plan with milestones for OAuth2 integration, including provider setup, token management, and security considerations.' <commentary>Since this is a complex feature implementation, the code-goal-planner will break it down into testable milestones.</commentary></example> <example>Context: User wants to improve application performance. user: 'Our app is slow, we need to optimize database queries' assistant: 'I'll use the code-goal-planner agent to develop a performance optimization plan with measurable targets for query optimization, including profiling, indexing strategies, and caching implementation.' <commentary>Performance optimization requires systematic planning with clear metrics, perfect for code-goal-planner.</commentary></example>"
4
4
  ---
5
5
 
6
6
  You are a Code-Centric Goal-Oriented Action Planning (GOAP) specialist integrated with SPARC methodology, focused exclusively on software development objectives. You excel at transforming vague development requirements into concrete, achievable coding milestones using the systematic SPARC approach (Specification, Pseudocode, Architecture, Refinement, Completion) with clear success criteria and measurable outcomes.
@@ -0,0 +1,174 @@
1
+ /**
2
+ * agent-bridge-hook.cjs — bind real Claude Code subagents into Swarmdo's
3
+ * canonical agent registry, automatically.
4
+ *
5
+ * #108. `src/agent-bridge/bridge.ts` was written to solve "a session can run
6
+ * four Claude Code agents while `swarmdo agent list` stays empty", and is pure
7
+ * by design because "All fs / MCP / spawning lives in the command + hook
8
+ * layers". The command layer got built (`swarmdo agent bridge register`); the
9
+ * hook layer never did. So nothing ever registered a Task/Agent-tool subagent,
10
+ * `.swarmdo/agents/store.json` stayed `{"agents":{}}`, and the statusline's
11
+ * `🐝 Swarms N 🤖 Agents M` sat at 0/0 forever. This file is that missing
12
+ * hook layer.
13
+ *
14
+ * Why shell out to the CLI instead of writing the store here: registering is
15
+ * not just a store write — `agent_bridge_register` also auto-forms a swarm from
16
+ * config and enrolls the agent (agent-tools.ts:462), which is what makes the
17
+ * Swarms counter move too. bridge.ts's own rule is to go through the canonical
18
+ * registerAgent path — "NO parallel store". Reimplementing that in CJS would
19
+ * fork the registry. The CLI costs ~850ms to boot (it loads ONNX), far too slow
20
+ * to block every subagent spawn, so calls are fired detached and unref'd: the
21
+ * hook returns immediately and the registry lands ~1s later. The statusline
22
+ * polls every 5s, so eventual consistency is invisible here.
23
+ */
24
+
25
+ const fs = require('fs');
26
+ const os = require('os');
27
+ const path = require('path');
28
+ const { spawn } = require('child_process');
29
+
30
+ /**
31
+ * Mirror of src/agent-bridge/bridge.ts `bridgeAgentId` — kept in sync by hand,
32
+ * because this hook is standalone CommonJS and cannot import the ESM engine
33
+ * (the same constraint router.cjs already works under for classifyPrompt).
34
+ * __tests__/agent-bridge-hook.test.ts asserts the two implementations agree.
35
+ *
36
+ * Deterministic, so SubagentStart and SubagentStop derive the SAME id from the
37
+ * same agent_id and the stop reliably terminates the record the start created.
38
+ */
39
+ function bridgeAgentId(d) {
40
+ const sess = d.sessionId
41
+ ? d.sessionId.replace(/[^A-Za-z0-9]/g, '').slice(0, 8) || 'nosess'
42
+ : 'nosess';
43
+ const safe = String(d.name || '').replace(/[^A-Za-z0-9_-]+/g, '-').replace(/^-+|-+$/g, '') || 'agent';
44
+ return `cc-${sess}-${safe}`;
45
+ }
46
+
47
+ /**
48
+ * Locate an installed CLI bin. Mirror of statusline.cjs resolveCliBin() — same
49
+ * candidate order, same reason (#2337): never `npx @latest` from a hook.
50
+ * Returns null when nothing is installed, in which case we no-op rather than
51
+ * pay a registry round-trip on every subagent spawn.
52
+ */
53
+ function resolveCliBin(cwd) {
54
+ try {
55
+ const home = os.homedir();
56
+ const base = cwd || process.cwd();
57
+ const candidates = [
58
+ path.join(home, '.claude', 'plugins', 'marketplaces', 'swarmdo', 'bin', 'cli.js'),
59
+ path.join(base, 'node_modules', '@swarmdo', 'cli', 'bin', 'cli.js'),
60
+ path.join(base, 'node_modules', 'swarmdo', 'bin', 'cli.js'),
61
+ path.join(base, 'v3', '@swarmdo', 'cli', 'bin', 'cli.js'),
62
+ ];
63
+ try {
64
+ const binDir = path.dirname(process.execPath);
65
+ const globalModuleDirs = [
66
+ path.join(binDir, '..', 'lib', 'node_modules'),
67
+ path.join(binDir, 'node_modules'),
68
+ '/opt/homebrew/lib/node_modules',
69
+ '/usr/local/lib/node_modules',
70
+ ];
71
+ for (const prefix of [process.env.npm_config_prefix, process.env.PREFIX, path.join(home, '.npm-global')]) {
72
+ if (prefix) globalModuleDirs.push(path.join(prefix, 'lib', 'node_modules'));
73
+ }
74
+ for (const gm of globalModuleDirs) {
75
+ candidates.push(
76
+ path.join(gm, 'swarmdo', 'bin', 'cli.js'),
77
+ path.join(gm, '@swarmdo', 'cli', 'bin', 'cli.js'),
78
+ );
79
+ }
80
+ } catch { /* ignore */ }
81
+ for (const p of candidates) {
82
+ if (fs.existsSync(p)) return p;
83
+ }
84
+ } catch { /* ignore */ }
85
+ return null;
86
+ }
87
+
88
+ /**
89
+ * Is this hook payload a real subagent event we should act on? `agent_id` is
90
+ * present ONLY when the hook fires for a subagent, so it doubles as the guard
91
+ * against main-thread invocations. Pure.
92
+ */
93
+ function isSubagentEvent(hookInput) {
94
+ const id = hookInput && (hookInput.agent_id || hookInput.agentId);
95
+ return typeof id === 'string' && id.length > 0;
96
+ }
97
+
98
+ /**
99
+ * Build the `agent bridge register` argv for a SubagentStart payload, or null
100
+ * when the payload is not a subagent event. Pure — the spawn happens in
101
+ * register(). Registering is idempotent on name+session, so a duplicate
102
+ * SubagentStart updates the bound record rather than forking a second one.
103
+ */
104
+ function buildRegisterArgs(hookInput) {
105
+ if (!isSubagentEvent(hookInput)) return null;
106
+ const agentId = hookInput.agent_id || hookInput.agentId;
107
+ const sessionId = hookInput.session_id || hookInput.sessionId || '';
108
+ const agentType = hookInput.agent_type || hookInput.agentType || 'general-purpose';
109
+ const args = ['agent', 'bridge', 'register', '-n', agentId, '-t', agentType];
110
+ if (sessionId) args.push('-s', sessionId);
111
+ return args;
112
+ }
113
+
114
+ /**
115
+ * Build the `agent stop` argv for a SubagentStop payload, or null when the
116
+ * payload is not a subagent event. `agent stop` sets status='terminated'
117
+ * (agent-tools.ts:721), which is precisely what computeSwarmStatus filters on,
118
+ * so the Agents count decrements when a subagent finishes. `-f` because a hook
119
+ * has no TTY and must not hit the interactive confirm. Pure.
120
+ */
121
+ function buildTerminateArgs(hookInput) {
122
+ if (!isSubagentEvent(hookInput)) return null;
123
+ const id = bridgeAgentId({
124
+ name: hookInput.agent_id || hookInput.agentId,
125
+ sessionId: hookInput.session_id || hookInput.sessionId,
126
+ });
127
+ return ['agent', 'stop', id, '-f'];
128
+ }
129
+
130
+ /**
131
+ * Fire a CLI subcommand and forget it. Detached + unref'd + stdio ignored so
132
+ * the hook process can exit immediately without waiting on the CLI's ~850ms
133
+ * boot, and without the child dying alongside it.
134
+ */
135
+ function spawnDetached(args, cwd) {
136
+ const cliBin = resolveCliBin(cwd);
137
+ if (!cliBin) return false;
138
+ try {
139
+ const child = spawn(process.execPath, [cliBin, ...args], {
140
+ cwd: cwd || process.cwd(),
141
+ detached: true,
142
+ stdio: 'ignore',
143
+ });
144
+ child.unref();
145
+ return true;
146
+ } catch {
147
+ return false;
148
+ }
149
+ }
150
+
151
+ /** SubagentStart → bind the subagent (and auto-form its swarm). */
152
+ function register(hookInput, cwd) {
153
+ const args = buildRegisterArgs(hookInput);
154
+ if (!args) return false;
155
+ return spawnDetached(args, cwd || (hookInput && hookInput.cwd));
156
+ }
157
+
158
+ /** SubagentStop → mark the bound record terminated. */
159
+ function terminate(hookInput, cwd) {
160
+ const args = buildTerminateArgs(hookInput);
161
+ if (!args) return false;
162
+ return spawnDetached(args, cwd || (hookInput && hookInput.cwd));
163
+ }
164
+
165
+ module.exports = {
166
+ bridgeAgentId,
167
+ resolveCliBin,
168
+ isSubagentEvent,
169
+ buildRegisterArgs,
170
+ buildTerminateArgs,
171
+ spawnDetached,
172
+ register,
173
+ terminate,
174
+ };
@@ -34,6 +34,7 @@ const router = safeRequire(path.join(helpersDir, 'router.cjs'));
34
34
  const session = safeRequire(path.join(helpersDir, 'session.cjs'));
35
35
  const memory = safeRequire(path.join(helpersDir, 'memory.cjs'));
36
36
  const intelligence = safeRequire(path.join(helpersDir, 'intelligence.cjs'));
37
+ const agentBridge = safeRequire(path.join(helpersDir, 'agent-bridge-hook.cjs'));
37
38
 
38
39
  // ── Intelligence timeout protection (fixes #1530, #1531) ───────────────────
39
40
  var INTELLIGENCE_TIMEOUT_MS = 3000;
@@ -143,19 +144,23 @@ const handlers = {
143
144
  } else {
144
145
  console.log('[INFO] Router not available, using default routing');
145
146
  }
146
- // Agentic prompts → remind the main agent to actually USE Swarmdo: spawn
147
- // Claude Code agents AND bridge them so Swarmdo tracks the work and
148
- // auto-forms a swarm. Advisory + fully guarded — never breaks the prompt.
147
+ // Agentic prompts → suggest spawning a swarm, and which roles. Swarmdo
148
+ // cannot call Claude Code's Agent tool itself, so this advisory is the only
149
+ // way it can ask. Fully guarded — never breaks the prompt.
150
+ //
151
+ // Deliberately does NOT mention `agent bridge register` (#108): the
152
+ // SubagentStart hook registers every subagent on spawn, so telling the main
153
+ // agent to register by hand is both wrong and redundant work. This fires on
154
+ // every agentic prompt, so it is kept to one line — the three lines of
155
+ // manual-registration instructions it replaced were pure token cost.
149
156
  try {
150
157
  if (router && router.classifyAgentic) {
151
158
  const intent = router.classifyAgentic(prompt);
152
159
  if (intent.requiresAgents) {
153
160
  const roles = intent.roles.join(', ');
154
161
  console.log('');
155
- console.log('[SWARMDO] Agentic task — use the swarm: after you spawn Claude Code agents,');
156
- console.log(' register each so Swarmdo tracks them and auto-forms a swarm from your config:');
157
- console.log(' swarmdo agent bridge register -n <agent-name> -t <role> -s <session>');
158
- console.log(' suggested roles: ' + roles + ' · then: swarmdo agent bridge list / swarm status');
162
+ console.log('[SWARMDO] Agentic task — consider spawning agents: ' + roles
163
+ + ' (auto-registered on spawn; see `swarmdo swarm status`)');
159
164
  }
160
165
  }
161
166
  } catch (e) { /* advisory only — never break the prompt */ }
@@ -270,6 +275,27 @@ const handlers = {
270
275
  console.log('[OK] Status check');
271
276
  },
272
277
 
278
+ // SubagentStart — bind the spawned Claude Code subagent into Swarmdo's
279
+ // canonical registry so `swarmdo agent list` and the statusline's
280
+ // `🐝 Swarms N 🤖 Agents M` reflect agents that actually exist (#108).
281
+ // Registering also auto-forms the swarm, so both counters move.
282
+ 'agent-register': () => {
283
+ if (!agentBridge) return;
284
+ if (!agentBridge.isSubagentEvent(hookInput)) return; // main-thread call
285
+ var ok = agentBridge.register(hookInput);
286
+ console.log(ok
287
+ ? '[OK] Bridged subagent ' + (hookInput.agent_type || 'agent') + ' into Swarmdo'
288
+ : '[WARN] Could not bridge subagent (no installed CLI found)');
289
+ },
290
+
291
+ // SubagentStop — mark the bound record terminated so the Agents count
292
+ // decrements. Same deterministic id the register side derived (#108).
293
+ 'agent-terminate': () => {
294
+ if (!agentBridge) return;
295
+ if (!agentBridge.isSubagentEvent(hookInput)) return;
296
+ agentBridge.terminate(hookInput);
297
+ },
298
+
273
299
  'stats': () => {
274
300
  if (intelligence && intelligence.stats) {
275
301
  intelligence.stats(args.includes('--json'));
@@ -288,7 +314,7 @@ if (command && handlers[command]) {
288
314
  } else if (command) {
289
315
  console.log('[OK] Hook: ' + command);
290
316
  } else {
291
- console.log('Usage: hook-handler.cjs <route|pre-bash|post-edit|session-restore|session-end|pre-task|post-task|compact-manual|compact-auto|status|stats>');
317
+ console.log('Usage: hook-handler.cjs <route|pre-bash|post-edit|session-restore|session-end|pre-task|post-task|agent-register|agent-terminate|compact-manual|compact-auto|status|stats>');
292
318
  }
293
319
  }
294
320
 
@@ -144,6 +144,17 @@
144
144
  ]
145
145
  }
146
146
  ],
147
+ "SubagentStart": [
148
+ {
149
+ "hooks": [
150
+ {
151
+ "type": "command",
152
+ "command": "node \"$CLAUDE_PROJECT_DIR/.claude/helpers/hook-handler.cjs\" agent-register",
153
+ "timeout": 5000
154
+ }
155
+ ]
156
+ }
157
+ ],
147
158
  "SubagentStop": [
148
159
  {
149
160
  "hooks": [
@@ -151,6 +162,11 @@
151
162
  "type": "command",
152
163
  "command": "node \"$CLAUDE_PROJECT_DIR/.claude/helpers/hook-handler.cjs\" post-task",
153
164
  "timeout": 5000
165
+ },
166
+ {
167
+ "type": "command",
168
+ "command": "node \"$CLAUDE_PROJECT_DIR/.claude/helpers/hook-handler.cjs\" agent-terminate",
169
+ "timeout": 5000
154
170
  }
155
171
  ]
156
172
  }
@@ -0,0 +1,7 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(gh run *)"
5
+ ]
6
+ }
7
+ }
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![swarmdo](swarmdo/assets/brand/logo-full.svg)](https://swarmdo.com)
4
4
 
5
- [![npm version (swarmdo)](https://img.shields.io/badge/npx%20swarmdo-v1.58.15-cb3837?style=for-the-badge&logo=npm&logoColor=white)](https://github.com/SwarmDo/swarmdo/releases)
5
+ [![npm version (swarmdo)](https://img.shields.io/badge/npx%20swarmdo-v1.58.23-cb3837?style=for-the-badge&logo=npm&logoColor=white)](https://github.com/SwarmDo/swarmdo/releases)
6
6
  [![MIT License](https://img.shields.io/badge/License-MIT-yellow?style=for-the-badge)](https://github.com/SwarmDo/swarmdo/blob/main/LICENSE)
7
7
  [![Website](https://img.shields.io/badge/swarmdo.com-e2a33c?style=for-the-badge&logoColor=black)](https://swarmdo.com)
8
8
  [![Star on GitHub](https://img.shields.io/github/stars/SwarmDo/swarmdo?style=for-the-badge&logo=github&color=gold)](https://github.com/SwarmDo/swarmdo)
@@ -294,7 +294,7 @@ The recent release train added a full day-to-day operations layer around the swa
294
294
  | `swarmdo hidden-coupling` | **Co-change with no import edge** — join the two graphs swarmdo already owns (temporal `coupling` from git + `codegraph`'s import graph) and emit the set difference: file pairs that keep changing together yet nothing in the code links them ("logical minus structural coupling" — a config and its consumers, a schema and its mirror type). The co-edit `affected` can't see. `--since`, `--min-shared`, `--csv`, `--format json`. Grounded in Gall et al. (ICSM 1998). Deterministic |
295
295
  | `swarmdo standup` (alias `mine`) | **What did I do?** — your commits since your last working day, grouped by day with a diffstat. **Weekend-aware** (git-standup parity): on Monday it reaches back to Friday, on Sunday to Friday, otherwise to yesterday — one-command recall for a standup or for re-orienting at the start of a session. Defaults to the current git user; `--author <name>`/`--all` for teammates, `--days N` or `--since 2w` to override the window, `--format json`. Pure engine (weekend math + per-day fold) → fixture-tested. Deterministic |
296
296
  | `swarmdo commands` (alias `slash`) | **Hot/cold/orphan usage report** for your authored `.claude/` surface — which custom slash-commands (`.claude/commands/**`) and subagents (`.claude/agents/**`) you actually invoke (**hot**, with counts), which are **cold** (defined but never used → prune candidates), and which are **orphan** (invoked but undefined → a typo or a builtin). `config lint` says "are these valid?"; this says "are these used?" — joining the defined files against invocation counts mined from local transcripts (`<command-name>` markers + `subagent_type` fields). `--unused` prints just the prune list, `--unused --strict` is a CI gate (exit 1 if anything's dead), `--all` counts across every project, `--json`. Pure parsers + join → fixture-tested |
297
- | `swarmdo agent bridge` | **Link Claude Code agents ⇄ Swarmdo** — the fix for "Swarmdo is installed but never actually used." Swarmdo can't call Claude Code's `Agent` tool (only the main loop can), so `agent bridge register -n <name>` binds a real Claude Code agent into Swarmdo's registry (`swarmdo agent list` stops being empty) and **auto-spins-up a swarm from your config, enrolling the agent** — the next bind joins the same swarm. `bridge list` (bound vs native), `bridge sync --live a,b` (reconcile drift), `bridge advise "<prompt>"` (should this warrant a swarm? which roles?). Also MCP tools `agent_bridge_register`/`agent_bridge_list`. Pure engine → 16 tests |
297
+ | `swarmdo agent bridge` | **Link Claude Code agents ⇄ Swarmdo** — the fix for "Swarmdo is installed but never actually used." Swarmdo can't call Claude Code's `Agent` tool (only the main loop can), so `agent bridge register -n <name>` binds a real Claude Code agent into Swarmdo's registry (`swarmdo agent list` stops being empty) and **auto-spins-up a swarm from your config, enrolling the agent** — the next bind joins the same swarm. **Automatic since 1.58.18:** `swarmdo init` wires a `SubagentStart` hook that registers every Claude Code subagent as it spawns, and a `SubagentStop` hook that marks it terminated — so the statusline's `🐝 Swarms N 🤖 Agents M` tracks real agents with no manual step (#108). `bridge list` (bound vs native), `bridge sync --live a,b` (reconcile drift), `bridge advise "<prompt>"` (should this warrant a swarm? which roles?). Also MCP tools `agent_bridge_register`/`agent_bridge_list`. Pure engine → 16 tests |
298
298
  | `swarmdo testreport` | **JUnit/TAP → failure digest** — turn raw test-result files into the exact failing test names + `file:line` + assertion messages, instead of scanning hundreds of log lines. The front-half of the test→fix loop: feed the failures straight into `repair`. Reads a file, a directory, or stdin; `--ci` exits 1 on any failure, `--format json`. Also an MCP tool (`testreport`). Deterministic |
299
299
  | `swarmdo integrations` (alias `integrate`) | **Use swarmdo from Codex CLI, GitHub Copilot CLI, and pi** — one command wires AGENTS.md + each CLI's MCP config (idempotent, dry-run first, never touches your Claude Code setup) |
300
300
  | OpenRouter model pool | **Let swarms pick from any models you configure** — declare tier-mapped OpenRouter models in `swarmdo.config.json`; the router Thompson-samples among them per task and the execution layer dispatches the winner |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swarmdo",
3
- "version": "1.58.15",
3
+ "version": "1.58.23",
4
4
  "description": "Swarmdo - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -0,0 +1,174 @@
1
+ /**
2
+ * agent-bridge-hook.cjs — bind real Claude Code subagents into Swarmdo's
3
+ * canonical agent registry, automatically.
4
+ *
5
+ * #108. `src/agent-bridge/bridge.ts` was written to solve "a session can run
6
+ * four Claude Code agents while `swarmdo agent list` stays empty", and is pure
7
+ * by design because "All fs / MCP / spawning lives in the command + hook
8
+ * layers". The command layer got built (`swarmdo agent bridge register`); the
9
+ * hook layer never did. So nothing ever registered a Task/Agent-tool subagent,
10
+ * `.swarmdo/agents/store.json` stayed `{"agents":{}}`, and the statusline's
11
+ * `🐝 Swarms N 🤖 Agents M` sat at 0/0 forever. This file is that missing
12
+ * hook layer.
13
+ *
14
+ * Why shell out to the CLI instead of writing the store here: registering is
15
+ * not just a store write — `agent_bridge_register` also auto-forms a swarm from
16
+ * config and enrolls the agent (agent-tools.ts:462), which is what makes the
17
+ * Swarms counter move too. bridge.ts's own rule is to go through the canonical
18
+ * registerAgent path — "NO parallel store". Reimplementing that in CJS would
19
+ * fork the registry. The CLI costs ~850ms to boot (it loads ONNX), far too slow
20
+ * to block every subagent spawn, so calls are fired detached and unref'd: the
21
+ * hook returns immediately and the registry lands ~1s later. The statusline
22
+ * polls every 5s, so eventual consistency is invisible here.
23
+ */
24
+
25
+ const fs = require('fs');
26
+ const os = require('os');
27
+ const path = require('path');
28
+ const { spawn } = require('child_process');
29
+
30
+ /**
31
+ * Mirror of src/agent-bridge/bridge.ts `bridgeAgentId` — kept in sync by hand,
32
+ * because this hook is standalone CommonJS and cannot import the ESM engine
33
+ * (the same constraint router.cjs already works under for classifyPrompt).
34
+ * __tests__/agent-bridge-hook.test.ts asserts the two implementations agree.
35
+ *
36
+ * Deterministic, so SubagentStart and SubagentStop derive the SAME id from the
37
+ * same agent_id and the stop reliably terminates the record the start created.
38
+ */
39
+ function bridgeAgentId(d) {
40
+ const sess = d.sessionId
41
+ ? d.sessionId.replace(/[^A-Za-z0-9]/g, '').slice(0, 8) || 'nosess'
42
+ : 'nosess';
43
+ const safe = String(d.name || '').replace(/[^A-Za-z0-9_-]+/g, '-').replace(/^-+|-+$/g, '') || 'agent';
44
+ return `cc-${sess}-${safe}`;
45
+ }
46
+
47
+ /**
48
+ * Locate an installed CLI bin. Mirror of statusline.cjs resolveCliBin() — same
49
+ * candidate order, same reason (#2337): never `npx @latest` from a hook.
50
+ * Returns null when nothing is installed, in which case we no-op rather than
51
+ * pay a registry round-trip on every subagent spawn.
52
+ */
53
+ function resolveCliBin(cwd) {
54
+ try {
55
+ const home = os.homedir();
56
+ const base = cwd || process.cwd();
57
+ const candidates = [
58
+ path.join(home, '.claude', 'plugins', 'marketplaces', 'swarmdo', 'bin', 'cli.js'),
59
+ path.join(base, 'node_modules', '@swarmdo', 'cli', 'bin', 'cli.js'),
60
+ path.join(base, 'node_modules', 'swarmdo', 'bin', 'cli.js'),
61
+ path.join(base, 'v3', '@swarmdo', 'cli', 'bin', 'cli.js'),
62
+ ];
63
+ try {
64
+ const binDir = path.dirname(process.execPath);
65
+ const globalModuleDirs = [
66
+ path.join(binDir, '..', 'lib', 'node_modules'),
67
+ path.join(binDir, 'node_modules'),
68
+ '/opt/homebrew/lib/node_modules',
69
+ '/usr/local/lib/node_modules',
70
+ ];
71
+ for (const prefix of [process.env.npm_config_prefix, process.env.PREFIX, path.join(home, '.npm-global')]) {
72
+ if (prefix) globalModuleDirs.push(path.join(prefix, 'lib', 'node_modules'));
73
+ }
74
+ for (const gm of globalModuleDirs) {
75
+ candidates.push(
76
+ path.join(gm, 'swarmdo', 'bin', 'cli.js'),
77
+ path.join(gm, '@swarmdo', 'cli', 'bin', 'cli.js'),
78
+ );
79
+ }
80
+ } catch { /* ignore */ }
81
+ for (const p of candidates) {
82
+ if (fs.existsSync(p)) return p;
83
+ }
84
+ } catch { /* ignore */ }
85
+ return null;
86
+ }
87
+
88
+ /**
89
+ * Is this hook payload a real subagent event we should act on? `agent_id` is
90
+ * present ONLY when the hook fires for a subagent, so it doubles as the guard
91
+ * against main-thread invocations. Pure.
92
+ */
93
+ function isSubagentEvent(hookInput) {
94
+ const id = hookInput && (hookInput.agent_id || hookInput.agentId);
95
+ return typeof id === 'string' && id.length > 0;
96
+ }
97
+
98
+ /**
99
+ * Build the `agent bridge register` argv for a SubagentStart payload, or null
100
+ * when the payload is not a subagent event. Pure — the spawn happens in
101
+ * register(). Registering is idempotent on name+session, so a duplicate
102
+ * SubagentStart updates the bound record rather than forking a second one.
103
+ */
104
+ function buildRegisterArgs(hookInput) {
105
+ if (!isSubagentEvent(hookInput)) return null;
106
+ const agentId = hookInput.agent_id || hookInput.agentId;
107
+ const sessionId = hookInput.session_id || hookInput.sessionId || '';
108
+ const agentType = hookInput.agent_type || hookInput.agentType || 'general-purpose';
109
+ const args = ['agent', 'bridge', 'register', '-n', agentId, '-t', agentType];
110
+ if (sessionId) args.push('-s', sessionId);
111
+ return args;
112
+ }
113
+
114
+ /**
115
+ * Build the `agent stop` argv for a SubagentStop payload, or null when the
116
+ * payload is not a subagent event. `agent stop` sets status='terminated'
117
+ * (agent-tools.ts:721), which is precisely what computeSwarmStatus filters on,
118
+ * so the Agents count decrements when a subagent finishes. `-f` because a hook
119
+ * has no TTY and must not hit the interactive confirm. Pure.
120
+ */
121
+ function buildTerminateArgs(hookInput) {
122
+ if (!isSubagentEvent(hookInput)) return null;
123
+ const id = bridgeAgentId({
124
+ name: hookInput.agent_id || hookInput.agentId,
125
+ sessionId: hookInput.session_id || hookInput.sessionId,
126
+ });
127
+ return ['agent', 'stop', id, '-f'];
128
+ }
129
+
130
+ /**
131
+ * Fire a CLI subcommand and forget it. Detached + unref'd + stdio ignored so
132
+ * the hook process can exit immediately without waiting on the CLI's ~850ms
133
+ * boot, and without the child dying alongside it.
134
+ */
135
+ function spawnDetached(args, cwd) {
136
+ const cliBin = resolveCliBin(cwd);
137
+ if (!cliBin) return false;
138
+ try {
139
+ const child = spawn(process.execPath, [cliBin, ...args], {
140
+ cwd: cwd || process.cwd(),
141
+ detached: true,
142
+ stdio: 'ignore',
143
+ });
144
+ child.unref();
145
+ return true;
146
+ } catch {
147
+ return false;
148
+ }
149
+ }
150
+
151
+ /** SubagentStart → bind the subagent (and auto-form its swarm). */
152
+ function register(hookInput, cwd) {
153
+ const args = buildRegisterArgs(hookInput);
154
+ if (!args) return false;
155
+ return spawnDetached(args, cwd || (hookInput && hookInput.cwd));
156
+ }
157
+
158
+ /** SubagentStop → mark the bound record terminated. */
159
+ function terminate(hookInput, cwd) {
160
+ const args = buildTerminateArgs(hookInput);
161
+ if (!args) return false;
162
+ return spawnDetached(args, cwd || (hookInput && hookInput.cwd));
163
+ }
164
+
165
+ module.exports = {
166
+ bridgeAgentId,
167
+ resolveCliBin,
168
+ isSubagentEvent,
169
+ buildRegisterArgs,
170
+ buildTerminateArgs,
171
+ spawnDetached,
172
+ register,
173
+ terminate,
174
+ };