@thinkingai/ae-cli 6.1.18 → 6.1.20

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 (127) hide show
  1. package/README.md +97 -38
  2. package/README.zh.md +101 -38
  3. package/dist/{auth-ROB2EDYV.js → auth-FUM37MHF.js} +241 -126
  4. package/dist/{capability-DKMYUTLC.js → capability-AXFQW5WM.js} +49 -35
  5. package/dist/{chunk-JHENBQ5B.js → chunk-4P355ZWB.js} +70 -1
  6. package/dist/chunk-6ZIQV5GW.js +26 -0
  7. package/dist/{chunk-TUKQZTMI.js → chunk-7K24F7T2.js} +2 -0
  8. package/dist/{chunk-OO6XR6LK.js → chunk-AMBFK2K3.js} +2 -0
  9. package/dist/chunk-ATSM5XAW.js +623 -0
  10. package/dist/{chunk-4XXOWOTA.js → chunk-BBEFP4SB.js} +31 -38
  11. package/dist/{chunk-BYYS3ANB.js → chunk-CZU3V3DQ.js} +5 -15
  12. package/dist/{chunk-VTWMIC5L.js → chunk-E2JKXMVO.js} +2 -0
  13. package/dist/chunk-ECBLHAZO.js +15 -0
  14. package/dist/{sync-HKIOZXQE.js → chunk-I4WQAEYB.js} +31 -540
  15. package/dist/{chunk-DWO43OIB.js → chunk-JQ3ENZZH.js} +2 -0
  16. package/dist/chunk-LNZBEQXW.js +25216 -0
  17. package/dist/{chunk-ZQ47LWTI.js → chunk-QJQZH5GQ.js} +49 -79
  18. package/dist/{chunk-QZ3AS4KK.js → chunk-RSG4ONOI.js} +9 -8
  19. package/dist/{chunk-4NN5IWVN.js → chunk-T6OSFQZD.js} +2 -0
  20. package/dist/{chunk-Y3LOALAV.js → chunk-TAL6CZH6.js} +8 -7
  21. package/dist/{chunk-3KWQYGYI.js → chunk-TKHSULJT.js} +2 -0
  22. package/dist/chunk-VXNMYUXU.js +202 -0
  23. package/dist/{chunk-3FY3RJ26.js → chunk-WZ6YVQSF.js} +15 -14
  24. package/dist/{chunk-6EIJSNBD.js → chunk-Y74WTIKJ.js} +2 -0
  25. package/dist/{community-report-client-C7WDGET3.js → community-report-client-XXWGSBSD.js} +3 -4
  26. package/dist/{config-BMYZX2UE.js → config-EXUGQN5T.js} +10 -10
  27. package/dist/{data-integration-QEKDWQDY.js → data-integration-4NZ53OMT.js} +920 -97
  28. package/dist/index.js +56 -81
  29. package/dist/{local-data-upload-client-4YYHSYD6.js → local-data-upload-client-KYOKVYZV.js} +3 -4
  30. package/dist/{memory-I2WXDTV2.js → memory-ATNKZNW5.js} +6 -7
  31. package/dist/{metadata-I4C2EWUN.js → metadata-VZVC7YMH.js} +10 -11
  32. package/dist/{model-HLHIEFMU.js → model-E4JMQ4V2.js} +8 -9
  33. package/dist/{personal-semantic-preference-LIPACBDX.js → personal-semantic-preference-7S2SQ3UV.js} +9 -10
  34. package/dist/{project-semantic-RT3R2VQD.js → project-semantic-2SZP2OPO.js} +13 -14
  35. package/dist/sync-YV3E66IF.js +520 -0
  36. package/dist/{te-agent-BR6VDBNX.js → te-agent-JB5T3PO7.js} +396 -92
  37. package/dist/{te-analysis-7VUNUYWZ.js → te-analysis-3YJAAT2D.js} +196 -43
  38. package/dist/{te-community-5DMNKJWY.js → te-community-UDBI672N.js} +12 -34
  39. package/dist/{te-dataops-6P5IKWNJ.js → te-dataops-ZLYOCXZ4.js} +480 -81
  40. package/dist/{te-engage-KZPR5R22.js → te-engage-4XG6OJML.js} +88 -16
  41. package/dist/{te-experiment-6BITX4RD.js → te-experiment-VXUWPINJ.js} +83 -12
  42. package/dist/te-kb-WYQWHFSC.js +1732 -0
  43. package/dist/{te-system-FXITO2JG.js → te-system-7G6F2LJA.js} +569 -35
  44. package/dist/{te-team-ADOC2ROP.js → te-team-E7FBBXMQ.js} +8 -7
  45. package/dist/{update-YCYCKJOO.js → update-D47BUG25.js} +8 -8
  46. package/package.json +22 -10
  47. package/skills/ae-agent/SKILL.md +30 -13
  48. package/skills/ae-agent/references/agent-distribution.md +94 -0
  49. package/skills/ae-agent/references/approval-request.md +4 -0
  50. package/skills/ae-agent/references/command_index.md +9 -2
  51. package/skills/ae-agent/references/create-automation.md +20 -2
  52. package/skills/ae-agent/references/get-agent-context.md +70 -0
  53. package/skills/ae-agent/references/list-automations.md +18 -3
  54. package/skills/ae-agent/references/list-mcp-credentials.md +1 -1
  55. package/skills/ae-agent/references/mcp-token.md +3 -3
  56. package/skills/ae-agent/references/set-mcp-credential.md +0 -1
  57. package/skills/ae-agent/references/update-automation.md +18 -0
  58. package/skills/ae-analysis/SKILL.md +11 -2
  59. package/skills/ae-analysis/references/adhoc_run.md +2 -0
  60. package/skills/ae-analysis/references/ai_models.md +23 -3
  61. package/skills/ae-analysis/references/analysis_gateway_assets.md +3 -3
  62. package/skills/ae-analysis/references/audience_models.md +18 -0
  63. package/skills/ae-analysis/references/command_index.md +9 -9
  64. package/skills/ae-analysis/references/cross_source_config.md +84 -0
  65. package/skills/ae-analysis/references/dashboard_update.md +1 -1
  66. package/skills/ae-analysis/references/project_timezone_update.md +13 -4
  67. package/skills/ae-analysis/references/property_create.md +2 -0
  68. package/skills/ae-analysis/references/super_metadata_batch_create.md +2 -0
  69. package/skills/ae-analysis/references/user_cluster_models.md +2 -0
  70. package/skills/ae-analysis/references/user_cluster_update.md +8 -4
  71. package/skills/ae-analysis/references/user_tag_create.md +30 -2
  72. package/skills/ae-analysis/references/user_tag_models.md +17 -3
  73. package/skills/ae-analysis/references/user_tag_update.md +14 -2
  74. package/skills/ae-data-integration/SKILL.md +3 -1
  75. package/skills/ae-data-integration/references/dimension-routing.md +36 -0
  76. package/skills/ae-data-integration/references/error-handling.md +54 -1
  77. package/skills/ae-data-integration/references/local-analysis.md +2 -0
  78. package/skills/ae-data-integration/references/source-inspect.md +18 -2
  79. package/skills/ae-data-integration/references/tracking-plan.md +1 -1
  80. package/skills/ae-data-integration/references/transform.md +4 -2
  81. package/skills/ae-data-integration/references/ue-mapping.md +5 -2
  82. package/skills/ae-data-integration/references/ue-routing.md +40 -1
  83. package/skills/ae-dataops/SKILL.md +11 -1
  84. package/skills/ae-dataops/references/dataops-backfill.md +135 -0
  85. package/skills/ae-engage/SKILL.md +5 -0
  86. package/skills/ae-engage/references/build-task-save-guide.md +5 -1
  87. package/skills/ae-engage/references/save-flow.md +37 -1
  88. package/skills/ae-engage/references/save-task.md +6 -0
  89. package/skills/ae-experiment/SKILL.md +6 -2
  90. package/skills/ae-experiment/references/save_metric.md +20 -8
  91. package/skills/ae-generate-tracking-plan/SKILL.md +25 -13
  92. package/skills/ae-generate-tracking-plan/references/business-dimension-mapping.md +1 -1
  93. package/skills/ae-kb/SKILL.md +218 -36
  94. package/skills/ae-kb/references/query-workflow.md +59 -29
  95. package/skills/ae-kb/references/versions.md +46 -0
  96. package/skills/ae-system/SKILL.md +29 -31
  97. package/skills/ae-system/references/channel-management.md +303 -0
  98. package/skills/ae-use-agent/SKILL.md +42 -0
  99. package/skills/ae-use-agent/references/local-agent.md +114 -0
  100. package/dist/auth-GBMV6TEJ.js +0 -14
  101. package/dist/capability-HYVVPG25.js +0 -352
  102. package/dist/chunk-EFH4XWYC.js +0 -556
  103. package/dist/chunk-J2DEBMRF.js +0 -313
  104. package/dist/chunk-JRJY5DMJ.js +0 -71
  105. package/dist/chunk-OMPRXM3V.js +0 -349
  106. package/dist/chunk-QNOLN2LJ.js +0 -509
  107. package/dist/chunk-RJDU7NYP.js +0 -1198
  108. package/dist/chunk-RNAALWJK.js +0 -98
  109. package/dist/chunk-SERWF6G5.js +0 -13
  110. package/dist/chunk-UW5UN47B.js +0 -70
  111. package/dist/chunk-ZQKDZXDO.js +0 -317
  112. package/dist/client-L2YDMHQ6.js +0 -203
  113. package/dist/memory-3ORCR7JH.js +0 -893
  114. package/dist/metadata-VUOQJE26.js +0 -339
  115. package/dist/model-UGRDX4MW.js +0 -139
  116. package/dist/personal-semantic-preference-OEISBRHM.js +0 -239
  117. package/dist/project-semantic-FFPWFPIW.js +0 -1114
  118. package/dist/sync-TFHU2UTG.js +0 -10261
  119. package/dist/te-agent-VLYOV7S4.js +0 -3894
  120. package/dist/te-analysis-4YGQL5RC.js +0 -9357
  121. package/dist/te-community-ISDQWJU7.js +0 -1859
  122. package/dist/te-dataops-CVULXNVB.js +0 -2209
  123. package/dist/te-engage-N5WI32H6.js +0 -4898
  124. package/dist/te-experiment-UVR4HLND.js +0 -988
  125. package/dist/te-kb-RCLSSH2Q.js +0 -935
  126. package/dist/te-system-K2GYMCTB.js +0 -2213
  127. package/skills/ae-agent/references/auto-provision-mcp-credentials.md +0 -57
