taskmeld 0.1.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 (204) hide show
  1. package/LICENSE +18 -0
  2. package/README.md +172 -0
  3. package/README.zh-CN.md +172 -0
  4. package/dist/src/app/app-context-env.js +51 -0
  5. package/dist/src/app/create-app-context.js +127 -0
  6. package/dist/src/app/data-dir.js +29 -0
  7. package/dist/src/app/pipeline-config.js +105 -0
  8. package/dist/src/app/pipeline-plugin-config.js +2 -0
  9. package/dist/src/app/pipeline-registry.js +502 -0
  10. package/dist/src/app/pipeline-runtime.js +202 -0
  11. package/dist/src/app/runtime-store.js +151 -0
  12. package/dist/src/app/user-config.js +37 -0
  13. package/dist/src/artifacts/artifact-cleanup.js +192 -0
  14. package/dist/src/artifacts/artifact-index.js +262 -0
  15. package/dist/src/artifacts/artifact-rebuilder.js +120 -0
  16. package/dist/src/artifacts/storage-service.js +371 -0
  17. package/dist/src/cli/bootstrap.js +226 -0
  18. package/dist/src/cli/commands/agent.js +126 -0
  19. package/dist/src/cli/commands/artifact.js +175 -0
  20. package/dist/src/cli/commands/init.js +150 -0
  21. package/dist/src/cli/commands/pipeline/errors.js +37 -0
  22. package/dist/src/cli/commands/pipeline/result.js +179 -0
  23. package/dist/src/cli/commands/pipeline/selector.js +51 -0
  24. package/dist/src/cli/commands/pipeline/types.js +2 -0
  25. package/dist/src/cli/commands/pipeline/watch.js +67 -0
  26. package/dist/src/cli/commands/pipeline.js +339 -0
  27. package/dist/src/cli/commands/scheduler.js +81 -0
  28. package/dist/src/cli/commands/server.js +70 -0
  29. package/dist/src/cli/commands/system.js +21 -0
  30. package/dist/src/cli/errors.js +71 -0
  31. package/dist/src/cli/help.js +184 -0
  32. package/dist/src/cli/index.js +65 -0
  33. package/dist/src/cli/output.js +19 -0
  34. package/dist/src/cli/renderers/engine/json.js +67 -0
  35. package/dist/src/cli/renderers/engine/markdown.js +95 -0
  36. package/dist/src/cli/renderers/engine/types.js +2 -0
  37. package/dist/src/cli/renderers/engine/utils.js +32 -0
  38. package/dist/src/cli/renderers/index.js +27 -0
  39. package/dist/src/cli/renderers/specs/agent.js +78 -0
  40. package/dist/src/cli/renderers/specs/artifact.js +32 -0
  41. package/dist/src/cli/renderers/specs/index.js +36 -0
  42. package/dist/src/cli/renderers/specs/init.js +25 -0
  43. package/dist/src/cli/renderers/specs/pipeline.js +561 -0
  44. package/dist/src/cli/renderers/specs/scheduler.js +46 -0
  45. package/dist/src/cli/renderers/specs/server.js +38 -0
  46. package/dist/src/cli/renderers/specs/system.js +36 -0
  47. package/dist/src/cli/router.js +199 -0
  48. package/dist/src/cli/server-runtime-client.js +780 -0
  49. package/dist/src/cli/types.js +2 -0
  50. package/dist/src/gateway/frame-sanitizer.js +78 -0
  51. package/dist/src/gateway/gateway-client.js +462 -0
  52. package/dist/src/gateway/index.js +18 -0
  53. package/dist/src/gateway/types.js +2 -0
  54. package/dist/src/index.js +123 -0
  55. package/dist/src/logs/run-log-reader.js +141 -0
  56. package/dist/src/logs/run-log-service.js +42 -0
  57. package/dist/src/logs/run-log-types.js +2 -0
  58. package/dist/src/pipeline/agent-activity.js +191 -0
  59. package/dist/src/pipeline/artifact-storage.js +208 -0
  60. package/dist/src/pipeline/diagnostics/dependency-diagnostic.js +105 -0
  61. package/dist/src/pipeline/diagnostics/index.js +6 -0
  62. package/dist/src/pipeline/dispatch/pipeline-inbound-queue.js +215 -0
  63. package/dist/src/pipeline/dispatch/pipeline-link-dispatcher.js +66 -0
  64. package/dist/src/pipeline/dispatch/pipeline-link-store.js +94 -0
  65. package/dist/src/pipeline/dispatch/pipeline-queue-drainer.js +71 -0
  66. package/dist/src/pipeline/execution/dependency-check.js +52 -0
  67. package/dist/src/pipeline/execution/execution-result.js +2 -0
  68. package/dist/src/pipeline/execution/group-item-executor.js +128 -0
  69. package/dist/src/pipeline/execution/index.js +5 -0
  70. package/dist/src/pipeline/execution/node-item-executor.js +58 -0
  71. package/dist/src/pipeline/execution/node-runner.js +159 -0
  72. package/dist/src/pipeline/execution/readiness-state.js +10 -0
  73. package/dist/src/pipeline/execution/reject-handler.js +94 -0
  74. package/dist/src/pipeline/execution/rejected-artifact-archiver.js +45 -0
  75. package/dist/src/pipeline/execution/route-item-manager.js +253 -0
  76. package/dist/src/pipeline/execution/run-abort-controller.js +66 -0
  77. package/dist/src/pipeline/execution/run-state-helpers.js +257 -0
  78. package/dist/src/pipeline/execution/service.js +165 -0
  79. package/dist/src/pipeline/execution/session-registry.js +96 -0
  80. package/dist/src/pipeline/execution/structured-node-runner.js +411 -0
  81. package/dist/src/pipeline/execution-status.js +96 -0
  82. package/dist/src/pipeline/execution-timeout.js +21 -0
  83. package/dist/src/pipeline/identity/index.js +32 -0
  84. package/dist/src/pipeline/identity/types.js +2 -0
  85. package/dist/src/pipeline/item-batch-controller.js +227 -0
  86. package/dist/src/pipeline/output/pipeline-output-resolver.js +91 -0
  87. package/dist/src/pipeline/output/pipeline-output-store.js +60 -0
  88. package/dist/src/pipeline/runtime-model.js +173 -0
  89. package/dist/src/pipeline/scheduler/dependency-state.js +144 -0
  90. package/dist/src/pipeline/scheduler-service.js +314 -0
  91. package/dist/src/pipeline/state/group-item-state.js +50 -0
  92. package/dist/src/pipeline/state/group-run-state.js +41 -0
  93. package/dist/src/pipeline/state/index.js +20 -0
  94. package/dist/src/pipeline/state/node-item-state.js +67 -0
  95. package/dist/src/pipeline/state/node-run-state.js +51 -0
  96. package/dist/src/pipeline/state/types.js +2 -0
  97. package/dist/src/pipeline/state-machine.js +101 -0
  98. package/dist/src/pipeline/structured-output/contract.js +133 -0
  99. package/dist/src/pipeline/structured-output/index.js +22 -0
  100. package/dist/src/pipeline/structured-output/parser.js +214 -0
  101. package/dist/src/pipeline/structured-output/prompt.js +290 -0
  102. package/dist/src/pipeline/structured-output/waiter.js +139 -0
  103. package/dist/src/pipeline/template.js +135 -0
  104. package/dist/src/pipeline/timeline-log-store.js +57 -0
  105. package/dist/src/pipeline/tool-activity.js +94 -0
  106. package/dist/src/pipeline/types/pipeline-link.js +7 -0
  107. package/dist/src/pipeline/types/pipeline-output.js +11 -0
  108. package/dist/src/pipeline/types/workflow.js +2 -0
  109. package/dist/src/pipeline/workflow/branch-rules.js +74 -0
  110. package/dist/src/pipeline/workflow/defaults.js +48 -0
  111. package/dist/src/pipeline/workflow/io.js +89 -0
  112. package/dist/src/pipeline/workflow/normalize.js +347 -0
  113. package/dist/src/pipeline/workflow/routes.js +16 -0
  114. package/dist/src/pipeline/workflow/template-mapper.js +113 -0
  115. package/dist/src/pipeline/workflow/validate.js +312 -0
  116. package/dist/src/pipeline/workflow-graph.js +165 -0
  117. package/dist/src/server/api-handler.js +163 -0
  118. package/dist/src/server/http-utils.js +34 -0
  119. package/dist/src/server/middleware.js +61 -0
  120. package/dist/src/server/router.js +105 -0
  121. package/dist/src/server/routes/agents.js +189 -0
  122. package/dist/src/server/routes/artifacts.js +163 -0
  123. package/dist/src/server/routes/gateway.js +18 -0
  124. package/dist/src/server/routes/health.js +16 -0
  125. package/dist/src/server/routes/logs.js +73 -0
  126. package/dist/src/server/routes/pipeline-batch.js +163 -0
  127. package/dist/src/server/routes/pipeline-diagnostics.js +33 -0
  128. package/dist/src/server/routes/pipeline-identity.js +24 -0
  129. package/dist/src/server/routes/pipeline-links.js +117 -0
  130. package/dist/src/server/routes/pipeline-outputs.js +27 -0
  131. package/dist/src/server/routes/pipeline-queue.js +62 -0
  132. package/dist/src/server/routes/pipeline-runtime.js +162 -0
  133. package/dist/src/server/routes/pipeline-scheduler.js +69 -0
  134. package/dist/src/server/routes/pipeline-workflow.js +180 -0
  135. package/dist/src/server/routes/pipelines.js +96 -0
  136. package/dist/src/server/routes/sessions.js +244 -0
  137. package/dist/src/server/routes/timeline.js +14 -0
  138. package/dist/src/server/serve-static.js +42 -0
  139. package/dist/src/server/types.js +2 -0
  140. package/dist/src/services/agent-service.js +79 -0
  141. package/dist/src/services/artifact-service.js +74 -0
  142. package/dist/src/services/gateway-read-helpers.js +10 -0
  143. package/dist/src/services/index.js +23 -0
  144. package/dist/src/services/pipeline-service.js +529 -0
  145. package/dist/src/services/pipeline-status.js +93 -0
  146. package/dist/src/services/read-services.js +60 -0
  147. package/dist/src/services/scheduler-service.js +37 -0
  148. package/dist/src/services/session-service.js +227 -0
  149. package/dist/src/services/system-service.js +26 -0
  150. package/dist/src/transport/ws-broker.js +48 -0
  151. package/dist/src/utils/array.js +17 -0
  152. package/dist/src/utils/guards.js +5 -0
  153. package/dist/src/utils/session.js +60 -0
  154. package/dist/src/version.js +5 -0
  155. package/package.json +61 -0
  156. package/web/dist/assets/index-CWnfhkn-.js +65 -0
  157. package/web/dist/assets/index-gZ0xOfSO.css +1 -0
  158. package/web/dist/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
  159. package/web/dist/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
  160. package/web/dist/assets/jetbrains-mono-cyrillic-500-normal-DJqRU3vO.woff +0 -0
  161. package/web/dist/assets/jetbrains-mono-cyrillic-500-normal-DmUKJPL_.woff2 +0 -0
  162. package/web/dist/assets/jetbrains-mono-cyrillic-700-normal-BWTpRfYl.woff2 +0 -0
  163. package/web/dist/assets/jetbrains-mono-cyrillic-700-normal-CEoEElIJ.woff +0 -0
  164. package/web/dist/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
  165. package/web/dist/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
  166. package/web/dist/assets/jetbrains-mono-greek-500-normal-D7SFKleX.woff +0 -0
  167. package/web/dist/assets/jetbrains-mono-greek-500-normal-JpySY46c.woff2 +0 -0
  168. package/web/dist/assets/jetbrains-mono-greek-700-normal-C6CZE3T8.woff2 +0 -0
  169. package/web/dist/assets/jetbrains-mono-greek-700-normal-DEigVDxa.woff +0 -0
  170. package/web/dist/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
  171. package/web/dist/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
  172. package/web/dist/assets/jetbrains-mono-latin-500-normal-BWZEU5yA.woff2 +0 -0
  173. package/web/dist/assets/jetbrains-mono-latin-500-normal-CJOVTJB7.woff +0 -0
  174. package/web/dist/assets/jetbrains-mono-latin-700-normal-BYuf6tUa.woff2 +0 -0
  175. package/web/dist/assets/jetbrains-mono-latin-700-normal-D3wTyLJW.woff +0 -0
  176. package/web/dist/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
  177. package/web/dist/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
  178. package/web/dist/assets/jetbrains-mono-latin-ext-500-normal-Cut-4mMH.woff2 +0 -0
  179. package/web/dist/assets/jetbrains-mono-latin-ext-500-normal-ckzbgY84.woff +0 -0
  180. package/web/dist/assets/jetbrains-mono-latin-ext-700-normal-CZipNAKV.woff2 +0 -0
  181. package/web/dist/assets/jetbrains-mono-latin-ext-700-normal-CxPITLHs.woff +0 -0
  182. package/web/dist/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
  183. package/web/dist/assets/jetbrains-mono-vietnamese-500-normal-DNRqzVM1.woff +0 -0
  184. package/web/dist/assets/jetbrains-mono-vietnamese-700-normal-BDLVIk2r.woff +0 -0
  185. package/web/dist/assets/space-grotesk-latin-400-normal-BnQMeOim.woff +0 -0
  186. package/web/dist/assets/space-grotesk-latin-400-normal-CJ-V5oYT.woff2 +0 -0
  187. package/web/dist/assets/space-grotesk-latin-500-normal-CNSSEhBt.woff +0 -0
  188. package/web/dist/assets/space-grotesk-latin-500-normal-lFbtlQH6.woff2 +0 -0
  189. package/web/dist/assets/space-grotesk-latin-700-normal-CwsQ-cCU.woff +0 -0
  190. package/web/dist/assets/space-grotesk-latin-700-normal-RjhwGPKo.woff2 +0 -0
  191. package/web/dist/assets/space-grotesk-latin-ext-400-normal-CfP_5XZW.woff2 +0 -0
  192. package/web/dist/assets/space-grotesk-latin-ext-400-normal-DRPE3kg4.woff +0 -0
  193. package/web/dist/assets/space-grotesk-latin-ext-500-normal-3dgZTiw9.woff +0 -0
  194. package/web/dist/assets/space-grotesk-latin-ext-500-normal-DUe3BAxM.woff2 +0 -0
  195. package/web/dist/assets/space-grotesk-latin-ext-700-normal-BQnZhY3m.woff2 +0 -0
  196. package/web/dist/assets/space-grotesk-latin-ext-700-normal-HVCqSBdx.woff +0 -0
  197. package/web/dist/assets/space-grotesk-vietnamese-400-normal-B7xT_GF5.woff2 +0 -0
  198. package/web/dist/assets/space-grotesk-vietnamese-400-normal-BIWiOVfw.woff +0 -0
  199. package/web/dist/assets/space-grotesk-vietnamese-500-normal-BTqKIpxg.woff +0 -0
  200. package/web/dist/assets/space-grotesk-vietnamese-500-normal-BmEvtly_.woff2 +0 -0
  201. package/web/dist/assets/space-grotesk-vietnamese-700-normal-DMty7AZE.woff2 +0 -0
  202. package/web/dist/assets/space-grotesk-vietnamese-700-normal-Duxec5Rn.woff +0 -0
  203. package/web/dist/favicon.svg +10 -0
  204. package/web/dist/index.html +14 -0
