openclaw-swarm-layer 0.1.0

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 (120) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +169 -0
  3. package/dist/src/cli/context.d.ts +18 -0
  4. package/dist/src/cli/context.js +60 -0
  5. package/dist/src/cli/output.d.ts +1 -0
  6. package/dist/src/cli/output.js +9 -0
  7. package/dist/src/cli/register-swarm-cli.d.ts +6 -0
  8. package/dist/src/cli/register-swarm-cli.js +130 -0
  9. package/dist/src/cli/swarm-doctor.d.ts +40 -0
  10. package/dist/src/cli/swarm-doctor.js +69 -0
  11. package/dist/src/cli/swarm-init.d.ts +9 -0
  12. package/dist/src/cli/swarm-init.js +10 -0
  13. package/dist/src/cli/swarm-plan.d.ts +13 -0
  14. package/dist/src/cli/swarm-plan.js +39 -0
  15. package/dist/src/cli/swarm-report.d.ts +9 -0
  16. package/dist/src/cli/swarm-report.js +14 -0
  17. package/dist/src/cli/swarm-review.d.ts +8 -0
  18. package/dist/src/cli/swarm-review.js +34 -0
  19. package/dist/src/cli/swarm-run.d.ts +7 -0
  20. package/dist/src/cli/swarm-run.js +39 -0
  21. package/dist/src/cli/swarm-session-cancel.d.ts +6 -0
  22. package/dist/src/cli/swarm-session-cancel.js +64 -0
  23. package/dist/src/cli/swarm-session-cleanup.d.ts +16 -0
  24. package/dist/src/cli/swarm-session-cleanup.js +34 -0
  25. package/dist/src/cli/swarm-session-close.d.ts +6 -0
  26. package/dist/src/cli/swarm-session-close.js +53 -0
  27. package/dist/src/cli/swarm-session-followup.d.ts +7 -0
  28. package/dist/src/cli/swarm-session-followup.js +63 -0
  29. package/dist/src/cli/swarm-session-inspect.d.ts +5 -0
  30. package/dist/src/cli/swarm-session-inspect.js +12 -0
  31. package/dist/src/cli/swarm-session-list.d.ts +4 -0
  32. package/dist/src/cli/swarm-session-list.js +19 -0
  33. package/dist/src/cli/swarm-session-status.d.ts +5 -0
  34. package/dist/src/cli/swarm-session-status.js +85 -0
  35. package/dist/src/cli/swarm-session-steer.d.ts +6 -0
  36. package/dist/src/cli/swarm-session-steer.js +40 -0
  37. package/dist/src/cli/swarm-status.d.ts +81 -0
  38. package/dist/src/cli/swarm-status.js +56 -0
  39. package/dist/src/config.d.ts +159 -0
  40. package/dist/src/config.js +292 -0
  41. package/dist/src/index.d.ts +10 -0
  42. package/dist/src/index.js +24 -0
  43. package/dist/src/lib/json-file.d.ts +5 -0
  44. package/dist/src/lib/json-file.js +42 -0
  45. package/dist/src/lib/paths.d.ts +25 -0
  46. package/dist/src/lib/paths.js +41 -0
  47. package/dist/src/planning/planner.d.ts +3 -0
  48. package/dist/src/planning/planner.js +39 -0
  49. package/dist/src/planning/task-graph.d.ts +8 -0
  50. package/dist/src/planning/task-graph.js +59 -0
  51. package/dist/src/reporting/obsidian-journal.d.ts +7 -0
  52. package/dist/src/reporting/obsidian-journal.js +126 -0
  53. package/dist/src/reporting/operator-summary.d.ts +32 -0
  54. package/dist/src/reporting/operator-summary.js +124 -0
  55. package/dist/src/reporting/reporter.d.ts +10 -0
  56. package/dist/src/reporting/reporter.js +128 -0
  57. package/dist/src/review/review-gate.d.ts +15 -0
  58. package/dist/src/review/review-gate.js +116 -0
  59. package/dist/src/runtime/acp-mapping.d.ts +23 -0
  60. package/dist/src/runtime/acp-mapping.js +50 -0
  61. package/dist/src/runtime/acp-runner.d.ts +11 -0
  62. package/dist/src/runtime/acp-runner.js +83 -0
  63. package/dist/src/runtime/bridge-errors.d.ts +8 -0
  64. package/dist/src/runtime/bridge-errors.js +59 -0
  65. package/dist/src/runtime/bridge-manifest.d.ts +30 -0
  66. package/dist/src/runtime/bridge-manifest.js +87 -0
  67. package/dist/src/runtime/bridge-openclaw-session-adapter.d.ts +48 -0
  68. package/dist/src/runtime/bridge-openclaw-session-adapter.js +142 -0
  69. package/dist/src/runtime/bridge-openclaw-subagent-adapter.d.ts +33 -0
  70. package/dist/src/runtime/bridge-openclaw-subagent-adapter.js +149 -0
  71. package/dist/src/runtime/manual-runner.d.ts +9 -0
  72. package/dist/src/runtime/manual-runner.js +53 -0
  73. package/dist/src/runtime/openclaw-exec-bridge.d.ts +211 -0
  74. package/dist/src/runtime/openclaw-exec-bridge.js +498 -0
  75. package/dist/src/runtime/openclaw-session-adapter.d.ts +48 -0
  76. package/dist/src/runtime/openclaw-session-adapter.js +14 -0
  77. package/dist/src/runtime/openclaw-subagent-adapter.d.ts +42 -0
  78. package/dist/src/runtime/openclaw-subagent-adapter.js +11 -0
  79. package/dist/src/runtime/public-api-seams.d.ts +23 -0
  80. package/dist/src/runtime/public-api-seams.js +79 -0
  81. package/dist/src/runtime/real-openclaw-session-adapter.d.ts +83 -0
  82. package/dist/src/runtime/real-openclaw-session-adapter.js +91 -0
  83. package/dist/src/runtime/retry-engine.d.ts +7 -0
  84. package/dist/src/runtime/retry-engine.js +29 -0
  85. package/dist/src/runtime/runner-registry.d.ts +6 -0
  86. package/dist/src/runtime/runner-registry.js +25 -0
  87. package/dist/src/runtime/session-sync.d.ts +9 -0
  88. package/dist/src/runtime/session-sync.js +165 -0
  89. package/dist/src/runtime/subagent-mapping.d.ts +9 -0
  90. package/dist/src/runtime/subagent-mapping.js +31 -0
  91. package/dist/src/runtime/subagent-runner.d.ts +9 -0
  92. package/dist/src/runtime/subagent-runner.js +63 -0
  93. package/dist/src/runtime/task-runner.d.ts +38 -0
  94. package/dist/src/runtime/task-runner.js +1 -0
  95. package/dist/src/schemas/run.schema.json +51 -0
  96. package/dist/src/schemas/spec.schema.json +30 -0
  97. package/dist/src/schemas/task.schema.json +48 -0
  98. package/dist/src/schemas/workflow-state.schema.json +46 -0
  99. package/dist/src/services/orchestrator.d.ts +47 -0
  100. package/dist/src/services/orchestrator.js +224 -0
  101. package/dist/src/session/session-lifecycle.d.ts +6 -0
  102. package/dist/src/session/session-lifecycle.js +84 -0
  103. package/dist/src/session/session-selector.d.ts +12 -0
  104. package/dist/src/session/session-selector.js +72 -0
  105. package/dist/src/session/session-store.d.ts +14 -0
  106. package/dist/src/session/session-store.js +84 -0
  107. package/dist/src/spec/spec-importer.d.ts +4 -0
  108. package/dist/src/spec/spec-importer.js +80 -0
  109. package/dist/src/state/state-store.d.ts +22 -0
  110. package/dist/src/state/state-store.js +187 -0
  111. package/dist/src/tools/index.d.ts +2 -0
  112. package/dist/src/tools/index.js +116 -0
  113. package/dist/src/types.d.ts +151 -0
  114. package/dist/src/types.js +1 -0
  115. package/dist/src/workspace/workspace-manager.d.ts +8 -0
  116. package/dist/src/workspace/workspace-manager.js +18 -0
  117. package/openclaw.plugin.json +121 -0
  118. package/package.json +62 -0
  119. package/scripts/openclaw-exec-bridge.mjs +4 -0
  120. package/skills/swarm-layer/SKILL.md +358 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Xu Cheng
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,169 @@
1
+ <div align="center">
2
+
3
+ # OpenClaw Swarm Layer
4
+
5
+ ### Spec-Driven Workflow Orchestration for AI Agent Swarms
6
+
7
+ **The Evolution of Agent Orchestration:** Spec &rarr; Plan &rarr; Execute &rarr; Review &rarr; Ship
8
+
9
+ Turn workflow specifications into executable task graphs, dispatch through pluggable runners, and orchestrate multi-agent collaboration with persistent sessions.
10
+
11
+ [![MIT License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
12
+ [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D22-green.svg)](https://nodejs.org)
13
+ [![OpenClaw](https://img.shields.io/badge/OpenClaw-%3E%3D2026.2-purple.svg)](https://openclaw.dev)
14
+ [![Tests](https://img.shields.io/badge/Tests-187%20unit%20%7C%2022%20e2e-brightgreen.svg)](#development)
15
+
16
+ [Quick Start](#quick-start) &bull; [Features](#features) &bull; [CLI Reference](#cli-commands) &bull; [Configuration](docs/configuration.md) &bull; [License](LICENSE)
17
+
18
+ ![TypeScript](https://img.shields.io/badge/TypeScript-Strict-3178C6?logo=typescript&logoColor=white)
19
+ ![OpenClaw Plugin](https://img.shields.io/badge/OpenClaw-Plugin-8B5CF6)
20
+ ![ACP Runner](https://img.shields.io/badge/Runner-ACP-FF6B35)
21
+ ![Subagent Runner](https://img.shields.io/badge/Runner-Subagent-0EA5E9)
22
+ ![Session Reuse](https://img.shields.io/badge/Session-Reuse-10B981)
23
+ ![Thread Binding](https://img.shields.io/badge/Thread-Binding-F59E0B)
24
+ ![Review Gates](https://img.shields.io/badge/Review-Gates-EF4444)
25
+
26
+ </div>
27
+
28
+ ---
29
+
30
+ ## Features
31
+
32
+ - **Spec-driven orchestration** — import a spec, generate a task graph, execute in dependency order
33
+ - **Multiple runners** — manual (operator-driven), ACP (external harness), subagent (OpenClaw-native)
34
+ - **Review gates** — tasks require approval before marking done
35
+ - **Session management** — persistent sessions with reuse, thread binding, follow-up/steer
36
+ - **Automatic retry** — configurable retry policy with dead letter tracking
37
+ - **Operator UX** — attention items, highlights, recommended actions, reports
38
+ - **Report sync** — local reports + optional Obsidian vault sync
39
+
40
+ ## Prerequisites
41
+
42
+ - Node.js >= 22
43
+ - [OpenClaw](https://openclaw.dev) >= 2026.2.24
44
+
45
+ ## Installation
46
+
47
+ ```bash
48
+ # Clone the repository
49
+ git clone https://github.com/xucheng/openclaw-swarm-layer.git
50
+ cd openclaw-swarm-layer
51
+ npm install
52
+ npm run build
53
+
54
+ # Install as an OpenClaw plugin
55
+ openclaw plugins install -l /path/to/openclaw-swarm-layer
56
+ ```
57
+
58
+ ## Quick Start
59
+
60
+ ```bash
61
+ # 1. Initialize a project
62
+ openclaw swarm init --project /path/to/your/project
63
+
64
+ # 2. Write a spec file (Markdown with Goals/Phases/Tasks sections)
65
+ cat > SPEC.md << 'EOF'
66
+ # My Workflow
67
+
68
+ ## Goals
69
+ - Build and test the feature
70
+
71
+ ## Phases
72
+ ### Phase 1
73
+ - Implement the core logic
74
+ - Write unit tests
75
+ ### Phase 2
76
+ - Integration testing
77
+ EOF
78
+
79
+ # 3. Import the spec and generate task graph
80
+ openclaw swarm plan --project . --spec SPEC.md
81
+
82
+ # 4. Check status
83
+ openclaw swarm status --project .
84
+
85
+ # 5. Execute (dry-run first)
86
+ openclaw swarm run --project . --dry-run
87
+ openclaw swarm run --project .
88
+
89
+ # 6. Review completed tasks
90
+ openclaw swarm review --project . --task <taskId> --approve
91
+
92
+ # 7. Generate report
93
+ openclaw swarm report --project .
94
+ ```
95
+
96
+ ## CLI Commands
97
+
98
+ ### Core Workflow
99
+ | Command | Description |
100
+ |---------|-------------|
101
+ | `swarm init --project <path>` | Initialize swarm state for a project |
102
+ | `swarm status --project <path>` | Show workflow status with attention items |
103
+ | `swarm plan --project <path> --spec <path>` | Import spec and build task graph |
104
+ | `swarm run --project <path> [--runner acp\|manual\|subagent] [--dry-run]` | Execute next runnable task |
105
+ | `swarm review --project <path> --task <id> --approve\|--reject` | Approve or reject a task |
106
+ | `swarm report --project <path>` | Generate workflow report |
107
+ | `swarm doctor` | Diagnose bridge compatibility |
108
+
109
+ ### Session Management
110
+ | Command | Description |
111
+ |---------|-------------|
112
+ | `swarm session list --project <path>` | List all sessions |
113
+ | `swarm session inspect --project <path> --session <id>` | Inspect a session |
114
+ | `swarm session status --project <path> --run <id>` | Poll session status |
115
+ | `swarm session cancel --project <path> --run <id>` | Cancel an active session |
116
+ | `swarm session close --project <path> --run <id>` | Close a session |
117
+ | `swarm session follow-up --project <path> --session <id> --task <desc>` | Inject follow-up task |
118
+ | `swarm session steer --project <path> --session <id> --message <text>` | Send steering message |
119
+ | `swarm session cleanup --project <path> [--stale-minutes <n>]` | Clean up orphaned sessions |
120
+
121
+ ## Architecture
122
+
123
+ ```
124
+ CLI (src/cli/) <-> Tools (src/tools/)
125
+ | |
126
+ SwarmOrchestrator (src/services/orchestrator.ts)
127
+ |
128
+ RunnerRegistry -> TaskRunner implementations
129
+ | | |
130
+ ManualRunner AcpRunner SubagentRunner
131
+ |
132
+ StateStore + SessionStore (src/state/, src/session/)
133
+ ```
134
+
135
+ See [docs/configuration.md](docs/configuration.md) for all configuration options.
136
+
137
+ ## Development
138
+
139
+ ```bash
140
+ npm run build # TypeScript -> dist/
141
+ npm test # Unit + e2e tests
142
+ npm run test:unit # Unit tests only
143
+ npm run test:e2e # E2E tests only
144
+ npm run test:watch # Watch mode
145
+ ```
146
+
147
+ ## Documentation
148
+
149
+ **User Guides:**
150
+ - [User Manual](docs/user-manual.md) — complete usage guide from install to daily operations (Chinese)
151
+ - [Skills Guide](docs/skills-guide.md) — unified skill with 5 modules (setup/operate/diagnose/report/tools)
152
+ - [Configuration Reference](docs/configuration.md) — all config options, journal setup, directory structure
153
+
154
+ **Operations:**
155
+ - [Operator Runbook](docs/operator-runbook.md) — install, smoke test, upgrade, rollback
156
+ - [Migration Checklist](docs/migration-checklist.md) — bridge replacement strategy
157
+
158
+ **Project History:**
159
+ - [Roadmap](docs/roadmap.md) — M1-M3 milestone structure
160
+ - [Milestones](docs/milestones.md) — definition of done per milestone
161
+ - [Current Plan](docs/current-plan.md) — delivery status and future directions
162
+
163
+ ## License
164
+
165
+ [MIT](LICENSE)
166
+
167
+ ## Contributing
168
+
169
+ See [CONTRIBUTING.md](CONTRIBUTING.md).
@@ -0,0 +1,18 @@
1
+ import type { PluginRuntime } from "openclaw/plugin-sdk";
2
+ import type { SwarmPluginConfig } from "../config.js";
3
+ import { type OpenClawSessionAdapter } from "../runtime/openclaw-session-adapter.js";
4
+ import { type OpenClawSubagentAdapter } from "../runtime/openclaw-subagent-adapter.js";
5
+ import { SessionStore } from "../session/session-store.js";
6
+ import { StateStore } from "../state/state-store.js";
7
+ export type SwarmCliContext = {
8
+ config?: Partial<SwarmPluginConfig>;
9
+ stateStore?: StateStore;
10
+ sessionStore?: SessionStore;
11
+ sessionAdapter?: OpenClawSessionAdapter;
12
+ subagentAdapter?: OpenClawSubagentAdapter;
13
+ runtime?: Pick<PluginRuntime, "config" | "system">;
14
+ };
15
+ export declare function resolveStateStore(context?: SwarmCliContext): StateStore;
16
+ export declare function resolveSessionStore(context?: SwarmCliContext): SessionStore;
17
+ export declare function resolveSessionAdapter(context?: SwarmCliContext): OpenClawSessionAdapter;
18
+ export declare function resolveSubagentAdapter(context?: SwarmCliContext): OpenClawSubagentAdapter;
@@ -0,0 +1,60 @@
1
+ import { defaultSwarmPluginConfig } from "../config.js";
2
+ import { createBridgeSessionAdapter } from "../runtime/bridge-openclaw-session-adapter.js";
3
+ import { createBridgeSubagentAdapter } from "../runtime/bridge-openclaw-subagent-adapter.js";
4
+ import { UnsupportedOpenClawSessionAdapter } from "../runtime/openclaw-session-adapter.js";
5
+ import { UnsupportedOpenClawSubagentAdapter } from "../runtime/openclaw-subagent-adapter.js";
6
+ import { createSessionAdapter } from "../runtime/real-openclaw-session-adapter.js";
7
+ import { SessionStore } from "../session/session-store.js";
8
+ import { StateStore } from "../state/state-store.js";
9
+ export function resolveStateStore(context) {
10
+ return context?.stateStore ?? new StateStore(context?.config);
11
+ }
12
+ export function resolveSessionStore(context) {
13
+ return context?.sessionStore ?? new SessionStore(context?.stateStore?.config ?? context?.config);
14
+ }
15
+ export function resolveSessionAdapter(context) {
16
+ if (context?.sessionAdapter) {
17
+ return context.sessionAdapter;
18
+ }
19
+ const config = context?.stateStore?.config
20
+ ? context.stateStore.config
21
+ : context?.config
22
+ ? {
23
+ ...defaultSwarmPluginConfig,
24
+ ...context.config,
25
+ acp: {
26
+ ...defaultSwarmPluginConfig.acp,
27
+ ...context.config.acp,
28
+ },
29
+ }
30
+ : defaultSwarmPluginConfig;
31
+ const bridgeAdapter = createBridgeSessionAdapter(context?.runtime, { acp: config.acp, bridge: config.bridge });
32
+ if (bridgeAdapter) {
33
+ return bridgeAdapter;
34
+ }
35
+ const runtimeAdapter = createSessionAdapter(context?.runtime, { acp: config.acp });
36
+ return runtimeAdapter ?? new UnsupportedOpenClawSessionAdapter();
37
+ }
38
+ export function resolveSubagentAdapter(context) {
39
+ if (context?.subagentAdapter) {
40
+ return context.subagentAdapter;
41
+ }
42
+ const config = context?.stateStore?.config
43
+ ? context.stateStore.config
44
+ : context?.config
45
+ ? {
46
+ ...defaultSwarmPluginConfig,
47
+ ...context.config,
48
+ acp: {
49
+ ...defaultSwarmPluginConfig.acp,
50
+ ...context.config.acp,
51
+ },
52
+ bridge: {
53
+ ...defaultSwarmPluginConfig.bridge,
54
+ ...context.config.bridge,
55
+ },
56
+ }
57
+ : defaultSwarmPluginConfig;
58
+ const bridgeAdapter = createBridgeSubagentAdapter({ bridge: config.bridge });
59
+ return bridgeAdapter ?? new UnsupportedOpenClawSubagentAdapter();
60
+ }
@@ -0,0 +1 @@
1
+ export declare function formatOutput(payload: unknown, asJson?: boolean): string;
@@ -0,0 +1,9 @@
1
+ export function formatOutput(payload, asJson) {
2
+ if (asJson) {
3
+ return JSON.stringify(payload, null, 2);
4
+ }
5
+ if (typeof payload === "string") {
6
+ return payload;
7
+ }
8
+ return JSON.stringify(payload, null, 2);
9
+ }
@@ -0,0 +1,6 @@
1
+ import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
2
+ import { type SwarmCliContext } from "./context.js";
3
+ export declare function registerSwarmCli(api: OpenClawPluginApi): void;
4
+ export declare function registerSwarmCliCommands(ctx: {
5
+ program: any;
6
+ }, cliContext?: SwarmCliContext): void;
@@ -0,0 +1,130 @@
1
+ import { resolvePluginConfigFromApi } from "../config.js";
2
+ import { StateStore } from "../state/state-store.js";
3
+ import { runSwarmInit } from "./swarm-init.js";
4
+ import { formatOutput } from "./output.js";
5
+ import { runSwarmPlan } from "./swarm-plan.js";
6
+ import { runSwarmDoctor } from "./swarm-doctor.js";
7
+ import { runSwarmReport } from "./swarm-report.js";
8
+ import { runSwarmReview } from "./swarm-review.js";
9
+ import { runSwarmSessionCancel } from "./swarm-session-cancel.js";
10
+ import { runSwarmSessionCleanup } from "./swarm-session-cleanup.js";
11
+ import { runSwarmSessionClose } from "./swarm-session-close.js";
12
+ import { runSwarmSessionFollowup } from "./swarm-session-followup.js";
13
+ import { runSwarmSessionInspect } from "./swarm-session-inspect.js";
14
+ import { runSwarmSessionList } from "./swarm-session-list.js";
15
+ import { runSwarmRun } from "./swarm-run.js";
16
+ import { runSwarmSessionStatus } from "./swarm-session-status.js";
17
+ import { runSwarmSessionSteer } from "./swarm-session-steer.js";
18
+ import { runSwarmStatus } from "./swarm-status.js";
19
+ function bindCommand(command, action) {
20
+ command.action(async (options) => {
21
+ const output = await action(options);
22
+ if (output !== undefined) {
23
+ process.stdout.write(`${formatOutput(output, Boolean(options?.json))}\n`);
24
+ }
25
+ });
26
+ }
27
+ export function registerSwarmCli(api) {
28
+ api.registerCli((ctx) => {
29
+ registerSwarmCliCommands(ctx, {
30
+ config: resolvePluginConfigFromApi(api),
31
+ stateStore: new StateStore(resolvePluginConfigFromApi(api)),
32
+ runtime: api.runtime,
33
+ });
34
+ }, { commands: ["swarm"] });
35
+ }
36
+ export function registerSwarmCliCommands(ctx, cliContext) {
37
+ const swarm = ctx.program.command("swarm").description("Swarm workflow commands");
38
+ const init = swarm.command("init").requiredOption("--project <path>").option("--json");
39
+ bindCommand(init, (options) => runSwarmInit({ project: options.project }, cliContext));
40
+ const status = swarm.command("status").requiredOption("--project <path>").option("--json");
41
+ bindCommand(status, (options) => runSwarmStatus({ project: options.project }, cliContext));
42
+ const plan = swarm
43
+ .command("plan")
44
+ .requiredOption("--project <path>")
45
+ .requiredOption("--spec <path>")
46
+ .option("--json");
47
+ bindCommand(plan, (options) => runSwarmPlan({ project: options.project, spec: options.spec }, cliContext));
48
+ const run = swarm
49
+ .command("run")
50
+ .requiredOption("--project <path>")
51
+ .option("--task <taskId>")
52
+ .option("--dry-run")
53
+ .option("--runner <kind>")
54
+ .option("--json");
55
+ bindCommand(run, (options) => runSwarmRun({
56
+ project: options.project,
57
+ task: options.task,
58
+ dryRun: options.dryRun,
59
+ runner: options.runner,
60
+ }, cliContext));
61
+ const review = swarm
62
+ .command("review")
63
+ .requiredOption("--project <path>")
64
+ .requiredOption("--task <taskId>")
65
+ .option("--approve")
66
+ .option("--reject")
67
+ .option("--note <text>")
68
+ .option("--json");
69
+ bindCommand(review, (options) => runSwarmReview({
70
+ project: options.project,
71
+ task: options.task,
72
+ approve: options.approve,
73
+ reject: options.reject,
74
+ note: options.note,
75
+ }, cliContext));
76
+ const report = swarm.command("report").requiredOption("--project <path>").option("--json");
77
+ bindCommand(report, (options) => runSwarmReport({ project: options.project }, cliContext));
78
+ const doctor = swarm.command("doctor").option("--json");
79
+ bindCommand(doctor, () => runSwarmDoctor({}, cliContext));
80
+ const session = swarm.command("session").description("ACP session operator commands");
81
+ const sessionList = session.command("list").requiredOption("--project <path>").option("--json");
82
+ bindCommand(sessionList, (options) => runSwarmSessionList({ project: options.project }, cliContext));
83
+ const sessionInspect = session
84
+ .command("inspect")
85
+ .requiredOption("--project <path>")
86
+ .requiredOption("--session <sessionId>")
87
+ .option("--json");
88
+ bindCommand(sessionInspect, (options) => runSwarmSessionInspect({ project: options.project, session: options.session }, cliContext));
89
+ const sessionStatus = session
90
+ .command("status")
91
+ .requiredOption("--project <path>")
92
+ .requiredOption("--run <runId>")
93
+ .option("--json");
94
+ bindCommand(sessionStatus, (options) => runSwarmSessionStatus({ project: options.project, run: options.run }, cliContext));
95
+ const sessionCancel = session
96
+ .command("cancel")
97
+ .requiredOption("--project <path>")
98
+ .requiredOption("--run <runId>")
99
+ .option("--reason <text>")
100
+ .option("--json");
101
+ bindCommand(sessionCancel, (options) => runSwarmSessionCancel({ project: options.project, run: options.run, reason: options.reason }, cliContext));
102
+ const sessionClose = session
103
+ .command("close")
104
+ .requiredOption("--project <path>")
105
+ .requiredOption("--run <runId>")
106
+ .option("--reason <text>")
107
+ .option("--json");
108
+ bindCommand(sessionClose, (options) => runSwarmSessionClose({ project: options.project, run: options.run, reason: options.reason }, cliContext));
109
+ const sessionFollowup = session
110
+ .command("follow-up")
111
+ .requiredOption("--project <path>")
112
+ .requiredOption("--session <sessionId>")
113
+ .requiredOption("--task <description>")
114
+ .option("--runner <kind>")
115
+ .option("--json");
116
+ bindCommand(sessionFollowup, (options) => runSwarmSessionFollowup({ project: options.project, session: options.session, task: options.task, runner: options.runner }, cliContext));
117
+ const sessionCleanup = session
118
+ .command("cleanup")
119
+ .requiredOption("--project <path>")
120
+ .option("--stale-minutes <minutes>")
121
+ .option("--json");
122
+ bindCommand(sessionCleanup, (options) => runSwarmSessionCleanup({ project: options.project, staleMinutes: options.staleMinutes ? Number(options.staleMinutes) : undefined }, cliContext));
123
+ const sessionSteer = session
124
+ .command("steer")
125
+ .requiredOption("--project <path>")
126
+ .requiredOption("--session <sessionId>")
127
+ .requiredOption("--message <text>")
128
+ .option("--json");
129
+ bindCommand(sessionSteer, (options) => runSwarmSessionSteer({ project: options.project, session: options.session, message: options.message }, cliContext));
130
+ }
@@ -0,0 +1,40 @@
1
+ import { runBridgeCommandDirect } from "../runtime/bridge-openclaw-session-adapter.js";
2
+ import { type SwarmCliContext } from "./context.js";
3
+ type BridgeDoctorResult = {
4
+ ok: boolean;
5
+ severity: "healthy" | "warning" | "blocked";
6
+ openclawRoot: string;
7
+ version?: string;
8
+ compatibility: {
9
+ strategy?: "internal-bundle";
10
+ testedAt?: string;
11
+ supportedRunners: string[];
12
+ replacementCandidates: string[];
13
+ notes: string[];
14
+ };
15
+ publicApi: {
16
+ acpControlPlaneExport: boolean;
17
+ subagentSpawnExport: boolean;
18
+ readyReplacementPoints: string[];
19
+ };
20
+ replacementPlan: Array<{
21
+ runner: "acp" | "subagent";
22
+ publicExport: string;
23
+ available: boolean;
24
+ status: "ready" | "blocked";
25
+ currentImplementation: string;
26
+ targetImplementation: string;
27
+ affectedModules: string[];
28
+ nextStep: string;
29
+ }>;
30
+ migrationChecklist: string[];
31
+ checks: Record<string, boolean>;
32
+ blockers: string[];
33
+ warnings: string[];
34
+ risks: string[];
35
+ remediation: string[];
36
+ nextAction: string;
37
+ };
38
+ export type BridgeCommandRunner = typeof runBridgeCommandDirect;
39
+ export declare function runSwarmDoctor(_options: Record<string, never>, context?: SwarmCliContext, commandRunner?: BridgeCommandRunner): Promise<BridgeDoctorResult>;
40
+ export {};
@@ -0,0 +1,69 @@
1
+ import { defaultSwarmPluginConfig } from "../config.js";
2
+ import { resolveBridgeScriptPath, resolveTsxLoaderPath, runBridgeCommandDirect } from "../runtime/bridge-openclaw-session-adapter.js";
3
+ function resolveEffectiveConfig(context) {
4
+ if (context?.stateStore?.config) {
5
+ return context.stateStore.config;
6
+ }
7
+ if (context?.config) {
8
+ return {
9
+ ...defaultSwarmPluginConfig,
10
+ ...context.config,
11
+ acp: {
12
+ ...defaultSwarmPluginConfig.acp,
13
+ ...context.config.acp,
14
+ },
15
+ bridge: {
16
+ ...defaultSwarmPluginConfig.bridge,
17
+ ...context.config.bridge,
18
+ },
19
+ };
20
+ }
21
+ return defaultSwarmPluginConfig;
22
+ }
23
+ export async function runSwarmDoctor(_options, context, commandRunner = runBridgeCommandDirect) {
24
+ const config = resolveEffectiveConfig(context);
25
+ if (!config.bridge.enabled) {
26
+ return {
27
+ ok: false,
28
+ severity: "blocked",
29
+ openclawRoot: config.bridge.openclawRoot ?? "(unset)",
30
+ compatibility: {
31
+ supportedRunners: [],
32
+ replacementCandidates: [],
33
+ notes: [],
34
+ },
35
+ publicApi: {
36
+ acpControlPlaneExport: false,
37
+ subagentSpawnExport: false,
38
+ readyReplacementPoints: [],
39
+ },
40
+ replacementPlan: [],
41
+ migrationChecklist: [
42
+ "Enable bridge mode first, then rerun `openclaw swarm doctor --json` to generate a migration checklist.",
43
+ ],
44
+ checks: {
45
+ bridgeEnabled: false,
46
+ },
47
+ blockers: ["bridge.enabled=false"],
48
+ warnings: [],
49
+ risks: ["bridge mode is disabled"],
50
+ remediation: ["Enable plugins.entries.openclaw-swarm-layer.config.bridge.enabled before using bridge-backed execution."],
51
+ nextAction: "Enable bridge mode before running bridge-backed ACP or subagent execution.",
52
+ };
53
+ }
54
+ const result = await commandRunner([config.bridge.nodePath ?? process.execPath, "--import", resolveTsxLoaderPath(), resolveBridgeScriptPath(), "doctor"], {
55
+ timeoutMs: 120_000,
56
+ cwd: process.cwd(),
57
+ input: JSON.stringify({
58
+ bridge: {
59
+ openclawRoot: config.bridge.openclawRoot,
60
+ versionAllow: config.bridge.versionAllow,
61
+ },
62
+ }),
63
+ });
64
+ if (result.code !== 0) {
65
+ throw new Error(result.stderr.trim() || result.stdout.trim() || "bridge doctor failed");
66
+ }
67
+ const parsed = JSON.parse(result.stdout);
68
+ return parsed.result;
69
+ }
@@ -0,0 +1,9 @@
1
+ import { type SwarmCliContext } from "./context.js";
2
+ export type SwarmInitResult = {
3
+ ok: true;
4
+ projectRoot: string;
5
+ swarmRoot: string;
6
+ };
7
+ export declare function runSwarmInit(options: {
8
+ project: string;
9
+ }, context?: SwarmCliContext): Promise<SwarmInitResult>;
@@ -0,0 +1,10 @@
1
+ import { resolveStateStore } from "./context.js";
2
+ export async function runSwarmInit(options, context) {
3
+ const stateStore = resolveStateStore(context);
4
+ const paths = await stateStore.initProject(options.project);
5
+ return {
6
+ ok: true,
7
+ projectRoot: paths.projectRoot,
8
+ swarmRoot: paths.swarmRoot,
9
+ };
10
+ }
@@ -0,0 +1,13 @@
1
+ import { type SwarmCliContext } from "./context.js";
2
+ export type SwarmPlanResult = {
3
+ ok: true;
4
+ specId: string;
5
+ taskCount: number;
6
+ activeSpecId: string;
7
+ localReportPath: string;
8
+ obsidianReportPath?: string;
9
+ };
10
+ export declare function runSwarmPlan(options: {
11
+ project: string;
12
+ spec: string;
13
+ }, context?: SwarmCliContext): Promise<SwarmPlanResult>;
@@ -0,0 +1,39 @@
1
+ import { resolveSwarmPaths } from "../lib/paths.js";
2
+ import { planTasksFromSpec } from "../planning/planner.js";
3
+ import { journalSpecArchive } from "../reporting/obsidian-journal.js";
4
+ import { writeWorkflowReport } from "../reporting/reporter.js";
5
+ import { importSpecFromMarkdown } from "../spec/spec-importer.js";
6
+ import { resolveStateStore } from "./context.js";
7
+ export async function runSwarmPlan(options, context) {
8
+ const stateStore = resolveStateStore(context);
9
+ const reportConfig = context?.config ?? stateStore.config;
10
+ const workflow = await stateStore.loadWorkflow(options.project);
11
+ const spec = await importSpecFromMarkdown(options.spec, { defaultProjectRoot: workflow.projectRoot });
12
+ const tasks = planTasksFromSpec(spec, context?.config);
13
+ await stateStore.writeSpec(options.project, spec);
14
+ const nextWorkflow = {
15
+ ...workflow,
16
+ activeSpecId: spec.specId,
17
+ lifecycle: tasks.length > 0 ? "planned" : workflow.lifecycle,
18
+ tasks,
19
+ reviewQueue: [],
20
+ lastAction: {
21
+ at: new Date().toISOString(),
22
+ type: "plan",
23
+ message: `planned ${tasks.length} tasks for ${spec.specId}`,
24
+ },
25
+ };
26
+ await stateStore.saveWorkflow(options.project, nextWorkflow);
27
+ const report = await writeWorkflowReport(options.project, nextWorkflow, reportConfig);
28
+ // Obsidian journal: spec archive
29
+ const paths = resolveSwarmPaths(options.project, reportConfig);
30
+ await journalSpecArchive(paths, stateStore.config.obsidianJournal, spec);
31
+ return {
32
+ ok: true,
33
+ specId: spec.specId,
34
+ taskCount: tasks.length,
35
+ activeSpecId: spec.specId,
36
+ localReportPath: report.localReportPath,
37
+ obsidianReportPath: report.obsidianReportPath,
38
+ };
39
+ }
@@ -0,0 +1,9 @@
1
+ import { type SwarmCliContext } from "./context.js";
2
+ export declare function runSwarmReport(options: {
3
+ project: string;
4
+ }, context?: SwarmCliContext): Promise<{
5
+ ok: true;
6
+ report: string;
7
+ localReportPath: string;
8
+ obsidianReportPath?: string;
9
+ }>;
@@ -0,0 +1,14 @@
1
+ import { writeWorkflowReport } from "../reporting/reporter.js";
2
+ import { resolveStateStore } from "./context.js";
3
+ export async function runSwarmReport(options, context) {
4
+ const stateStore = resolveStateStore(context);
5
+ const reportConfig = context?.config ?? stateStore.config;
6
+ const workflow = await stateStore.loadWorkflow(options.project);
7
+ const written = await writeWorkflowReport(options.project, workflow, reportConfig);
8
+ return {
9
+ ok: true,
10
+ report: written.report,
11
+ localReportPath: written.localReportPath,
12
+ obsidianReportPath: written.obsidianReportPath,
13
+ };
14
+ }
@@ -0,0 +1,8 @@
1
+ import { type SwarmCliContext } from "./context.js";
2
+ export declare function runSwarmReview(options: {
3
+ project: string;
4
+ task: string;
5
+ approve?: boolean;
6
+ reject?: boolean;
7
+ note?: string;
8
+ }, context?: SwarmCliContext): Promise<unknown>;