@@ -1,556 +0,0 @@
1
- import {
2
- resolveGatewayDomain
3
- } from "./chunk-3KWQYGYI.js";
4
- import {
5
- readOutputMetadata,
6
- unwrapOutputData,
7
- withOutputMetadata
8
- } from "./chunk-BYYS3ANB.js";
9
- import {
10
- CapabilityGatewayError,
11
- fetchCapabilityGateway,
12
- requestCapabilityGateway
13
- } from "./chunk-ZQ47LWTI.js";
14
- import {
15
- PermissionError
16
- } from "./chunk-UW5UN47B.js";
17
-
18
- // src/core/analysis-async-artifact.ts
19
- import { randomBytes } from "crypto";
20
- import { createWriteStream } from "fs";
21
- import { access, link, mkdir, rename, stat, unlink } from "fs/promises";
22
- import { Readable } from "stream";
23
- import { pipeline } from "stream/promises";
24
- import { basename, dirname, join, resolve } from "path";
25
- var MATERIALIZATION_GRACE_MS = 6e4;
26
- var DEFAULT_EFFECTIVE_TIMEOUT_MS = 216e5;
27
- var DEFAULT_WAIT_TIMEOUT_SECONDS = 600;
28
- var MAX_WAIT_TIMEOUT_SECONDS = 21600;
29
- var MAX_TRANSIENT_FAILURES = 3;
30
- var asyncArtifactLifecycleFlags = [
31
- {
32
- name: "wait",
33
- type: "boolean",
34
- required: false,
35
- desc: "Wait for the remote run and artifact to reach a terminal state. Polling uses short inspect requests; interrupting does not cancel the remote run."
36
- },
37
- {
38
- name: "wait-timeout-seconds",
39
- type: "number",
40
- required: false,
41
- min: 1,
42
- max: MAX_WAIT_TIMEOUT_SECONDS,
43
- desc: "Maximum time this CLI process waits. Default: 600 seconds; expiry never cancels the remote run."
44
- },
45
- {
46
- name: "output",
47
- type: "string",
48
- required: false,
49
- desc: "Wait, then stream the completed artifact to this local file. Implies --wait."
50
- },
51
- {
52
- name: "force",
53
- type: "boolean",
54
- required: false,
55
- desc: "Allow --output to atomically replace an existing file. Without this flag, existing paths are refused."
56
- }
57
- ];
58
- function withAsyncArtifactLifecycle(command, options = {}) {
59
- const originalValidate = command.validate;
60
- const originalPreflight = command.preflight;
61
- return {
62
- ...command,
63
- flags: [...command.flags, ...asyncArtifactLifecycleFlags],
64
- validate: (ctx) => {
65
- originalValidate?.(ctx);
66
- validateLifecycleFlags(ctx);
67
- },
68
- preflight: (ctx) => {
69
- originalPreflight?.(ctx);
70
- validateLifecycleFlags(ctx);
71
- },
72
- execute: async (ctx) => {
73
- validateLifecycleFlags(ctx);
74
- const output = optionalString(ctx, "output");
75
- if (output) {
76
- if (options.preflightOutput) {
77
- await options.preflightOutput({
78
- ctx,
79
- output,
80
- force: ctx.bool("force")
81
- });
82
- } else {
83
- await assertOutputPathAvailable(output, ctx.bool("force"));
84
- }
85
- }
86
- const submission = await command.execute(ctx);
87
- const descriptor = asDescriptor(unwrapOutputData(submission));
88
- const runId = nonEmptyString(descriptor.run_id);
89
- const artifactId = descriptorArtifactId(descriptor);
90
- if (!runId || !artifactId) {
91
- throw protocolError(
92
- "Async artifact submission did not return both run_id and artifact_id.",
93
- runId
94
- );
95
- }
96
- announceSubmitted(runId, artifactId);
97
- if (!ctx.bool("wait") && output === void 0) {
98
- return submission;
99
- }
100
- const finalResult = await withInterruptSignal(async (signal) => {
101
- const finalDescriptor = await waitForAnalysisRun(ctx.host(), runId, {
102
- expectedArtifactId: artifactId,
103
- initialDescriptor: descriptor,
104
- signal,
105
- waitTimeoutSeconds: clientWaitTimeoutSeconds(ctx)
106
- });
107
- if (!output) return finalDescriptor;
108
- const download = options.materialize ? await options.materialize({
109
- ctx,
110
- runId,
111
- artifactId,
112
- output,
113
- force: ctx.bool("force"),
114
- signal,
115
- finalDescriptor
116
- }) : await downloadAnalysisArtifact(
117
- ctx.host(),
118
- runId,
119
- artifactId,
120
- output,
121
- { force: ctx.bool("force"), signal, ensureReady: false }
122
- );
123
- return { ...finalDescriptor, ...download };
124
- }, runId);
125
- return withOutputMetadata(finalResult, readOutputMetadata(submission));
126
- }
127
- };
128
- }
129
- async function waitForAnalysisRun(host, runId, options = {}) {
130
- const now = options.now ?? Date.now;
131
- const sleep = options.sleep ?? abortableSleep;
132
- const inspect = options.inspect ?? inspectAnalysisRun;
133
- const startedAt = now();
134
- const waitTimeoutSeconds = options.waitTimeoutSeconds ?? DEFAULT_WAIT_TIMEOUT_SECONDS;
135
- const clientDeadline = startedAt + waitTimeoutSeconds * 1e3;
136
- let deadline = deriveDeadline(options.initialDescriptor, startedAt);
137
- let delayMs = 1e3;
138
- let transientFailures = 0;
139
- let lastState = "";
140
- let materializationStartedAt;
141
- let descriptor = options.initialDescriptor;
142
- while (true) {
143
- throwIfAborted(options.signal, runId);
144
- if (descriptor !== void 0 && descriptorRunStatus(descriptor) === void 0) {
145
- descriptor = void 0;
146
- }
147
- if (descriptor === void 0) {
148
- try {
149
- descriptor = asDescriptor(await inspect(host, runId));
150
- transientFailures = 0;
151
- } catch (error) {
152
- if (error instanceof PermissionError) throw error;
153
- if (error instanceof CapabilityGatewayError && error.httpStatus === 404) {
154
- throw new CapabilityGatewayError(
155
- `Async run ${runId} was not found on the current host.`,
156
- "ASYNC_RUN_NOT_FOUND",
157
- 404,
158
- "Do not keep polling. Verify that the run ID belongs to this host and that the run lifecycle route is deployed.",
159
- { run_id: runId }
160
- );
161
- }
162
- if (!isTransientPollError(error) || ++transientFailures >= MAX_TRANSIENT_FAILURES) {
163
- throw waitError(
164
- `Could not inspect async run ${runId}${transientFailures > 0 ? ` after ${transientFailures} transient failures` : ""}.`,
165
- "ASYNC_RUN_INSPECT_FAILED",
166
- runId,
167
- error
168
- );
169
- }
170
- await sleep(delayMs, options.signal);
171
- delayMs = nextDelay(delayMs);
172
- continue;
173
- }
174
- }
175
- deadline = Math.min(deadline, deriveDeadline(descriptor, startedAt));
176
- const runStatus = descriptorRunStatus(descriptor);
177
- const artifactStatus = normalizedStatus(descriptor.artifact_status ?? descriptor.artifact?.status);
178
- const artifactId = descriptorArtifactId(descriptor);
179
- if (options.expectedArtifactId && artifactId && artifactId !== options.expectedArtifactId) {
180
- throw new CapabilityGatewayError(
181
- `artifact_id ${artifactId} does not match the submitted artifact ${options.expectedArtifactId}.`,
182
- "ARTIFACT_RUN_MISMATCH",
183
- 400,
184
- resumeHint(runId),
185
- { run_id: runId, artifact_id: artifactId, expected_artifact_id: options.expectedArtifactId }
186
- );
187
- }
188
- const state = `${runStatus || "UNKNOWN"}/${artifactStatus || "UNKNOWN"}`;
189
- if (state !== lastState) {
190
- process.stderr.write(`[ae-cli] run_id=${runId} state=${state}
191
- `);
192
- lastState = state;
193
- }
194
- if (runStatus === "FAILED" || runStatus === "CANCELED") {
195
- throw terminalError(descriptor, runId, `Run ended with status ${runStatus}.`);
196
- }
197
- if (artifactStatus === "FAILED" || artifactStatus === "CANCELED") {
198
- throw terminalError(descriptor, runId, `Artifact ended with status ${artifactStatus}.`);
199
- }
200
- if (runStatus === "SUCCEEDED" && artifactStatus === "COMPLETED") {
201
- if (!artifactId) {
202
- throw protocolError("Completed async run has no artifact_id.", runId);
203
- }
204
- return descriptor;
205
- }
206
- if (runStatus !== "RUNNING" && runStatus !== "SUCCEEDED") {
207
- throw protocolError(`Unknown async run status: ${runStatus || "missing"}.`, runId);
208
- }
209
- if (artifactStatus && artifactStatus !== "RUNNING" && artifactStatus !== "COMPLETED") {
210
- throw protocolError(`Unknown async artifact status: ${artifactStatus}.`, runId);
211
- }
212
- if (runStatus === "RUNNING" && artifactStatus === "COMPLETED") {
213
- throw protocolError("Artifact is COMPLETED while its run is still RUNNING.", runId);
214
- }
215
- if (runStatus === "SUCCEEDED" && materializationStartedAt === void 0) {
216
- materializationStartedAt = now();
217
- }
218
- const lifecycleDeadline = materializationStartedAt === void 0 ? deadline : Math.min(deadline, materializationStartedAt + MATERIALIZATION_GRACE_MS);
219
- const effectiveDeadline = Math.min(clientDeadline, lifecycleDeadline);
220
- if (now() >= effectiveDeadline) {
221
- if (clientDeadline <= lifecycleDeadline) {
222
- throw waitError(
223
- `Stopped waiting after ${waitTimeoutSeconds} seconds for run ${runId}. The remote run was not canceled.`,
224
- "ASYNC_WAIT_TIMEOUT",
225
- runId,
226
- void 0,
227
- descriptor,
228
- { wait_timeout_seconds: waitTimeoutSeconds }
229
- );
230
- }
231
- throw waitError(
232
- `Stopped waiting because the server-declared deadline for run ${runId} was reached. The remote run was not canceled.`,
233
- "ASYNC_WAIT_DEADLINE_REACHED",
234
- runId,
235
- void 0,
236
- descriptor
237
- );
238
- }
239
- await sleep(Math.min(delayMs, Math.max(0, effectiveDeadline - now())), options.signal);
240
- delayMs = nextDelay(delayMs);
241
- descriptor = void 0;
242
- }
243
- }
244
- async function downloadAnalysisArtifact(host, runId, artifactId, output, options = {}) {
245
- const outputPath = resolve(output);
246
- await assertOutputPathAvailable(outputPath, options.force, { run_id: runId, artifact_id: artifactId });
247
- if (options.ensureReady !== false) {
248
- const descriptor = await inspectAnalysisRun(host, runId);
249
- ensureCompletedDescriptor(descriptor, runId, artifactId);
250
- }
251
- await mkdir(dirname(outputPath), { recursive: true });
252
- const tempPath = join(
253
- dirname(outputPath),
254
- `.${basename(outputPath)}.part-${process.pid}-${randomBytes(6).toString("hex")}`
255
- );
256
- let tempPresent = false;
257
- try {
258
- throwIfAborted(options.signal, runId);
259
- const response = await fetchArtifact(host, runId, artifactId);
260
- if (!response.body) {
261
- throw protocolError("Artifact download response has no body.", runId);
262
- }
263
- tempPresent = true;
264
- const source = Readable.fromWeb(response.body);
265
- await pipeline(source, createWriteStream(tempPath, { flags: "wx" }), {
266
- signal: options.signal
267
- });
268
- const file = await stat(tempPath);
269
- if (options.force) {
270
- await rename(tempPath, outputPath);
271
- } else {
272
- try {
273
- await link(tempPath, outputPath);
274
- } catch (error) {
275
- if (error?.code === "EEXIST") {
276
- throw new CapabilityGatewayError(
277
- `Output path already exists: ${outputPath}`,
278
- "OUTPUT_ALREADY_EXISTS",
279
- 409,
280
- "Choose another --output path or pass --force to replace the existing file.",
281
- { run_id: runId, artifact_id: artifactId, output_path: outputPath }
282
- );
283
- }
284
- throw error;
285
- }
286
- await unlink(tempPath);
287
- }
288
- tempPresent = false;
289
- return {
290
- run_id: runId,
291
- artifact_id: artifactId,
292
- output_path: outputPath,
293
- bytes: file.size,
294
- content_type: response.headers.get("content-type") ?? void 0,
295
- content_encoding: response.headers.get("content-encoding") ?? void 0,
296
- content_disposition: response.headers.get("content-disposition") ?? void 0
297
- };
298
- } catch (error) {
299
- if (options.signal?.aborted) {
300
- throw interruptedError(runId);
301
- }
302
- throw error;
303
- } finally {
304
- if (tempPresent) await unlink(tempPath).catch(() => void 0);
305
- }
306
- }
307
- function validateLifecycleFlags(ctx, waitImplied = false) {
308
- const output = optionalString(ctx, "output");
309
- if (ctx.bool("force") && output === void 0) {
310
- const error = new Error("--force requires --output.");
311
- error.type = "validation";
312
- throw error;
313
- }
314
- const waitTimeout = optionalContextNumber(ctx, "wait-timeout-seconds");
315
- if (waitTimeout !== void 0) {
316
- if (!Number.isInteger(waitTimeout) || waitTimeout < 1 || waitTimeout > MAX_WAIT_TIMEOUT_SECONDS) {
317
- const error = new Error(`--wait-timeout-seconds must be an integer between 1 and ${MAX_WAIT_TIMEOUT_SECONDS}.`);
318
- error.type = "validation";
319
- throw error;
320
- }
321
- if (!waitImplied && !ctx.bool("wait") && output === void 0) {
322
- const error = new Error("--wait-timeout-seconds requires --wait or --output.");
323
- error.type = "validation";
324
- throw error;
325
- }
326
- }
327
- }
328
- function clientWaitTimeoutSeconds(ctx) {
329
- return optionalContextNumber(ctx, "wait-timeout-seconds") ?? DEFAULT_WAIT_TIMEOUT_SECONDS;
330
- }
331
- function optionalContextNumber(ctx, name) {
332
- if (typeof ctx.optionalNum === "function") {
333
- return ctx.optionalNum(name);
334
- }
335
- const raw = ctx.str(name);
336
- return raw.trim() === "" ? void 0 : Number(raw);
337
- }
338
- async function assertOutputPathAvailable(output, force = false, meta = {}) {
339
- const outputPath = resolve(output);
340
- if (force || !await pathExists(outputPath)) return;
341
- throw new CapabilityGatewayError(
342
- `Output path already exists: ${outputPath}`,
343
- "OUTPUT_ALREADY_EXISTS",
344
- 409,
345
- "Choose another --output path or pass --force to replace the existing file.",
346
- { ...meta, output_path: outputPath }
347
- );
348
- }
349
- async function withInterruptSignal(operation, runId) {
350
- const controller = new AbortController();
351
- const onInterrupt = () => controller.abort();
352
- process.once("SIGINT", onInterrupt);
353
- try {
354
- return await operation(controller.signal);
355
- } catch (error) {
356
- if (controller.signal.aborted) throw interruptedError(runId);
357
- throw error;
358
- } finally {
359
- process.removeListener("SIGINT", onInterrupt);
360
- }
361
- }
362
- async function inspectAnalysisRun(host, runId) {
363
- return asDescriptor(await requestCapabilityGateway(
364
- host,
365
- resolveGatewayDomain("analysis"),
366
- `runs/${encodeURIComponent(runId)}`
367
- ));
368
- }
369
- function ensureCompletedDescriptor(descriptor, runId, artifactId) {
370
- const actualArtifactId = descriptorArtifactId(descriptor);
371
- if (actualArtifactId && actualArtifactId !== artifactId) {
372
- throw new CapabilityGatewayError(
373
- `artifact_id ${artifactId} does not belong to run_id ${runId}`,
374
- "ARTIFACT_RUN_MISMATCH",
375
- 400,
376
- "Use the run_id and artifact_id pair from the same export response."
377
- );
378
- }
379
- const runStatus = descriptorRunStatus(descriptor);
380
- const artifactStatus = normalizedStatus(descriptor.artifact_status ?? descriptor.artifact?.status);
381
- if (runStatus === "SUCCEEDED" && artifactStatus === "COMPLETED") return;
382
- if (runStatus === "FAILED" || runStatus === "CANCELED" || artifactStatus === "FAILED" || artifactStatus === "CANCELED") {
383
- throw terminalError(descriptor, runId, "Artifact cannot be downloaded because the remote lifecycle failed.");
384
- }
385
- throw new CapabilityGatewayError(
386
- `Artifact is not ready: run_status=${runStatus || "UNKNOWN"}, artifact_status=${artifactStatus || "UNKNOWN"}`,
387
- "ARTIFACT_NOT_READY",
388
- 409,
389
- `Resume with: ae-cli analysis run wait --run-id ${runId}`,
390
- { run_id: runId, artifact_id: artifactId }
391
- );
392
- }
393
- function descriptorArtifactId(descriptor) {
394
- return nonEmptyString(descriptor.artifact_id) ?? nonEmptyString(descriptor.artifact?.artifact_id) ?? nonEmptyString(descriptor.artifact?.id);
395
- }
396
- function descriptorRunStatus(descriptor) {
397
- return normalizedStatus(descriptor.status ?? descriptor.run_status);
398
- }
399
- function deriveDeadline(descriptor, fallbackFrom) {
400
- const declaredDeadline = timestampMillis(descriptor?.deadline_at);
401
- if (declaredDeadline !== void 0) return declaredDeadline + MATERIALIZATION_GRACE_MS;
402
- const expiresAt = timestampMillis(descriptor?.expires_at);
403
- if (expiresAt !== void 0) return expiresAt;
404
- const effectiveTimeout = Number(descriptor?.effective_timeout_seconds);
405
- if (Number.isFinite(effectiveTimeout) && effectiveTimeout > 0) {
406
- return fallbackFrom + effectiveTimeout * 1e3 + MATERIALIZATION_GRACE_MS;
407
- }
408
- return fallbackFrom + DEFAULT_EFFECTIVE_TIMEOUT_MS + MATERIALIZATION_GRACE_MS;
409
- }
410
- function timestampMillis(value) {
411
- if (typeof value === "number" && Number.isFinite(value)) {
412
- return value < 1e10 ? value * 1e3 : value;
413
- }
414
- if (typeof value !== "string" || value.trim() === "") return void 0;
415
- const numeric = Number(value);
416
- if (Number.isFinite(numeric)) return timestampMillis(numeric);
417
- const parsed = Date.parse(value);
418
- return Number.isFinite(parsed) ? parsed : void 0;
419
- }
420
- function nextDelay(current) {
421
- return Math.min(5e3, Math.ceil(current * 1.5));
422
- }
423
- function normalizedStatus(value) {
424
- return typeof value === "string" && value.trim() ? value.trim().toUpperCase() : void 0;
425
- }
426
- function asDescriptor(value) {
427
- if (!value || typeof value !== "object" || Array.isArray(value)) {
428
- throw protocolError("Async run response is not an object.");
429
- }
430
- return value;
431
- }
432
- function nonEmptyString(value) {
433
- return typeof value === "string" && value.trim() ? value.trim() : void 0;
434
- }
435
- function optionalString(ctx, name) {
436
- return nonEmptyString(ctx.str(name));
437
- }
438
- function terminalError(descriptor, runId, message) {
439
- return new CapabilityGatewayError(
440
- message,
441
- "ASYNC_RUN_TERMINAL_FAILURE",
442
- 409,
443
- `The remote lifecycle is terminal and will not succeed on retry. Inspect details with: ae-cli analysis run inspect --run-id ${runId}`,
444
- {
445
- run_id: runId,
446
- artifact_id: descriptorArtifactId(descriptor),
447
- run_status: descriptorRunStatus(descriptor),
448
- artifact_status: normalizedStatus(descriptor.artifact_status ?? descriptor.artifact?.status),
449
- error: descriptor.error ?? descriptor.artifact?.error ?? descriptor.error_message ?? descriptor.artifact?.error_message
450
- }
451
- );
452
- }
453
- function protocolError(message, runId) {
454
- return new CapabilityGatewayError(
455
- message,
456
- "ASYNC_RUN_PROTOCOL_ERROR",
457
- 502,
458
- runId ? resumeHint(runId) : "Inspect the gateway response and verify the async run contract.",
459
- runId ? { run_id: runId } : void 0
460
- );
461
- }
462
- function waitError(message, code, runId, cause, descriptor, extraMeta = {}) {
463
- const resumeCommand = `ae-cli analysis run wait --run-id ${runId}`;
464
- const error = new CapabilityGatewayError(
465
- message,
466
- code,
467
- void 0,
468
- resumeHint(runId),
469
- {
470
- run_id: runId,
471
- artifact_id: descriptor ? descriptorArtifactId(descriptor) : void 0,
472
- run_status: descriptor ? descriptorRunStatus(descriptor) : void 0,
473
- artifact_status: descriptor ? normalizedStatus(descriptor.artifact_status ?? descriptor.artifact?.status) : void 0,
474
- remote_run_canceled: false,
475
- resume_command: resumeCommand,
476
- ...extraMeta
477
- }
478
- );
479
- if (cause !== void 0) error.cause = cause;
480
- return error;
481
- }
482
- function interruptedError(runId) {
483
- return waitError(
484
- `Stopped waiting for run ${runId}. The remote run was not canceled.`,
485
- "ASYNC_WAIT_INTERRUPTED",
486
- runId
487
- );
488
- }
489
- function resumeHint(runId) {
490
- return `Resume with: ae-cli analysis run wait --run-id ${runId}`;
491
- }
492
- function announceSubmitted(runId, artifactId) {
493
- process.stderr.write(
494
- `[ae-cli] async run submitted run_id=${runId} artifact_id=${artifactId}; ${resumeHint(runId)}
495
- `
496
- );
497
- }
498
- function isTransientPollError(error) {
499
- if (error instanceof CapabilityGatewayError) {
500
- return error.httpStatus === 429 || error.httpStatus !== void 0 && error.httpStatus >= 500;
501
- }
502
- return error instanceof TypeError || error instanceof Error && /fetch|network|socket|timeout/i.test(error.message);
503
- }
504
- function throwIfAborted(signal, runId) {
505
- if (signal?.aborted) throw interruptedError(runId);
506
- }
507
- async function abortableSleep(milliseconds, signal) {
508
- if (milliseconds <= 0) return;
509
- await new Promise((resolveSleep, reject) => {
510
- let timer;
511
- const finish = () => {
512
- signal?.removeEventListener("abort", onAbort);
513
- resolveSleep();
514
- };
515
- const onAbort = () => {
516
- if (timer !== void 0) clearTimeout(timer);
517
- signal?.removeEventListener("abort", onAbort);
518
- reject(new DOMException("The operation was aborted", "AbortError"));
519
- };
520
- if (signal?.aborted) return onAbort();
521
- signal?.addEventListener("abort", onAbort, { once: true });
522
- timer = setTimeout(finish, milliseconds);
523
- });
524
- }
525
- async function pathExists(path) {
526
- try {
527
- await access(path);
528
- return true;
529
- } catch (error) {
530
- if (error?.code === "ENOENT") return false;
531
- throw error;
532
- }
533
- }
534
- function artifactPath(runId, artifactId) {
535
- return `runs/${encodeURIComponent(runId)}/artifacts/${encodeURIComponent(artifactId)}/download`;
536
- }
537
- function fetchArtifact(host, runId, artifactId) {
538
- return fetchCapabilityGateway(
539
- host,
540
- resolveGatewayDomain("analysis"),
541
- artifactPath(runId, artifactId),
542
- "GET",
543
- void 0,
544
- "application/octet-stream"
545
- );
546
- }
547
-
548
- export {
549
- withAsyncArtifactLifecycle,
550
- waitForAnalysisRun,
551
- downloadAnalysisArtifact,
552
- validateLifecycleFlags,
553
- clientWaitTimeoutSeconds,
554
- assertOutputPathAvailable,
555
- withInterruptSignal
556
- };