package/LICENSE ADDED
@@ -0,0 +1,18 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 TaskMeld
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
6
+ associated documentation files (the "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
9
+ following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all copies or substantial
12
+ portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
15
+ LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
16
+ EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
18
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,172 @@
1
+ <p align="center">
2
+ <strong>English</strong>
3
+ &nbsp;·&nbsp;
4
+ <a href="./README.zh-CN.md">简体中文</a>
5
+ &nbsp;·&nbsp;
6
+ <a href="https://taskmeld.com">Website</a>
7
+ </p>
8
+
9
+ <p align="center">
10
+ <a href="./LICENSE"><img src="https://img.shields.io/npm/l/taskmeld.svg?style=flat-square&color=8b949e&labelColor=161b22" alt="license"/></a>
11
+ <a href="./package.json"><img src="https://img.shields.io/node/v/taskmeld.svg?style=flat-square&color=5fa04e&labelColor=161b22&logo=nodedotjs&logoColor=white" alt="node"/></a>
12
+ </p>
13
+
14
+ <br/>
15
+
16
+ <h3 align="center">Agent Pipeline Orchestration Platform</h3>
17
+ <p align="center">Compose OpenClaw agents into executable pipelines — define, run, observe, and iterate. File-based persistence, zero external database.</p>
18
+
19
+ <br/>
20
+
21
+ > [!TIP]
22
+ > TaskMeld is the pipeline runtime for OpenClaw. OpenClaw handles agent execution; TaskMeld chains agents into DAG workflows with routing, retries, and artifact tracking.
23
+
24
+ <br/>
25
+
26
+ ## Install
27
+
28
+ Requires Node ≥ 18. Works on macOS · Linux · Windows.
29
+
30
+ ~~~bash
31
+ npm install -g taskmeld
32
+ ~~~
33
+
34
+ <br/>
35
+
36
+ ## Quick Start
37
+
38
+ ~~~bash
39
+ # Initialize — guided setup for OpenClaw Gateway connection
40
+ taskmeld init
41
+
42
+ # Start the backend daemon
43
+ taskmeld server start
44
+
45
+ # List available pipelines
46
+ taskmeld pipeline list
47
+
48
+ # Run a pipeline
49
+ taskmeld pipeline start <pipelineId>
50
+
51
+ # Watch a pipeline run in real time
52
+ taskmeld pipeline watch <pipelineId>
53
+ ~~~
54
+
55
+ | Command | When |
56
+ |---|---|
57
+ | `taskmeld pipeline list` | See what pipelines are available |
58
+ | `taskmeld pipeline start <id>` | Kick off a pipeline run |
59
+ | `taskmeld pipeline watch <id>` | Follow a run live via WebSocket |
60
+ | `taskmeld pipeline status <id>` | One-shot status snapshot |
61
+ | `taskmeld pipeline stop <id>` | Stop a running pipeline |
62
+ | `taskmeld pipeline retry-node <id> <node>` | Retry a failed node |
63
+ | `taskmeld server start` | Start the backend daemon |
64
+ | `taskmeld agent list` | List registered agents |
65
+ | `taskmeld artifact list` | Browse pipeline artifacts |
66
+
67
+ Full command reference: `taskmeld --help` or [CLI docs](docs/cli.md).
68
+
69
+ <br/>
70
+
71
+ ## Features
72
+
73
+ - **DAG Pipeline Engine** — Node dependency graph, parallel groups, routing branches, per-node retry, state persistence
74
+ - **CLI Tool** — Full lifecycle: list, run, status, stop, retry, watch (WebSocket streaming)
75
+ - **HTTP + WebSocket API** — REST endpoints for control, WS broadcast for real-time observability
76
+ - **Web Console** — React 19 dashboard with DAG visualization, agent sessions, artifact browser, log viewer
77
+ - **Gateway Integration** — WebSocket client for OpenClaw Gateway auth, event relay, and agent session delegation
78
+ - **File-based Persistence** — All state stored as JSON and log files under `~/.taskmeld/` (`TASKMELD_DATA_DIR` can override it); zero external database
79
+
80
+ <br/>
81
+
82
+ ## Architecture
83
+
84
+ ```
85
+ CLI (taskmeld) · Web Console (React)
86
+ │ │
87
+ HTTP API ─────── WS Broker
88
+ │ │
89
+ App Assembly (registry + runtime)
90
+
91
+ Pipeline Engine (DAG · scheduler · state machine)
92
+
93
+ Gateway Client (OpenClaw — auth, events, sessions)
94
+ ```
95
+
96
+ | Directory | Purpose |
97
+ |-----------|---------|
98
+ | `src/cli/` | CLI entry, routing, output rendering |
99
+ | `src/pipeline/` | Pipeline engine (runtime, scheduler, execution, DAG) |
100
+ | `src/server/` | HTTP API server + route modules |
101
+ | `src/transport/` | WebSocket broadcast |
102
+ | `src/gateway/` | External Gateway WebSocket client |
103
+ | `src/services/` | Service layer (read/write facades) |
104
+ | `src/app/` | Application assembly (registry, runtime, context) |
105
+ | `src/artifacts/` | Artifact storage |
106
+ | `src/logs/` | Timeline log storage |
107
+ | `web/` | React management frontend |
108
+
109
+ <br/>
110
+
111
+ ## Development Status
112
+
113
+ > [!WARNING]
114
+ > TaskMeld is in its initial testing phase. Features are being built out incrementally, APIs may evolve between releases, and some surfaces are still rough. Production use is at your own discretion — we welcome early adopters and feedback.
115
+
116
+ <br/>
117
+
118
+ ## Roadmap
119
+
120
+ ### Now
121
+
122
+ - **Pipeline execution** — Node-driven: each node binds an OpenClaw agent. The CLI exposes a full command set that external agents can invoke programmatically (`pipeline list`, `pipeline start`, `pipeline status`, etc.).
123
+ - **Agent management** — Primarily read-only (chat, edit core files like `agent.md` / `memory.md` / `soul.md`). Creating agents and configuring skills still requires switching to OpenClaw directly.
124
+ - **Data storage** — File-based persistence (JSON + log files under `~/.taskmeld/` by default), zero external dependencies.
125
+
126
+ ### Next
127
+
128
+ - **Built-in autonomous agent** — A first-class runtime component that owns the full pipeline lifecycle: scheduling runs, creating and reviewing pipeline definitions, triaging failures, and curating artifacts. The goal is to move from *you operate the pipelines* to *the agent operates the pipelines, and you steer*.
129
+ - **Agent lifecycle management** — Agent creation, skill configuration, and core file editing unified within TaskMeld, driven by the built-in agent — no more switching to OpenClaw.
130
+ - **Database-backed storage** — Evolve from file-based persistence to a database storage layer, improving query performance, concurrent access, and scalability while keeping a zero-dependency path for single-node setups.
131
+
132
+ <br/>
133
+
134
+ ## Development
135
+
136
+ ```bash
137
+ npm install # Install dependencies
138
+ npm run build # Build
139
+ npm run typecheck # Type check only
140
+ npm run lint # Lint
141
+ npm test # Run tests
142
+ npm run dev:web # Start frontend dev server (Vite HMR)
143
+ ```
144
+
145
+ | Layer | Technology |
146
+ |-------|------------|
147
+ | Language | TypeScript (strict, CommonJS) |
148
+ | Runtime | Node.js |
149
+ | Backend HTTP | Node.js built-in `http` |
150
+ | WebSocket | `ws` |
151
+ | Frontend | React 19 + Vite 7 |
152
+ | CSS | Tailwind CSS 4 |
153
+ | Testing | Vitest |
154
+ | Linting | ESLint 9 |
155
+
156
+ <br/>
157
+
158
+ ## Documentation
159
+
160
+ - [CLI Reference](docs/cli.md)
161
+ - [Backend Architecture](docs/backend.md)
162
+ - [Frontend Architecture](docs/web.md)
163
+ - [Pipeline Engine](docs/pipeline/)
164
+ - [Contributing](CONTRIBUTING.md)
165
+
166
+ <br/>
167
+
168
+ ---
169
+
170
+ <p align="center">
171
+ <sub>MIT — see <a href="./LICENSE">LICENSE</a></sub>
172
+ </p>
@@ -0,0 +1,172 @@
1
+ <p align="center">
2
+ <a href="./README.md">English</a>
3
+ &nbsp;·&nbsp;
4
+ <strong>简体中文</strong>
5
+ &nbsp;·&nbsp;
6
+ <a href="https://taskmeld.com">Website</a>
7
+ </p>
8
+
9
+ <p align="center">
10
+ <a href="./LICENSE"><img src="https://img.shields.io/npm/l/taskmeld.svg?style=flat-square&color=8b949e&labelColor=161b22" alt="license"/></a>
11
+ <a href="./package.json"><img src="https://img.shields.io/node/v/taskmeld.svg?style=flat-square&color=5fa04e&labelColor=161b22&logo=nodedotjs&logoColor=white" alt="node"/></a>
12
+ </p>
13
+
14
+ <br/>
15
+
16
+ <h3 align="center">Agent 流水线编排平台</h3>
17
+ <p align="center">将 OpenClaw Agent 编排为可执行流水线——定义、运行、观察、迭代。文件持久化,零外部数据库。</p>
18
+
19
+ <br/>
20
+
21
+ > [!TIP]
22
+ > TaskMeld 是 OpenClaw 的流水线运行时。OpenClaw 负责 Agent 执行,TaskMeld 负责将 Agent 串成 DAG 工作流,含路由分流、重试和产物追踪。
23
+
24
+ <br/>
25
+
26
+ ## 安装
27
+
28
+ 需要 Node ≥ 18。支持 macOS · Linux · Windows。
29
+
30
+ ~~~bash
31
+ npm install -g taskmeld
32
+ ~~~
33
+
34
+ <br/>
35
+
36
+ ## 快速开始
37
+
38
+ ~~~bash
39
+ # 初始化 — 引导式配置 OpenClaw Gateway 连接
40
+ taskmeld init
41
+
42
+ # 启动后端守护进程
43
+ taskmeld server start
44
+
45
+ # 查看可用流水线
46
+ taskmeld pipeline list
47
+
48
+ # 运行一条流水线
49
+ taskmeld pipeline start <pipelineId>
50
+
51
+ # 实时监听流水线运行
52
+ taskmeld pipeline watch <pipelineId>
53
+ ~~~
54
+
55
+ | 命令 | 场景 |
56
+ |---|---|
57
+ | `taskmeld pipeline list` | 查看有哪些流水线 |
58
+ | `taskmeld pipeline start <id>` | 启动一条流水线 |
59
+ | `taskmeld pipeline watch <id>` | 通过 WebSocket 实时跟踪运行 |
60
+ | `taskmeld pipeline status <id>` | 一次性状态快照 |
61
+ | `taskmeld pipeline stop <id>` | 停止运行中的流水线 |
62
+ | `taskmeld pipeline retry-node <id> <node>` | 重试失败的节点 |
63
+ | `taskmeld server start` | 启动后端守护进程 |
64
+ | `taskmeld agent list` | 列出已注册的 Agent |
65
+ | `taskmeld artifact list` | 浏览流水线产物 |
66
+
67
+ 完整命令参考:`taskmeld --help` 或 [CLI 文档](docs/cli.md)。
68
+
69
+ <br/>
70
+
71
+ ## 特性
72
+
73
+ - **DAG 流水线引擎** — 节点依赖图、并行组、路由分支、节点级重试、状态持久化
74
+ - **CLI 工具** — 全生命周期管理:list, run, status, stop, retry, watch(WebSocket 流式监听)
75
+ - **HTTP + WebSocket API** — REST 端点用于控制面,WS 广播用于实时可观测性
76
+ - **Web 控制台** — React 19 仪表盘,含 DAG 可视化、Agent 会话、产物浏览器、日志查看器
77
+ - **Gateway 集成** — WebSocket 客户端,对接 OpenClaw Gateway 鉴权、事件中继与 Agent 会话委托
78
+ - **文件持久化** — 所有状态以 JSON 和日志文件默认存储在 `~/.taskmeld/` 下,可用 `TASKMELD_DATA_DIR` 覆盖,无需外部数据库
79
+
80
+ <br/>
81
+
82
+ ## 架构
83
+
84
+ ```
85
+ CLI (taskmeld) · Web 控制台 (React)
86
+ │ │
87
+ HTTP API ─────── WS Broker
88
+ │ │
89
+ App Assembly (注册表 + 运行时)
90
+
91
+ Pipeline Engine (DAG · 调度器 · 状态机)
92
+
93
+ Gateway Client (OpenClaw — 鉴权、事件、会话)
94
+ ```
95
+
96
+ | 目录 | 说明 |
97
+ |------|------|
98
+ | `src/cli/` | CLI 入口、路由、输出渲染 |
99
+ | `src/pipeline/` | 流水线引擎(运行时、调度器、执行、DAG) |
100
+ | `src/server/` | HTTP API 服务 + 路由模块 |
101
+ | `src/transport/` | WebSocket 广播 |
102
+ | `src/gateway/` | 外部 Gateway WebSocket 客户端 |
103
+ | `src/services/` | 服务层(读写 facade) |
104
+ | `src/app/` | 应用装配(注册表、运行时、上下文) |
105
+ | `src/artifacts/` | 产物存储 |
106
+ | `src/logs/` | 时间线日志 |
107
+ | `web/` | React 管理前端 |
108
+
109
+ <br/>
110
+
111
+ ## 开发状态
112
+
113
+ > [!WARNING]
114
+ > TaskMeld 当前处于初始测试阶段。功能正在逐步构建,API 可能在版本之间变化,部分界面仍较为粗糙。生产环境使用请自行评估——欢迎早期用户试用和反馈。
115
+
116
+ <br/>
117
+
118
+ ## 后续规划
119
+
120
+ ### 现状
121
+
122
+ - **流水线执行** — 节点驱动模式,每个节点绑定一个 OpenClaw Agent。CLI 已暴露完整命令集,外部 Agent 可通过编程方式调用(`pipeline list`、`pipeline start`、`pipeline status` 等)。
123
+ - **Agent 管理** — 以只读操作为主(对话、编辑核心文件如 `agent.md` / `memory.md` / `soul.md`)。创建 Agent、配置 Skill 等操作仍需切换到 OpenClaw 中完成。
124
+ - **数据存储** — 基于文件持久化(默认 `~/.taskmeld/` 下的 JSON + 日志文件),零外部依赖。
125
+
126
+ ### 计划
127
+
128
+ - **内置自主 Agent** — 作为一等运行时组件,全权负责流水线的完整生命周期:调度运行、创建与审查流水线定义、故障分类、产物整理。目标是从*你来操作流水线*过渡到*Agent 操作流水线,你来指挥*。
129
+ - **Agent 生命周期管理** — 创建 Agent、配置 Skill、编辑核心文件等操作统一收敛到 TaskMeld 内,由内置 Agent 驱动,不再需要切换到 OpenClaw。
130
+ - **数据库存储层** — 从文件持久化演进为数据库存储,提升查询性能、并发访问和可扩展性,同时保留单节点零依赖的轻量体验。
131
+
132
+ <br/>
133
+
134
+ ## 开发
135
+
136
+ ```bash
137
+ npm install # 安装依赖
138
+ npm run build # 构建
139
+ npm run typecheck # 仅类型检查
140
+ npm run lint # 代码检查
141
+ npm test # 运行测试
142
+ npm run dev:web # 启动前端开发服务器(Vite HMR)
143
+ ```
144
+
145
+ | 层面 | 技术 |
146
+ |------|------|
147
+ | 语言 | TypeScript(strict, CommonJS) |
148
+ | 运行时 | Node.js |
149
+ | 后端 HTTP | Node.js 内置 `http` |
150
+ | WebSocket | `ws` |
151
+ | 前端 | React 19 + Vite 7 |
152
+ | CSS | Tailwind CSS 4 |
153
+ | 测试 | Vitest |
154
+ | Lint | ESLint 9 |
155
+
156
+ <br/>
157
+
158
+ ## 文档
159
+
160
+ - [CLI 参考](docs/cli.md)
161
+ - [后端架构](docs/backend.md)
162
+ - [前端架构](docs/web.md)
163
+ - [流水线引擎](docs/pipeline/)
164
+ - [参与贡献](CONTRIBUTING.md)
165
+
166
+ <br/>
167
+
168
+ ---
169
+
170
+ <p align="center">
171
+ <sub>MIT — 详见 <a href="./LICENSE">LICENSE</a></sub>
172
+ </p>
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveAppContextConfig = exports.DEFAULT_ITEM_KEYS = exports.DEFAULT_GATEWAY_SCOPES = exports.DEFAULT_WEB_ORIGIN = exports.DEFAULT_API_HOST = exports.DEFAULT_API_PORT = void 0;
4
+ exports.DEFAULT_API_PORT = 3100;
5
+ exports.DEFAULT_API_HOST = "0.0.0.0";
6
+ exports.DEFAULT_WEB_ORIGIN = "*";
7
+ exports.DEFAULT_GATEWAY_SCOPES = ["operator.read", "operator.write", "operator.admin"];
8
+ exports.DEFAULT_ITEM_KEYS = ["global"];
9
+ const parseCsvUnique = (raw) => {
10
+ const seen = new Set();
11
+ const out = [];
12
+ for (const item of raw.split(",")) {
13
+ const normalized = item.trim();
14
+ if (!normalized || seen.has(normalized))
15
+ continue;
16
+ seen.add(normalized);
17
+ out.push(normalized);
18
+ }
19
+ return out;
20
+ };
21
+ const resolveGatewayScopes = (options) => {
22
+ if (options.gatewayScopes && options.gatewayScopes.length > 0) {
23
+ return [...new Set(options.gatewayScopes.map((scope) => scope.trim()).filter(Boolean))];
24
+ }
25
+ const env = options.env ?? process.env;
26
+ const parsed = parseCsvUnique(String(env.OPENCLAW_GATEWAY_SCOPES ?? ""));
27
+ return parsed.length > 0 ? parsed : exports.DEFAULT_GATEWAY_SCOPES;
28
+ };
29
+ const resolveDefaultItemKeys = (options) => {
30
+ if (options.defaultItemKeys && options.defaultItemKeys.length > 0) {
31
+ return [...new Set(options.defaultItemKeys.map((item) => item.trim()).filter(Boolean))];
32
+ }
33
+ const env = options.env ?? process.env;
34
+ const parsed = parseCsvUnique(String(env.OPENCLAW_PIPELINE_ITEMS ?? ""));
35
+ return parsed.length > 0 ? parsed : exports.DEFAULT_ITEM_KEYS;
36
+ };
37
+ const resolveAppContextConfig = (options = {}) => {
38
+ const env = options.env ?? process.env;
39
+ const apiPortRaw = options.apiPort ?? Number(env.API_PORT ?? exports.DEFAULT_API_PORT);
40
+ const apiPort = Number.isFinite(apiPortRaw) && apiPortRaw > 0 ? Math.trunc(apiPortRaw) : exports.DEFAULT_API_PORT;
41
+ const apiHost = options.apiHost?.trim() || env.API_HOST?.trim() || exports.DEFAULT_API_HOST;
42
+ const webOrigin = options.webOrigin?.trim() || env.WEB_ORIGIN?.trim() || exports.DEFAULT_WEB_ORIGIN;
43
+ return {
44
+ apiPort,
45
+ apiHost,
46
+ webOrigin,
47
+ defaultItemKeys: resolveDefaultItemKeys(options),
48
+ gatewayScopes: resolveGatewayScopes(options),
49
+ };
50
+ };
51
+ exports.resolveAppContextConfig = resolveAppContextConfig;
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createAppContext = void 0;
4
+ const gateway_1 = require("../gateway");
5
+ const pipeline_registry_1 = require("./pipeline-registry");
6
+ const app_context_env_1 = require("./app-context-env");
7
+ const services_1 = require("../services");
8
+ const normalizeRequiredEnvString = (value, key) => {
9
+ const normalized = String(value ?? "").trim();
10
+ if (!normalized) {
11
+ throw new Error(`missing_required_env:${key}`);
12
+ }
13
+ return normalized;
14
+ };
15
+ const normalizeOptionalEnvString = (value) => {
16
+ const normalized = String(value ?? "").trim();
17
+ return normalized ? normalized : null;
18
+ };
19
+ const resolveGatewayCredentials = (options, env) => ({
20
+ url: normalizeRequiredEnvString(options.gatewayUrl ?? env.OPENCLAW_GATEWAY_URL, "OPENCLAW_GATEWAY_URL"),
21
+ token: normalizeRequiredEnvString(options.gatewayToken ?? env.OPENCLAW_GATEWAY_TOKEN, "OPENCLAW_GATEWAY_TOKEN"),
22
+ });
23
+ const createAppContext = (options = {}) => {
24
+ const env = options.env ?? process.env;
25
+ const config = (0, app_context_env_1.resolveAppContextConfig)({ ...options, env });
26
+ const gatewayUrl = normalizeOptionalEnvString(options.gatewayUrl ?? env.OPENCLAW_GATEWAY_URL);
27
+ const gatewayToken = normalizeOptionalEnvString(options.gatewayToken ?? env.OPENCLAW_GATEWAY_TOKEN);
28
+ const gatewayHandlers = {
29
+ onStatus: options.onGatewayStatus ?? (() => { }),
30
+ onFrame: options.onGatewayFrame ?? (() => { }),
31
+ onError: options.onGatewayError ?? (() => { }),
32
+ };
33
+ let appRef = null;
34
+ let clientRef = null;
35
+ const ensureGatewayClient = () => {
36
+ if (clientRef)
37
+ return clientRef;
38
+ // dev/server 进程允许先在“网关未配置/未就绪”状态下启动 HTTP/WS,
39
+ // 真正触发 connect/sendReq 时再校验凭据,才能兼容本地调试与需要网关的命令两类路径。
40
+ const credentials = resolveGatewayCredentials(options, env);
41
+ clientRef = (0, gateway_1.createGatewayClient)({
42
+ gatewayUrl: credentials.url,
43
+ token: credentials.token,
44
+ scopes: config.gatewayScopes,
45
+ onStatus: (status) => {
46
+ gatewayHandlers.onStatus(status);
47
+ appRef?.onGatewayStatus(status);
48
+ },
49
+ onFrame: (frame) => {
50
+ gatewayHandlers.onFrame(frame);
51
+ appRef?.onGatewayFrame(frame);
52
+ },
53
+ onRawFrame: (rawFrame) => {
54
+ appRef?.onGatewayRawFrame(rawFrame);
55
+ },
56
+ onError: (error) => {
57
+ gatewayHandlers.onError(error);
58
+ appRef?.onGatewayError(error);
59
+ },
60
+ });
61
+ return clientRef;
62
+ };
63
+ const client = {
64
+ connect: () => ensureGatewayClient().connect(),
65
+ close: () => {
66
+ clientRef?.close();
67
+ },
68
+ sendReq: (method, params, opts) => ensureGatewayClient().sendReq(method, params, opts),
69
+ onEvent: (handler) => ensureGatewayClient().onEvent(handler),
70
+ getStatus: () => clientRef?.getStatus() ?? {
71
+ status: "idle",
72
+ lastError: null,
73
+ lastHelloAt: null,
74
+ protocol: null,
75
+ scopes: [...config.gatewayScopes],
76
+ },
77
+ getSocket: () => clientRef?.getSocket() ?? null,
78
+ };
79
+ const app = (0, pipeline_registry_1.createPipelineRegistry)({
80
+ client,
81
+ webOrigin: config.webOrigin,
82
+ defaultItemKeys: config.defaultItemKeys,
83
+ });
84
+ appRef = app;
85
+ const appServices = (0, services_1.createAppServices)(app);
86
+ // 网关握手成功后需要把 hello 回灌到 registry,保证运行态上下文完整。
87
+ const connect = async () => {
88
+ const hello = await client.connect();
89
+ app.onGatewayReady(hello);
90
+ return hello;
91
+ };
92
+ return {
93
+ config,
94
+ app,
95
+ services: {
96
+ readonly: appServices.readonly,
97
+ writable: appServices.writable,
98
+ },
99
+ api: {
100
+ port: config.apiPort,
101
+ host: config.apiHost,
102
+ webOrigin: config.webOrigin,
103
+ },
104
+ gateway: {
105
+ url: gatewayUrl,
106
+ token: gatewayToken,
107
+ scopes: config.gatewayScopes,
108
+ client,
109
+ setHandlers: (next) => {
110
+ if (next.onStatus)
111
+ gatewayHandlers.onStatus = next.onStatus;
112
+ if (next.onFrame)
113
+ gatewayHandlers.onFrame = next.onFrame;
114
+ if (next.onError)
115
+ gatewayHandlers.onError = next.onError;
116
+ },
117
+ getHandlers: () => ({ ...gatewayHandlers }),
118
+ connect,
119
+ },
120
+ initialize: () => app.initialize(),
121
+ dispose: () => {
122
+ client.close();
123
+ app.dispose();
124
+ },
125
+ };
126
+ };
127
+ exports.createAppContext = createAppContext;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveTaskMeldDataPath = exports.getTaskMeldDataDir = exports.isTaskMeldTestRuntime = void 0;
4
+ const node_os_1 = require("node:os");
5
+ const node_path_1 = require("node:path");
6
+ const TEST_ARG_PATTERN = /(^|[\\/])(test|dist[\\/]test)[\\/]/;
7
+ const isTaskMeldTestRuntime = (options = {}) => {
8
+ const env = options.env ?? process.env;
9
+ const argv = options.argv ?? process.argv;
10
+ if (env.TASKMELD_TEST_MODE === "1" || env.NODE_ENV === "test") {
11
+ return true;
12
+ }
13
+ return argv.some((arg) => TEST_ARG_PATTERN.test(arg));
14
+ };
15
+ exports.isTaskMeldTestRuntime = isTaskMeldTestRuntime;
16
+ const getTaskMeldDataDir = (options = {}) => {
17
+ const env = options.env ?? process.env;
18
+ const override = env.TASKMELD_DATA_DIR?.trim();
19
+ if (override)
20
+ return override;
21
+ // 测试用例默认隔离到当前仓库,避免污染用户真实的 ~/.taskmeld 数据。
22
+ if ((0, exports.isTaskMeldTestRuntime)({ env, argv: options.argv })) {
23
+ return (0, node_path_1.join)(options.cwd ?? process.cwd(), ".data");
24
+ }
25
+ return (0, node_path_1.join)(options.homeDir ?? (0, node_os_1.homedir)(), ".taskmeld");
26
+ };
27
+ exports.getTaskMeldDataDir = getTaskMeldDataDir;
28
+ const resolveTaskMeldDataPath = (...segments) => (0, node_path_1.join)((0, exports.getTaskMeldDataDir)(), ...segments);
29
+ exports.resolveTaskMeldDataPath = resolveTaskMeldDataPath;
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getDeletedPipelineRootDir = exports.getPipelineRootDir = exports.getPipelineDefinitionsFilePath = exports.getDefaultPipelineId = exports.loadPipelineDefinitionsDocument = exports.loadPipelineDefinitions = exports.ensurePipelineDefinitions = exports.savePipelineDefinitions = exports.isValidPipelineId = exports.createPipelineDefinition = exports.DEFAULT_REMOTE_BATCH_URL = void 0;
4
+ const node_fs_1 = require("node:fs");
5
+ const node_path_1 = require("node:path");
6
+ const data_dir_1 = require("./data-dir");
7
+ exports.DEFAULT_REMOTE_BATCH_URL = String(process.env.OPENCLAW_PIPELINE_POOL_URL ?? "").trim();
8
+ const PIPELINE_ROOT_DIR = (0, data_dir_1.resolveTaskMeldDataPath)("pipelines");
9
+ const PIPELINE_DEFINITIONS_FILE = (0, node_path_1.join)(PIPELINE_ROOT_DIR, "index.json");
10
+ const PIPELINE_DELETED_ROOT_DIR = (0, node_path_1.join)(PIPELINE_ROOT_DIR, "_deleted");
11
+ const DEFAULT_PIPELINE_IDS = ["A", "B"];
12
+ const DEFAULT_PIPELINE_ID_FALLBACK = "A";
13
+ const PIPELINE_ID_PATTERN = /^[A-Za-z0-9_-]+$/;
14
+ const createPipelineDefinition = (id, title) => {
15
+ const baseDir = (0, node_path_1.join)(PIPELINE_ROOT_DIR, id);
16
+ return {
17
+ id,
18
+ title: title?.trim() || `流水线 DAG-${id}`,
19
+ workflowFilePath: (0, node_path_1.join)(baseDir, "workflow.json"),
20
+ runStateFile: (0, node_path_1.join)(baseDir, "run-state.json"),
21
+ artifactDir: (0, node_path_1.join)(baseDir, "artifacts"),
22
+ };
23
+ };
24
+ exports.createPipelineDefinition = createPipelineDefinition;
25
+ const createDefaultDefinitionsDocument = () => ({
26
+ version: 1,
27
+ defaultPipelineId: DEFAULT_PIPELINE_ID_FALLBACK,
28
+ items: DEFAULT_PIPELINE_IDS.map((pipelineId) => ({
29
+ id: pipelineId,
30
+ title: `流水线 DAG-${pipelineId}`,
31
+ })),
32
+ });
33
+ const isValidPipelineId = (value) => typeof value === "string" && PIPELINE_ID_PATTERN.test(value.trim());
34
+ exports.isValidPipelineId = isValidPipelineId;
35
+ const normalizeDefinitionItems = (items) => {
36
+ if (!Array.isArray(items))
37
+ return [];
38
+ const deduped = new Map();
39
+ for (const item of items) {
40
+ if (!item || typeof item !== "object")
41
+ continue;
42
+ const record = item;
43
+ if (!(0, exports.isValidPipelineId)(record.id))
44
+ continue;
45
+ const id = record.id.trim();
46
+ const title = typeof record.title === "string" && record.title.trim() ? record.title.trim() : `流水线 DAG-${id}`;
47
+ deduped.set(id, { id, title });
48
+ }
49
+ return [...deduped.values()];
50
+ };
51
+ const normalizeDefinitionsDocument = (value) => {
52
+ const record = value && typeof value === "object" ? value : null;
53
+ const normalizedItems = normalizeDefinitionItems(record?.items);
54
+ const items = normalizedItems.length > 0 ? normalizedItems : createDefaultDefinitionsDocument().items;
55
+ const defaultPipelineId = typeof record?.defaultPipelineId === "string" && items.some((item) => item.id === record.defaultPipelineId)
56
+ ? record.defaultPipelineId
57
+ : items[0]?.id ?? DEFAULT_PIPELINE_ID_FALLBACK;
58
+ return {
59
+ version: 1,
60
+ defaultPipelineId,
61
+ items,
62
+ };
63
+ };
64
+ const readDefinitionsDocumentFromDisk = () => {
65
+ try {
66
+ if (!(0, node_fs_1.existsSync)(PIPELINE_DEFINITIONS_FILE))
67
+ return null;
68
+ const raw = (0, node_fs_1.readFileSync)(PIPELINE_DEFINITIONS_FILE, "utf8");
69
+ return normalizeDefinitionsDocument(JSON.parse(raw));
70
+ }
71
+ catch {
72
+ return null;
73
+ }
74
+ };
75
+ const savePipelineDefinitions = (document) => {
76
+ const normalizedDocument = normalizeDefinitionsDocument(document);
77
+ (0, node_fs_1.mkdirSync)(PIPELINE_ROOT_DIR, { recursive: true });
78
+ (0, node_fs_1.writeFileSync)(PIPELINE_DEFINITIONS_FILE, JSON.stringify(normalizedDocument, null, 2), "utf8");
79
+ return normalizedDocument;
80
+ };
81
+ exports.savePipelineDefinitions = savePipelineDefinitions;
82
+ const ensurePipelineDefinitions = () => {
83
+ const fromDisk = readDefinitionsDocumentFromDisk();
84
+ if (fromDisk) {
85
+ // 每次启动都按当前约束回写一遍,避免 defaultPipelineId 指向失效项或 title 为空。
86
+ return (0, exports.savePipelineDefinitions)(fromDisk);
87
+ }
88
+ return (0, exports.savePipelineDefinitions)(createDefaultDefinitionsDocument());
89
+ };
90
+ exports.ensurePipelineDefinitions = ensurePipelineDefinitions;
91
+ const loadPipelineDefinitions = () => {
92
+ const document = (0, exports.ensurePipelineDefinitions)();
93
+ return document.items.map((item) => (0, exports.createPipelineDefinition)(item.id, item.title));
94
+ };
95
+ exports.loadPipelineDefinitions = loadPipelineDefinitions;
96
+ const loadPipelineDefinitionsDocument = () => (0, exports.ensurePipelineDefinitions)();
97
+ exports.loadPipelineDefinitionsDocument = loadPipelineDefinitionsDocument;
98
+ const getDefaultPipelineId = () => (0, exports.ensurePipelineDefinitions)().defaultPipelineId;
99
+ exports.getDefaultPipelineId = getDefaultPipelineId;
100
+ const getPipelineDefinitionsFilePath = () => PIPELINE_DEFINITIONS_FILE;
101
+ exports.getPipelineDefinitionsFilePath = getPipelineDefinitionsFilePath;
102
+ const getPipelineRootDir = () => PIPELINE_ROOT_DIR;
103
+ exports.getPipelineRootDir = getPipelineRootDir;
104
+ const getDeletedPipelineRootDir = () => PIPELINE_DELETED_ROOT_DIR;
105
+ exports.getDeletedPipelineRootDir = getDeletedPipelineRootDir;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });