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
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.agentRoutes = exports.agentSendCommand = exports.agentSessionCommand = exports.agentListCommand = void 0;
4
+ const errors_1 = require("../errors");
5
+ const readFlagAsPositiveInteger = (value, fallback) => {
6
+ if (typeof value !== "string")
7
+ return fallback;
8
+ const parsed = Number.parseInt(value.trim(), 10);
9
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
10
+ };
11
+ const agentListCommand = async (_input, ctx) => {
12
+ return ctx.app.agentService.listAgents();
13
+ };
14
+ exports.agentListCommand = agentListCommand;
15
+ const parseSessionId = (id) => {
16
+ const parts = id.split(":");
17
+ if (parts.length >= 3 && parts[0] === "agent") {
18
+ return { agentId: parts[1], sessionId: parts.slice(2).join(":") };
19
+ }
20
+ return { agentId: null, sessionId: id };
21
+ };
22
+ const agentSessionCommand = async (input, ctx) => {
23
+ const agentId = input.args[0];
24
+ const sessions = agentId
25
+ ? await ctx.app.agentService.filterSessionsByAgent(agentId)
26
+ : await ctx.app.agentService.listSessions();
27
+ const items = Array.isArray(sessions) ? sessions : [];
28
+ return items.map((s) => {
29
+ const rawId = typeof s.id === "string" ? s.id : "";
30
+ const parsed = parseSessionId(rawId);
31
+ return {
32
+ agentId: parsed.agentId,
33
+ sessionId: parsed.sessionId,
34
+ raw: s,
35
+ };
36
+ });
37
+ };
38
+ exports.agentSessionCommand = agentSessionCommand;
39
+ const readPipedStdin = async (stdin) => {
40
+ if (!stdin || stdin.isTTY)
41
+ return "";
42
+ return new Promise((resolve, reject) => {
43
+ let content = "";
44
+ stdin.setEncoding?.("utf8");
45
+ stdin.on("data", (chunk) => {
46
+ content += typeof chunk === "string" ? chunk : chunk.toString("utf8");
47
+ });
48
+ stdin.on("end", () => resolve(content.trim()));
49
+ stdin.on("error", reject);
50
+ });
51
+ };
52
+ const agentSendCommand = async (input, ctx) => {
53
+ const agentId = (0, errors_1.assertRequiredArg)(input.args[0], "agentId");
54
+ const messageFromArgs = (input.args[1] ?? "").trim().replace(/\\n/g, "\n");
55
+ const messageFromStdin = !messageFromArgs ? await readPipedStdin(input.stdin) : "";
56
+ const message = messageFromArgs || messageFromStdin;
57
+ if (!message) {
58
+ throw new errors_1.CliError("Missing message: provide a positional argument or pipe via stdin", {
59
+ code: "INVALID_ARGUMENT",
60
+ exitCode: 2,
61
+ });
62
+ }
63
+ const sessionId = typeof input.flags.session === "string" && input.flags.session.trim()
64
+ ? input.flags.session.trim()
65
+ : "main";
66
+ const fullSessionId = `agent:${sessionId}:${agentId}`;
67
+ const timeoutMs = readFlagAsPositiveInteger(input.flags.timeout, 120_000);
68
+ const streamVal = input.flags.stream;
69
+ const isStreaming = streamVal === true || (typeof streamVal === "string" && streamVal === "true");
70
+ if (isStreaming && ctx.global.format !== "json") {
71
+ const result = await ctx.app.agentService.sendMessageAndWaitForReply({ sessionId: fullSessionId, message }, {
72
+ timeoutMs,
73
+ onChunk: (text) => {
74
+ process.stdout.write(text);
75
+ },
76
+ });
77
+ process.stdout.write("\n");
78
+ return { ...result, streamed: true };
79
+ }
80
+ return ctx.app.agentService.sendMessageAndWaitForReply({ sessionId: fullSessionId, message }, { timeoutMs });
81
+ };
82
+ exports.agentSendCommand = agentSendCommand;
83
+ exports.agentRoutes = [
84
+ {
85
+ key: "agent.list",
86
+ path: ["agent", "list"],
87
+ description: "输出智能体列表",
88
+ handler: exports.agentListCommand,
89
+ bootstrap: { gateway: "required" },
90
+ help: {
91
+ usage: "taskmeld agent list [--format <json|md>]",
92
+ summary: "输出智能体列表",
93
+ },
94
+ },
95
+ {
96
+ key: "agent.session",
97
+ path: ["agent", "session"],
98
+ description: "输出会话列表(全部或按 agent 过滤)",
99
+ handler: exports.agentSessionCommand,
100
+ bootstrap: { gateway: "required" },
101
+ help: {
102
+ usage: "taskmeld agent session [agentId] [--format <json|md>]",
103
+ summary: "输出会话列表(全部或按 agent 过滤)",
104
+ args: [{ name: "agentId", required: false, description: "按 Agent ID 过滤会话" }],
105
+ },
106
+ },
107
+ {
108
+ key: "agent.send",
109
+ path: ["agent", "send"],
110
+ description: "向指定 agent 会话发送消息",
111
+ handler: exports.agentSendCommand,
112
+ bootstrap: { gateway: "required" },
113
+ help: {
114
+ usage: "taskmeld agent send <agentId> <message> [--session <id>] [--format <json|md>]",
115
+ summary: "向指定 agent 会话发送消息并等待回复",
116
+ args: [
117
+ { name: "agentId", required: true, description: "Agent ID" },
118
+ { name: "message", required: true, description: "消息内容" },
119
+ ],
120
+ options: [
121
+ { flags: ["--session"], valueName: "id", description: "会话 ID(默认 main)" },
122
+ { flags: ["--stream"], description: "流式输出回复内容" },
123
+ ],
124
+ },
125
+ },
126
+ ];
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.artifactRoutes = exports.artifactIndexCommand = exports.artifactCleanupCommand = exports.artifactExportCommand = exports.artifactShowCommand = exports.artifactListCommand = void 0;
4
+ const errors_1 = require("../errors");
5
+ const pickOptionalString = (value) => {
6
+ if (typeof value !== "string")
7
+ return undefined;
8
+ const trimmed = value.trim();
9
+ return trimmed ? trimmed : undefined;
10
+ };
11
+ const pickCsvStrings = (value) => {
12
+ if (typeof value !== "string")
13
+ return undefined;
14
+ const values = value.split(",").map((item) => item.trim()).filter(Boolean);
15
+ return values.length ? values : undefined;
16
+ };
17
+ const pickPositiveInteger = (value, flagName) => {
18
+ if (value === undefined)
19
+ return undefined;
20
+ if (value === true) {
21
+ throw new errors_1.CliError(`Invalid flag: --${flagName} requires a positive integer`, {
22
+ code: "INVALID_ARGUMENT",
23
+ exitCode: 2,
24
+ });
25
+ }
26
+ const parsed = Number(value);
27
+ if (!Number.isInteger(parsed) || parsed <= 0) {
28
+ throw new errors_1.CliError(`Invalid flag: --${flagName} must be a positive integer`, {
29
+ code: "INVALID_ARGUMENT",
30
+ exitCode: 2,
31
+ });
32
+ }
33
+ return parsed;
34
+ };
35
+ const artifactListCommand = async (input, ctx) => {
36
+ return ctx.app.artifactService.listArtifacts({
37
+ pipelineId: pickOptionalString(input.flags.pipeline),
38
+ nodeId: pickOptionalString(input.flags.node),
39
+ status: pickOptionalString(input.flags.status),
40
+ kind: pickOptionalString(input.flags.kind),
41
+ batchRunId: pickOptionalString(input.flags.batch),
42
+ runId: pickOptionalString(input.flags.run),
43
+ cursor: pickOptionalString(input.flags.cursor),
44
+ });
45
+ };
46
+ exports.artifactListCommand = artifactListCommand;
47
+ const artifactShowCommand = async (input, ctx) => {
48
+ const pipelineId = (0, errors_1.assertRequiredArg)(input.args[0], "pipelineId");
49
+ const relativePath = (0, errors_1.assertRequiredArg)(input.args[1], "relativePath");
50
+ return ctx.app.artifactService.getArtifactContent({ pipelineId, relativePath });
51
+ };
52
+ exports.artifactShowCommand = artifactShowCommand;
53
+ const artifactExportCommand = async (input, ctx) => {
54
+ return ctx.app.artifactService.exportArtifacts({
55
+ pipelineId: pickOptionalString(input.flags.pipeline),
56
+ nodeId: pickOptionalString(input.flags.node),
57
+ status: pickOptionalString(input.flags.status),
58
+ kind: pickOptionalString(input.flags.kind),
59
+ batchRunId: pickOptionalString(input.flags.batch),
60
+ dateFrom: pickOptionalString(input.flags.from),
61
+ dateTo: pickOptionalString(input.flags.to),
62
+ limit: pickPositiveInteger(input.flags.limit, "limit"),
63
+ });
64
+ };
65
+ exports.artifactExportCommand = artifactExportCommand;
66
+ const artifactCleanupCommand = async (input, ctx) => {
67
+ const pipelineId = (0, errors_1.assertRequiredArg)(input.args[0], "pipelineId");
68
+ const plan = await ctx.app.artifactService.planCleanup(pipelineId, {
69
+ olderThanDays: pickPositiveInteger(input.flags["older-than"], "older-than"),
70
+ statuses: pickCsvStrings(input.flags.status),
71
+ });
72
+ const planObj = plan;
73
+ if (input.flags.confirm !== true) {
74
+ return { ...planObj, dryRun: true, message: "dry-run 模式,候选文件不会删除。传入 --confirm 执行真实删除。" };
75
+ }
76
+ const result = await ctx.app.artifactService.executeCleanup(pipelineId, plan);
77
+ return { ...planObj, dryRun: false, ...result };
78
+ };
79
+ exports.artifactCleanupCommand = artifactCleanupCommand;
80
+ const artifactIndexCommand = async (input, ctx) => {
81
+ const action = (0, errors_1.assertRequiredArg)(input.args[0], "action");
82
+ if (action !== "rebuild") {
83
+ throw new errors_1.CliError(`Unknown artifact index action: ${action}`, {
84
+ code: "UNKNOWN_COMMAND",
85
+ exitCode: 2,
86
+ details: { action },
87
+ });
88
+ }
89
+ return ctx.app.artifactService.rebuildIndex(pickOptionalString(input.flags.pipeline));
90
+ };
91
+ exports.artifactIndexCommand = artifactIndexCommand;
92
+ exports.artifactRoutes = [
93
+ {
94
+ key: "artifact.index",
95
+ path: ["artifact", "index"],
96
+ description: "重建产物索引",
97
+ handler: exports.artifactIndexCommand,
98
+ help: {
99
+ usage: "taskmeld artifact index rebuild [--pipeline <id>] [--format <json|md>]",
100
+ args: [{ name: "rebuild", required: true, description: "重建 index.jsonl" }],
101
+ options: [{ flags: ["--pipeline"], valueName: "id", description: "只重建指定流水线" }],
102
+ summary: "扫描产物目录并重建 index.jsonl,用于升级后纳入历史文件或修复索引不一致",
103
+ },
104
+ },
105
+ {
106
+ key: "artifact.list",
107
+ path: ["artifact", "list"],
108
+ description: "输出产物列表",
109
+ handler: exports.artifactListCommand,
110
+ help: {
111
+ usage: "taskmeld artifact list [--pipeline <id>] [--node <id>] [--status <status>] [--kind <kind>] [--batch <id>] [--run <id>] [--cursor <cursor>] [--format <json|md>]",
112
+ options: [
113
+ { flags: ["--pipeline"], valueName: "id", description: "按流水线过滤" },
114
+ { flags: ["--node"], valueName: "id", description: "按节点过滤" },
115
+ { flags: ["--status"], valueName: "status", description: "success,failed,rejected" },
116
+ { flags: ["--kind"], valueName: "kind", description: "artifact,envelope,adapter,group" },
117
+ { flags: ["--batch"], valueName: "id", description: "按批跑ID过滤" },
118
+ { flags: ["--run"], valueName: "id", description: "按运行RunId过滤" },
119
+ { flags: ["--cursor"], valueName: "cursor", description: "分页游标" },
120
+ ],
121
+ summary: "输出产物列表,支持状态/类型/批跑/游标分页",
122
+ },
123
+ },
124
+ {
125
+ key: "artifact.show",
126
+ path: ["artifact", "show"],
127
+ description: "输出产物内容",
128
+ handler: exports.artifactShowCommand,
129
+ help: {
130
+ usage: "taskmeld artifact show <pipelineId> <relativePath> [--format <json|md>]",
131
+ args: [
132
+ { name: "pipelineId", required: true, description: "流水线 ID" },
133
+ { name: "relativePath", required: true, description: "产物相对路径" },
134
+ ],
135
+ summary: "输出指定产物的文件内容",
136
+ },
137
+ },
138
+ {
139
+ key: "artifact.export",
140
+ path: ["artifact", "export"],
141
+ description: "导出产物内容",
142
+ handler: exports.artifactExportCommand,
143
+ help: {
144
+ usage: "taskmeld artifact export [--pipeline <id>] [--from <date>] [--to <date>] [--format <json>]",
145
+ options: [
146
+ { flags: ["--pipeline"], valueName: "id", description: "按流水线过滤" },
147
+ { flags: ["--node"], valueName: "id", description: "按节点过滤" },
148
+ { flags: ["--status"], valueName: "status", description: "success,failed,rejected" },
149
+ { flags: ["--kind"], valueName: "kind", description: "artifact,envelope,adapter,group" },
150
+ { flags: ["--batch"], valueName: "id", description: "按批跑ID过滤" },
151
+ { flags: ["--from"], valueName: "date", description: "开始日期 YYYY-MM-DD" },
152
+ { flags: ["--to"], valueName: "date", description: "结束日期 YYYY-MM-DD" },
153
+ { flags: ["--limit"], valueName: "n", description: "最大导出条数,默认20000" },
154
+ ],
155
+ summary: "导出产物内容为 日期->流水线->节点 三层JSON",
156
+ },
157
+ },
158
+ {
159
+ key: "artifact.cleanup",
160
+ path: ["artifact", "cleanup"],
161
+ description: "清理旧产物",
162
+ handler: exports.artifactCleanupCommand,
163
+ help: {
164
+ usage: "taskmeld artifact cleanup <pipelineId> [--older-than <days>] [--status <status>] [--confirm]",
165
+ args: [{ name: "pipelineId", required: true, description: "流水线 ID" }],
166
+ options: [
167
+ { flags: ["--pipeline"], valueName: "id", description: "按流水线过滤" },
168
+ { flags: ["--older-than"], valueName: "days", description: "保留天数,默认 success=30/failed=90/rejected=90" },
169
+ { flags: ["--status"], valueName: "status", description: "success,failed,rejected" },
170
+ { flags: ["--confirm"], description: "必须显式传入才执行真实删除,否则 dry-run" },
171
+ ],
172
+ summary: "清理旧产物文件,默认 dry-run 只展示候选不删除,传 --confirm 执行真实删除并重建索引",
173
+ },
174
+ },
175
+ ];
@@ -0,0 +1,150 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.initRoutes = exports.initCommand = void 0;
4
+ const node_readline_1 = require("node:readline");
5
+ const node_os_1 = require("node:os");
6
+ const node_path_1 = require("node:path");
7
+ const promises_1 = require("node:fs/promises");
8
+ const userConfigDir = (0, node_path_1.join)((0, node_os_1.homedir)(), ".taskmeld");
9
+ const userConfigPath = (0, node_path_1.join)(userConfigDir, "config.json");
10
+ const c = {
11
+ reset: "\x1b[0m",
12
+ bold: "\x1b[1m",
13
+ dim: "\x1b[2m",
14
+ cyan: "\x1b[36m",
15
+ green: "\x1b[32m",
16
+ white: "\x1b[37m",
17
+ black: "\x1b[30m",
18
+ bgCyan: "\x1b[46m",
19
+ bgGreen: "\x1b[42m",
20
+ };
21
+ const hr = () => {
22
+ process.stdout.write(`\n ${c.dim}${"─".repeat(50)}${c.reset}\n\n`);
23
+ };
24
+ const fieldPrompt = (rl, label, hint, prefill) => {
25
+ return new Promise((resolve) => {
26
+ process.stdout.write(` ${c.bold}${c.white}${label}${c.reset}\n`);
27
+ process.stdout.write(` ${c.dim}${hint}${c.reset}\n\n`);
28
+ rl.question(` ${c.green}${c.bold}>${c.reset} `, (answer) => {
29
+ resolve(answer.trim());
30
+ });
31
+ if (prefill) {
32
+ rl.write(prefill);
33
+ }
34
+ });
35
+ };
36
+ const readConfig = async () => {
37
+ try {
38
+ const raw = await (0, promises_1.readFile)(userConfigPath, "utf8");
39
+ return JSON.parse(raw);
40
+ }
41
+ catch {
42
+ return {};
43
+ }
44
+ };
45
+ const writeConfig = async (config) => {
46
+ await (0, promises_1.mkdir)(userConfigDir, { recursive: true });
47
+ const existing = await readConfig();
48
+ const merged = { ...existing, ...config };
49
+ await (0, promises_1.writeFile)(userConfigPath, JSON.stringify(merged, null, 2) + "\n", "utf8");
50
+ };
51
+ const initCommand = async (input) => {
52
+ let url = typeof input.flags.url === "string" ? input.flags.url.trim() : "";
53
+ let token = typeof input.flags.token === "string" ? input.flags.token.trim() : "";
54
+ const interactive = !url || !token;
55
+ if (interactive) {
56
+ console.log("");
57
+ console.log(` ${c.bold}${c.cyan}TaskMeld${c.reset} ${c.dim}· First-time Setup${c.reset}`);
58
+ console.log("");
59
+ console.log(` ${c.dim}Configure your OpenClaw Gateway connection to get started.${c.reset}`);
60
+ console.log(` ${c.dim}Config ${userConfigPath}${c.reset}`);
61
+ const rl = (0, node_readline_1.createInterface)({
62
+ input: process.stdin,
63
+ output: process.stdout,
64
+ });
65
+ if (!url) {
66
+ hr();
67
+ url = await fieldPrompt(rl, "Gateway URL", "ws:// or wss:// address of your OpenClaw Gateway", "ws://127.0.0.1:18789") || "ws://127.0.0.1:18789";
68
+ }
69
+ if (url && !token) {
70
+ hr();
71
+ token = await fieldPrompt(rl, "Gateway Token", "Authentication token for the Gateway");
72
+ }
73
+ rl.close();
74
+ if (!url || !token) {
75
+ throw new Error("Both Gateway URL and Token are required to complete setup.");
76
+ }
77
+ }
78
+ if (!url.startsWith("ws://") && !url.startsWith("wss://")) {
79
+ throw new Error(`Invalid Gateway URL: ${url}. Must start with ws:// or wss://`);
80
+ }
81
+ await writeConfig({
82
+ gatewayUrl: url,
83
+ gatewayToken: token,
84
+ });
85
+ if (interactive) {
86
+ console.log("");
87
+ console.log(` ${c.bgGreen}${c.black}${c.bold} > Gateway configured successfully ${c.reset}`);
88
+ console.log("");
89
+ console.log(` ${c.dim}URL${c.reset} ${url}`);
90
+ console.log(` ${c.dim}Config${c.reset} ${userConfigPath}`);
91
+ console.log("");
92
+ console.log(` ${c.dim}Run ${c.white}\"taskmeld server start\"${c.reset}${c.dim} to begin.${c.reset}`);
93
+ console.log("");
94
+ }
95
+ return {
96
+ ok: true,
97
+ gatewayUrl: url,
98
+ configPath: userConfigPath,
99
+ interactive,
100
+ };
101
+ };
102
+ exports.initCommand = initCommand;
103
+ exports.initRoutes = [
104
+ {
105
+ key: "init",
106
+ path: ["init"],
107
+ description: "Guided setup for OpenClaw Gateway connection",
108
+ handler: exports.initCommand,
109
+ renderHelp: () => {
110
+ const lines = [
111
+ "Usage:",
112
+ " taskmeld init [--url <url>] [--token <token>]",
113
+ "",
114
+ "Description:",
115
+ " Guided first-time setup — configure the OpenClaw Gateway connection.",
116
+ ` Config is saved to ${userConfigPath}`,
117
+ "",
118
+ "Options:",
119
+ " --url <url> Gateway WebSocket URL (ws:// or wss://)",
120
+ " --token <token> Gateway authentication token",
121
+ "",
122
+ "Examples:",
123
+ " taskmeld init",
124
+ " taskmeld init --url ws://127.0.0.1:18789 --token your-token",
125
+ "",
126
+ "Notes:",
127
+ " Running without flags starts an interactive guided setup.",
128
+ " Environment variables (OPENCLAW_GATEWAY_URL/TOKEN) take precedence over this config.",
129
+ ];
130
+ return lines.join("\n");
131
+ },
132
+ help: {
133
+ usage: "taskmeld init [--url <url>] [--token <token>]",
134
+ summary: "Guided first-time setup — configure the OpenClaw Gateway connection.",
135
+ options: [
136
+ { flags: ["--url"], valueName: "url", description: "Gateway WebSocket URL (ws:// or wss://)" },
137
+ { flags: ["--token"], valueName: "token", description: "Gateway authentication token" },
138
+ ],
139
+ examples: [
140
+ "taskmeld init",
141
+ "taskmeld init --url ws://127.0.0.1:18789 --token your-token",
142
+ ],
143
+ notes: [
144
+ "Running without flags starts an interactive guided setup.",
145
+ "Config is saved to ~/.taskmeld/config.json.",
146
+ "Environment variables (OPENCLAW_GATEWAY_URL/TOKEN) take precedence over this config.",
147
+ ],
148
+ },
149
+ },
150
+ ];
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.throwSelectorScopedError = void 0;
4
+ const errors_1 = require("../../errors");
5
+ const selector_1 = require("./selector");
6
+ const throwSelectorScopedError = (result, selector) => {
7
+ if (result.error === "pipeline_not_found" && selector.pipelineId) {
8
+ throw new errors_1.CliError(`Pipeline not found: ${selector.pipelineId}`, {
9
+ code: "PIPELINE_NOT_FOUND",
10
+ exitCode: 3,
11
+ details: selector,
12
+ });
13
+ }
14
+ if (result.error === "run_not_found" && selector.runId) {
15
+ throw new errors_1.CliError(`Run not found: ${selector.runId}`, {
16
+ code: "RUN_NOT_FOUND",
17
+ exitCode: 3,
18
+ details: selector,
19
+ });
20
+ }
21
+ if (result.error === "batch_run_not_found" && selector.batchRunId) {
22
+ throw new errors_1.CliError(`Batch run not found: ${selector.batchRunId}`, {
23
+ code: "BATCH_RUN_NOT_FOUND",
24
+ exitCode: 3,
25
+ details: selector,
26
+ });
27
+ }
28
+ throw new errors_1.CliError(`Pipeline selector not found: ${(0, selector_1.describePipelineSelector)(selector)}`, {
29
+ code: "PIPELINE_TARGET_NOT_FOUND",
30
+ exitCode: 3,
31
+ details: {
32
+ ...selector,
33
+ error: result.error ?? "unknown_error",
34
+ },
35
+ });
36
+ };
37
+ exports.throwSelectorScopedError = throwSelectorScopedError;
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.pipelineResultRoutes = exports.pipelineResultCommand = void 0;
4
+ const errors_1 = require("../../errors");
5
+ const groupItemRunsByBaseKey = (itemRuns) => {
6
+ const batchMap = new Map();
7
+ for (const item of itemRuns) {
8
+ const rawKey = String(item.itemKey ?? "");
9
+ const baseKey = rawKey.split("::")[0];
10
+ if (!batchMap.has(baseKey)) {
11
+ batchMap.set(baseKey, {
12
+ nodeIds: new Set(),
13
+ itemKeys: new Set(),
14
+ nodeStatusMap: new Map(),
15
+ });
16
+ }
17
+ const batch = batchMap.get(baseKey);
18
+ const nodeId = String(item.nodeId ?? "");
19
+ batch.nodeIds.add(nodeId);
20
+ if (rawKey)
21
+ batch.itemKeys.add(rawKey);
22
+ batch.nodeStatusMap.set(nodeId, {
23
+ status: String(item.status ?? "unknown"),
24
+ lastError: typeof item.lastError === "string" ? item.lastError : null,
25
+ });
26
+ }
27
+ return [...batchMap.entries()].map(([baseKey, batch]) => ({
28
+ baseKey,
29
+ nodeIds: batch.nodeIds,
30
+ itemKeys: batch.itemKeys,
31
+ nodeStatusMap: batch.nodeStatusMap,
32
+ }));
33
+ };
34
+ const extractEnvelopeContents = (content) => {
35
+ const obj = content;
36
+ if (!obj)
37
+ return { contents: [], logs: null };
38
+ const contents = Array.isArray(obj.contents) ? obj.contents : [];
39
+ const logs = Array.isArray(obj.logs) ? obj.logs : null;
40
+ return { contents, logs };
41
+ };
42
+ const pipelineResultCommand = async (input, ctx) => {
43
+ const pipelineId = (0, errors_1.assertRequiredArg)(input.args[0], "pipelineId");
44
+ const targetNodeId = typeof input.flags.node === "string" ? input.flags.node.trim() : undefined;
45
+ const includeLogs = input.flags.logs === true;
46
+ const detail = await ctx.app.pipelineService.getPipelineById(pipelineId);
47
+ if (!detail) {
48
+ throw new errors_1.CliError(`Pipeline not found: ${pipelineId}`, {
49
+ code: "PIPELINE_NOT_FOUND",
50
+ exitCode: 3,
51
+ details: { pipelineId },
52
+ });
53
+ }
54
+ const d = detail;
55
+ const run = d.run;
56
+ const runId = String(run.id ?? "");
57
+ const runStatus = String(run.status ?? "unknown");
58
+ const workflow = d.workflow;
59
+ const workflowNodes = Array.isArray(workflow.nodes) ? workflow.nodes : [];
60
+ const nodeTitleMap = new Map();
61
+ for (const wn of workflowNodes) {
62
+ const id = String(wn.id ?? "");
63
+ const title = String(wn.name ?? wn.title ?? id);
64
+ if (id)
65
+ nodeTitleMap.set(id, title);
66
+ }
67
+ const workflowPlugins = workflow.plugins;
68
+ const remoteBatchPlugin = workflowPlugins?.remoteBatch;
69
+ const isBatch = remoteBatchPlugin?.enabled === true;
70
+ const itemRuns = Array.isArray(run.itemRuns) ? run.itemRuns : [];
71
+ const batchRun = d.batchRun;
72
+ const batchRunId = typeof batchRun?.batchRunId === "string" ? batchRun.batchRunId : null;
73
+ const result = {
74
+ command: "pipeline.result",
75
+ pipelineId,
76
+ title: String(d.title ?? pipelineId),
77
+ runId,
78
+ runStatus,
79
+ batchRunId,
80
+ isBatch,
81
+ batches: [],
82
+ nodes: [],
83
+ };
84
+ // 通过 artifact service 查询 envelope 文件(复用统一读取语义)
85
+ const envelopeList = await ctx.app.artifactService.listArtifacts({
86
+ pipelineId,
87
+ runId,
88
+ kind: "envelope",
89
+ });
90
+ const envelopeItems = Array.isArray(envelopeList?.items) ? envelopeList.items : [];
91
+ // 按 nodeId 索引 envelope 的 relativePath
92
+ const envelopePathByNode = new Map();
93
+ for (const item of envelopeItems) {
94
+ const nid = item.nodeId?.trim();
95
+ const rp = item.relativePath?.trim();
96
+ if (nid && rp)
97
+ envelopePathByNode.set(nid, rp);
98
+ }
99
+ const fetchNodeContent = async (nodeId) => {
100
+ const relativePath = envelopePathByNode.get(nodeId);
101
+ if (!relativePath)
102
+ return { content: [], logs: null };
103
+ try {
104
+ const raw = await ctx.app.artifactService.getArtifactContent({ pipelineId, relativePath });
105
+ if (!raw?.content)
106
+ return { content: [], logs: null };
107
+ const { contents, logs } = extractEnvelopeContents(raw.content);
108
+ const content = contents.map((c) => (typeof c === "string" ? c : JSON.stringify(c)));
109
+ return { content, logs: includeLogs ? logs : null };
110
+ }
111
+ catch {
112
+ return { content: [], logs: null };
113
+ }
114
+ };
115
+ if (isBatch) {
116
+ const groups = groupItemRunsByBaseKey(itemRuns);
117
+ for (const group of groups) {
118
+ const batchNodes = [];
119
+ for (const nodeId of group.nodeIds) {
120
+ if (targetNodeId && nodeId !== targetNodeId)
121
+ continue;
122
+ const { content, logs } = await fetchNodeContent(nodeId);
123
+ const nodeStatus = group.nodeStatusMap.get(nodeId);
124
+ batchNodes.push({
125
+ nodeId,
126
+ title: nodeTitleMap.get(nodeId) ?? nodeId,
127
+ status: nodeStatus?.status ?? "unknown",
128
+ lastError: nodeStatus?.lastError ?? null,
129
+ content,
130
+ logs,
131
+ });
132
+ }
133
+ if (batchNodes.length > 0) {
134
+ result.batches.push({
135
+ itemKey: group.baseKey,
136
+ items: [...group.itemKeys],
137
+ nodes: batchNodes,
138
+ });
139
+ }
140
+ }
141
+ }
142
+ else {
143
+ const nodes = Array.isArray(run.nodes) ? run.nodes : [];
144
+ for (const node of nodes) {
145
+ const nodeId = String(node.id ?? "");
146
+ if (targetNodeId && nodeId !== targetNodeId)
147
+ continue;
148
+ const { content, logs } = await fetchNodeContent(nodeId);
149
+ result.nodes.push({
150
+ nodeId,
151
+ title: nodeTitleMap.get(nodeId) ?? String(node.title ?? nodeId),
152
+ status: String(node.status ?? "unknown"),
153
+ lastError: typeof node.lastError === "string" ? node.lastError : null,
154
+ content,
155
+ logs,
156
+ });
157
+ }
158
+ }
159
+ return result;
160
+ };
161
+ exports.pipelineResultCommand = pipelineResultCommand;
162
+ exports.pipelineResultRoutes = [
163
+ {
164
+ key: "pipeline.result",
165
+ path: ["pipeline", "result"],
166
+ description: "输出流水线运行结果",
167
+ handler: exports.pipelineResultCommand,
168
+ help: {
169
+ usage: "taskmeld pipeline result <pipelineId> [--node <nodeId>] [--logs] [--format <json|md>]",
170
+ args: [{ name: "pipelineId", required: true, description: "流水线 ID" }],
171
+ options: [
172
+ { flags: ["--node"], valueName: "nodeId", description: "过滤到指定节点" },
173
+ { flags: ["--logs"], description: "同时展示处理日志" },
174
+ { flags: ["--format"], valueName: "json|md", description: "输出格式,默认 md" },
175
+ ],
176
+ summary: "输出流水线运行后各节点的产物内容",
177
+ },
178
+ },
179
+ ];