@openrig/cli 0.3.0 → 0.3.1

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 (282) hide show
  1. package/daemon/assets/plugins/openrig-core/.claude-plugin/plugin.json +15 -0
  2. package/daemon/assets/plugins/openrig-core/.codex-plugin/plugin.json +24 -0
  3. package/daemon/assets/plugins/openrig-core/LICENSE +200 -0
  4. package/daemon/assets/plugins/openrig-core/README.md +42 -0
  5. package/daemon/assets/plugins/openrig-core/hooks/claude.json +78 -0
  6. package/daemon/assets/plugins/openrig-core/hooks/codex.json +37 -0
  7. package/daemon/assets/{openrig-activity-hook-relay.cjs → plugins/openrig-core/hooks/scripts/activity-relay.cjs} +12 -0
  8. package/daemon/assets/plugins/openrig-core/hooks/scripts/compaction-restore-bridge.cjs +172 -0
  9. package/daemon/assets/plugins/openrig-core/skills/agent-startup-and-context-ingestion/SKILL.md +104 -0
  10. package/daemon/assets/plugins/openrig-core/skills/claude-compaction-restore/SKILL.md +131 -0
  11. package/daemon/assets/plugins/openrig-core/skills/claude-compaction-restore/scripts/precompact-hook.mjs +174 -0
  12. package/daemon/assets/plugins/openrig-core/skills/claude-compaction-restore/scripts/restore-from-jsonl.mjs +433 -0
  13. package/daemon/assets/plugins/openrig-core/skills/claude-compaction-restore/templates/compact-instruction.md +1 -0
  14. package/daemon/assets/plugins/openrig-core/skills/claude-compaction-restore/templates/post-compact-restore-instruction.md +1 -0
  15. package/daemon/assets/plugins/openrig-core/skills/forming-an-openrig-mental-model/SKILL.md +305 -0
  16. package/daemon/{specs/agents/shared/skills/rig-architect → assets/plugins/openrig-core/skills/openrig-architect}/SKILL.md +38 -19
  17. package/daemon/assets/plugins/openrig-core/skills/openrig-operator/SKILL.md +222 -0
  18. package/daemon/assets/plugins/openrig-core/skills/openrig-user/SKILL.md +597 -0
  19. package/daemon/assets/plugins/openrig-core/skills/queue-handoff/SKILL.md +122 -0
  20. package/daemon/assets/plugins/openrig-core/skills/seat-continuity-and-handover/SKILL.md +137 -0
  21. package/daemon/assets/vm-preview-fixtures/README.md +48 -0
  22. package/daemon/assets/vm-preview-fixtures/workflows/sample-basic-loop.yaml +79 -0
  23. package/daemon/dist/adapters/claude-code-adapter.d.ts +1 -3
  24. package/daemon/dist/adapters/claude-code-adapter.d.ts.map +1 -1
  25. package/daemon/dist/adapters/claude-code-adapter.js +17 -57
  26. package/daemon/dist/adapters/claude-code-adapter.js.map +1 -1
  27. package/daemon/dist/adapters/cmux-transport.d.ts.map +1 -1
  28. package/daemon/dist/adapters/cmux-transport.js +81 -2
  29. package/daemon/dist/adapters/cmux-transport.js.map +1 -1
  30. package/daemon/dist/adapters/cmux.d.ts +4 -0
  31. package/daemon/dist/adapters/cmux.d.ts.map +1 -1
  32. package/daemon/dist/adapters/cmux.js +87 -0
  33. package/daemon/dist/adapters/cmux.js.map +1 -1
  34. package/daemon/dist/adapters/codex-runtime-adapter.d.ts +14 -3
  35. package/daemon/dist/adapters/codex-runtime-adapter.d.ts.map +1 -1
  36. package/daemon/dist/adapters/codex-runtime-adapter.js +43 -57
  37. package/daemon/dist/adapters/codex-runtime-adapter.js.map +1 -1
  38. package/daemon/dist/db/migrations/040_workflow_specs_diagnostic.d.ts +32 -0
  39. package/daemon/dist/db/migrations/040_workflow_specs_diagnostic.d.ts.map +1 -0
  40. package/daemon/dist/db/migrations/040_workflow_specs_diagnostic.js +37 -0
  41. package/daemon/dist/db/migrations/040_workflow_specs_diagnostic.js.map +1 -0
  42. package/daemon/dist/domain/agent-manifest.d.ts.map +1 -1
  43. package/daemon/dist/domain/agent-manifest.js +116 -37
  44. package/daemon/dist/domain/agent-manifest.js.map +1 -1
  45. package/daemon/dist/domain/agent-resolver.js +1 -1
  46. package/daemon/dist/domain/agent-resolver.js.map +1 -1
  47. package/daemon/dist/domain/claude-compaction-enforcer.d.ts +81 -0
  48. package/daemon/dist/domain/claude-compaction-enforcer.d.ts.map +1 -0
  49. package/daemon/dist/domain/claude-compaction-enforcer.js +242 -0
  50. package/daemon/dist/domain/claude-compaction-enforcer.js.map +1 -0
  51. package/daemon/dist/domain/cmux-layout-service.d.ts +41 -0
  52. package/daemon/dist/domain/cmux-layout-service.d.ts.map +1 -0
  53. package/daemon/dist/domain/cmux-layout-service.js +184 -0
  54. package/daemon/dist/domain/cmux-layout-service.js.map +1 -0
  55. package/daemon/dist/domain/context-monitor.d.ts +15 -1
  56. package/daemon/dist/domain/context-monitor.d.ts.map +1 -1
  57. package/daemon/dist/domain/context-monitor.js +38 -3
  58. package/daemon/dist/domain/context-monitor.js.map +1 -1
  59. package/daemon/dist/domain/kernel-boot-tracker.d.ts +74 -0
  60. package/daemon/dist/domain/kernel-boot-tracker.d.ts.map +1 -0
  61. package/daemon/dist/domain/kernel-boot-tracker.js +213 -0
  62. package/daemon/dist/domain/kernel-boot-tracker.js.map +1 -0
  63. package/daemon/dist/domain/kernel-boot.d.ts +50 -0
  64. package/daemon/dist/domain/kernel-boot.d.ts.map +1 -0
  65. package/daemon/dist/domain/kernel-boot.js +147 -0
  66. package/daemon/dist/domain/kernel-boot.js.map +1 -0
  67. package/daemon/dist/domain/mission-control/mission-control-read-layer.d.ts +5 -0
  68. package/daemon/dist/domain/mission-control/mission-control-read-layer.d.ts.map +1 -1
  69. package/daemon/dist/domain/mission-control/mission-control-read-layer.js +16 -2
  70. package/daemon/dist/domain/mission-control/mission-control-read-layer.js.map +1 -1
  71. package/daemon/dist/domain/mission-control/mission-control-write-contract.d.ts.map +1 -1
  72. package/daemon/dist/domain/mission-control/mission-control-write-contract.js +3 -1
  73. package/daemon/dist/domain/mission-control/mission-control-write-contract.js.map +1 -1
  74. package/daemon/dist/domain/plugin-discovery-service.d.ts +150 -0
  75. package/daemon/dist/domain/plugin-discovery-service.d.ts.map +1 -0
  76. package/daemon/dist/domain/plugin-discovery-service.js +468 -0
  77. package/daemon/dist/domain/plugin-discovery-service.js.map +1 -0
  78. package/daemon/dist/domain/plugin-vendor-service.d.ts +54 -0
  79. package/daemon/dist/domain/plugin-vendor-service.d.ts.map +1 -0
  80. package/daemon/dist/domain/plugin-vendor-service.js +111 -0
  81. package/daemon/dist/domain/plugin-vendor-service.js.map +1 -0
  82. package/daemon/dist/domain/profile-resolver.d.ts +3 -3
  83. package/daemon/dist/domain/profile-resolver.d.ts.map +1 -1
  84. package/daemon/dist/domain/profile-resolver.js +7 -7
  85. package/daemon/dist/domain/profile-resolver.js.map +1 -1
  86. package/daemon/dist/domain/projection-planner.d.ts +7 -1
  87. package/daemon/dist/domain/projection-planner.d.ts.map +1 -1
  88. package/daemon/dist/domain/projection-planner.js +44 -4
  89. package/daemon/dist/domain/projection-planner.js.map +1 -1
  90. package/daemon/dist/domain/queue-repository.d.ts +8 -1
  91. package/daemon/dist/domain/queue-repository.d.ts.map +1 -1
  92. package/daemon/dist/domain/queue-repository.js +14 -5
  93. package/daemon/dist/domain/queue-repository.js.map +1 -1
  94. package/daemon/dist/domain/session-transport.d.ts.map +1 -1
  95. package/daemon/dist/domain/session-transport.js +33 -0
  96. package/daemon/dist/domain/session-transport.js.map +1 -1
  97. package/daemon/dist/domain/skill-library-discovery.d.ts +68 -0
  98. package/daemon/dist/domain/skill-library-discovery.d.ts.map +1 -0
  99. package/daemon/dist/domain/skill-library-discovery.js +144 -0
  100. package/daemon/dist/domain/skill-library-discovery.js.map +1 -0
  101. package/daemon/dist/domain/slices/slice-indexer.d.ts +19 -0
  102. package/daemon/dist/domain/slices/slice-indexer.d.ts.map +1 -1
  103. package/daemon/dist/domain/slices/slice-indexer.js +88 -6
  104. package/daemon/dist/domain/slices/slice-indexer.js.map +1 -1
  105. package/daemon/dist/domain/spec-library-service.d.ts +6 -0
  106. package/daemon/dist/domain/spec-library-service.d.ts.map +1 -1
  107. package/daemon/dist/domain/spec-library-service.js.map +1 -1
  108. package/daemon/dist/domain/spec-library-workflow-scanner.d.ts +43 -0
  109. package/daemon/dist/domain/spec-library-workflow-scanner.d.ts.map +1 -1
  110. package/daemon/dist/domain/spec-library-workflow-scanner.js +157 -3
  111. package/daemon/dist/domain/spec-library-workflow-scanner.js.map +1 -1
  112. package/daemon/dist/domain/spec-review-service.d.ts +1 -1
  113. package/daemon/dist/domain/spec-review-service.d.ts.map +1 -1
  114. package/daemon/dist/domain/spec-review-service.js +14 -1
  115. package/daemon/dist/domain/spec-review-service.js.map +1 -1
  116. package/daemon/dist/domain/types.d.ts +27 -7
  117. package/daemon/dist/domain/types.d.ts.map +1 -1
  118. package/daemon/dist/domain/types.js.map +1 -1
  119. package/daemon/dist/domain/user-settings/settings-store.d.ts +25 -1
  120. package/daemon/dist/domain/user-settings/settings-store.d.ts.map +1 -1
  121. package/daemon/dist/domain/user-settings/settings-store.js +186 -4
  122. package/daemon/dist/domain/user-settings/settings-store.js.map +1 -1
  123. package/daemon/dist/domain/workflow-spec-cache.d.ts +27 -0
  124. package/daemon/dist/domain/workflow-spec-cache.d.ts.map +1 -1
  125. package/daemon/dist/domain/workflow-spec-cache.js +59 -0
  126. package/daemon/dist/domain/workflow-spec-cache.js.map +1 -1
  127. package/daemon/dist/domain/workspace/default-workspace-scaffold.d.ts.map +1 -1
  128. package/daemon/dist/domain/workspace/default-workspace-scaffold.js +45 -0
  129. package/daemon/dist/domain/workspace/default-workspace-scaffold.js.map +1 -1
  130. package/daemon/dist/domain/workspace/getting-started-narrative.d.ts +15 -0
  131. package/daemon/dist/domain/workspace/getting-started-narrative.d.ts.map +1 -0
  132. package/daemon/dist/domain/workspace/getting-started-narrative.js +237 -0
  133. package/daemon/dist/domain/workspace/getting-started-narrative.js.map +1 -0
  134. package/daemon/dist/index.d.ts +2 -1
  135. package/daemon/dist/index.d.ts.map +1 -1
  136. package/daemon/dist/index.js +52 -17
  137. package/daemon/dist/index.js.map +1 -1
  138. package/daemon/dist/lib/pane-envelope.d.ts +7 -0
  139. package/daemon/dist/lib/pane-envelope.d.ts.map +1 -0
  140. package/daemon/dist/lib/pane-envelope.js +38 -0
  141. package/daemon/dist/lib/pane-envelope.js.map +1 -0
  142. package/daemon/dist/middleware/auth-bearer-token.d.ts +47 -5
  143. package/daemon/dist/middleware/auth-bearer-token.d.ts.map +1 -1
  144. package/daemon/dist/middleware/auth-bearer-token.js +109 -8
  145. package/daemon/dist/middleware/auth-bearer-token.js.map +1 -1
  146. package/daemon/dist/routes/kernel-status.d.ts +3 -0
  147. package/daemon/dist/routes/kernel-status.d.ts.map +1 -0
  148. package/daemon/dist/routes/kernel-status.js +40 -0
  149. package/daemon/dist/routes/kernel-status.js.map +1 -0
  150. package/daemon/dist/routes/mission-control.d.ts.map +1 -1
  151. package/daemon/dist/routes/mission-control.js +25 -2
  152. package/daemon/dist/routes/mission-control.js.map +1 -1
  153. package/daemon/dist/routes/missions.d.ts +3 -0
  154. package/daemon/dist/routes/missions.d.ts.map +1 -0
  155. package/daemon/dist/routes/missions.js +195 -0
  156. package/daemon/dist/routes/missions.js.map +1 -0
  157. package/daemon/dist/routes/plugins.d.ts +3 -0
  158. package/daemon/dist/routes/plugins.d.ts.map +1 -0
  159. package/daemon/dist/routes/plugins.js +223 -0
  160. package/daemon/dist/routes/plugins.js.map +1 -0
  161. package/daemon/dist/routes/rig-cmux.d.ts +3 -0
  162. package/daemon/dist/routes/rig-cmux.d.ts.map +1 -0
  163. package/daemon/dist/routes/rig-cmux.js +121 -0
  164. package/daemon/dist/routes/rig-cmux.js.map +1 -0
  165. package/daemon/dist/routes/skills.d.ts +3 -0
  166. package/daemon/dist/routes/skills.d.ts.map +1 -0
  167. package/daemon/dist/routes/skills.js +147 -0
  168. package/daemon/dist/routes/skills.js.map +1 -0
  169. package/daemon/dist/routes/slices.d.ts.map +1 -1
  170. package/daemon/dist/routes/slices.js +15 -0
  171. package/daemon/dist/routes/slices.js.map +1 -1
  172. package/daemon/dist/routes/spec-library.d.ts.map +1 -1
  173. package/daemon/dist/routes/spec-library.js +16 -1
  174. package/daemon/dist/routes/spec-library.js.map +1 -1
  175. package/daemon/dist/server.d.ts +31 -0
  176. package/daemon/dist/server.d.ts.map +1 -1
  177. package/daemon/dist/server.js +30 -0
  178. package/daemon/dist/server.js.map +1 -1
  179. package/daemon/dist/startup.d.ts.map +1 -1
  180. package/daemon/dist/startup.js +194 -5
  181. package/daemon/dist/startup.js.map +1 -1
  182. package/daemon/specs/agents/apps/vault-specialist/agent.yaml +0 -1
  183. package/daemon/specs/agents/conveyor/builder/agent.yaml +0 -1
  184. package/daemon/specs/agents/conveyor/lead/agent.yaml +0 -1
  185. package/daemon/specs/agents/conveyor/planner/agent.yaml +0 -1
  186. package/daemon/specs/agents/conveyor/reviewer/agent.yaml +0 -1
  187. package/daemon/specs/agents/design/product-designer/agent.yaml +0 -1
  188. package/daemon/specs/agents/development/implementer/agent.yaml +0 -1
  189. package/daemon/specs/agents/development/qa/agent.yaml +0 -1
  190. package/daemon/specs/agents/development/qa/guidance/role.md +0 -2
  191. package/daemon/specs/agents/orchestration/orchestrator/agent.yaml +0 -1
  192. package/daemon/specs/agents/research/analyst/agent.yaml +0 -1
  193. package/daemon/specs/agents/research/synthesizer/agent.yaml +0 -1
  194. package/daemon/specs/agents/review/independent-reviewer/agent.yaml +0 -1
  195. package/daemon/specs/agents/shared/agent.yaml +6 -6
  196. package/daemon/specs/agents/shared/skills/core/openrig-architect/SKILL.md +361 -0
  197. package/daemon/specs/agents/shared/skills/core/openrig-installer/SKILL.md +142 -0
  198. package/daemon/specs/agents/shared/skills/core/openrig-user/SKILL.md +6 -1
  199. package/daemon/specs/agents/shared/skills/core/openrig-user-settings/SKILL.md +4 -4
  200. package/daemon/specs/agents/shared/skills/core/rig-lifecycle/SKILL.md +116 -0
  201. package/daemon/specs/agents/shared/skills/pods/development-team/SKILL.md +0 -1
  202. package/daemon/specs/agents/shared/skills/pods/orchestration-team/SKILL.md +2 -2
  203. package/daemon/specs/agents/shared/skills/process/agent-browser/LOCAL-INSIGHTS.md +6 -6
  204. package/daemon/specs/agents/shared/skills/process/agent-browser/OPENRIG.md +40 -0
  205. package/daemon/specs/agents/shared/skills/process/agent-browser/SKILL.md +10 -0
  206. package/daemon/specs/agents/shared/skills/process/brainstorming/OPENRIG.md +48 -0
  207. package/daemon/specs/agents/shared/skills/process/brainstorming/SKILL.md +11 -0
  208. package/daemon/specs/agents/shared/skills/process/dogfood/SKILL.md +5 -0
  209. package/daemon/specs/agents/shared/skills/process/executing-plans/OPENRIG.md +56 -0
  210. package/daemon/specs/agents/shared/skills/process/executing-plans/SKILL.md +10 -0
  211. package/daemon/specs/agents/shared/skills/process/frontend-design/SKILL.md +5 -0
  212. package/daemon/specs/agents/shared/skills/process/systematic-debugging/SKILL.md +5 -0
  213. package/daemon/specs/agents/shared/skills/process/test-driven-development/SKILL.md +5 -0
  214. package/daemon/specs/agents/shared/skills/process/using-superpowers/OPENRIG.md +48 -0
  215. package/daemon/specs/agents/shared/skills/process/using-superpowers/SKILL.md +11 -0
  216. package/daemon/specs/agents/shared/skills/process/verification-before-completion/SKILL.md +5 -0
  217. package/daemon/specs/agents/shared/skills/process/writing-plans/OPENRIG.md +52 -0
  218. package/daemon/specs/agents/shared/skills/process/writing-plans/SKILL.md +12 -2
  219. package/daemon/specs/rigs/launch/kernel/agents/advisor/lead/agent.yaml +35 -0
  220. package/daemon/specs/rigs/launch/kernel/agents/advisor/lead/guidance/role.md +50 -0
  221. package/daemon/specs/rigs/launch/kernel/agents/advisor/lead/startup/context.md +37 -0
  222. package/daemon/specs/rigs/launch/kernel/agents/operator/agent/agent.yaml +35 -0
  223. package/daemon/specs/rigs/launch/kernel/agents/operator/agent/guidance/role.md +49 -0
  224. package/daemon/specs/rigs/launch/kernel/agents/operator/agent/startup/context.md +63 -0
  225. package/daemon/specs/rigs/launch/kernel/agents/queue/worker/agent.yaml +35 -0
  226. package/daemon/specs/rigs/launch/kernel/agents/queue/worker/guidance/role.md +33 -0
  227. package/daemon/specs/rigs/launch/kernel/agents/queue/worker/startup/context.md +30 -0
  228. package/daemon/specs/rigs/launch/kernel/culture/CULTURE.md +69 -0
  229. package/daemon/specs/rigs/launch/kernel/rig-claude-only.yaml +59 -0
  230. package/daemon/specs/rigs/launch/kernel/rig-codex-only.yaml +59 -0
  231. package/daemon/specs/rigs/launch/kernel/rig.yaml +69 -0
  232. package/dist/commands/config-init-workspace.d.ts.map +1 -1
  233. package/dist/commands/config-init-workspace.js +253 -0
  234. package/dist/commands/config-init-workspace.js.map +1 -1
  235. package/dist/commands/config.d.ts.map +1 -1
  236. package/dist/commands/config.js +11 -3
  237. package/dist/commands/config.js.map +1 -1
  238. package/dist/commands/daemon.d.ts.map +1 -1
  239. package/dist/commands/daemon.js +53 -1
  240. package/dist/commands/daemon.js.map +1 -1
  241. package/dist/commands/heartbeat.d.ts.map +1 -1
  242. package/dist/commands/heartbeat.js +0 -5
  243. package/dist/commands/heartbeat.js.map +1 -1
  244. package/dist/commands/plugin.d.ts +4 -0
  245. package/dist/commands/plugin.d.ts.map +1 -0
  246. package/dist/commands/plugin.js +395 -0
  247. package/dist/commands/plugin.js.map +1 -0
  248. package/dist/commands/send.d.ts +8 -0
  249. package/dist/commands/send.d.ts.map +1 -1
  250. package/dist/commands/send.js +8 -0
  251. package/dist/commands/send.js.map +1 -1
  252. package/dist/commands/up.d.ts.map +1 -1
  253. package/dist/commands/up.js +13 -1
  254. package/dist/commands/up.js.map +1 -1
  255. package/dist/config-store.d.ts +18 -1
  256. package/dist/config-store.d.ts.map +1 -1
  257. package/dist/config-store.js +167 -4
  258. package/dist/config-store.js.map +1 -1
  259. package/dist/daemon-lifecycle.d.ts +20 -1
  260. package/dist/daemon-lifecycle.d.ts.map +1 -1
  261. package/dist/daemon-lifecycle.js +57 -7
  262. package/dist/daemon-lifecycle.js.map +1 -1
  263. package/dist/host-registry.d.ts +1 -1
  264. package/dist/host-registry.js +1 -1
  265. package/dist/index.d.ts +1 -0
  266. package/dist/index.d.ts.map +1 -1
  267. package/dist/index.js +2 -0
  268. package/dist/index.js.map +1 -1
  269. package/package.json +1 -1
  270. package/ui/dist/assets/index-C_Q5FczU.css +1 -0
  271. package/ui/dist/assets/index-Rl3ZBrUg.js +547 -0
  272. package/ui/dist/index.html +2 -2
  273. package/daemon/specs/agents/shared/skills/claude-compact-in-place/SKILL.md +0 -100
  274. package/daemon/specs/agents/shared/skills/process/containerized-e2e/SKILL.md +0 -256
  275. package/daemon/specs/agents/shared/skills/process/containerized-e2e/scripts/Dockerfile +0 -39
  276. package/daemon/specs/agents/shared/skills/process/containerized-e2e/scripts/build-e2e-image.sh +0 -37
  277. package/daemon/specs/agents/shared/skills/process/containerized-e2e/templates/control-plane-test.yaml +0 -40
  278. package/daemon/specs/agents/shared/skills/process/containerized-e2e/templates/e2e-report-template.md +0 -94
  279. package/daemon/specs/agents/shared/skills/process/containerized-e2e/templates/expansion-collision-fragment.yaml +0 -13
  280. package/daemon/specs/agents/shared/skills/process/containerized-e2e/templates/expansion-pod-fragment.yaml +0 -14
  281. package/ui/dist/assets/index-BDHU1JUK.js +0 -412
  282. package/ui/dist/assets/index-DXTyJSqu.css +0 -1
@@ -0,0 +1,195 @@
1
+ // V0.3.1 slice 12 walk-item 1 — mission scope data layer.
2
+ // V0.3.1 slice 13 walk-item 7 — extended with workflow_spec frontmatter
3
+ // + projected topology spec graph.
4
+ //
5
+ // GET /api/missions/:missionId — returns aggregated mission metadata
6
+ // (missionPath + slices + optional workflow_spec declaration + optional
7
+ // projected topology). Powers the Mission Overview / Progress / Topology
8
+ // tabs in the Project surface; pairs with useScopeMarkdown for README /
9
+ // PROGRESS content via the existing /api/files/read route.
10
+ //
11
+ // Returns:
12
+ // 200 {
13
+ // missionId, missionPath, slices,
14
+ // workflow_spec: { name, version } | null,
15
+ // topology: { specGraph: SpecGraphPayload | null } | null
16
+ // }
17
+ // 404 { error: "mission_not_found" } when no slices match
18
+ // 503 { error: "slices_indexer_unavailable" } when indexer not wired
19
+ // 503 { error: "slices_root_not_configured" } when indexer not ready
20
+ //
21
+ // workflow_spec is parsed lazily from <missionPath>/README.md frontmatter
22
+ // using the same parser the slice-indexer uses. topology.specGraph is
23
+ // projected via projectSpecGraph(spec, null) when the spec is in the
24
+ // WorkflowSpecCache; { specGraph: null } when declared but not cached;
25
+ // null when nothing is declared.
26
+ import { Hono } from "hono";
27
+ import * as fs from "node:fs";
28
+ import * as path from "node:path";
29
+ import { parseWorkflowSpecRef } from "../domain/slices/slice-indexer.js";
30
+ import { projectSpecGraph } from "../domain/workflow/slice-workflow-projection.js";
31
+ export function missionsRoutes() {
32
+ const app = new Hono();
33
+ app.get("/:missionId", (c) => {
34
+ const indexer = c.get("sliceIndexer");
35
+ if (!indexer) {
36
+ return c.json({
37
+ error: "slices_indexer_unavailable",
38
+ hint: "Mission data layer requires the SliceIndexer to be wired into AppDeps.",
39
+ }, 503);
40
+ }
41
+ if (!indexer.isReady()) {
42
+ return c.json({
43
+ error: "slices_root_not_configured",
44
+ hint: "Run rig config init-workspace, or set workspace.slices_root to workspace/missions. Supported shape: missions/<mission>/slices/<slice>.",
45
+ }, 503);
46
+ }
47
+ const missionId = c.req.param("missionId");
48
+ const allSlices = indexer.list();
49
+ const slices = allSlices.filter((s) => s.missionId === missionId);
50
+ if (slices.length === 0) {
51
+ return c.json({ error: "mission_not_found", missionId }, 404);
52
+ }
53
+ const missionPath = computeMissionPath(slices[0]);
54
+ const workflowSpec = readMissionWorkflowSpec(missionPath);
55
+ const topology = computeMissionTopology(workflowSpec, c.get("workflowSpecCache"));
56
+ const status = readMissionStatus(missionPath);
57
+ return c.json({
58
+ missionId,
59
+ missionPath,
60
+ slices,
61
+ workflow_spec: workflowSpec,
62
+ topology,
63
+ status,
64
+ });
65
+ });
66
+ // Slice 18 §3.5 — Mark mission complete (Getting Started complete-and-hide).
67
+ // Writes `status: complete` to the mission README.md frontmatter; the UI
68
+ // storytelling preview gates on this so completed missions disappear from
69
+ // the band. The daemon is the audit-trail surface; the UI maintains
70
+ // an optimistic local mirror via localStorage so the hide is instant.
71
+ app.post("/:missionId/complete", (c) => {
72
+ const indexer = c.get("sliceIndexer");
73
+ if (!indexer) {
74
+ return c.json({ error: "slices_indexer_unavailable" }, 503);
75
+ }
76
+ const missionId = c.req.param("missionId");
77
+ const allSlices = indexer.list();
78
+ const slices = allSlices.filter((s) => s.missionId === missionId);
79
+ if (slices.length === 0) {
80
+ return c.json({ error: "mission_not_found", missionId }, 404);
81
+ }
82
+ const missionPath = computeMissionPath(slices[0]);
83
+ try {
84
+ writeMissionStatusComplete(missionPath);
85
+ }
86
+ catch (err) {
87
+ return c.json({
88
+ error: "mission_complete_write_failed",
89
+ missionId,
90
+ message: err.message,
91
+ }, 500);
92
+ }
93
+ return c.json({ missionId, status: "complete" });
94
+ });
95
+ return app;
96
+ }
97
+ /** Slice 18 §3.5 — write `status: complete` to a mission README's
98
+ * frontmatter, creating the frontmatter block when absent and
99
+ * replacing an existing status field when present. Idempotent.
100
+ * Preserves unrelated frontmatter fields. */
101
+ function writeMissionStatusComplete(missionPath) {
102
+ const readmePath = path.join(missionPath, "README.md");
103
+ let body = fs.existsSync(readmePath) ? fs.readFileSync(readmePath, "utf-8") : "";
104
+ const fmMatch = body.match(/^---\r?\n([\s\S]*?)\r?\n---/);
105
+ if (fmMatch) {
106
+ const fmInner = fmMatch[1] ?? "";
107
+ const statusLineRegex = /^\s*status\s*:\s*[^\r\n]*$/m;
108
+ let newFm;
109
+ if (statusLineRegex.test(fmInner)) {
110
+ newFm = fmInner.replace(statusLineRegex, "status: complete");
111
+ }
112
+ else {
113
+ newFm = fmInner.trimEnd() + "\nstatus: complete";
114
+ }
115
+ body = body.replace(fmMatch[0], `---\n${newFm}\n---`);
116
+ }
117
+ else {
118
+ body = `---\nstatus: complete\n---\n${body}`;
119
+ }
120
+ fs.writeFileSync(readmePath, body);
121
+ }
122
+ /** Derive the mission folder's absolute path from any slice's
123
+ * `slicePath`. Slices live at
124
+ * `<missionsRoot>/<missionId>/slices/<sliceName>` per the workspace
125
+ * contract, so going up two levels yields the mission folder. */
126
+ function computeMissionPath(slice) {
127
+ return path.resolve(slice.slicePath, "..", "..");
128
+ }
129
+ /** Slice 18 §3.5 — parse the `status` field from the mission README's
130
+ * frontmatter. Returns the string when present (no enum validation —
131
+ * v0 callers care primarily about the "complete" value but other
132
+ * workflow states may appear), or null when the README is missing /
133
+ * the field is absent. Powers the durable storytelling-filter for
134
+ * Getting Started complete-and-hide. */
135
+ function readMissionStatus(missionPath) {
136
+ const readmePath = path.join(missionPath, "README.md");
137
+ if (!fs.existsSync(readmePath))
138
+ return null;
139
+ const raw = fs.readFileSync(readmePath, "utf-8");
140
+ const fm = parseSimpleFrontmatter(raw);
141
+ const value = fm["status"];
142
+ return typeof value === "string" && value.length > 0 ? value : null;
143
+ }
144
+ /** V0.3.1 slice 13 walk-item 7 — parse `workflow_spec` from the mission
145
+ * README's frontmatter. Returns null when the README is missing or the
146
+ * field is absent / malformed. Uses the same parseWorkflowSpecRef
147
+ * helper the slice-indexer uses so both surfaces stay in lockstep. */
148
+ function readMissionWorkflowSpec(missionPath) {
149
+ const readmePath = path.join(missionPath, "README.md");
150
+ if (!fs.existsSync(readmePath))
151
+ return null;
152
+ const raw = fs.readFileSync(readmePath, "utf-8");
153
+ const fm = parseSimpleFrontmatter(raw);
154
+ return parseWorkflowSpecRef(fm["workflow_spec"]);
155
+ }
156
+ /** Minimal frontmatter parser. The slice-indexer's parseFrontmatter is
157
+ * private; duplicating the v0 shape here is cheaper than exposing
158
+ * internal API and keeps the missions route's surface minimal. */
159
+ function parseSimpleFrontmatter(text) {
160
+ const m = text.match(/^---\r?\n([\s\S]*?)\r?\n---/);
161
+ if (!m)
162
+ return {};
163
+ const out = {};
164
+ for (const line of m[1].split(/\r?\n/)) {
165
+ const trimmed = line.trim();
166
+ if (!trimmed || trimmed.startsWith("#"))
167
+ continue;
168
+ const colonIdx = trimmed.indexOf(":");
169
+ if (colonIdx === -1)
170
+ continue;
171
+ const key = trimmed.slice(0, colonIdx).trim();
172
+ let value = trimmed.slice(colonIdx + 1).trim();
173
+ if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
174
+ value = value.slice(1, -1);
175
+ }
176
+ out[key] = value;
177
+ }
178
+ return out;
179
+ }
180
+ /** V0.3.1 slice 13 walk-item 7 — project the spec graph when both the
181
+ * declaration AND the cached spec are present. Returns the topology
182
+ * envelope with `specGraph: null` when declared but not yet cached;
183
+ * returns `null` for the whole envelope when nothing is declared. */
184
+ function computeMissionTopology(workflowSpec, specCache) {
185
+ if (!workflowSpec)
186
+ return null;
187
+ if (!specCache)
188
+ return { specGraph: null };
189
+ const row = specCache.getByNameVersion(workflowSpec.name, workflowSpec.version);
190
+ if (!row)
191
+ return { specGraph: null };
192
+ // WorkflowSpecRow.spec is the WorkflowSpec object the projector expects.
193
+ return { specGraph: projectSpecGraph(row.spec, null) };
194
+ }
195
+ //# sourceMappingURL=missions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"missions.js","sourceRoot":"","sources":["../../src/routes/missions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Hono } from "hono";
2
+ export declare function pluginsRoutes(): Hono;
3
+ //# sourceMappingURL=plugins.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugins.d.ts","sourceRoot":"","sources":["../../src/routes/plugins.ts"],"names":[],"mappings":"AAwCA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAkE5B,wBAAgB,aAAa,IAAI,IAAI,CA4HpC"}
@@ -0,0 +1,223 @@
1
+ // Phase 3a slice 3.3 — Plugins HTTP routes (read-only).
2
+ //
3
+ // SC-29 EXCEPTION #8 declared verbatim:
4
+ // "Slice 3.3 (UI plugin surface) requires daemon-side plugin-discovery-service
5
+ // + 3 HTTP routes (GET /api/plugins, GET /api/plugins/:id, GET /api/plugins/:id/used-by)
6
+ // as backing API. No additional state, no SQL migration, no mutation routes.
7
+ // Read-only discovery surface aggregating filesystem-scan unions per
8
+ // DESIGN.md §5.4. Per IMPL-PRD §3.3 'Code touches' this allocation is explicit;
9
+ // documenting in compliance with banked SC-29 verbatim-declaration rule."
10
+ //
11
+ // SC-29 EXCEPTION #11 (slice 28 library-explorer-finishing) declared verbatim:
12
+ // "Slice 28 (Library Explorer finishing — founder-walk follow-up) requires:
13
+ // (a) two additive read-only HTTP routes — GET /api/plugins/:id/files/list
14
+ // and GET /api/plugins/:id/files/read — that wrap the existing path-safety
15
+ // machinery (resolveAllowedDirectory/File) with the discovered plugin's
16
+ // absolute path acting as a synthetic single-root allowlist. Enables
17
+ // docs-browser file navigation of a plugin's on-disk folder without
18
+ // requiring the operator to allowlist ~/.openrig/plugins/ in
19
+ // OPENRIG_FILES_ALLOWLIST.
20
+ // (b) one PluginEntry shape extension — skillCount: number — populated in
21
+ // detectPlugin() by readdir of <plugin>/skills/. Surfaces skill-count in
22
+ // the plugin list response so PluginsIndexPage can render the column
23
+ // without an N+1 detail fetch per row.
24
+ // No additional state, no SQL migration, no write mutations on plugin
25
+ // folders. Read-only docs-browser surface per slice 28 founder direction
26
+ // 'finishing it is 0.3.1 work, not 0.3.2'. Routing decision
27
+ // qitem-20260513042155-f31c11c3 (orch OPT-A authorization)."
28
+ //
29
+ // Endpoint shape:
30
+ // GET /api/plugins → PluginEntry[] (?runtime=, ?source= filters)
31
+ // GET /api/plugins/:id → PluginDetail (404 when unknown)
32
+ // GET /api/plugins/:id/used-by → AgentReference[]
33
+ // GET /api/plugins/:id/files/list?path=<rel> → FilesListResponse (slice 28)
34
+ // GET /api/plugins/:id/files/read?path=<rel> → FilesReadResponse (slice 28)
35
+ //
36
+ // All endpoints return 503 when the service is not provisioned in context
37
+ // (consistent with the existing daemon route pattern for optional services).
38
+ // /files/list + /files/read use the discovered plugin path as a synthetic
39
+ // AllowlistRoot + reuse resolveAllowedDirectory/File for path-safety.
40
+ import { Hono } from "hono";
41
+ import * as fs from "node:fs";
42
+ import * as path from "node:path";
43
+ import { resolveAllowedDirectory, resolveAllowedFile, FilePathSafetyError, } from "../domain/files/path-safety.js";
44
+ import { sha256Hex } from "../domain/files/file-write-service.js";
45
+ import { FILE_READ_TRUNCATION_BYTES } from "./files.js";
46
+ function getService(c) {
47
+ return c.get("pluginDiscoveryService");
48
+ }
49
+ function parseRuntimeFilter(value) {
50
+ if (value === "claude" || value === "codex")
51
+ return value;
52
+ return undefined;
53
+ }
54
+ function parseSourceFilter(value) {
55
+ if (value === "vendored" || value === "claude-cache" || value === "codex-cache")
56
+ return value;
57
+ return undefined;
58
+ }
59
+ function pluginRootAllowlist(absolutePath) {
60
+ // Synthetic single-root allowlist scoped to the plugin's folder.
61
+ // Reuses the existing path-safety helpers for ../ escape / symlink
62
+ // realpath containment checks without any allowlist env-var coupling
63
+ // (operator does not need to declare plugin paths in OPENRIG_FILES_ALLOWLIST).
64
+ //
65
+ // Normalize via fs.realpathSync so the containment check (realpath vs
66
+ // canonicalPath) holds on platforms where the input path is itself
67
+ // a symlink chain (e.g. macOS /tmp → /private/tmp, /var/folders →
68
+ // /private/var/folders). Matches decodeAllowlist's normalization in
69
+ // path-safety.ts.
70
+ let canonical;
71
+ try {
72
+ canonical = fs.realpathSync(absolutePath);
73
+ }
74
+ catch {
75
+ canonical = path.resolve(absolutePath);
76
+ }
77
+ return [{ name: "plugin", canonicalPath: canonical }];
78
+ }
79
+ function pathSafetyErrorResponse(c, err) {
80
+ const status = err.code === "root_unknown" ? 400
81
+ : err.code === "path_invalid" || err.code === "path_escape" ? 400
82
+ : err.code === "stat_failed" ? 404
83
+ : err.code === "not_a_file" || err.code === "not_a_directory" ? 400
84
+ : 500;
85
+ return c.json({ error: err.code, message: err.message, ...(err.details ?? {}) }, status);
86
+ }
87
+ export function pluginsRoutes() {
88
+ const router = new Hono();
89
+ // GET / — list discoverable plugins
90
+ router.get("/", (c) => {
91
+ const service = getService(c);
92
+ if (!service)
93
+ return c.json({ error: "plugin_discovery_unavailable" }, 503);
94
+ const runtimeFilter = parseRuntimeFilter(c.req.query("runtime"));
95
+ const sourceFilter = parseSourceFilter(c.req.query("source"));
96
+ // Slice 3.3 fix-C — DESIGN §5.4 union 4th category: rig-bundled
97
+ // <cwd>/.claude/plugins/* + <cwd>/.codex/plugins/*. The API caller
98
+ // (UI in rig context, CLI in slice 3.4) passes ?cwd=<path> when
99
+ // they want the rig-cwd discoveries included; the Library page
100
+ // omits it (cross-cutting view).
101
+ const cwd = c.req.query("cwd");
102
+ const cwdScanRoots = cwd ? [cwd] : undefined;
103
+ const plugins = service.listPlugins({ runtimeFilter, sourceFilter, cwdScanRoots });
104
+ return c.json(plugins);
105
+ });
106
+ // GET /:id/used-by — reverse query for agents referencing this plugin.
107
+ // Mounted BEFORE /:id so the literal sub-path doesn't get eaten by the
108
+ // bare-param catchall (per spec-library-routes Phase A R1 SSE route-order
109
+ // lesson banked in that file).
110
+ router.get("/:id/used-by", (c) => {
111
+ const service = getService(c);
112
+ if (!service)
113
+ return c.json({ error: "plugin_discovery_unavailable" }, 503);
114
+ const id = c.req.param("id");
115
+ return c.json(service.findUsedBy(id));
116
+ });
117
+ // Slice 28 — GET /:id/files/list?path=<rel>
118
+ // Lists directory entries inside the plugin's source folder. Uses the
119
+ // existing path-safety helpers with a synthetic single-root allowlist
120
+ // built from the discovered plugin's absolute path. Mounted BEFORE the
121
+ // bare /:id route (same route-order discipline as /:id/used-by).
122
+ router.get("/:id/files/list", (c) => {
123
+ const service = getService(c);
124
+ if (!service)
125
+ return c.json({ error: "plugin_discovery_unavailable" }, 503);
126
+ const id = c.req.param("id");
127
+ const detail = service.getPlugin(id);
128
+ if (!detail)
129
+ return c.notFound();
130
+ const relativePath = c.req.query("path") ?? "";
131
+ try {
132
+ const allowlist = pluginRootAllowlist(detail.entry.path);
133
+ const resolved = resolveAllowedDirectory(allowlist, "plugin", relativePath);
134
+ const entries = fs.readdirSync(resolved, { withFileTypes: true });
135
+ return c.json({
136
+ pluginId: id,
137
+ path: relativePath,
138
+ entries: entries
139
+ .map((entry) => {
140
+ const fullPath = path.join(resolved, entry.name);
141
+ let stat = null;
142
+ try {
143
+ stat = fs.statSync(fullPath);
144
+ }
145
+ catch { /* skip stat-failed */ }
146
+ return {
147
+ name: entry.name,
148
+ type: entry.isDirectory() ? "dir" : entry.isFile() ? "file" : "other",
149
+ size: stat?.isFile() ? stat.size : null,
150
+ mtime: stat ? stat.mtime.toISOString() : null,
151
+ };
152
+ })
153
+ .sort((a, b) => {
154
+ if (a.type !== b.type)
155
+ return a.type === "dir" ? -1 : 1;
156
+ return a.name.localeCompare(b.name);
157
+ }),
158
+ });
159
+ }
160
+ catch (err) {
161
+ if (err instanceof FilePathSafetyError)
162
+ return pathSafetyErrorResponse(c, err);
163
+ return c.json({ error: "list_failed", message: err instanceof Error ? err.message : String(err) }, 500);
164
+ }
165
+ });
166
+ // Slice 28 — GET /:id/files/read?path=<rel>
167
+ // Reads a file inside the plugin's source folder. Same truncation cap
168
+ // semantics as /api/files/read (FILE_READ_TRUNCATION_BYTES; hash over
169
+ // full content for honest edit-conflict semantics — but plugin folders
170
+ // are read-only at v0 so the hash is informational only).
171
+ router.get("/:id/files/read", (c) => {
172
+ const service = getService(c);
173
+ if (!service)
174
+ return c.json({ error: "plugin_discovery_unavailable" }, 503);
175
+ const id = c.req.param("id");
176
+ const detail = service.getPlugin(id);
177
+ if (!detail)
178
+ return c.notFound();
179
+ const relativePath = c.req.query("path") ?? "";
180
+ if (!relativePath)
181
+ return c.json({ error: "path_required" }, 400);
182
+ try {
183
+ const allowlist = pluginRootAllowlist(detail.entry.path);
184
+ const resolved = resolveAllowedFile(allowlist, "plugin", relativePath);
185
+ const stat = fs.statSync(resolved);
186
+ const fullContent = fs.readFileSync(resolved);
187
+ const truncated = stat.size > FILE_READ_TRUNCATION_BYTES;
188
+ const returnedContent = truncated
189
+ ? fullContent.subarray(0, FILE_READ_TRUNCATION_BYTES)
190
+ : fullContent;
191
+ return c.json({
192
+ pluginId: id,
193
+ path: relativePath,
194
+ absolutePath: resolved,
195
+ content: returnedContent.toString("utf-8"),
196
+ mtime: stat.mtime.toISOString(),
197
+ contentHash: sha256Hex(fullContent),
198
+ size: stat.size,
199
+ truncated,
200
+ truncatedAtBytes: truncated ? FILE_READ_TRUNCATION_BYTES : null,
201
+ totalBytes: stat.size,
202
+ });
203
+ }
204
+ catch (err) {
205
+ if (err instanceof FilePathSafetyError)
206
+ return pathSafetyErrorResponse(c, err);
207
+ return c.json({ error: "read_failed", message: err instanceof Error ? err.message : String(err) }, 500);
208
+ }
209
+ });
210
+ // GET /:id — plugin detail
211
+ router.get("/:id", (c) => {
212
+ const service = getService(c);
213
+ if (!service)
214
+ return c.json({ error: "plugin_discovery_unavailable" }, 503);
215
+ const id = c.req.param("id");
216
+ const detail = service.getPlugin(id);
217
+ if (!detail)
218
+ return c.notFound();
219
+ return c.json(detail);
220
+ });
221
+ return router;
222
+ }
223
+ //# sourceMappingURL=plugins.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugins.js","sourceRoot":"","sources":["../../src/routes/plugins.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Hono } from "hono";
2
+ export declare const rigCmuxRoutes: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
3
+ //# sourceMappingURL=rig-cmux.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rig-cmux.d.ts","sourceRoot":"","sources":["../../src/routes/rig-cmux.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAK5B,eAAO,MAAM,aAAa,4EAAa,CAAC"}
@@ -0,0 +1,121 @@
1
+ // Slice 24 — POST /api/rigs/:rigId/cmux/launch.
2
+ //
3
+ // Per-rig "Launch in CMUX" endpoint. Coordination:
4
+ // 1. rigRepo.getRig(rigId) → 404 if missing
5
+ // 2. cmuxAdapter.isAvailable() → 503 if cmux not connected
6
+ // 3. nodeInventoryFn(rigId) → map logicalId → canonicalSessionName
7
+ // 4. order agents by rig.nodes DB order (ORDER BY created_at = pod-then-member from spec)
8
+ // 5. filter to running (has canonicalSessionName) → 412 if none running
9
+ // 6. chunkAgents into MAX_PER_WORKSPACE-sized chunks
10
+ // 7. pick non-colliding workspace name per chunk
11
+ // (auto-append -2/-3/... per README R2 + multi-workspace handling)
12
+ // 8. cmuxLayoutService.buildWorkspace per chunk (sequential)
13
+ // → 500 with partial info if any buildWorkspace fails mid-flight
14
+ // 9. 200 with { ok, workspaces[] }
15
+ //
16
+ // Deps wired via Hono context (see server.ts deps wiring block).
17
+ import { Hono } from "hono";
18
+ import { CmuxLayoutService } from "../domain/cmux-layout-service.js";
19
+ export const rigCmuxRoutes = new Hono();
20
+ function getDeps(c) {
21
+ return {
22
+ rigRepo: c.get("rigRepo"),
23
+ cmuxAdapter: c.get("cmuxAdapter"),
24
+ cmuxLayoutService: c.get("cmuxLayoutService"),
25
+ nodeInventoryFn: c.get("nodeInventoryFn"),
26
+ };
27
+ }
28
+ function pickNonCollidingName(baseName, existing) {
29
+ if (!existing.has(baseName))
30
+ return baseName;
31
+ let suffix = 2;
32
+ while (existing.has(`${baseName}-${suffix}`))
33
+ suffix += 1;
34
+ return `${baseName}-${suffix}`;
35
+ }
36
+ rigCmuxRoutes.post("/launch", async (c) => {
37
+ const rigId = c.req.param("rigId");
38
+ const { rigRepo, cmuxAdapter, cmuxLayoutService, nodeInventoryFn } = getDeps(c);
39
+ const rigWithRelations = rigRepo.getRig(rigId);
40
+ if (!rigWithRelations) {
41
+ return c.json({
42
+ ok: false,
43
+ error: "rig_not_found",
44
+ message: `Rig "${rigId}" not found — can't launch cmux workspace — try: rig ps`,
45
+ }, 404);
46
+ }
47
+ if (!cmuxAdapter.isAvailable()) {
48
+ return c.json({
49
+ ok: false,
50
+ error: "cmux_unavailable",
51
+ message: "cmux is not available on this host — can't launch workspace — install cmux from https://cmux.io and run: cmux ping",
52
+ }, 503);
53
+ }
54
+ const inventory = nodeInventoryFn(rigId);
55
+ // Filter inventory: a node is launchable for cmux attach only if
56
+ // (a) it has a canonicalSessionName recorded AND (b) sessionStatus
57
+ // is "running" AND (c) the attachment is tmux-compatible (default
58
+ // when attachmentType is null/undefined; falsey-strict reject only
59
+ // when an explicit non-tmux value is present). Stale entries with
60
+ // a recorded session name but sessionStatus="exited"/"detached"/
61
+ // null would attach-to-a-dead-tmux-session inside the cmux panel
62
+ // and fail silently — violates README HG-6 / R5 honest-failure.
63
+ const launchableByLogical = new Map();
64
+ for (const entry of inventory) {
65
+ if (!entry.canonicalSessionName)
66
+ continue;
67
+ if (entry.sessionStatus !== "running")
68
+ continue;
69
+ if (entry.attachmentType != null && entry.attachmentType !== "tmux")
70
+ continue;
71
+ launchableByLogical.set(entry.logicalId, entry.canonicalSessionName);
72
+ }
73
+ // rig.nodes is in DB ORDER BY created_at, which corresponds to spec
74
+ // pod-then-member declaration order (pods created first, members
75
+ // within each pod in spec order). Use that as the deterministic
76
+ // agent ordering — no name-based sorting per README §52.
77
+ const orderedSessions = [];
78
+ for (const node of rigWithRelations.nodes) {
79
+ const session = launchableByLogical.get(node.logicalId);
80
+ if (session)
81
+ orderedSessions.push(session);
82
+ }
83
+ if (orderedSessions.length === 0) {
84
+ const rigName = rigWithRelations.rig.name;
85
+ return c.json({
86
+ ok: false,
87
+ error: "rig_not_running",
88
+ message: `Rig "${rigName}" has no running tmux sessions — can't attach to anything — run: rig up ${rigName}`,
89
+ }, 412);
90
+ }
91
+ // Discover existing workspaces for collision-avoidance. If
92
+ // listWorkspaces fails, treat the existing set as empty — the
93
+ // operator can rename the resulting workspace if needed; better to
94
+ // ship cleanly than block on an enumeration failure.
95
+ const listResult = await cmuxAdapter.listWorkspaces();
96
+ const existingNames = new Set(listResult.ok ? listResult.data.map((w) => w.name) : []);
97
+ const chunks = CmuxLayoutService.chunkAgents(orderedSessions);
98
+ const baseName = rigWithRelations.rig.name;
99
+ const workspaces = [];
100
+ for (let i = 0; i < chunks.length; i++) {
101
+ const desired = i === 0 ? baseName : `${baseName}-${i + 1}`;
102
+ const name = pickNonCollidingName(desired, existingNames);
103
+ existingNames.add(name);
104
+ const build = await cmuxLayoutService.buildWorkspace(name, undefined, chunks[i]);
105
+ if (!build.ok) {
106
+ return c.json({
107
+ ok: false,
108
+ error: "build_workspace_failed",
109
+ message: build.message,
110
+ partial: workspaces,
111
+ }, 500);
112
+ }
113
+ workspaces.push({
114
+ name: build.data.workspaceName,
115
+ agents: build.data.agents,
116
+ blanks: build.data.blanks,
117
+ });
118
+ }
119
+ return c.json({ ok: true, workspaces });
120
+ });
121
+ //# sourceMappingURL=rig-cmux.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rig-cmux.js","sourceRoot":"","sources":["../../src/routes/rig-cmux.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Hono } from "hono";
2
+ export declare function skillsRoutes(): Hono;
3
+ //# sourceMappingURL=skills.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/routes/skills.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AA6C5B,wBAAgB,YAAY,IAAI,IAAI,CAuFnC"}