deepline 0.1.12 → 0.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.
- package/README.md +14 -6
- package/dist/cli/index.js +1346 -717
- package/dist/cli/index.mjs +1342 -713
- package/dist/index.d.mts +199 -23
- package/dist/index.d.ts +199 -23
- package/dist/index.js +221 -14
- package/dist/index.mjs +221 -14
- package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +214 -77
- package/dist/repo/apps/play-runner-workers/src/dedup-do.ts +85 -60
- package/dist/repo/apps/play-runner-workers/src/entry.ts +385 -66
- package/dist/repo/sdk/src/client.ts +237 -0
- package/dist/repo/sdk/src/config.ts +125 -8
- package/dist/repo/sdk/src/http.ts +29 -5
- package/dist/repo/sdk/src/play.ts +19 -36
- package/dist/repo/sdk/src/plays/bundle-play-file.ts +22 -8
- package/dist/repo/sdk/src/plays/local-file-discovery.ts +207 -160
- package/dist/repo/sdk/src/types.ts +25 -0
- package/dist/repo/sdk/src/version.ts +2 -2
- package/dist/repo/shared_libs/play-runtime/tool-result.ts +237 -145
- package/dist/repo/shared_libs/plays/bundling/index.ts +206 -229
- package/dist/repo/shared_libs/plays/dataset.ts +28 -0
- package/dist/repo/shared_libs/plays/row-identity.ts +59 -4
- package/package.json +5 -4
- package/dist/cli/index.js.map +0 -1
- package/dist/cli/index.mjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/repo/apps/play-runner-workers/src/runtime/README.md +0 -21
- package/dist/repo/apps/play-runner-workers/src/runtime/batching.ts +0 -177
- package/dist/repo/apps/play-runner-workers/src/runtime/execution-plan.ts +0 -52
- package/dist/repo/apps/play-runner-workers/src/runtime/tool-batch.ts +0 -100
- package/dist/repo/sdk/src/cli/commands/auth.ts +0 -500
- package/dist/repo/sdk/src/cli/commands/billing.ts +0 -188
- package/dist/repo/sdk/src/cli/commands/csv.ts +0 -123
- package/dist/repo/sdk/src/cli/commands/db.ts +0 -119
- package/dist/repo/sdk/src/cli/commands/feedback.ts +0 -40
- package/dist/repo/sdk/src/cli/commands/org.ts +0 -117
- package/dist/repo/sdk/src/cli/commands/play.ts +0 -3441
- package/dist/repo/sdk/src/cli/commands/tools.ts +0 -687
- package/dist/repo/sdk/src/cli/dataset-stats.ts +0 -415
- package/dist/repo/sdk/src/cli/index.ts +0 -148
- package/dist/repo/sdk/src/cli/progress.ts +0 -149
- package/dist/repo/sdk/src/cli/skills-sync.ts +0 -141
- package/dist/repo/sdk/src/cli/trace.ts +0 -61
- package/dist/repo/sdk/src/cli/utils.ts +0 -145
- package/dist/repo/sdk/src/compat.ts +0 -77
- package/dist/repo/shared_libs/observability/node-tracing.ts +0 -129
- package/dist/repo/shared_libs/observability/tracing.ts +0 -98
- package/dist/repo/shared_libs/play-runtime/context.ts +0 -4242
- package/dist/repo/shared_libs/play-runtime/ctx-contract.ts +0 -250
- package/dist/repo/shared_libs/play-runtime/ctx-types.ts +0 -725
- package/dist/repo/shared_libs/play-runtime/dataset-id.ts +0 -10
- package/dist/repo/shared_libs/play-runtime/db-session-crypto.ts +0 -304
- package/dist/repo/shared_libs/play-runtime/db-session.ts +0 -462
- package/dist/repo/shared_libs/play-runtime/live-events.ts +0 -214
- package/dist/repo/shared_libs/play-runtime/live-state-contract.ts +0 -50
- package/dist/repo/shared_libs/play-runtime/map-execution-frame.ts +0 -114
- package/dist/repo/shared_libs/play-runtime/map-row-identity.ts +0 -158
- package/dist/repo/shared_libs/play-runtime/progress-emitter.ts +0 -172
- package/dist/repo/shared_libs/play-runtime/protocol.ts +0 -121
- package/dist/repo/shared_libs/play-runtime/public-play-contract.ts +0 -42
- package/dist/repo/shared_libs/play-runtime/result-normalization.ts +0 -33
- package/dist/repo/shared_libs/play-runtime/runtime-api.ts +0 -1873
- package/dist/repo/shared_libs/play-runtime/runtime-constraints.ts +0 -2
- package/dist/repo/shared_libs/play-runtime/runtime-pg-driver-neon-serverless.ts +0 -201
- package/dist/repo/shared_libs/play-runtime/runtime-pg-driver-pg.ts +0 -48
- package/dist/repo/shared_libs/play-runtime/runtime-pg-driver.ts +0 -84
- package/dist/repo/shared_libs/play-runtime/static-pipeline-types.ts +0 -147
- package/dist/repo/shared_libs/play-runtime/suspension.ts +0 -68
- package/dist/repo/shared_libs/play-runtime/tracing.ts +0 -31
- package/dist/repo/shared_libs/play-runtime/waterfall-replay.ts +0 -75
- package/dist/repo/shared_libs/play-runtime/worker-api-types.ts +0 -140
- package/dist/repo/shared_libs/plays/artifact-transport.ts +0 -14
- package/dist/repo/shared_libs/plays/artifact-types.ts +0 -49
- package/dist/repo/shared_libs/plays/compiler-manifest.ts +0 -186
- package/dist/repo/shared_libs/plays/definition.ts +0 -264
- package/dist/repo/shared_libs/plays/file-refs.ts +0 -11
- package/dist/repo/shared_libs/plays/rate-limit-scheduler.ts +0 -206
- package/dist/repo/shared_libs/plays/resolve-static-pipeline.ts +0 -164
- package/dist/repo/shared_libs/plays/runtime-validation.ts +0 -395
- package/dist/repo/shared_libs/temporal/constants.ts +0 -39
- package/dist/repo/shared_libs/temporal/preview-config.ts +0 -153
package/dist/cli/index.js
CHANGED
|
@@ -70,6 +70,16 @@ var ConfigError = class extends DeeplineError {
|
|
|
70
70
|
var PROD_URL = "https://code.deepline.com";
|
|
71
71
|
var DEFAULT_TIMEOUT = 6e4;
|
|
72
72
|
var DEFAULT_MAX_RETRIES = 3;
|
|
73
|
+
var ACTIVE_DEEPLINE_ENV_FILE = ".env.deepline";
|
|
74
|
+
function isProdBaseUrl(baseUrl) {
|
|
75
|
+
return baseUrl.trim().replace(/\/$/, "") === PROD_URL;
|
|
76
|
+
}
|
|
77
|
+
function profileNameForBaseUrl(baseUrl) {
|
|
78
|
+
return isProdBaseUrl(baseUrl) ? "prod" : "dev";
|
|
79
|
+
}
|
|
80
|
+
function projectEnvStartDir() {
|
|
81
|
+
return process.env.DEEPLINE_PROJECT_ENV_DIR?.trim() || process.cwd();
|
|
82
|
+
}
|
|
73
83
|
function baseUrlSlug(baseUrl) {
|
|
74
84
|
let url;
|
|
75
85
|
try {
|
|
@@ -105,16 +115,52 @@ function parseEnvFile(filePath) {
|
|
|
105
115
|
}
|
|
106
116
|
return env;
|
|
107
117
|
}
|
|
108
|
-
function
|
|
118
|
+
function findNearestEnvFile(names, startDir = process.cwd()) {
|
|
109
119
|
let current = (0, import_node_path.resolve)(startDir);
|
|
110
120
|
while (true) {
|
|
111
|
-
const
|
|
112
|
-
|
|
121
|
+
for (const name of names) {
|
|
122
|
+
const filePath = (0, import_node_path.join)(current, name);
|
|
123
|
+
if ((0, import_node_fs.existsSync)(filePath)) return filePath;
|
|
124
|
+
}
|
|
113
125
|
const parent = (0, import_node_path.dirname)(current);
|
|
114
|
-
if (parent === current) return
|
|
126
|
+
if (parent === current) return null;
|
|
115
127
|
current = parent;
|
|
116
128
|
}
|
|
117
129
|
}
|
|
130
|
+
function findNearestEnv(names, startDir = process.cwd()) {
|
|
131
|
+
const filePath = findNearestEnvFile(names, startDir);
|
|
132
|
+
return filePath ? parseEnvFile(filePath) : {};
|
|
133
|
+
}
|
|
134
|
+
function findNearestWorktreeEnv(startDir = process.cwd()) {
|
|
135
|
+
return findNearestEnv([".env.worktree"], startDir);
|
|
136
|
+
}
|
|
137
|
+
function resolveProfileEnvFileNames() {
|
|
138
|
+
const explicitProfile = process.env.DEEPLINE_ENV_PROFILE?.trim() || process.env.DEEPLINE_PROFILE?.trim() || "";
|
|
139
|
+
const names = [];
|
|
140
|
+
if (explicitProfile) names.push(`.env.deepline.${explicitProfile}`);
|
|
141
|
+
const nodeEnv = process.env.NODE_ENV?.trim();
|
|
142
|
+
if (nodeEnv === "production") names.push(".env.deepline.prod");
|
|
143
|
+
else if (nodeEnv === "staging") names.push(".env.deepline.staging");
|
|
144
|
+
names.push(ACTIVE_DEEPLINE_ENV_FILE);
|
|
145
|
+
return names;
|
|
146
|
+
}
|
|
147
|
+
function resolveProjectAppEnvFileNames() {
|
|
148
|
+
const nodeEnv = process.env.NODE_ENV?.trim();
|
|
149
|
+
const names = [];
|
|
150
|
+
if (nodeEnv === "production") names.push(".env.prod");
|
|
151
|
+
if (nodeEnv === "staging") names.push(".env.staging");
|
|
152
|
+
names.push(".env.local", ".env");
|
|
153
|
+
return names;
|
|
154
|
+
}
|
|
155
|
+
function resolveBaseUrlFromEnvValues(env) {
|
|
156
|
+
return env.DEEPLINE_ORIGIN_URL?.trim() || env.DEEPLINE_API_BASE_URL?.trim() || "";
|
|
157
|
+
}
|
|
158
|
+
function loadProjectDeeplineEnv() {
|
|
159
|
+
return findNearestEnv(resolveProfileEnvFileNames(), projectEnvStartDir());
|
|
160
|
+
}
|
|
161
|
+
function loadProjectAppEnv() {
|
|
162
|
+
return findNearestEnv(resolveProjectAppEnvFileNames(), projectEnvStartDir());
|
|
163
|
+
}
|
|
118
164
|
function normalizeWorktreeBaseUrl(baseUrl, worktreeEnv = findNearestWorktreeEnv()) {
|
|
119
165
|
const trimmed = baseUrl.trim().replace(/\/$/, "");
|
|
120
166
|
if (!trimmed) return trimmed;
|
|
@@ -166,6 +212,10 @@ function autoDetectBaseUrl() {
|
|
|
166
212
|
if (envOrigin) return normalizeWorktreeBaseUrl(envOrigin);
|
|
167
213
|
const envBase = process.env.DEEPLINE_API_BASE_URL?.trim();
|
|
168
214
|
if (envBase) return normalizeWorktreeBaseUrl(envBase);
|
|
215
|
+
const projectDeeplineBaseUrl = resolveBaseUrlFromEnvValues(loadProjectDeeplineEnv());
|
|
216
|
+
if (projectDeeplineBaseUrl) return normalizeWorktreeBaseUrl(projectDeeplineBaseUrl);
|
|
217
|
+
const projectAppBaseUrl = resolveBaseUrlFromEnvValues(loadProjectAppEnv());
|
|
218
|
+
if (projectAppBaseUrl) return normalizeWorktreeBaseUrl(projectAppBaseUrl);
|
|
169
219
|
const worktreeBaseUrl = resolveWorktreeBaseUrl();
|
|
170
220
|
if (worktreeBaseUrl) return worktreeBaseUrl;
|
|
171
221
|
const globalEnv = loadGlobalCliEnv();
|
|
@@ -177,7 +227,9 @@ function resolveConfig(options) {
|
|
|
177
227
|
const requestedBaseUrl = options?.baseUrl?.trim() || autoDetectBaseUrl();
|
|
178
228
|
const baseUrl = normalizeWorktreeBaseUrl(requestedBaseUrl);
|
|
179
229
|
const cliEnv = loadCliEnv(baseUrl);
|
|
180
|
-
const
|
|
230
|
+
const projectDeeplineEnv = loadProjectDeeplineEnv();
|
|
231
|
+
const projectAppEnv = loadProjectAppEnv();
|
|
232
|
+
const apiKey = options?.apiKey?.trim() || process.env.DEEPLINE_API_KEY?.trim() || projectDeeplineEnv.DEEPLINE_API_KEY || projectAppEnv.DEEPLINE_API_KEY || cliEnv.DEEPLINE_API_KEY || "";
|
|
181
233
|
if (!apiKey) {
|
|
182
234
|
throw new ConfigError(
|
|
183
235
|
`No API key found. Set DEEPLINE_API_KEY env var, pass apiKey option, or run: deepline auth register`
|
|
@@ -190,10 +242,32 @@ function resolveConfig(options) {
|
|
|
190
242
|
maxRetries: options?.maxRetries ?? DEFAULT_MAX_RETRIES
|
|
191
243
|
};
|
|
192
244
|
}
|
|
245
|
+
function mergeEnvFile(filePath, values) {
|
|
246
|
+
const existing = (0, import_node_fs.existsSync)(filePath) ? parseEnvFile(filePath) : {};
|
|
247
|
+
const merged = { ...existing, ...values };
|
|
248
|
+
const dir = (0, import_node_path.dirname)(filePath);
|
|
249
|
+
if (!(0, import_node_fs.existsSync)(dir)) (0, import_node_fs.mkdirSync)(dir, { recursive: true });
|
|
250
|
+
const lines = Object.entries(merged).filter(([, value]) => value !== "").map(([key, value]) => `${key}=${value}`);
|
|
251
|
+
(0, import_node_fs.writeFileSync)(filePath, `${lines.join("\n")}
|
|
252
|
+
`, "utf-8");
|
|
253
|
+
}
|
|
254
|
+
function saveProjectDeeplineEnvValues(baseUrl, values, startDir = projectEnvStartDir()) {
|
|
255
|
+
const root = (0, import_node_path.resolve)(startDir);
|
|
256
|
+
const profile = profileNameForBaseUrl(baseUrl);
|
|
257
|
+
const files = [
|
|
258
|
+
(0, import_node_path.join)(root, ACTIVE_DEEPLINE_ENV_FILE),
|
|
259
|
+
(0, import_node_path.join)(root, `.env.deepline.${profile}`)
|
|
260
|
+
];
|
|
261
|
+
if (profile === "dev") files.push((0, import_node_path.join)(root, ".env"));
|
|
262
|
+
for (const filePath of files) {
|
|
263
|
+
mergeEnvFile(filePath, values);
|
|
264
|
+
}
|
|
265
|
+
return files;
|
|
266
|
+
}
|
|
193
267
|
|
|
194
268
|
// src/version.ts
|
|
195
|
-
var SDK_VERSION = "0.1.
|
|
196
|
-
var SDK_API_CONTRACT = "2026-
|
|
269
|
+
var SDK_VERSION = "0.1.20";
|
|
270
|
+
var SDK_API_CONTRACT = "2026-05-runs-v2";
|
|
197
271
|
|
|
198
272
|
// ../shared_libs/play-runtime/coordinator-headers.ts
|
|
199
273
|
var COORDINATOR_INTERNAL_TOKEN_HEADER = "x-deepline-internal-token";
|
|
@@ -299,7 +373,8 @@ var HttpClient = class {
|
|
|
299
373
|
parsed = body;
|
|
300
374
|
}
|
|
301
375
|
if (!response.ok) {
|
|
302
|
-
const
|
|
376
|
+
const errorValue = typeof parsed === "object" && parsed && "error" in parsed ? parsed.error : void 0;
|
|
377
|
+
const msg = typeof errorValue === "string" ? errorValue : errorValue && typeof errorValue === "object" && "message" in errorValue && typeof errorValue.message === "string" ? errorValue.message : typeof parsed === "object" && parsed && "message" in parsed && typeof parsed.message === "string" ? parsed.message : `HTTP ${response.status}`;
|
|
303
378
|
throw new DeeplineError(msg, response.status, "API_ERROR", {
|
|
304
379
|
response: parsed
|
|
305
380
|
});
|
|
@@ -386,8 +461,12 @@ var HttpClient = class {
|
|
|
386
461
|
* @param path - API path
|
|
387
462
|
* @param body - Request body (will be JSON-serialized)
|
|
388
463
|
*/
|
|
389
|
-
async post(path, body) {
|
|
390
|
-
return this.request(path, {
|
|
464
|
+
async post(path, body, headers) {
|
|
465
|
+
return this.request(path, {
|
|
466
|
+
method: "POST",
|
|
467
|
+
body,
|
|
468
|
+
headers
|
|
469
|
+
});
|
|
391
470
|
}
|
|
392
471
|
/**
|
|
393
472
|
* Send a DELETE request.
|
|
@@ -467,6 +546,7 @@ function sleep(ms) {
|
|
|
467
546
|
|
|
468
547
|
// src/client.ts
|
|
469
548
|
var TERMINAL_PLAY_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
|
|
549
|
+
var INCLUDE_TOOL_METADATA_HEADER = "x-deepline-include-tool-metadata";
|
|
470
550
|
function isRecord(value) {
|
|
471
551
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
472
552
|
}
|
|
@@ -499,6 +579,7 @@ function mapLegacyTemporalStatus(status) {
|
|
|
499
579
|
var DeeplineClient = class {
|
|
500
580
|
http;
|
|
501
581
|
config;
|
|
582
|
+
runs;
|
|
502
583
|
/**
|
|
503
584
|
* @param options - Optional overrides for API key, base URL, timeout, and retries.
|
|
504
585
|
* @throws {@link ConfigError} if no API key can be resolved from any source.
|
|
@@ -506,6 +587,13 @@ var DeeplineClient = class {
|
|
|
506
587
|
constructor(options) {
|
|
507
588
|
this.config = resolveConfig(options);
|
|
508
589
|
this.http = new HttpClient(this.config);
|
|
590
|
+
this.runs = {
|
|
591
|
+
get: (runId) => this.getRunStatus(runId),
|
|
592
|
+
list: (options2) => this.listRuns(options2),
|
|
593
|
+
tail: (runId, options2) => this.tailRun(runId, options2),
|
|
594
|
+
logs: (runId, options2) => this.getRunLogs(runId, options2),
|
|
595
|
+
stop: (runId, options2) => this.stopRun(runId, options2)
|
|
596
|
+
};
|
|
509
597
|
}
|
|
510
598
|
/** The resolved base URL this client is targeting (e.g. `"http://localhost:3000"`). */
|
|
511
599
|
get baseUrl() {
|
|
@@ -594,6 +682,31 @@ var DeeplineClient = class {
|
|
|
594
682
|
);
|
|
595
683
|
return res.tools;
|
|
596
684
|
}
|
|
685
|
+
/**
|
|
686
|
+
* Search available tools using Deepline's ranked backend search.
|
|
687
|
+
*
|
|
688
|
+
* This is the same discovery surface used by the legacy CLI: it ranks across
|
|
689
|
+
* tool metadata, categories, agent guidance, and input schema fields.
|
|
690
|
+
*/
|
|
691
|
+
async searchTools(options = {}) {
|
|
692
|
+
const params = new URLSearchParams();
|
|
693
|
+
const query = options.query?.trim() ?? "";
|
|
694
|
+
params.set("q", query);
|
|
695
|
+
params.set(
|
|
696
|
+
"include_search_debug",
|
|
697
|
+
options.includeSearchDebug ? "true" : "false"
|
|
698
|
+
);
|
|
699
|
+
params.set("search_mode", options.searchMode ?? "v2");
|
|
700
|
+
if (options.categories?.trim()) {
|
|
701
|
+
params.set("categories", options.categories.trim());
|
|
702
|
+
}
|
|
703
|
+
if (options.searchTerms?.trim()) {
|
|
704
|
+
params.set("search_terms", options.searchTerms.trim());
|
|
705
|
+
}
|
|
706
|
+
return this.http.get(
|
|
707
|
+
`/api/v2/integrations/list?${params.toString()}`
|
|
708
|
+
);
|
|
709
|
+
}
|
|
597
710
|
/**
|
|
598
711
|
* Get detailed metadata for a single tool.
|
|
599
712
|
*
|
|
@@ -629,12 +742,17 @@ var DeeplineClient = class {
|
|
|
629
742
|
* Top-level fields such as `status`, `job_id`, and `billing` describe the
|
|
630
743
|
* Deepline execution.
|
|
631
744
|
*/
|
|
632
|
-
async executeTool(toolId, input) {
|
|
745
|
+
async executeTool(toolId, input, options) {
|
|
746
|
+
const headers = options?.includeToolMetadata ? { [INCLUDE_TOOL_METADATA_HEADER]: "true" } : void 0;
|
|
633
747
|
return this.http.post(
|
|
634
748
|
`/api/v2/integrations/${encodeURIComponent(toolId)}/execute`,
|
|
635
|
-
{ payload: input }
|
|
749
|
+
{ payload: input },
|
|
750
|
+
headers
|
|
636
751
|
);
|
|
637
752
|
}
|
|
753
|
+
async executeToolRaw(toolId, input, options) {
|
|
754
|
+
return this.executeTool(toolId, input, options);
|
|
755
|
+
}
|
|
638
756
|
async queryCustomerDb(input) {
|
|
639
757
|
return this.http.post("/api/v2/db/query", {
|
|
640
758
|
sql: input.sql,
|
|
@@ -683,6 +801,7 @@ var DeeplineClient = class {
|
|
|
683
801
|
...request.revisionId ? { revisionId: request.revisionId } : {},
|
|
684
802
|
...request.artifactStorageKey ? { artifactStorageKey: request.artifactStorageKey } : {},
|
|
685
803
|
...request.sourceCode ? { sourceCode: request.sourceCode } : {},
|
|
804
|
+
...request.sourceFiles ? { sourceFiles: request.sourceFiles } : {},
|
|
686
805
|
..."staticPipeline" in request ? { staticPipeline: request.staticPipeline } : {},
|
|
687
806
|
...request.artifactHash ? { artifactHash: request.artifactHash } : {},
|
|
688
807
|
...request.graphHash ? { graphHash: request.graphHash } : {},
|
|
@@ -707,6 +826,7 @@ var DeeplineClient = class {
|
|
|
707
826
|
...request.revisionId ? { revisionId: request.revisionId } : {},
|
|
708
827
|
...request.artifactStorageKey ? { artifactStorageKey: request.artifactStorageKey } : {},
|
|
709
828
|
...request.sourceCode ? { sourceCode: request.sourceCode } : {},
|
|
829
|
+
...request.sourceFiles ? { sourceFiles: request.sourceFiles } : {},
|
|
710
830
|
..."staticPipeline" in request ? { staticPipeline: request.staticPipeline } : {},
|
|
711
831
|
...request.artifactHash ? { artifactHash: request.artifactHash } : {},
|
|
712
832
|
...request.graphHash ? { graphHash: request.graphHash } : {},
|
|
@@ -743,6 +863,7 @@ var DeeplineClient = class {
|
|
|
743
863
|
const compilerManifest = input.compilerManifest ?? await this.compilePlayManifest({
|
|
744
864
|
name: input.name,
|
|
745
865
|
sourceCode: input.sourceCode,
|
|
866
|
+
sourceFiles: input.sourceFiles,
|
|
746
867
|
artifact: input.artifact
|
|
747
868
|
});
|
|
748
869
|
return this.http.post("/api/v2/plays/artifacts", {
|
|
@@ -757,6 +878,7 @@ var DeeplineClient = class {
|
|
|
757
878
|
compilerManifest: artifact.compilerManifest ?? await this.compilePlayManifest({
|
|
758
879
|
name: artifact.name,
|
|
759
880
|
sourceCode: artifact.sourceCode,
|
|
881
|
+
sourceFiles: artifact.sourceFiles,
|
|
760
882
|
artifact: artifact.artifact
|
|
761
883
|
})
|
|
762
884
|
}))
|
|
@@ -783,11 +905,13 @@ var DeeplineClient = class {
|
|
|
783
905
|
const compilerManifest = input.compilerManifest ?? await this.compilePlayManifest({
|
|
784
906
|
name: input.name,
|
|
785
907
|
sourceCode: input.sourceCode,
|
|
908
|
+
sourceFiles: input.sourceFiles,
|
|
786
909
|
artifact: input.artifact
|
|
787
910
|
});
|
|
788
911
|
const registeredArtifact = await this.registerPlayArtifact({
|
|
789
912
|
name: input.name,
|
|
790
913
|
sourceCode: input.sourceCode,
|
|
914
|
+
sourceFiles: input.sourceFiles,
|
|
791
915
|
artifact: input.artifact,
|
|
792
916
|
compilerManifest,
|
|
793
917
|
publish: false
|
|
@@ -847,11 +971,13 @@ var DeeplineClient = class {
|
|
|
847
971
|
const compilerManifest = options?.compilerManifest ?? await this.compilePlayManifest({
|
|
848
972
|
name,
|
|
849
973
|
sourceCode,
|
|
974
|
+
sourceFiles: options?.sourceFiles,
|
|
850
975
|
artifact
|
|
851
976
|
});
|
|
852
977
|
const registeredArtifact = await this.registerPlayArtifact({
|
|
853
978
|
name,
|
|
854
979
|
sourceCode,
|
|
980
|
+
sourceFiles: options?.sourceFiles,
|
|
855
981
|
artifact,
|
|
856
982
|
compilerManifest,
|
|
857
983
|
publish: false
|
|
@@ -1035,6 +1161,112 @@ var DeeplineClient = class {
|
|
|
1035
1161
|
);
|
|
1036
1162
|
return response.runs ?? [];
|
|
1037
1163
|
}
|
|
1164
|
+
/**
|
|
1165
|
+
* Get a run by id using the public runs resource model.
|
|
1166
|
+
*
|
|
1167
|
+
* This is the SDK equivalent of:
|
|
1168
|
+
*
|
|
1169
|
+
* ```bash
|
|
1170
|
+
* deepline runs get <run-id> --json
|
|
1171
|
+
* ```
|
|
1172
|
+
*/
|
|
1173
|
+
async getRunStatus(runId) {
|
|
1174
|
+
const response = await this.http.get(
|
|
1175
|
+
`/api/v2/runs/${encodeURIComponent(runId)}`
|
|
1176
|
+
);
|
|
1177
|
+
return normalizePlayStatus(response);
|
|
1178
|
+
}
|
|
1179
|
+
/**
|
|
1180
|
+
* List play runs using the public runs resource model.
|
|
1181
|
+
*
|
|
1182
|
+
* This is the SDK equivalent of:
|
|
1183
|
+
*
|
|
1184
|
+
* ```bash
|
|
1185
|
+
* deepline runs list --play <play-name> --status failed --json
|
|
1186
|
+
* ```
|
|
1187
|
+
*/
|
|
1188
|
+
async listRuns(options) {
|
|
1189
|
+
const playName = options.play.trim();
|
|
1190
|
+
if (!playName) {
|
|
1191
|
+
throw new Error("runs.list requires options.play.");
|
|
1192
|
+
}
|
|
1193
|
+
const params = new URLSearchParams({ play: playName });
|
|
1194
|
+
const status = options.status?.trim();
|
|
1195
|
+
if (status) {
|
|
1196
|
+
params.set("status", status);
|
|
1197
|
+
}
|
|
1198
|
+
const response = await this.http.get(
|
|
1199
|
+
`/api/v2/runs?${params.toString()}`
|
|
1200
|
+
);
|
|
1201
|
+
return response.runs ?? [];
|
|
1202
|
+
}
|
|
1203
|
+
/**
|
|
1204
|
+
* Fetch the lightweight tail status for a run using the public runs resource model.
|
|
1205
|
+
*
|
|
1206
|
+
* This is the SDK equivalent of:
|
|
1207
|
+
*
|
|
1208
|
+
* ```bash
|
|
1209
|
+
* deepline runs tail <run-id> --json
|
|
1210
|
+
* ```
|
|
1211
|
+
*/
|
|
1212
|
+
async tailRun(runId, options) {
|
|
1213
|
+
const afterLogIndex = typeof options?.afterLogIndex === "number" ? options.afterLogIndex : typeof options?.cursor === "number" ? options.cursor : typeof options?.cursor === "string" && options.cursor.trim() ? Number(options.cursor) : void 0;
|
|
1214
|
+
const params = new URLSearchParams();
|
|
1215
|
+
if (Number.isFinite(afterLogIndex)) {
|
|
1216
|
+
params.set("afterLogIndex", String(Number(afterLogIndex)));
|
|
1217
|
+
}
|
|
1218
|
+
if (typeof options?.waitMs === "number") {
|
|
1219
|
+
params.set("waitMs", String(options.waitMs));
|
|
1220
|
+
}
|
|
1221
|
+
if (options?.terminalOnly) {
|
|
1222
|
+
params.set("terminalOnly", "true");
|
|
1223
|
+
}
|
|
1224
|
+
const suffix = params.toString() ? `?${params.toString()}` : "";
|
|
1225
|
+
const response = await this.http.get(
|
|
1226
|
+
`/api/v2/runs/${encodeURIComponent(runId)}/tail${suffix}`
|
|
1227
|
+
);
|
|
1228
|
+
return normalizePlayStatus(response);
|
|
1229
|
+
}
|
|
1230
|
+
/**
|
|
1231
|
+
* Fetch persisted logs for a run using the public runs resource model.
|
|
1232
|
+
*
|
|
1233
|
+
* This is the SDK equivalent of:
|
|
1234
|
+
*
|
|
1235
|
+
* ```bash
|
|
1236
|
+
* deepline runs logs <run-id> --limit 200 --json
|
|
1237
|
+
* ```
|
|
1238
|
+
*/
|
|
1239
|
+
async getRunLogs(runId, options) {
|
|
1240
|
+
const status = await this.getRunStatus(runId);
|
|
1241
|
+
const logs = status.progress?.logs ?? [];
|
|
1242
|
+
const limit = typeof options?.limit === "number" && Number.isFinite(options.limit) ? Math.max(0, Math.trunc(options.limit)) : 200;
|
|
1243
|
+
const entries = logs.slice(Math.max(0, logs.length - limit));
|
|
1244
|
+
return {
|
|
1245
|
+
runId: status.runId,
|
|
1246
|
+
totalCount: logs.length,
|
|
1247
|
+
returnedCount: entries.length,
|
|
1248
|
+
firstSequence: logs.length === 0 ? null : logs.length - entries.length + 1,
|
|
1249
|
+
lastSequence: logs.length === 0 ? null : logs.length,
|
|
1250
|
+
truncated: logs.length > entries.length,
|
|
1251
|
+
hasMore: logs.length > entries.length,
|
|
1252
|
+
entries
|
|
1253
|
+
};
|
|
1254
|
+
}
|
|
1255
|
+
/**
|
|
1256
|
+
* Stop a run by id using the public runs resource model.
|
|
1257
|
+
*
|
|
1258
|
+
* This is the SDK equivalent of:
|
|
1259
|
+
*
|
|
1260
|
+
* ```bash
|
|
1261
|
+
* deepline runs stop <run-id> --reason "stale lock" --json
|
|
1262
|
+
* ```
|
|
1263
|
+
*/
|
|
1264
|
+
async stopRun(runId, options) {
|
|
1265
|
+
return this.http.post(
|
|
1266
|
+
`/api/v2/runs/${encodeURIComponent(runId)}/stop`,
|
|
1267
|
+
options?.reason ? { reason: options.reason } : {}
|
|
1268
|
+
);
|
|
1269
|
+
}
|
|
1038
1270
|
async listPlays() {
|
|
1039
1271
|
const response = await this.http.get(
|
|
1040
1272
|
"/api/v2/plays"
|
|
@@ -1421,6 +1653,7 @@ function saveEnvValues(values, baseUrl) {
|
|
|
1421
1653
|
const merged = { ...existing, ...values };
|
|
1422
1654
|
const lines = Object.entries(merged).filter(([, v]) => v !== "").map(([k, v]) => `${k}=${v}`);
|
|
1423
1655
|
(0, import_node_fs3.writeFileSync)(filePath, lines.join("\n") + "\n", "utf-8");
|
|
1656
|
+
saveProjectDeeplineEnvValues(baseUrl, values);
|
|
1424
1657
|
}
|
|
1425
1658
|
async function httpJson(method, url, apiKey, body) {
|
|
1426
1659
|
const headers = { "Content-Type": "application/json" };
|
|
@@ -2021,6 +2254,9 @@ function rowArray(value) {
|
|
|
2021
2254
|
function readNumber(value) {
|
|
2022
2255
|
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.trunc(value) : null;
|
|
2023
2256
|
}
|
|
2257
|
+
function numericStat(value) {
|
|
2258
|
+
return readNumber(value) ?? 0;
|
|
2259
|
+
}
|
|
2024
2260
|
function inferColumns(rows) {
|
|
2025
2261
|
const columns = [];
|
|
2026
2262
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -2100,6 +2336,31 @@ function extractCanonicalRowsInfo(statusOrResult) {
|
|
|
2100
2336
|
function percentText(numerator, denominator) {
|
|
2101
2337
|
return denominator > 0 ? `${numerator}/${denominator} (${Math.round(100 * numerator / denominator)}%)` : "0/0 (0%)";
|
|
2102
2338
|
}
|
|
2339
|
+
function isDatasetExecutionStatsInput(value) {
|
|
2340
|
+
return isRecord2(value) && isRecord2(value.columnStats) && Object.values(value.columnStats).every(isRecord2);
|
|
2341
|
+
}
|
|
2342
|
+
function extractDatasetExecutionStats(statusOrResult) {
|
|
2343
|
+
if (!isRecord2(statusOrResult)) {
|
|
2344
|
+
return null;
|
|
2345
|
+
}
|
|
2346
|
+
const direct = statusOrResult.dataset_execution_stats;
|
|
2347
|
+
if (isDatasetExecutionStatsInput(direct)) {
|
|
2348
|
+
return direct;
|
|
2349
|
+
}
|
|
2350
|
+
const nested = isRecord2(statusOrResult.result) ? statusOrResult.result.dataset_execution_stats : null;
|
|
2351
|
+
return isDatasetExecutionStatsInput(nested) ? nested : null;
|
|
2352
|
+
}
|
|
2353
|
+
function formatExecutionStats(raw, denominator) {
|
|
2354
|
+
return {
|
|
2355
|
+
queued: percentText(numericStat(raw.queued), denominator),
|
|
2356
|
+
running: percentText(numericStat(raw.running), denominator),
|
|
2357
|
+
"completed:executed": percentText(numericStat(raw.completed), denominator),
|
|
2358
|
+
"completed:reused": percentText(numericStat(raw.cached), denominator),
|
|
2359
|
+
"skipped:condition": percentText(numericStat(raw.skipped), denominator),
|
|
2360
|
+
"skipped:missed": percentText(numericStat(raw.missed), denominator),
|
|
2361
|
+
failed: percentText(numericStat(raw.failed), denominator)
|
|
2362
|
+
};
|
|
2363
|
+
}
|
|
2103
2364
|
function countPercentText(count, denominator) {
|
|
2104
2365
|
return denominator > 0 ? `${count} (${Math.round(100 * count / denominator)}%)` : "0 (0%)";
|
|
2105
2366
|
}
|
|
@@ -2192,7 +2453,7 @@ function compactCell(value) {
|
|
|
2192
2453
|
}
|
|
2193
2454
|
return compactScalar(parsed, 120);
|
|
2194
2455
|
}
|
|
2195
|
-
function buildDatasetStats(rows, totalRows = rows.length, columns = inferColumns(rows)) {
|
|
2456
|
+
function buildDatasetStats(rows, totalRows = rows.length, columns = inferColumns(rows), executionStats) {
|
|
2196
2457
|
const sanitized = sanitizeCsvProjectionInfo({ rows, columns });
|
|
2197
2458
|
const columnStats = {};
|
|
2198
2459
|
for (const column of sanitized.columns) {
|
|
@@ -2220,6 +2481,10 @@ function buildDatasetStats(rows, totalRows = rows.length, columns = inferColumns
|
|
|
2220
2481
|
non_empty: percentText(nonEmpty, denominator),
|
|
2221
2482
|
unique: valueCounts.size
|
|
2222
2483
|
};
|
|
2484
|
+
const rawExecutionStats = executionStats?.columnStats[column];
|
|
2485
|
+
if (rawExecutionStats) {
|
|
2486
|
+
stat3.execution = formatExecutionStats(rawExecutionStats, totalRows);
|
|
2487
|
+
}
|
|
2223
2488
|
if (sampleValue !== void 0 && sampleValueType) {
|
|
2224
2489
|
stat3.sample_value = sampleValue;
|
|
2225
2490
|
stat3.sample_type = sampleValueType;
|
|
@@ -2566,7 +2831,6 @@ var import_node_os4 = require("os");
|
|
|
2566
2831
|
var import_node_path5 = require("path");
|
|
2567
2832
|
var import_node_module = require("module");
|
|
2568
2833
|
var import_esbuild = require("esbuild");
|
|
2569
|
-
var import_typescript = __toESM(require("typescript"));
|
|
2570
2834
|
|
|
2571
2835
|
// ../shared_libs/play-runtime/backend.ts
|
|
2572
2836
|
var PLAY_RUNTIME_BACKENDS = {
|
|
@@ -2651,56 +2915,6 @@ function formatEsbuildMessage(message) {
|
|
|
2651
2915
|
const location = message.location ? `${message.location.file}:${message.location.line}:${message.location.column}` : null;
|
|
2652
2916
|
return location ? `${location} ${message.text}` : message.text;
|
|
2653
2917
|
}
|
|
2654
|
-
function formatTypeScriptDiagnostic(diagnostic) {
|
|
2655
|
-
if (!diagnostic.file) {
|
|
2656
|
-
const message2 = import_typescript.default.flattenDiagnosticMessageText(diagnostic.messageText, "\n").trim();
|
|
2657
|
-
return message2 || null;
|
|
2658
|
-
}
|
|
2659
|
-
const start = diagnostic.start ?? 0;
|
|
2660
|
-
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(start);
|
|
2661
|
-
const message = import_typescript.default.flattenDiagnosticMessageText(diagnostic.messageText, "\n").trim();
|
|
2662
|
-
if (!message) {
|
|
2663
|
-
return null;
|
|
2664
|
-
}
|
|
2665
|
-
return `${diagnostic.file.fileName}:${line + 1}:${character + 1} ${message}`;
|
|
2666
|
-
}
|
|
2667
|
-
function resolveBundledTypeRoots() {
|
|
2668
|
-
try {
|
|
2669
|
-
return [(0, import_node_path5.dirname)((0, import_node_path5.dirname)(playArtifactRequire.resolve("@types/node/package.json")))];
|
|
2670
|
-
} catch {
|
|
2671
|
-
return [];
|
|
2672
|
-
}
|
|
2673
|
-
}
|
|
2674
|
-
function typecheckPlaySource(input, adapter) {
|
|
2675
|
-
const rootNames = Array.from(
|
|
2676
|
-
/* @__PURE__ */ new Set([
|
|
2677
|
-
...input.importPolicy.localFiles,
|
|
2678
|
-
...input.importedPlayDependencies.map((dependency) => dependency.filePath)
|
|
2679
|
-
])
|
|
2680
|
-
);
|
|
2681
|
-
const sdkTypesPath = adapter.sdkTypesEntryFile ?? adapter.sdkEntryFile;
|
|
2682
|
-
const program = import_typescript.default.createProgram(rootNames, {
|
|
2683
|
-
target: import_typescript.default.ScriptTarget.ES2023,
|
|
2684
|
-
// SDK source uses fetch/RequestInit/URL and node-aware config helpers.
|
|
2685
|
-
// The play runtime import policy below still bans Node modules from play
|
|
2686
|
-
// source for workers_edge bundles.
|
|
2687
|
-
lib: ["lib.es2023.d.ts", "lib.dom.d.ts"],
|
|
2688
|
-
module: import_typescript.default.ModuleKind.ESNext,
|
|
2689
|
-
moduleResolution: import_typescript.default.ModuleResolutionKind.Bundler,
|
|
2690
|
-
paths: { deepline: [sdkTypesPath] },
|
|
2691
|
-
strict: true,
|
|
2692
|
-
skipLibCheck: true,
|
|
2693
|
-
noEmit: true,
|
|
2694
|
-
esModuleInterop: true,
|
|
2695
|
-
allowSyntheticDefaultImports: true,
|
|
2696
|
-
allowImportingTsExtensions: true,
|
|
2697
|
-
allowJs: true,
|
|
2698
|
-
resolveJsonModule: true,
|
|
2699
|
-
types: ["node"],
|
|
2700
|
-
typeRoots: resolveBundledTypeRoots()
|
|
2701
|
-
});
|
|
2702
|
-
return import_typescript.default.getPreEmitDiagnostics(program).map(formatTypeScriptDiagnostic).filter((message) => Boolean(message));
|
|
2703
|
-
}
|
|
2704
2918
|
function isLocalSpecifier(specifier) {
|
|
2705
2919
|
return specifier.startsWith("./") || specifier.startsWith("../") || specifier.startsWith("/") || specifier.startsWith("file:");
|
|
2706
2920
|
}
|
|
@@ -2724,11 +2938,8 @@ function assertWithinPlayWorkspace(input) {
|
|
|
2724
2938
|
if (isPathInsideDirectory(input.resolvedPath, input.workspace.rootDir)) {
|
|
2725
2939
|
return;
|
|
2726
2940
|
}
|
|
2727
|
-
const position = input.sourceFile.getLineAndCharacterOfPosition(
|
|
2728
|
-
input.node.getStart(input.sourceFile)
|
|
2729
|
-
);
|
|
2730
2941
|
throw new Error(
|
|
2731
|
-
`${input.importer}:${
|
|
2942
|
+
`${input.importer}:${input.line}:${input.column} Local play imports must stay inside the play workspace (${input.workspace.rootDir}). Import "${input.specifier}" resolved to ${input.resolvedPath}, which crosses into app/backend code. Use the public SDK/API surface or move shared helpers into the play workspace.`
|
|
2732
2943
|
);
|
|
2733
2944
|
}
|
|
2734
2945
|
function getPackageName(specifier) {
|
|
@@ -2738,72 +2949,135 @@ function getPackageName(specifier) {
|
|
|
2738
2949
|
}
|
|
2739
2950
|
return specifier.split("/")[0] ?? specifier;
|
|
2740
2951
|
}
|
|
2741
|
-
function scriptKindForFile(filePath) {
|
|
2742
|
-
const extension = (0, import_node_path5.extname)(filePath).toLowerCase();
|
|
2743
|
-
switch (extension) {
|
|
2744
|
-
case ".tsx":
|
|
2745
|
-
return import_typescript.default.ScriptKind.TSX;
|
|
2746
|
-
case ".jsx":
|
|
2747
|
-
return import_typescript.default.ScriptKind.JSX;
|
|
2748
|
-
case ".js":
|
|
2749
|
-
case ".mjs":
|
|
2750
|
-
case ".cjs":
|
|
2751
|
-
return import_typescript.default.ScriptKind.JS;
|
|
2752
|
-
case ".json":
|
|
2753
|
-
return import_typescript.default.ScriptKind.JSON;
|
|
2754
|
-
default:
|
|
2755
|
-
return import_typescript.default.ScriptKind.TS;
|
|
2756
|
-
}
|
|
2757
|
-
}
|
|
2758
2952
|
function isPlaySourceFile(filePath) {
|
|
2759
2953
|
return PLAY_SOURCE_FILE_PATTERN.test(filePath);
|
|
2760
2954
|
}
|
|
2761
|
-
function
|
|
2762
|
-
|
|
2763
|
-
|
|
2955
|
+
function stripCommentsToSpaces(source) {
|
|
2956
|
+
return source.replace(/\/\*[\s\S]*?\*\//g, (match) => match.replace(/[^\n]/g, " ")).replace(
|
|
2957
|
+
/(^|[^:])\/\/.*$/gm,
|
|
2958
|
+
(match, prefix) => prefix + " ".repeat(Math.max(0, match.length - prefix.length))
|
|
2959
|
+
);
|
|
2960
|
+
}
|
|
2961
|
+
function lineAndColumnAt(source, index) {
|
|
2962
|
+
const prefix = source.slice(0, index);
|
|
2963
|
+
const lines = prefix.split("\n");
|
|
2964
|
+
return { line: lines.length, column: lines[lines.length - 1].length + 1 };
|
|
2965
|
+
}
|
|
2966
|
+
function findSourceImportReferences(sourceCode) {
|
|
2967
|
+
const source = stripCommentsToSpaces(sourceCode);
|
|
2968
|
+
const references = [];
|
|
2969
|
+
const addReference = (specifier, specifierIndex, kind) => {
|
|
2970
|
+
if (!specifier) return;
|
|
2971
|
+
const position = lineAndColumnAt(sourceCode, specifierIndex);
|
|
2972
|
+
references.push({
|
|
2973
|
+
specifier,
|
|
2974
|
+
line: position.line,
|
|
2975
|
+
column: position.column,
|
|
2976
|
+
kind
|
|
2977
|
+
});
|
|
2978
|
+
};
|
|
2979
|
+
const staticImportPattern = /\b(?:import|export)\s+(?!type\b)(?:[\s\S]*?\s+from\s*)?(['"])([^'"\n]+)\1/g;
|
|
2980
|
+
for (const match of source.matchAll(staticImportPattern)) {
|
|
2981
|
+
addReference(match[2], match.index + match[0].lastIndexOf(match[1]), "static");
|
|
2982
|
+
}
|
|
2983
|
+
const dynamicImportPattern = /\bimport\s*\(\s*(['"])([^'"\n]+)\1/g;
|
|
2984
|
+
for (const match of source.matchAll(dynamicImportPattern)) {
|
|
2985
|
+
addReference(match[2], match.index + match[0].lastIndexOf(match[1]), "dynamic-import");
|
|
2986
|
+
}
|
|
2987
|
+
const requirePattern = /\brequire\s*\(\s*(['"])([^'"\n]+)\1/g;
|
|
2988
|
+
for (const match of source.matchAll(requirePattern)) {
|
|
2989
|
+
addReference(match[2], match.index + match[0].lastIndexOf(match[1]), "require");
|
|
2990
|
+
}
|
|
2991
|
+
const literalDynamicImportIndexes = new Set(
|
|
2992
|
+
[...source.matchAll(dynamicImportPattern)].map((match) => match.index)
|
|
2993
|
+
);
|
|
2994
|
+
for (const match of source.matchAll(/\bimport\s*\(/g)) {
|
|
2995
|
+
if (literalDynamicImportIndexes.has(match.index)) continue;
|
|
2996
|
+
const position = lineAndColumnAt(sourceCode, match.index);
|
|
2997
|
+
throw new Error(
|
|
2998
|
+
`:${position.line}:${position.column} Dynamic import() is not allowed in plays. Use static imports instead.`
|
|
2999
|
+
);
|
|
3000
|
+
}
|
|
3001
|
+
const literalRequireIndexes = new Set(
|
|
3002
|
+
[...source.matchAll(requirePattern)].map((match) => match.index)
|
|
3003
|
+
);
|
|
3004
|
+
for (const match of source.matchAll(/\brequire\s*\(/g)) {
|
|
3005
|
+
if (literalRequireIndexes.has(match.index)) continue;
|
|
3006
|
+
const position = lineAndColumnAt(sourceCode, match.index);
|
|
3007
|
+
throw new Error(
|
|
3008
|
+
`:${position.line}:${position.column} Dynamic require() is not allowed in plays. Use static imports or require("literal") only.`
|
|
3009
|
+
);
|
|
3010
|
+
}
|
|
3011
|
+
return references.sort(
|
|
3012
|
+
(left, right) => left.line === right.line ? left.column - right.column : left.line - right.line
|
|
3013
|
+
);
|
|
3014
|
+
}
|
|
3015
|
+
function unquoteStringLiteral(literal) {
|
|
3016
|
+
const trimmed = literal.trim();
|
|
3017
|
+
const quote = trimmed[0];
|
|
3018
|
+
if (quote !== '"' && quote !== "'" || trimmed[trimmed.length - 1] !== quote) {
|
|
3019
|
+
return null;
|
|
3020
|
+
}
|
|
3021
|
+
try {
|
|
3022
|
+
return JSON.parse(quote === '"' ? trimmed : `"${trimmed.slice(1, -1).replace(/"/g, '\\"')}"`);
|
|
3023
|
+
} catch {
|
|
3024
|
+
return trimmed.slice(1, -1);
|
|
3025
|
+
}
|
|
3026
|
+
}
|
|
3027
|
+
function findMatchingBrace(source, openIndex) {
|
|
3028
|
+
let depth = 0;
|
|
3029
|
+
let quote = null;
|
|
3030
|
+
let escaped = false;
|
|
3031
|
+
for (let index = openIndex; index < source.length; index += 1) {
|
|
3032
|
+
const char = source[index];
|
|
3033
|
+
if (quote) {
|
|
3034
|
+
if (escaped) {
|
|
3035
|
+
escaped = false;
|
|
3036
|
+
} else if (char === "\\") {
|
|
3037
|
+
escaped = true;
|
|
3038
|
+
} else if (char === quote) {
|
|
3039
|
+
quote = null;
|
|
3040
|
+
}
|
|
2764
3041
|
continue;
|
|
2765
3042
|
}
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
if (!matches) {
|
|
3043
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
3044
|
+
quote = char;
|
|
2769
3045
|
continue;
|
|
2770
3046
|
}
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
)
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
const
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
3047
|
+
if (char === "{") depth += 1;
|
|
3048
|
+
if (char === "}") {
|
|
3049
|
+
depth -= 1;
|
|
3050
|
+
if (depth === 0) return index;
|
|
3051
|
+
}
|
|
3052
|
+
}
|
|
3053
|
+
return -1;
|
|
3054
|
+
}
|
|
3055
|
+
function extractDefinedPlayName(sourceCode, _filePath) {
|
|
3056
|
+
const source = stripCommentsToSpaces(sourceCode);
|
|
3057
|
+
const callPattern = /(?:\b[A-Za-z_$][\w$]*\s*\.\s*)?\b(?:definePlay|defineWorkflow)\s*\(/g;
|
|
3058
|
+
for (const match of source.matchAll(callPattern)) {
|
|
3059
|
+
const openParen = match.index + match[0].length - 1;
|
|
3060
|
+
const firstArgStart = openParen + 1;
|
|
3061
|
+
const firstNonSpace = source.slice(firstArgStart).search(/\S/);
|
|
3062
|
+
if (firstNonSpace < 0) continue;
|
|
3063
|
+
const argIndex = firstArgStart + firstNonSpace;
|
|
3064
|
+
const quote = source[argIndex];
|
|
3065
|
+
if (quote === '"' || quote === "'") {
|
|
3066
|
+
const literalMatch = source.slice(argIndex).match(/^(['"])(?:\\.|(?!\1)[\s\S])*\1/);
|
|
3067
|
+
const value = literalMatch ? unquoteStringLiteral(literalMatch[0]) : null;
|
|
3068
|
+
if (value?.trim()) return value.trim();
|
|
3069
|
+
}
|
|
3070
|
+
if (quote === "{") {
|
|
3071
|
+
const closeBrace = findMatchingBrace(source, argIndex);
|
|
3072
|
+
if (closeBrace < 0) continue;
|
|
3073
|
+
const objectSource = source.slice(argIndex + 1, closeBrace);
|
|
3074
|
+
const idMatch = objectSource.match(/(?:^|[,{\s])(?:id|['"]id['"])\s*:\s*(['"])([\s\S]*?)\1/);
|
|
3075
|
+
if (idMatch?.[2]?.trim()) {
|
|
3076
|
+
return idMatch[2].trim();
|
|
2801
3077
|
}
|
|
2802
3078
|
}
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
visit(sourceFile);
|
|
2806
|
-
return detectedPlayName;
|
|
3079
|
+
}
|
|
3080
|
+
return null;
|
|
2807
3081
|
}
|
|
2808
3082
|
function getPackageRequireCandidates(fromFile) {
|
|
2809
3083
|
const candidates = [
|
|
@@ -3113,18 +3387,10 @@ async function analyzeSourceGraph(entryFile, adapter) {
|
|
|
3113
3387
|
if ((0, import_node_path5.extname)(absolutePath).toLowerCase() === ".json") {
|
|
3114
3388
|
return;
|
|
3115
3389
|
}
|
|
3116
|
-
const
|
|
3117
|
-
absolutePath,
|
|
3118
|
-
sourceCode2,
|
|
3119
|
-
import_typescript.default.ScriptTarget.Latest,
|
|
3120
|
-
true,
|
|
3121
|
-
scriptKindForFile(absolutePath)
|
|
3122
|
-
);
|
|
3123
|
-
const handleSpecifier = async (specifier, node, kind) => {
|
|
3390
|
+
const handleSpecifier = async (specifier, line, column, kind) => {
|
|
3124
3391
|
if (kind === "dynamic-import") {
|
|
3125
|
-
const position = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
3126
3392
|
throw new Error(
|
|
3127
|
-
`${absolutePath}:${
|
|
3393
|
+
`${absolutePath}:${line}:${column} Dynamic import() is not allowed in plays. Use static imports instead.`
|
|
3128
3394
|
);
|
|
3129
3395
|
}
|
|
3130
3396
|
if (NODE_BUILTIN_SET.has(specifier)) {
|
|
@@ -3138,16 +3404,15 @@ async function analyzeSourceGraph(entryFile, adapter) {
|
|
|
3138
3404
|
specifier,
|
|
3139
3405
|
resolvedPath: resolved,
|
|
3140
3406
|
workspace,
|
|
3141
|
-
|
|
3142
|
-
|
|
3407
|
+
line,
|
|
3408
|
+
column
|
|
3143
3409
|
});
|
|
3144
3410
|
if (resolved !== absoluteEntryFile && isPlaySourceFile(resolved)) {
|
|
3145
3411
|
const importedSource = await (0, import_promises2.readFile)(resolved, "utf-8");
|
|
3146
3412
|
const importedPlayName = extractDefinedPlayName(importedSource, resolved);
|
|
3147
3413
|
if (!importedPlayName) {
|
|
3148
|
-
const position = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
3149
3414
|
throw new Error(
|
|
3150
|
-
`${absolutePath}:${
|
|
3415
|
+
`${absolutePath}:${line}:${column} Imported play file "${specifier}" must export definePlay(...) so it can be runtime-composed.`
|
|
3151
3416
|
);
|
|
3152
3417
|
}
|
|
3153
3418
|
importedPlayDependencies.set(resolved, {
|
|
@@ -3160,44 +3425,28 @@ async function analyzeSourceGraph(entryFile, adapter) {
|
|
|
3160
3425
|
return;
|
|
3161
3426
|
}
|
|
3162
3427
|
if (specifier.includes(":")) {
|
|
3163
|
-
const position = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
3164
3428
|
throw new Error(
|
|
3165
|
-
`${absolutePath}:${
|
|
3429
|
+
`${absolutePath}:${line}:${column} Unsupported import specifier "${specifier}". Allowed imports are relative files, Node builtins, and installed packages.`
|
|
3166
3430
|
);
|
|
3167
3431
|
}
|
|
3168
3432
|
const packageImport = resolvePackageImport(specifier, absolutePath, adapter);
|
|
3169
3433
|
packages.set(packageImport.name, packageImport.version);
|
|
3170
3434
|
};
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
await handleSpecifier(
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
throw new Error(
|
|
3180
|
-
`${absolutePath}:${position.line + 1}:${position.character + 1} Dynamic import() is not allowed in plays. Use static imports instead.`
|
|
3181
|
-
);
|
|
3182
|
-
}
|
|
3183
|
-
await handleSpecifier(node.arguments[0].text, node, "dynamic-import");
|
|
3184
|
-
}
|
|
3185
|
-
if (import_typescript.default.isIdentifier(node.expression) && node.expression.text === "require") {
|
|
3186
|
-
const firstArgument = node.arguments[0];
|
|
3187
|
-
if (node.arguments.length !== 1 || !firstArgument || !import_typescript.default.isStringLiteralLike(firstArgument)) {
|
|
3188
|
-
const position = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
3189
|
-
throw new Error(
|
|
3190
|
-
`${absolutePath}:${position.line + 1}:${position.character + 1} Dynamic require() is not allowed in plays. Use static imports or require("literal") only.`
|
|
3191
|
-
);
|
|
3192
|
-
}
|
|
3193
|
-
await handleSpecifier(firstArgument.text, node, "require");
|
|
3194
|
-
}
|
|
3435
|
+
try {
|
|
3436
|
+
for (const reference of findSourceImportReferences(sourceCode2)) {
|
|
3437
|
+
await handleSpecifier(
|
|
3438
|
+
reference.specifier,
|
|
3439
|
+
reference.line,
|
|
3440
|
+
reference.column,
|
|
3441
|
+
reference.kind
|
|
3442
|
+
);
|
|
3195
3443
|
}
|
|
3196
|
-
|
|
3197
|
-
|
|
3444
|
+
} catch (error) {
|
|
3445
|
+
if (error instanceof Error && error.message.startsWith(":")) {
|
|
3446
|
+
throw new Error(`${absolutePath}${error.message}`);
|
|
3198
3447
|
}
|
|
3199
|
-
|
|
3200
|
-
|
|
3448
|
+
throw error;
|
|
3449
|
+
}
|
|
3201
3450
|
};
|
|
3202
3451
|
await visitFile(absoluteEntryFile);
|
|
3203
3452
|
const sourceCode = localFiles.get(absoluteEntryFile) ?? "";
|
|
@@ -3217,6 +3466,11 @@ async function analyzeSourceGraph(entryFile, adapter) {
|
|
|
3217
3466
|
const playName = extractDefinedPlayName(sourceCode, absoluteEntryFile);
|
|
3218
3467
|
return {
|
|
3219
3468
|
sourceCode,
|
|
3469
|
+
sourceFiles: Object.fromEntries(
|
|
3470
|
+
[...localFiles.entries()].sort(
|
|
3471
|
+
(left, right) => left[0].localeCompare(right[0])
|
|
3472
|
+
)
|
|
3473
|
+
),
|
|
3220
3474
|
sourceHash,
|
|
3221
3475
|
graphHash,
|
|
3222
3476
|
importPolicy: {
|
|
@@ -3280,8 +3534,7 @@ function normalizeSourceMapForRuntime(sourceMapText) {
|
|
|
3280
3534
|
parsed.sourceRoot = void 0;
|
|
3281
3535
|
return JSON.stringify(parsed);
|
|
3282
3536
|
}
|
|
3283
|
-
function
|
|
3284
|
-
const bundleBytes = Buffer.byteLength(bundledCode, "utf8");
|
|
3537
|
+
function getBundleSizeErrorForBytes(filePath, bundleBytes, artifactKind) {
|
|
3285
3538
|
if (bundleBytes > MAX_PLAY_BUNDLE_BYTES) {
|
|
3286
3539
|
return `${filePath} Play bundle exceeds the 30 MiB limit (${bundleBytes} bytes > ${MAX_PLAY_BUNDLE_BYTES} bytes).`;
|
|
3287
3540
|
}
|
|
@@ -3292,6 +3545,13 @@ function getBundleSizeError(filePath, bundledCode, artifactKind) {
|
|
|
3292
3545
|
}
|
|
3293
3546
|
return null;
|
|
3294
3547
|
}
|
|
3548
|
+
function getBundleSizeError(filePath, bundledCode, artifactKind) {
|
|
3549
|
+
return getBundleSizeErrorForBytes(
|
|
3550
|
+
filePath,
|
|
3551
|
+
Buffer.byteLength(bundledCode, "utf8"),
|
|
3552
|
+
artifactKind
|
|
3553
|
+
);
|
|
3554
|
+
}
|
|
3295
3555
|
async function runEsbuildForCjsNode(entryFile, importedPlayDependencies, adapter, exportName) {
|
|
3296
3556
|
const sdkAliasPlugin = localSdkAliasPlugin(adapter);
|
|
3297
3557
|
const playProxyPlugin = importedPlayProxyPlugin(importedPlayDependencies);
|
|
@@ -3424,6 +3684,23 @@ entry-export:${exportName}`
|
|
|
3424
3684
|
workers-harness:${harnessFingerprint}`
|
|
3425
3685
|
);
|
|
3426
3686
|
}
|
|
3687
|
+
const typecheckErrors = [
|
|
3688
|
+
...await adapter.typecheckPlaySource?.({
|
|
3689
|
+
sourceCode: analysis.sourceCode,
|
|
3690
|
+
sourcePath: absolutePath,
|
|
3691
|
+
importedFilePaths: [
|
|
3692
|
+
...analysis.importPolicy.localFiles,
|
|
3693
|
+
...analysis.importedPlayDependencies.map((dependency) => dependency.filePath)
|
|
3694
|
+
]
|
|
3695
|
+
}) ?? []
|
|
3696
|
+
];
|
|
3697
|
+
if (typecheckErrors.length > 0) {
|
|
3698
|
+
return {
|
|
3699
|
+
success: false,
|
|
3700
|
+
filePath: absolutePath,
|
|
3701
|
+
errors: typecheckErrors
|
|
3702
|
+
};
|
|
3703
|
+
}
|
|
3427
3704
|
const cachedArtifact = await readArtifactCache(analysis.graphHash, target, adapter);
|
|
3428
3705
|
const discoveredFiles = await adapter.discoverPackagedLocalFiles(absolutePath);
|
|
3429
3706
|
if (cachedArtifact) {
|
|
@@ -3443,6 +3720,7 @@ workers-harness:${harnessFingerprint}`
|
|
|
3443
3720
|
success: true,
|
|
3444
3721
|
artifact: { ...cachedArtifact, cacheHit: true },
|
|
3445
3722
|
sourceCode: analysis.sourceCode,
|
|
3723
|
+
sourceFiles: analysis.sourceFiles,
|
|
3446
3724
|
filePath: absolutePath,
|
|
3447
3725
|
playName: analysis.playName,
|
|
3448
3726
|
packagedFiles: discoveredFiles.files,
|
|
@@ -3450,24 +3728,6 @@ workers-harness:${harnessFingerprint}`
|
|
|
3450
3728
|
importedPlayDependencies: analysis.importedPlayDependencies
|
|
3451
3729
|
};
|
|
3452
3730
|
}
|
|
3453
|
-
const typecheckErrors = [
|
|
3454
|
-
...adapter.typecheckSdkTypes === false ? [] : typecheckPlaySource(analysis, adapter),
|
|
3455
|
-
...await adapter.typecheckPlaySource?.({
|
|
3456
|
-
sourceCode: analysis.sourceCode,
|
|
3457
|
-
sourcePath: absolutePath,
|
|
3458
|
-
importedFilePaths: [
|
|
3459
|
-
...analysis.importPolicy.localFiles,
|
|
3460
|
-
...analysis.importedPlayDependencies.map((dependency) => dependency.filePath)
|
|
3461
|
-
]
|
|
3462
|
-
}) ?? []
|
|
3463
|
-
];
|
|
3464
|
-
if (typecheckErrors.length > 0) {
|
|
3465
|
-
return {
|
|
3466
|
-
success: false,
|
|
3467
|
-
filePath: absolutePath,
|
|
3468
|
-
errors: typecheckErrors
|
|
3469
|
-
};
|
|
3470
|
-
}
|
|
3471
3731
|
const buildOutcome = target === PLAY_ARTIFACT_KINDS.esmWorkers ? await runEsbuildForEsmWorkers(absolutePath, analysis.importedPlayDependencies, adapter, exportName) : await runEsbuildForCjsNode(absolutePath, analysis.importedPlayDependencies, adapter, exportName);
|
|
3472
3732
|
if (Array.isArray(buildOutcome)) {
|
|
3473
3733
|
return {
|
|
@@ -3517,6 +3777,7 @@ workers-harness:${harnessFingerprint}`
|
|
|
3517
3777
|
success: true,
|
|
3518
3778
|
artifact,
|
|
3519
3779
|
sourceCode: analysis.sourceCode,
|
|
3780
|
+
sourceFiles: analysis.sourceFiles,
|
|
3520
3781
|
filePath: absolutePath,
|
|
3521
3782
|
playName: analysis.playName,
|
|
3522
3783
|
packagedFiles: discoveredFiles.files,
|
|
@@ -3598,7 +3859,6 @@ function resolveExecutionProfile(override) {
|
|
|
3598
3859
|
var import_node_crypto2 = require("crypto");
|
|
3599
3860
|
var import_promises3 = require("fs/promises");
|
|
3600
3861
|
var import_node_path6 = require("path");
|
|
3601
|
-
var import_typescript2 = __toESM(require("typescript"));
|
|
3602
3862
|
var SOURCE_EXTENSIONS2 = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs", ".json"];
|
|
3603
3863
|
function sha2562(buffer) {
|
|
3604
3864
|
return (0, import_node_crypto2.createHash)("sha256").update(buffer).digest("hex");
|
|
@@ -3610,94 +3870,181 @@ function contentTypeForFile(filePath) {
|
|
|
3610
3870
|
if (extension === ".txt") return "text/plain";
|
|
3611
3871
|
return "application/octet-stream";
|
|
3612
3872
|
}
|
|
3613
|
-
function
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
return import_typescript2.default.isIdentifier(target) && (target.text === "ctx" || target.text.endsWith("Ctx")) && node.expression.name.text === "csv";
|
|
3619
|
-
}
|
|
3620
|
-
function extractSourceFragment(source, node) {
|
|
3621
|
-
return source.slice(node.getStart(), node.getEnd()).trim();
|
|
3622
|
-
}
|
|
3623
|
-
function referencesInputIdentifier(node) {
|
|
3624
|
-
if (import_typescript2.default.isIdentifier(node) && node.text === "input") {
|
|
3625
|
-
return true;
|
|
3626
|
-
}
|
|
3627
|
-
return node.getChildren().some((child) => referencesInputIdentifier(child));
|
|
3873
|
+
function stripCommentsToSpaces2(source) {
|
|
3874
|
+
return source.replace(/\/\*[\s\S]*?\*\//g, (match) => match.replace(/[^\n]/g, " ")).replace(
|
|
3875
|
+
/(^|[^:])\/\/.*$/gm,
|
|
3876
|
+
(match, prefix) => prefix + " ".repeat(Math.max(0, match.length - prefix.length))
|
|
3877
|
+
);
|
|
3628
3878
|
}
|
|
3629
|
-
function
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
return import_typescript2.default.isIdentifier(node.expression) && node.expression.text === "input";
|
|
3635
|
-
}
|
|
3636
|
-
if (import_typescript2.default.isIdentifier(node)) {
|
|
3637
|
-
return node.text === "input";
|
|
3638
|
-
}
|
|
3639
|
-
if (import_typescript2.default.isParenthesizedExpression(node)) {
|
|
3640
|
-
return isRuntimeInputExpression(node.expression);
|
|
3879
|
+
function unquoteStringLiteral2(literal) {
|
|
3880
|
+
const trimmed = literal.trim();
|
|
3881
|
+
const quote = trimmed[0];
|
|
3882
|
+
if (quote !== '"' && quote !== "'" || trimmed[trimmed.length - 1] !== quote) {
|
|
3883
|
+
return null;
|
|
3641
3884
|
}
|
|
3642
|
-
|
|
3643
|
-
return
|
|
3885
|
+
try {
|
|
3886
|
+
return JSON.parse(quote === '"' ? trimmed : `"${trimmed.slice(1, -1).replace(/"/g, '\\"')}"`);
|
|
3887
|
+
} catch {
|
|
3888
|
+
return trimmed.slice(1, -1);
|
|
3644
3889
|
}
|
|
3645
|
-
|
|
3646
|
-
|
|
3890
|
+
}
|
|
3891
|
+
function splitTopLevelPlus(expression) {
|
|
3892
|
+
const parts = [];
|
|
3893
|
+
let start = 0;
|
|
3894
|
+
let depth = 0;
|
|
3895
|
+
let quote = null;
|
|
3896
|
+
let escaped = false;
|
|
3897
|
+
for (let index = 0; index < expression.length; index += 1) {
|
|
3898
|
+
const char = expression[index];
|
|
3899
|
+
if (quote) {
|
|
3900
|
+
if (escaped) {
|
|
3901
|
+
escaped = false;
|
|
3902
|
+
} else if (char === "\\") {
|
|
3903
|
+
escaped = true;
|
|
3904
|
+
} else if (char === quote) {
|
|
3905
|
+
quote = null;
|
|
3906
|
+
}
|
|
3907
|
+
continue;
|
|
3908
|
+
}
|
|
3909
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
3910
|
+
quote = char;
|
|
3911
|
+
continue;
|
|
3912
|
+
}
|
|
3913
|
+
if (char === "(" || char === "[" || char === "{") depth += 1;
|
|
3914
|
+
if (char === ")" || char === "]" || char === "}") depth -= 1;
|
|
3915
|
+
if (char === "+" && depth === 0) {
|
|
3916
|
+
parts.push(expression.slice(start, index));
|
|
3917
|
+
start = index + 1;
|
|
3918
|
+
}
|
|
3647
3919
|
}
|
|
3648
|
-
|
|
3920
|
+
if (parts.length === 0) return null;
|
|
3921
|
+
parts.push(expression.slice(start));
|
|
3922
|
+
return parts;
|
|
3649
3923
|
}
|
|
3650
|
-
function
|
|
3651
|
-
|
|
3652
|
-
|
|
3924
|
+
function stripOuterParens(expression) {
|
|
3925
|
+
let value = expression.trim();
|
|
3926
|
+
while (value.startsWith("(") && value.endsWith(")")) {
|
|
3927
|
+
value = value.slice(1, -1).trim();
|
|
3653
3928
|
}
|
|
3654
|
-
|
|
3655
|
-
|
|
3929
|
+
return value;
|
|
3930
|
+
}
|
|
3931
|
+
function isRuntimeInputExpression(expression) {
|
|
3932
|
+
return /(^|[^\w$])input([^\w$]|$)/.test(expression);
|
|
3933
|
+
}
|
|
3934
|
+
function resolveStringExpression(expression, constants) {
|
|
3935
|
+
const value = stripOuterParens(expression);
|
|
3936
|
+
if (/^(['"])(?:\\.|(?!\1)[\s\S])*\1$/.test(value)) {
|
|
3937
|
+
return unquoteStringLiteral2(value);
|
|
3656
3938
|
}
|
|
3657
|
-
if (
|
|
3658
|
-
return
|
|
3939
|
+
if (/^`(?:\\.|[^`$]|\$(?!\{))*`$/.test(value)) {
|
|
3940
|
+
return value.slice(1, -1);
|
|
3659
3941
|
}
|
|
3660
|
-
if (
|
|
3661
|
-
|
|
3662
|
-
for (const span of node.templateSpans) {
|
|
3663
|
-
const resolved = resolveStringExpression(span.expression, constants);
|
|
3664
|
-
if (resolved == null) {
|
|
3665
|
-
return null;
|
|
3666
|
-
}
|
|
3667
|
-
value += resolved + span.literal.text;
|
|
3668
|
-
}
|
|
3669
|
-
return value;
|
|
3942
|
+
if (/^[A-Za-z_$][\w$]*$/.test(value)) {
|
|
3943
|
+
return constants.get(value) ?? null;
|
|
3670
3944
|
}
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
const
|
|
3674
|
-
|
|
3675
|
-
return null;
|
|
3676
|
-
}
|
|
3677
|
-
return left + right;
|
|
3945
|
+
const parts = splitTopLevelPlus(value);
|
|
3946
|
+
if (parts) {
|
|
3947
|
+
const resolved = parts.map((part) => resolveStringExpression(part, constants));
|
|
3948
|
+
return resolved.every((part) => part != null) ? resolved.join("") : null;
|
|
3678
3949
|
}
|
|
3679
3950
|
return null;
|
|
3680
3951
|
}
|
|
3681
|
-
function collectTopLevelStringConstants(
|
|
3952
|
+
function collectTopLevelStringConstants(sourceCode) {
|
|
3682
3953
|
const constants = /* @__PURE__ */ new Map();
|
|
3683
|
-
|
|
3684
|
-
|
|
3954
|
+
const source = stripCommentsToSpaces2(sourceCode);
|
|
3955
|
+
for (const match of source.matchAll(/(?:^|\n)\s*const\s+([A-Za-z_$][\w$]*)\s*=\s*([^;\n]+)/g)) {
|
|
3956
|
+
const resolved = resolveStringExpression(match[2], constants);
|
|
3957
|
+
if (resolved != null) {
|
|
3958
|
+
constants.set(match[1], resolved);
|
|
3959
|
+
}
|
|
3960
|
+
}
|
|
3961
|
+
return constants;
|
|
3962
|
+
}
|
|
3963
|
+
function findMatchingGenericEnd(source, openIndex) {
|
|
3964
|
+
let depth = 0;
|
|
3965
|
+
let quote = null;
|
|
3966
|
+
let escaped = false;
|
|
3967
|
+
for (let index = openIndex; index < source.length; index += 1) {
|
|
3968
|
+
const char = source[index];
|
|
3969
|
+
if (quote) {
|
|
3970
|
+
if (escaped) {
|
|
3971
|
+
escaped = false;
|
|
3972
|
+
} else if (char === "\\") {
|
|
3973
|
+
escaped = true;
|
|
3974
|
+
} else if (char === quote) {
|
|
3975
|
+
quote = null;
|
|
3976
|
+
}
|
|
3685
3977
|
continue;
|
|
3686
3978
|
}
|
|
3687
|
-
if (
|
|
3979
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
3980
|
+
quote = char;
|
|
3688
3981
|
continue;
|
|
3689
3982
|
}
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3983
|
+
if (char === "<") depth += 1;
|
|
3984
|
+
if (char === ">") {
|
|
3985
|
+
depth -= 1;
|
|
3986
|
+
if (depth === 0) return index;
|
|
3987
|
+
}
|
|
3988
|
+
}
|
|
3989
|
+
return -1;
|
|
3990
|
+
}
|
|
3991
|
+
function findCallOpenParen(source, afterCsvIndex) {
|
|
3992
|
+
let index = afterCsvIndex;
|
|
3993
|
+
while (/\s/.test(source[index] ?? "")) index += 1;
|
|
3994
|
+
if (source[index] === "<") {
|
|
3995
|
+
const genericEnd = findMatchingGenericEnd(source, index);
|
|
3996
|
+
if (genericEnd < 0) return -1;
|
|
3997
|
+
index = genericEnd + 1;
|
|
3998
|
+
while (/\s/.test(source[index] ?? "")) index += 1;
|
|
3999
|
+
}
|
|
4000
|
+
return source[index] === "(" ? index : -1;
|
|
4001
|
+
}
|
|
4002
|
+
function firstCallArgument(source, openParen) {
|
|
4003
|
+
let depth = 0;
|
|
4004
|
+
let quote = null;
|
|
4005
|
+
let escaped = false;
|
|
4006
|
+
const start = openParen + 1;
|
|
4007
|
+
for (let index = start; index < source.length; index += 1) {
|
|
4008
|
+
const char = source[index];
|
|
4009
|
+
if (quote) {
|
|
4010
|
+
if (escaped) {
|
|
4011
|
+
escaped = false;
|
|
4012
|
+
} else if (char === "\\") {
|
|
4013
|
+
escaped = true;
|
|
4014
|
+
} else if (char === quote) {
|
|
4015
|
+
quote = null;
|
|
3697
4016
|
}
|
|
4017
|
+
continue;
|
|
4018
|
+
}
|
|
4019
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
4020
|
+
quote = char;
|
|
4021
|
+
continue;
|
|
4022
|
+
}
|
|
4023
|
+
if (char === "(" || char === "[" || char === "{") depth += 1;
|
|
4024
|
+
if (char === ")" && depth === 0) {
|
|
4025
|
+
const text = source.slice(start, index).trim();
|
|
4026
|
+
return text ? { text, start, end: index } : null;
|
|
3698
4027
|
}
|
|
4028
|
+
if (char === "," && depth === 0) {
|
|
4029
|
+
const text = source.slice(start, index).trim();
|
|
4030
|
+
return text ? { text, start, end: index } : null;
|
|
4031
|
+
}
|
|
4032
|
+
if (char === ")" || char === "]" || char === "}") depth -= 1;
|
|
3699
4033
|
}
|
|
3700
|
-
return
|
|
4034
|
+
return null;
|
|
4035
|
+
}
|
|
4036
|
+
function localImportSpecifiers(sourceCode) {
|
|
4037
|
+
const source = stripCommentsToSpaces2(sourceCode);
|
|
4038
|
+
const specifiers = [];
|
|
4039
|
+
for (const match of source.matchAll(
|
|
4040
|
+
/\b(?:import|export)\s+(?!type\b)(?:[\s\S]*?\s+from\s*)?['"]([^'"]+)['"]/g
|
|
4041
|
+
)) {
|
|
4042
|
+
if (match[1]?.startsWith(".")) specifiers.push(match[1]);
|
|
4043
|
+
}
|
|
4044
|
+
for (const match of source.matchAll(/\brequire\s*\(\s*(['"])(\.[^'"]*)\1\s*\)/g)) {
|
|
4045
|
+
specifiers.push(match[2]);
|
|
4046
|
+
}
|
|
4047
|
+
return specifiers;
|
|
3701
4048
|
}
|
|
3702
4049
|
async function fileExists2(filePath) {
|
|
3703
4050
|
try {
|
|
@@ -3742,69 +4089,60 @@ async function discoverPackagedLocalFiles(entryFile) {
|
|
|
3742
4089
|
}
|
|
3743
4090
|
visitedFiles.add(absolutePath);
|
|
3744
4091
|
const sourceCode = await (0, import_promises3.readFile)(absolutePath, "utf-8");
|
|
3745
|
-
const
|
|
3746
|
-
|
|
3747
|
-
sourceCode,
|
|
3748
|
-
import_typescript2.default.ScriptTarget.Latest,
|
|
3749
|
-
true,
|
|
3750
|
-
import_typescript2.default.ScriptKind.TS
|
|
3751
|
-
);
|
|
3752
|
-
const constants = collectTopLevelStringConstants(sourceFile);
|
|
4092
|
+
const scanSource = stripCommentsToSpaces2(sourceCode);
|
|
4093
|
+
const constants = collectTopLevelStringConstants(sourceCode);
|
|
3753
4094
|
const childVisits = [];
|
|
3754
|
-
const
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
4095
|
+
for (const match of scanSource.matchAll(/\b([A-Za-z_$][\w$]*)\s*\.\s*csv\b/g)) {
|
|
4096
|
+
const target = match[1];
|
|
4097
|
+
if (target !== "ctx" && !target.endsWith("Ctx")) {
|
|
4098
|
+
continue;
|
|
4099
|
+
}
|
|
4100
|
+
const openParen = findCallOpenParen(scanSource, match.index + match[0].length);
|
|
4101
|
+
if (openParen < 0) {
|
|
4102
|
+
continue;
|
|
4103
|
+
}
|
|
4104
|
+
const argument = firstCallArgument(scanSource, openParen);
|
|
4105
|
+
if (!argument) {
|
|
4106
|
+
unresolved.push({
|
|
4107
|
+
sourceFragment: "ctx.csv()",
|
|
4108
|
+
message: "ctx.csv() requires a file path string or input reference."
|
|
4109
|
+
});
|
|
4110
|
+
} else if (!isRuntimeInputExpression(argument.text)) {
|
|
4111
|
+
const resolvedPath = resolveStringExpression(argument.text, constants);
|
|
4112
|
+
if (resolvedPath == null) {
|
|
3758
4113
|
unresolved.push({
|
|
3759
|
-
sourceFragment:
|
|
3760
|
-
message: "ctx.csv()
|
|
4114
|
+
sourceFragment: sourceCode.slice(argument.start, argument.end).trim(),
|
|
4115
|
+
message: "Could not resolve this ctx.csv(...) path at submit time. Use a string literal, a top-level const string, or pass a runtime input like input.file."
|
|
3761
4116
|
});
|
|
3762
|
-
} else
|
|
3763
|
-
const
|
|
3764
|
-
if (resolvedPath
|
|
4117
|
+
} else {
|
|
4118
|
+
const absoluteCsvPath = (0, import_node_path6.resolve)((0, import_node_path6.dirname)(absolutePath), resolvedPath);
|
|
4119
|
+
if ((0, import_node_path6.isAbsolute)(resolvedPath) || !isPathInsideDirectory2(absoluteCsvPath, packagingRoot)) {
|
|
3765
4120
|
unresolved.push({
|
|
3766
|
-
sourceFragment:
|
|
3767
|
-
message: "
|
|
3768
|
-
});
|
|
3769
|
-
} else {
|
|
3770
|
-
const absoluteCsvPath = (0, import_node_path6.resolve)((0, import_node_path6.dirname)(absolutePath), resolvedPath);
|
|
3771
|
-
if ((0, import_node_path6.isAbsolute)(resolvedPath) || !isPathInsideDirectory2(absoluteCsvPath, packagingRoot)) {
|
|
3772
|
-
unresolved.push({
|
|
3773
|
-
sourceFragment: extractSourceFragment(sourceCode, argument),
|
|
3774
|
-
message: "ctx.csv(...) packaged file paths must be relative paths inside the play directory. Pass external files at runtime with input.file instead."
|
|
3775
|
-
});
|
|
3776
|
-
return;
|
|
3777
|
-
}
|
|
3778
|
-
const buffer = await (0, import_promises3.readFile)(absoluteCsvPath);
|
|
3779
|
-
const stats = await (0, import_promises3.stat)(absoluteCsvPath);
|
|
3780
|
-
files.set(absoluteCsvPath, {
|
|
3781
|
-
sourceFragment: extractSourceFragment(sourceCode, argument),
|
|
3782
|
-
logicalPath: resolvedPath,
|
|
3783
|
-
absolutePath: absoluteCsvPath,
|
|
3784
|
-
bytes: stats.size,
|
|
3785
|
-
contentHash: sha2562(buffer),
|
|
3786
|
-
contentType: contentTypeForFile(absoluteCsvPath)
|
|
4121
|
+
sourceFragment: sourceCode.slice(argument.start, argument.end).trim(),
|
|
4122
|
+
message: "ctx.csv(...) packaged file paths must be relative paths inside the play directory. Pass external files at runtime with input.file instead."
|
|
3787
4123
|
});
|
|
4124
|
+
continue;
|
|
3788
4125
|
}
|
|
4126
|
+
const buffer = await (0, import_promises3.readFile)(absoluteCsvPath);
|
|
4127
|
+
const stats = await (0, import_promises3.stat)(absoluteCsvPath);
|
|
4128
|
+
files.set(absoluteCsvPath, {
|
|
4129
|
+
sourceFragment: sourceCode.slice(argument.start, argument.end).trim(),
|
|
4130
|
+
logicalPath: resolvedPath,
|
|
4131
|
+
absolutePath: absoluteCsvPath,
|
|
4132
|
+
bytes: stats.size,
|
|
4133
|
+
contentHash: sha2562(buffer),
|
|
4134
|
+
contentType: contentTypeForFile(absoluteCsvPath)
|
|
4135
|
+
});
|
|
3789
4136
|
}
|
|
3790
4137
|
}
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
)
|
|
3796
|
-
)
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
childVisits.push(
|
|
3800
|
-
resolveLocalImport2(absolutePath, node.arguments[0].text).then(
|
|
3801
|
-
(resolvedImport) => visitSourceFile(resolvedImport)
|
|
3802
|
-
)
|
|
3803
|
-
);
|
|
3804
|
-
}
|
|
3805
|
-
await Promise.all(node.getChildren(sourceFile).map((child) => visitNode(child)));
|
|
3806
|
-
};
|
|
3807
|
-
await visitNode(sourceFile);
|
|
4138
|
+
}
|
|
4139
|
+
for (const specifier of localImportSpecifiers(sourceCode)) {
|
|
4140
|
+
childVisits.push(
|
|
4141
|
+
resolveLocalImport2(absolutePath, specifier).then(
|
|
4142
|
+
(resolvedImport) => visitSourceFile(resolvedImport)
|
|
4143
|
+
)
|
|
4144
|
+
);
|
|
4145
|
+
}
|
|
3808
4146
|
await Promise.all(childVisits);
|
|
3809
4147
|
};
|
|
3810
4148
|
await visitSourceFile(absoluteEntryFile);
|
|
@@ -3816,7 +4154,7 @@ async function discoverPackagedLocalFiles(entryFile) {
|
|
|
3816
4154
|
|
|
3817
4155
|
// src/plays/bundle-play-file.ts
|
|
3818
4156
|
var import_meta2 = {};
|
|
3819
|
-
var PLAY_BUNDLE_CACHE_VERSION2 =
|
|
4157
|
+
var PLAY_BUNDLE_CACHE_VERSION2 = 26;
|
|
3820
4158
|
var MODULE_DIR = (0, import_node_path7.dirname)((0, import_node_url.fileURLToPath)(import_meta2.url));
|
|
3821
4159
|
var SDK_PACKAGE_ROOT = (0, import_node_path7.resolve)(MODULE_DIR, "..", "..");
|
|
3822
4160
|
var SOURCE_REPO_ROOT = (0, import_node_path7.resolve)(SDK_PACKAGE_ROOT, "..");
|
|
@@ -3831,7 +4169,7 @@ var PROJECT_ROOT = HAS_SOURCE_BUNDLING_SOURCES ? SOURCE_REPO_ROOT : HAS_PACKAGED
|
|
|
3831
4169
|
var SDK_SOURCE_ROOT = HAS_SOURCE_BUNDLING_SOURCES ? (0, import_node_path7.resolve)(SOURCE_REPO_ROOT, "sdk", "src") : HAS_PACKAGED_BUNDLING_SOURCES ? (0, import_node_path7.resolve)(PACKAGED_REPO_ROOT, "sdk", "src") : (0, import_node_path7.resolve)(SDK_PACKAGE_ROOT, "src");
|
|
3832
4170
|
var SDK_PACKAGE_JSON = (0, import_node_path7.resolve)(SDK_PACKAGE_ROOT, "package.json");
|
|
3833
4171
|
var SDK_ENTRY_FILE = (0, import_node_path7.resolve)(SDK_SOURCE_ROOT, "index.ts");
|
|
3834
|
-
var SDK_TYPES_ENTRY_FILE = (0, import_node_path7.resolve)(SDK_PACKAGE_ROOT, "dist", "index.d.ts");
|
|
4172
|
+
var SDK_TYPES_ENTRY_FILE = HAS_SOURCE_BUNDLING_SOURCES ? SDK_ENTRY_FILE : (0, import_node_path7.resolve)(SDK_PACKAGE_ROOT, "dist", "index.d.ts");
|
|
3835
4173
|
var SDK_WORKERS_ENTRY_FILE = (0, import_node_path7.resolve)(SDK_SOURCE_ROOT, "worker-play-entry.ts");
|
|
3836
4174
|
var WORKERS_HARNESS_ENTRY_FILE = (0, import_node_path7.resolve)(PROJECT_ROOT, "apps", "play-runner-workers", "src", "entry.ts");
|
|
3837
4175
|
var WORKERS_HARNESS_FILES_DIR = (0, import_node_path7.resolve)(PROJECT_ROOT, "apps", "play-runner-workers", "src");
|
|
@@ -3863,7 +4201,7 @@ function createSdkPlayBundlingAdapter() {
|
|
|
3863
4201
|
sdkSourceRoot: SDK_SOURCE_ROOT,
|
|
3864
4202
|
sdkPackageJson: SDK_PACKAGE_JSON,
|
|
3865
4203
|
sdkEntryFile: SDK_ENTRY_FILE,
|
|
3866
|
-
sdkTypesEntryFile: HAS_SOURCE_BUNDLING_SOURCES
|
|
4204
|
+
sdkTypesEntryFile: HAS_SOURCE_BUNDLING_SOURCES || !(0, import_node_fs5.existsSync)(SDK_TYPES_ENTRY_FILE) ? SDK_ENTRY_FILE : SDK_TYPES_ENTRY_FILE,
|
|
3867
4205
|
sdkWorkersEntryFile: SDK_WORKERS_ENTRY_FILE,
|
|
3868
4206
|
workersHarnessEntryFile: WORKERS_HARNESS_ENTRY_FILE,
|
|
3869
4207
|
workersHarnessFilesDir: WORKERS_HARNESS_FILES_DIR,
|
|
@@ -4100,13 +4438,15 @@ function formatLoadedPlayMessage(materializedFile) {
|
|
|
4100
4438
|
return `Loaded play here: ${materializedFile.path}`;
|
|
4101
4439
|
}
|
|
4102
4440
|
function buildReadonlyPrebuiltPlayError(reference) {
|
|
4441
|
+
const localName = reference.split("/").slice(1).join("/") || "custom-play";
|
|
4103
4442
|
return new Error(
|
|
4104
4443
|
`Cannot edit or push ${reference} because Deepline prebuilt plays are read-only.
|
|
4105
4444
|
To make your own version:
|
|
4106
|
-
1.
|
|
4107
|
-
2. Change definePlay('${
|
|
4108
|
-
3. Run: deepline plays
|
|
4109
|
-
4.
|
|
4445
|
+
1. Run: deepline plays get ${reference} --source --out ./${localName}.play.ts
|
|
4446
|
+
2. Change definePlay('${localName}', ...) to a new play name you own.
|
|
4447
|
+
3. Run: deepline plays check ./${localName}.play.ts
|
|
4448
|
+
4. Run: deepline plays publish ./${localName}.play.ts
|
|
4449
|
+
5. Your play will then live under your workspace namespace.`
|
|
4110
4450
|
);
|
|
4111
4451
|
}
|
|
4112
4452
|
async function ensureEditableRemotePlay(client, target) {
|
|
@@ -4247,6 +4587,15 @@ function fileInputBindingsFromStaticPipeline(staticPipeline) {
|
|
|
4247
4587
|
);
|
|
4248
4588
|
return inputField ? [{ inputPath: inputField }] : [];
|
|
4249
4589
|
}
|
|
4590
|
+
function applyCsvShortcutInput(input) {
|
|
4591
|
+
const csvValue = getDottedInputValue(input.runtimeInput, "csv");
|
|
4592
|
+
if (csvValue == null || csvValue === "") return;
|
|
4593
|
+
const candidate = input.bindings.find((binding) => binding.inputPath !== "csv")?.inputPath ?? input.fallbackInputPath ?? null;
|
|
4594
|
+
if (!candidate || candidate === "csv") return;
|
|
4595
|
+
const existing = getDottedInputValue(input.runtimeInput, candidate);
|
|
4596
|
+
if (existing != null && existing !== "") return;
|
|
4597
|
+
setDottedInputValue(input.runtimeInput, candidate, csvValue);
|
|
4598
|
+
}
|
|
4250
4599
|
function isLocalFilePathValue(value) {
|
|
4251
4600
|
if (typeof value !== "string" || !value.trim()) return false;
|
|
4252
4601
|
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(value.trim())) return false;
|
|
@@ -4370,6 +4719,7 @@ async function compileBundledPlayGraphManifests(client, graph) {
|
|
|
4370
4719
|
node.compilerManifest = await client.compilePlayManifest({
|
|
4371
4720
|
name,
|
|
4372
4721
|
sourceCode: node.sourceCode,
|
|
4722
|
+
sourceFiles: node.sourceFiles,
|
|
4373
4723
|
artifact: node.artifact,
|
|
4374
4724
|
importedPlayDependencies: node.importedPlayDependencies.map(
|
|
4375
4725
|
(dependency) => {
|
|
@@ -4419,6 +4769,7 @@ async function publishImportedPlayDependencies(client, graph) {
|
|
|
4419
4769
|
await client.registerPlayArtifact({
|
|
4420
4770
|
name: node.playName,
|
|
4421
4771
|
sourceCode: node.sourceCode,
|
|
4772
|
+
sourceFiles: node.sourceFiles,
|
|
4422
4773
|
artifact: node.artifact,
|
|
4423
4774
|
compilerManifest: requireCompilerManifest(node),
|
|
4424
4775
|
publish: true
|
|
@@ -4436,67 +4787,6 @@ function formatTimestamp(value) {
|
|
|
4436
4787
|
function formatRunLine(run) {
|
|
4437
4788
|
return `${run.workflowId} ${run.status} ${formatTimestamp(run.startTime)}`;
|
|
4438
4789
|
}
|
|
4439
|
-
function parsePlayRunTarget(input) {
|
|
4440
|
-
const { args, usage } = input;
|
|
4441
|
-
let runId = null;
|
|
4442
|
-
let playName = null;
|
|
4443
|
-
for (let index = 0; index < args.length; index += 1) {
|
|
4444
|
-
const arg = args[index];
|
|
4445
|
-
if (arg === "--json") {
|
|
4446
|
-
continue;
|
|
4447
|
-
}
|
|
4448
|
-
if (arg === "--reason" || arg === "--interval-ms" || arg === "--poll-interval-ms") {
|
|
4449
|
-
index += 1;
|
|
4450
|
-
continue;
|
|
4451
|
-
}
|
|
4452
|
-
if (arg === "--run-id" && args[index + 1]) {
|
|
4453
|
-
runId = args[++index].trim();
|
|
4454
|
-
continue;
|
|
4455
|
-
}
|
|
4456
|
-
if (arg === "--name" && args[index + 1] && input.allowName) {
|
|
4457
|
-
playName = parseReferencedPlayTarget(args[++index]).playName;
|
|
4458
|
-
continue;
|
|
4459
|
-
}
|
|
4460
|
-
if (arg.startsWith("--")) {
|
|
4461
|
-
continue;
|
|
4462
|
-
}
|
|
4463
|
-
throw new DeeplineError(
|
|
4464
|
-
`Unexpected positional target "${arg}". Use --run-id for run ids.
|
|
4465
|
-
${usage}`
|
|
4466
|
-
);
|
|
4467
|
-
}
|
|
4468
|
-
const explicitTargets = [runId, playName].filter(Boolean).length;
|
|
4469
|
-
if (explicitTargets > 1) {
|
|
4470
|
-
throw new DeeplineError(`Choose exactly one play run target.
|
|
4471
|
-
${usage}`);
|
|
4472
|
-
}
|
|
4473
|
-
if (runId) {
|
|
4474
|
-
return { kind: "run", runId };
|
|
4475
|
-
}
|
|
4476
|
-
if (playName) {
|
|
4477
|
-
return { kind: "name", name: playName };
|
|
4478
|
-
}
|
|
4479
|
-
throw new DeeplineError(usage);
|
|
4480
|
-
}
|
|
4481
|
-
async function resolvePlayRunId(client, target) {
|
|
4482
|
-
if (target.kind === "run") {
|
|
4483
|
-
try {
|
|
4484
|
-
const status = await client.getPlayStatus(target.runId);
|
|
4485
|
-
return status.runId;
|
|
4486
|
-
} catch (error) {
|
|
4487
|
-
if (!(error instanceof DeeplineError) || error.statusCode !== 404) {
|
|
4488
|
-
throw error;
|
|
4489
|
-
}
|
|
4490
|
-
throw new DeeplineError(`No play run found for run id: ${target.runId}`);
|
|
4491
|
-
}
|
|
4492
|
-
}
|
|
4493
|
-
const runs = await client.listPlayRuns(target.name);
|
|
4494
|
-
const workflowId = runs[0]?.workflowId ?? "";
|
|
4495
|
-
if (!workflowId) {
|
|
4496
|
-
throw new DeeplineError(`No runs found for play: ${target.name}`);
|
|
4497
|
-
}
|
|
4498
|
-
return workflowId;
|
|
4499
|
-
}
|
|
4500
4790
|
function isTransientPlayStatusPollError(error) {
|
|
4501
4791
|
if (error instanceof DeeplineError && typeof error.statusCode === "number") {
|
|
4502
4792
|
return error.statusCode >= 500 && error.statusCode < 600;
|
|
@@ -4600,7 +4890,7 @@ function assertPlayWaitNotTimedOut(input) {
|
|
|
4600
4890
|
if (input.waitTimeoutMs !== null && Date.now() - input.startedAt >= input.waitTimeoutMs) {
|
|
4601
4891
|
const hasRealRunId = input.workflowId.length > 0 && input.workflowId !== "pending";
|
|
4602
4892
|
const phaseSuffix = input.lastPhase && input.lastPhase.trim() ? ` (last observed phase: ${input.lastPhase.trim()})` : "";
|
|
4603
|
-
const tailHint = hasRealRunId ? ` Run 'deepline
|
|
4893
|
+
const tailHint = hasRealRunId ? ` Run 'deepline runs tail ${input.workflowId} --json' to inspect it, or rerun with a larger --tail-timeout-ms.` : ` The run never reported a workflow id \u2014 the start request likely failed before reaching the scheduler. Check server logs and rerun with a larger --tail-timeout-ms.`;
|
|
4604
4894
|
throw new DeeplineError(
|
|
4605
4895
|
`Timed out waiting for play ${hasRealRunId ? input.workflowId : "<no run id>"} after ${Math.ceil(input.waitTimeoutMs / 1e3)}s${phaseSuffix}.${tailHint}`,
|
|
4606
4896
|
void 0,
|
|
@@ -4613,66 +4903,6 @@ function assertPlayWaitNotTimedOut(input) {
|
|
|
4613
4903
|
);
|
|
4614
4904
|
}
|
|
4615
4905
|
}
|
|
4616
|
-
async function waitForPlayCompletionByStream(input) {
|
|
4617
|
-
const controller = new AbortController();
|
|
4618
|
-
let timedOut = false;
|
|
4619
|
-
let lastPhase = null;
|
|
4620
|
-
const timeout = input.waitTimeoutMs === null ? null : setTimeout(
|
|
4621
|
-
() => {
|
|
4622
|
-
timedOut = true;
|
|
4623
|
-
controller.abort();
|
|
4624
|
-
},
|
|
4625
|
-
Math.max(1, input.waitTimeoutMs - (Date.now() - input.startedAt))
|
|
4626
|
-
);
|
|
4627
|
-
try {
|
|
4628
|
-
for await (const event of input.client.streamPlayRunEvents(
|
|
4629
|
-
input.workflowId,
|
|
4630
|
-
{ signal: controller.signal }
|
|
4631
|
-
)) {
|
|
4632
|
-
assertPlayWaitNotTimedOut({ ...input, lastPhase });
|
|
4633
|
-
const phase = describeLiveEventPhase(event);
|
|
4634
|
-
if (phase) {
|
|
4635
|
-
lastPhase = phase;
|
|
4636
|
-
input.progress.phase(phase);
|
|
4637
|
-
}
|
|
4638
|
-
printPlayLogLines({
|
|
4639
|
-
lines: getLogLinesFromLiveEvent(event),
|
|
4640
|
-
status: null,
|
|
4641
|
-
jsonOutput: input.jsonOutput,
|
|
4642
|
-
emitLogs: input.emitLogs,
|
|
4643
|
-
state: input.state,
|
|
4644
|
-
progress: input.progress
|
|
4645
|
-
});
|
|
4646
|
-
const status = getStatusFromLiveEvent(event);
|
|
4647
|
-
if (status && TERMINAL_PLAY_STATUSES2.has(status)) {
|
|
4648
|
-
const finalStatus = await input.client.getPlayStatus(input.workflowId);
|
|
4649
|
-
if (TERMINAL_PLAY_STATUSES2.has(finalStatus.status)) {
|
|
4650
|
-
return finalStatus;
|
|
4651
|
-
}
|
|
4652
|
-
}
|
|
4653
|
-
}
|
|
4654
|
-
} catch (error) {
|
|
4655
|
-
if (timedOut) {
|
|
4656
|
-
assertPlayWaitNotTimedOut({ ...input, lastPhase });
|
|
4657
|
-
}
|
|
4658
|
-
throw error;
|
|
4659
|
-
} finally {
|
|
4660
|
-
if (timeout) {
|
|
4661
|
-
clearTimeout(timeout);
|
|
4662
|
-
}
|
|
4663
|
-
}
|
|
4664
|
-
const phaseSuffix = lastPhase && lastPhase.trim() ? ` (last observed phase: ${lastPhase.trim()})` : "";
|
|
4665
|
-
throw new DeeplineError(
|
|
4666
|
-
`Play live stream ended before the run reached a terminal state runId=${input.workflowId}${phaseSuffix}.`,
|
|
4667
|
-
void 0,
|
|
4668
|
-
"PLAY_LIVE_STREAM_ENDED",
|
|
4669
|
-
{
|
|
4670
|
-
runId: input.workflowId,
|
|
4671
|
-
workflowId: input.workflowId,
|
|
4672
|
-
...lastPhase ? { phase: lastPhase } : {}
|
|
4673
|
-
}
|
|
4674
|
-
);
|
|
4675
|
-
}
|
|
4676
4906
|
async function startAndWaitForPlayCompletionByStream(input) {
|
|
4677
4907
|
const startedAt = Date.now();
|
|
4678
4908
|
const state = {
|
|
@@ -4752,10 +4982,12 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
4752
4982
|
clearTimeout(timeout);
|
|
4753
4983
|
}
|
|
4754
4984
|
const reason = error instanceof Error ? error.message : String(error);
|
|
4755
|
-
|
|
4756
|
-
|
|
4985
|
+
if (!input.jsonOutput) {
|
|
4986
|
+
process.stderr.write(
|
|
4987
|
+
`[play watch] start stream failed after run ${lastKnownWorkflowId}; falling back to polling (${reason})
|
|
4757
4988
|
`
|
|
4758
|
-
|
|
4989
|
+
);
|
|
4990
|
+
}
|
|
4759
4991
|
return waitForPlayCompletionByPolling({
|
|
4760
4992
|
client: input.client,
|
|
4761
4993
|
workflowId: lastKnownWorkflowId,
|
|
@@ -4774,6 +5006,24 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
4774
5006
|
clearTimeout(timeout);
|
|
4775
5007
|
}
|
|
4776
5008
|
}
|
|
5009
|
+
if (lastKnownWorkflowId) {
|
|
5010
|
+
if (!input.jsonOutput) {
|
|
5011
|
+
input.progress.writeLine(
|
|
5012
|
+
`[play watch] start stream ended after run ${lastKnownWorkflowId}; falling back to polling`
|
|
5013
|
+
);
|
|
5014
|
+
}
|
|
5015
|
+
return waitForPlayCompletionByPolling({
|
|
5016
|
+
client: input.client,
|
|
5017
|
+
workflowId: lastKnownWorkflowId,
|
|
5018
|
+
pollIntervalMs: 500,
|
|
5019
|
+
jsonOutput: input.jsonOutput,
|
|
5020
|
+
emitLogs: input.emitLogs,
|
|
5021
|
+
waitTimeoutMs: input.waitTimeoutMs,
|
|
5022
|
+
startedAt,
|
|
5023
|
+
state,
|
|
5024
|
+
progress: input.progress
|
|
5025
|
+
});
|
|
5026
|
+
}
|
|
4777
5027
|
const phaseSuffix = lastPhase && lastPhase.trim() ? ` (last observed phase: ${lastPhase.trim()})` : "";
|
|
4778
5028
|
const idSuffix = lastKnownWorkflowId ? ` runId=${lastKnownWorkflowId}` : "";
|
|
4779
5029
|
throw new DeeplineError(
|
|
@@ -4851,38 +5101,6 @@ async function waitForPlayCompletionByPolling(input) {
|
|
|
4851
5101
|
}
|
|
4852
5102
|
}
|
|
4853
5103
|
}
|
|
4854
|
-
async function waitForPlayCompletion(input) {
|
|
4855
|
-
const startedAt = Date.now();
|
|
4856
|
-
const state = {
|
|
4857
|
-
lastLogIndex: 0,
|
|
4858
|
-
emittedRunnerStarted: false
|
|
4859
|
-
};
|
|
4860
|
-
try {
|
|
4861
|
-
return await waitForPlayCompletionByStream({
|
|
4862
|
-
...input,
|
|
4863
|
-
startedAt,
|
|
4864
|
-
state,
|
|
4865
|
-
progress: input.progress
|
|
4866
|
-
});
|
|
4867
|
-
} catch (error) {
|
|
4868
|
-
assertPlayWaitNotTimedOut({
|
|
4869
|
-
workflowId: input.workflowId,
|
|
4870
|
-
startedAt,
|
|
4871
|
-
waitTimeoutMs: input.waitTimeoutMs
|
|
4872
|
-
});
|
|
4873
|
-
const reason = error instanceof Error ? error.message : String(error);
|
|
4874
|
-
process.stderr.write(
|
|
4875
|
-
`[play watch] SSE stream failed; falling back to polling (${reason})
|
|
4876
|
-
`
|
|
4877
|
-
);
|
|
4878
|
-
return waitForPlayCompletionByPolling({
|
|
4879
|
-
...input,
|
|
4880
|
-
startedAt,
|
|
4881
|
-
state,
|
|
4882
|
-
progress: input.progress
|
|
4883
|
-
});
|
|
4884
|
-
}
|
|
4885
|
-
}
|
|
4886
5104
|
function formatInteger(value) {
|
|
4887
5105
|
return typeof value === "number" && Number.isFinite(value) ? value.toLocaleString("en-US") : String(value ?? "-");
|
|
4888
5106
|
}
|
|
@@ -4989,14 +5207,20 @@ function formatReturnValue(result) {
|
|
|
4989
5207
|
}
|
|
4990
5208
|
return lines;
|
|
4991
5209
|
}
|
|
4992
|
-
function buildOutputSummary(rowsInfo, exportedPath) {
|
|
5210
|
+
function buildOutputSummary(rowsInfo, runId, exportedPath) {
|
|
4993
5211
|
if (!rowsInfo) {
|
|
4994
5212
|
return exportedPath ? { csv_path: exportedPath } : null;
|
|
4995
5213
|
}
|
|
5214
|
+
const isPartial = !rowsInfo.complete;
|
|
4996
5215
|
return {
|
|
4997
5216
|
kind: "rows",
|
|
4998
5217
|
rowCount: rowsInfo.totalRows,
|
|
4999
5218
|
previewRowCount: rowsInfo.rows.length,
|
|
5219
|
+
...isPartial ? {
|
|
5220
|
+
isPartial: true,
|
|
5221
|
+
previewCount: rowsInfo.rows.length,
|
|
5222
|
+
totalCount: rowsInfo.totalRows
|
|
5223
|
+
} : { isPartial: false },
|
|
5000
5224
|
complete: rowsInfo.complete,
|
|
5001
5225
|
columns: rowsInfo.columns,
|
|
5002
5226
|
source: rowsInfo.source,
|
|
@@ -5007,21 +5231,174 @@ function buildRunWarnings(status, rowsInfo) {
|
|
|
5007
5231
|
if (status.status === "completed" && rowsInfo?.totalRows === 0) {
|
|
5008
5232
|
return ["Run completed with 0 output rows."];
|
|
5009
5233
|
}
|
|
5234
|
+
if (rowsInfo && !rowsInfo.complete) {
|
|
5235
|
+
return [
|
|
5236
|
+
`Run output is partial: showing ${rowsInfo.rows.length} preview row(s) of ${rowsInfo.totalRows}.`
|
|
5237
|
+
];
|
|
5238
|
+
}
|
|
5010
5239
|
return [];
|
|
5011
5240
|
}
|
|
5012
|
-
function buildRunNextCommands(runId) {
|
|
5241
|
+
function buildRunNextCommands(runId, rowsInfo) {
|
|
5242
|
+
const commands = {
|
|
5243
|
+
get: `deepline runs get ${runId} --json`,
|
|
5244
|
+
tail: `deepline runs tail ${runId} --json`,
|
|
5245
|
+
stop: `deepline runs stop ${runId} --reason "stale lock" --json`,
|
|
5246
|
+
logs: `deepline runs logs ${runId} --out run.log --json`
|
|
5247
|
+
};
|
|
5248
|
+
if (!rowsInfo || rowsInfo.complete) {
|
|
5249
|
+
commands.exportCsv = buildRunExportCommand(runId);
|
|
5250
|
+
}
|
|
5251
|
+
return commands;
|
|
5252
|
+
}
|
|
5253
|
+
function buildRunExportCommand(runId) {
|
|
5254
|
+
return `deepline runs export ${runId} --out output.csv`;
|
|
5255
|
+
}
|
|
5256
|
+
var RUN_LOG_PREVIEW_LIMIT = 20;
|
|
5257
|
+
function getRecordField(value, key) {
|
|
5258
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value[key] : void 0;
|
|
5259
|
+
}
|
|
5260
|
+
function getNumericField(value, key) {
|
|
5261
|
+
const field = getRecordField(value, key);
|
|
5262
|
+
return typeof field === "number" && Number.isFinite(field) ? field : null;
|
|
5263
|
+
}
|
|
5264
|
+
function getStringField(value, key) {
|
|
5265
|
+
const field = getRecordField(value, key);
|
|
5266
|
+
return typeof field === "string" && field.trim() ? field : null;
|
|
5267
|
+
}
|
|
5268
|
+
function normalizeRunStatusForEnvelope(status) {
|
|
5269
|
+
const run = status.run ?? null;
|
|
5013
5270
|
return {
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
5271
|
+
id: status.runId,
|
|
5272
|
+
playName: status.playName ?? status.name ?? getStringField(run, "playName") ?? null,
|
|
5273
|
+
status: status.status,
|
|
5274
|
+
runtime: getStringField(status, "runtime") ?? getStringField(status, "runtimeBackend") ?? getStringField(run, "runtime") ?? null,
|
|
5275
|
+
startedAt: getStringField(run, "startTime") ?? getStringField(run, "startedAt") ?? null,
|
|
5276
|
+
updatedAt: getStringField(status, "updatedAt") ?? getStringField(run, "updatedAt") ?? null,
|
|
5277
|
+
finishedAt: getStringField(run, "closeTime") ?? getStringField(run, "finishedAt") ?? null,
|
|
5278
|
+
source: getRecordField(status, "source") ?? getRecordField(status, "artifact") ?? null
|
|
5017
5279
|
};
|
|
5018
5280
|
}
|
|
5281
|
+
function normalizeProgressForEnvelope(status, rowsInfo) {
|
|
5282
|
+
const progress = status.progress;
|
|
5283
|
+
const total = getNumericField(progress, "totalRows") ?? getNumericField(progress, "total") ?? rowsInfo?.totalRows ?? null;
|
|
5284
|
+
const failed = getNumericField(progress, "failed") ?? getNumericField(progress, "failedRows") ?? null;
|
|
5285
|
+
const completed = getNumericField(progress, "completed") ?? getNumericField(progress, "completedRows") ?? (status.status === "completed" ? total : null);
|
|
5286
|
+
const pending = getNumericField(progress, "pending") ?? (typeof total === "number" && typeof completed === "number" && typeof failed === "number" ? Math.max(0, total - completed - failed) : null);
|
|
5287
|
+
return {
|
|
5288
|
+
total,
|
|
5289
|
+
completed,
|
|
5290
|
+
pending,
|
|
5291
|
+
failed,
|
|
5292
|
+
executed: getNumericField(progress, "executed"),
|
|
5293
|
+
reused: getNumericField(progress, "reused"),
|
|
5294
|
+
skipped: getNumericField(progress, "skipped"),
|
|
5295
|
+
retried: getNumericField(progress, "retried"),
|
|
5296
|
+
degraded: typeof getRecordField(progress, "degraded") === "boolean" ? getRecordField(progress, "degraded") : null,
|
|
5297
|
+
duplicates: getRecordField(progress, "duplicates") ?? null,
|
|
5298
|
+
active: getStringField(progress, "status") ?? getStringField(status, "activeStep") ?? getStringField(status, "activeNodeId") ?? null,
|
|
5299
|
+
wait: status.wait ?? null
|
|
5300
|
+
};
|
|
5301
|
+
}
|
|
5302
|
+
function normalizeOutputsForEnvelope(rowsInfo, runId, exportedPath) {
|
|
5303
|
+
if (!rowsInfo) {
|
|
5304
|
+
return exportedPath ? [{ name: "output", kind: "file", path: exportedPath }] : [];
|
|
5305
|
+
}
|
|
5306
|
+
const isPartial = !rowsInfo.complete;
|
|
5307
|
+
return [
|
|
5308
|
+
{
|
|
5309
|
+
name: "rows",
|
|
5310
|
+
kind: "dataset",
|
|
5311
|
+
rowCount: rowsInfo.totalRows,
|
|
5312
|
+
columns: rowsInfo.columns,
|
|
5313
|
+
preview: rowsInfo.rows.slice(0, 5),
|
|
5314
|
+
previewRowCount: Math.min(rowsInfo.rows.length, 5),
|
|
5315
|
+
previewLimit: 5,
|
|
5316
|
+
...isPartial ? {
|
|
5317
|
+
isPartial: true,
|
|
5318
|
+
previewCount: rowsInfo.rows.length,
|
|
5319
|
+
totalCount: rowsInfo.totalRows
|
|
5320
|
+
} : { isPartial: false },
|
|
5321
|
+
complete: rowsInfo.complete,
|
|
5322
|
+
source: rowsInfo.source,
|
|
5323
|
+
...exportedPath ? { csv_path: exportedPath } : {}
|
|
5324
|
+
}
|
|
5325
|
+
];
|
|
5326
|
+
}
|
|
5327
|
+
function normalizeStepsForEnvelope(status) {
|
|
5328
|
+
const directSteps = getRecordField(status, "steps");
|
|
5329
|
+
if (Array.isArray(directSteps)) {
|
|
5330
|
+
return directSteps;
|
|
5331
|
+
}
|
|
5332
|
+
const timeline = getRecordField(status, "timeline");
|
|
5333
|
+
if (Array.isArray(timeline)) {
|
|
5334
|
+
return timeline;
|
|
5335
|
+
}
|
|
5336
|
+
return [];
|
|
5337
|
+
}
|
|
5338
|
+
function normalizeErrorsForEnvelope(status, error) {
|
|
5339
|
+
const directErrors = getRecordField(status, "errors");
|
|
5340
|
+
if (Array.isArray(directErrors)) {
|
|
5341
|
+
return directErrors.filter(
|
|
5342
|
+
(entry) => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry)
|
|
5343
|
+
);
|
|
5344
|
+
}
|
|
5345
|
+
if (!error) {
|
|
5346
|
+
return [];
|
|
5347
|
+
}
|
|
5348
|
+
return [
|
|
5349
|
+
{
|
|
5350
|
+
code: getStringField(status, "errorCode") ?? "RUN_FAILED",
|
|
5351
|
+
phase: getStringField(status, "errorPhase") ?? "runtime",
|
|
5352
|
+
message: error,
|
|
5353
|
+
retryable: typeof getRecordField(status, "retryable") === "boolean" ? getRecordField(status, "retryable") : null,
|
|
5354
|
+
nextAction: `deepline runs get ${status.runId} --json`
|
|
5355
|
+
}
|
|
5356
|
+
];
|
|
5357
|
+
}
|
|
5358
|
+
function normalizeLogsForEnvelope(status) {
|
|
5359
|
+
const logs = Array.isArray(status.progress?.logs) ? status.progress.logs : [];
|
|
5360
|
+
const offset = typeof status.progress?.logOffset === "number" && Number.isFinite(status.progress.logOffset) ? Math.max(0, Math.trunc(status.progress.logOffset)) : 0;
|
|
5361
|
+
const totalCount = offset + logs.length;
|
|
5362
|
+
const entries = logs.slice(Math.max(0, logs.length - RUN_LOG_PREVIEW_LIMIT));
|
|
5363
|
+
const firstSequence = entries.length === 0 ? null : offset + logs.length - entries.length + 1;
|
|
5364
|
+
const lastSequence = totalCount === 0 ? null : totalCount;
|
|
5365
|
+
return {
|
|
5366
|
+
totalCount,
|
|
5367
|
+
returnedCount: entries.length,
|
|
5368
|
+
firstSequence,
|
|
5369
|
+
lastSequence,
|
|
5370
|
+
truncated: totalCount > entries.length,
|
|
5371
|
+
hasMore: totalCount > entries.length,
|
|
5372
|
+
entries,
|
|
5373
|
+
nextCursor: lastSequence
|
|
5374
|
+
};
|
|
5375
|
+
}
|
|
5376
|
+
function stripProviderSpendFromBilling(value) {
|
|
5377
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
5378
|
+
return value;
|
|
5379
|
+
}
|
|
5380
|
+
const next = {};
|
|
5381
|
+
for (const [key, item] of Object.entries(value)) {
|
|
5382
|
+
if (key === "providerCostUsd" || key === "totalProviderCostUsd") {
|
|
5383
|
+
continue;
|
|
5384
|
+
}
|
|
5385
|
+
next[key] = item;
|
|
5386
|
+
}
|
|
5387
|
+
return next;
|
|
5388
|
+
}
|
|
5019
5389
|
function compactPlayStatus(status, options) {
|
|
5020
5390
|
const rowsInfo = extractCanonicalRowsInfo(status);
|
|
5021
5391
|
const result = status && typeof status === "object" ? status.result : null;
|
|
5022
5392
|
const warnings = buildRunWarnings(status, rowsInfo);
|
|
5023
|
-
const datasetStats = rowsInfo && rowsInfo.complete ? buildDatasetStats(
|
|
5024
|
-
|
|
5393
|
+
const datasetStats = rowsInfo && rowsInfo.complete ? buildDatasetStats(
|
|
5394
|
+
rowsInfo.rows,
|
|
5395
|
+
rowsInfo.totalRows,
|
|
5396
|
+
rowsInfo.columns,
|
|
5397
|
+
extractDatasetExecutionStats(status)
|
|
5398
|
+
) : null;
|
|
5399
|
+
const billing = status && typeof status === "object" ? stripProviderSpendFromBilling(
|
|
5400
|
+
status.billing
|
|
5401
|
+
) : null;
|
|
5025
5402
|
const progressError = status.progress?.error;
|
|
5026
5403
|
const error = typeof progressError === "string" ? progressError : typeof status.error === "string" ? String(status.error) : null;
|
|
5027
5404
|
return {
|
|
@@ -5030,16 +5407,25 @@ function compactPlayStatus(status, options) {
|
|
|
5030
5407
|
...typeof status.name === "string" ? { name: status.name } : {},
|
|
5031
5408
|
...typeof status.playName === "string" ? { playName: status.playName } : {},
|
|
5032
5409
|
status: status.status,
|
|
5410
|
+
run: normalizeRunStatusForEnvelope(status),
|
|
5411
|
+
progress: normalizeProgressForEnvelope(status, rowsInfo),
|
|
5412
|
+
outputs: normalizeOutputsForEnvelope(
|
|
5413
|
+
rowsInfo,
|
|
5414
|
+
status.runId,
|
|
5415
|
+
options?.exportedPath
|
|
5416
|
+
),
|
|
5417
|
+
steps: normalizeStepsForEnvelope(status),
|
|
5418
|
+
errors: normalizeErrorsForEnvelope(status, error),
|
|
5419
|
+
logs: normalizeLogsForEnvelope(status),
|
|
5033
5420
|
...error ? { error } : {},
|
|
5034
5421
|
...warnings.length > 0 ? { warnings } : {},
|
|
5035
|
-
output: buildOutputSummary(rowsInfo, options?.exportedPath) ?? result ?? null,
|
|
5422
|
+
output: buildOutputSummary(rowsInfo, status.runId, options?.exportedPath) ?? result ?? null,
|
|
5036
5423
|
...result !== void 0 ? { result } : {},
|
|
5037
5424
|
...status.resultView ? { resultView: status.resultView } : {},
|
|
5038
5425
|
...datasetStats ? { dataset_stats: datasetStats } : {},
|
|
5039
5426
|
...rowsInfo ? { previewRows: rowsInfo.rows.slice(0, 5) } : {},
|
|
5040
5427
|
...billing ? { billing } : {},
|
|
5041
|
-
|
|
5042
|
-
next: buildRunNextCommands(status.runId)
|
|
5428
|
+
next: buildRunNextCommands(status.runId, rowsInfo)
|
|
5043
5429
|
};
|
|
5044
5430
|
}
|
|
5045
5431
|
function enrichPlayStatusWithDatasetStats(status) {
|
|
@@ -5052,7 +5438,8 @@ function enrichPlayStatusWithDatasetStats(status) {
|
|
|
5052
5438
|
dataset_stats: buildDatasetStats(
|
|
5053
5439
|
rowsInfo.rows,
|
|
5054
5440
|
rowsInfo.totalRows,
|
|
5055
|
-
rowsInfo.columns
|
|
5441
|
+
rowsInfo.columns,
|
|
5442
|
+
extractDatasetExecutionStats(status)
|
|
5056
5443
|
)
|
|
5057
5444
|
};
|
|
5058
5445
|
}
|
|
@@ -5067,8 +5454,9 @@ function formatDatasetStatsLines(datasetStats) {
|
|
|
5067
5454
|
)) {
|
|
5068
5455
|
const topValues = stat3.top_values ? `, top_values=${Object.entries(stat3.top_values).slice(0, 3).map(([value, count]) => `${value}=${count}`).join(", ")}` : "";
|
|
5069
5456
|
const sample = stat3.sample_value !== void 0 ? `, sample_value=${JSON.stringify(stat3.sample_value)}` : "";
|
|
5457
|
+
const execution = stat3.execution ? `, execution=${Object.entries(stat3.execution).map(([bucket, count]) => `${bucket}=${count}`).join(", ")}` : "";
|
|
5070
5458
|
lines.push(
|
|
5071
|
-
` ${column}: non_empty=${stat3.non_empty}, unique=${stat3.unique}${topValues}${sample}`
|
|
5459
|
+
` ${column}: non_empty=${stat3.non_empty}, unique=${stat3.unique}${topValues}${sample}${execution}`
|
|
5072
5460
|
);
|
|
5073
5461
|
}
|
|
5074
5462
|
return lines;
|
|
@@ -5091,14 +5479,28 @@ function writePlayResult(status, jsonOutput, options) {
|
|
|
5091
5479
|
lines.push(`${success ? "\u2713" : "\u2717"} ${publicStatus} ${runId}`);
|
|
5092
5480
|
const rowsInfo = extractCanonicalRowsInfo(status);
|
|
5093
5481
|
const warnings = buildRunWarnings(status, rowsInfo);
|
|
5094
|
-
const datasetStats = rowsInfo && rowsInfo.complete ? buildDatasetStats(
|
|
5095
|
-
|
|
5482
|
+
const datasetStats = rowsInfo && rowsInfo.complete ? buildDatasetStats(
|
|
5483
|
+
rowsInfo.rows,
|
|
5484
|
+
rowsInfo.totalRows,
|
|
5485
|
+
rowsInfo.columns,
|
|
5486
|
+
extractDatasetExecutionStats(status)
|
|
5487
|
+
) : null;
|
|
5488
|
+
const outputSummary = buildOutputSummary(
|
|
5489
|
+
rowsInfo,
|
|
5490
|
+
runId,
|
|
5491
|
+
options?.exportedPath
|
|
5492
|
+
);
|
|
5096
5493
|
if (outputSummary) {
|
|
5097
5494
|
const columns = Array.isArray(outputSummary.columns) ? outputSummary.columns.length : 0;
|
|
5098
5495
|
const path = typeof outputSummary.csv_path === "string" ? ` file=${outputSummary.csv_path}` : "";
|
|
5099
5496
|
lines.push(
|
|
5100
5497
|
` output: rows=${formatInteger(outputSummary.rowCount)} columns=${formatInteger(columns)}${path}`
|
|
5101
5498
|
);
|
|
5499
|
+
if (outputSummary.isPartial === true) {
|
|
5500
|
+
lines.push(
|
|
5501
|
+
` partial output: showing ${formatInteger(outputSummary.previewCount)} preview row(s) of ${formatInteger(outputSummary.totalCount)}`
|
|
5502
|
+
);
|
|
5503
|
+
}
|
|
5102
5504
|
}
|
|
5103
5505
|
for (const warning of warnings) {
|
|
5104
5506
|
lines.push(` warning: ${warning}`);
|
|
@@ -5128,6 +5530,11 @@ function exportPlayStatusRows(status, outPath) {
|
|
|
5128
5530
|
`Run ${status.runId} did not expose a row-shaped final output to export.`
|
|
5129
5531
|
);
|
|
5130
5532
|
}
|
|
5533
|
+
if (!rowsInfo.complete) {
|
|
5534
|
+
throw new DeeplineError(
|
|
5535
|
+
`Run output only includes ${rowsInfo.rows.length} preview row(s) of ${rowsInfo.totalRows}; full dataset export is not available from this status response yet.`
|
|
5536
|
+
);
|
|
5537
|
+
}
|
|
5131
5538
|
return writeCanonicalRowsCsv(rowsInfo, outPath);
|
|
5132
5539
|
}
|
|
5133
5540
|
function renderServerResultView(value) {
|
|
@@ -5210,10 +5617,10 @@ function writeStartedPlayRun(input) {
|
|
|
5210
5617
|
const lines = [
|
|
5211
5618
|
`Started ${input.playName}`,
|
|
5212
5619
|
` run id: ${input.runId}`,
|
|
5213
|
-
`
|
|
5214
|
-
` tail logs: deepline
|
|
5215
|
-
` stop run: deepline
|
|
5216
|
-
` result JSON: deepline
|
|
5620
|
+
` get status: deepline runs get ${input.runId} --json`,
|
|
5621
|
+
` tail logs: deepline runs tail ${input.runId} --json`,
|
|
5622
|
+
` stop run: deepline runs stop ${input.runId} --reason "stale lock" --json`,
|
|
5623
|
+
` result JSON: deepline runs get ${input.runId} --json`
|
|
5217
5624
|
];
|
|
5218
5625
|
if (input.dashboardUrl) {
|
|
5219
5626
|
lines.push(` play page: ${input.dashboardUrl}`);
|
|
@@ -5360,6 +5767,10 @@ function parsePlayCheckOptions(args) {
|
|
|
5360
5767
|
const jsonOutput = argsWantJson(args);
|
|
5361
5768
|
return { target, jsonOutput };
|
|
5362
5769
|
}
|
|
5770
|
+
function shouldUseLocalOnlyPlayCheck() {
|
|
5771
|
+
const value = process.env.DEEPLINE_PLAY_CHECK_LOCAL_ONLY?.trim().toLowerCase();
|
|
5772
|
+
return value === "1" || value === "true" || value === "yes" || value === "on";
|
|
5773
|
+
}
|
|
5363
5774
|
async function handlePlayCheck(args) {
|
|
5364
5775
|
const options = parsePlayCheckOptions(args);
|
|
5365
5776
|
if (!isFileTarget(options.target)) {
|
|
@@ -5385,10 +5796,28 @@ async function handlePlayCheck(args) {
|
|
|
5385
5796
|
return 1;
|
|
5386
5797
|
}
|
|
5387
5798
|
const playName = graph.root.playName ?? extractPlayName(sourceCode, absolutePlayPath);
|
|
5799
|
+
if (shouldUseLocalOnlyPlayCheck()) {
|
|
5800
|
+
const result2 = {
|
|
5801
|
+
valid: true,
|
|
5802
|
+
errors: [],
|
|
5803
|
+
staticPipeline: graph.root.compilerManifest?.staticPipeline ?? null,
|
|
5804
|
+
artifactHash: graph.root.artifact.artifactHash,
|
|
5805
|
+
graphHash: graph.root.artifact.graphHash
|
|
5806
|
+
};
|
|
5807
|
+
if (options.jsonOutput) {
|
|
5808
|
+
process.stdout.write(`${JSON.stringify({ name: playName, ...result2 })}
|
|
5809
|
+
`);
|
|
5810
|
+
} else {
|
|
5811
|
+
console.log(`\u2713 ${playName} passed local play check`);
|
|
5812
|
+
console.log(` artifact: ${result2.artifactHash.slice(0, 12)}`);
|
|
5813
|
+
}
|
|
5814
|
+
return 0;
|
|
5815
|
+
}
|
|
5388
5816
|
const client = new DeeplineClient();
|
|
5389
5817
|
const result = await client.checkPlayArtifact({
|
|
5390
5818
|
name: playName,
|
|
5391
5819
|
sourceCode: graph.root.sourceCode,
|
|
5820
|
+
sourceFiles: graph.root.sourceFiles,
|
|
5392
5821
|
artifact: graph.root.artifact
|
|
5393
5822
|
});
|
|
5394
5823
|
if (options.jsonOutput) {
|
|
@@ -5440,17 +5869,24 @@ async function handleFileBackedRun(options) {
|
|
|
5440
5869
|
const packagedFileUploads = bundleResult.packagedFiles.map(
|
|
5441
5870
|
(file) => stageFile(file.logicalPath, file.absolutePath)
|
|
5442
5871
|
);
|
|
5872
|
+
const fileInputBindings = fileInputBindingsFromStaticPipeline(
|
|
5873
|
+
requireCompilerManifest(bundleResult).staticPipeline
|
|
5874
|
+
);
|
|
5875
|
+
applyCsvShortcutInput({
|
|
5876
|
+
runtimeInput,
|
|
5877
|
+
bindings: fileInputBindings,
|
|
5878
|
+
fallbackInputPath: "file"
|
|
5879
|
+
});
|
|
5443
5880
|
const stagedFileInputs = await stageFileInputArgs({
|
|
5444
5881
|
client,
|
|
5445
5882
|
runtimeInput,
|
|
5446
|
-
bindings:
|
|
5447
|
-
requireCompilerManifest(bundleResult).staticPipeline
|
|
5448
|
-
),
|
|
5883
|
+
bindings: fileInputBindings,
|
|
5449
5884
|
progress
|
|
5450
5885
|
});
|
|
5451
5886
|
const startRequest = {
|
|
5452
5887
|
name: playName,
|
|
5453
5888
|
sourceCode: bundleResult.sourceCode,
|
|
5889
|
+
sourceFiles: bundleResult.sourceFiles,
|
|
5454
5890
|
runtimeArtifact: bundleResult.artifact,
|
|
5455
5891
|
compilerManifest: requireCompilerManifest(bundleResult),
|
|
5456
5892
|
packagedFileUploads,
|
|
@@ -5525,13 +5961,18 @@ async function handleNamedRun(options) {
|
|
|
5525
5961
|
selector: options.revisionSelector
|
|
5526
5962
|
});
|
|
5527
5963
|
const runtimeInput = options.input ? { ...options.input } : {};
|
|
5964
|
+
const fileInputBindings = [
|
|
5965
|
+
...fileInputBindingsFromPlaySchema(playDetail.play.inputSchema),
|
|
5966
|
+
...fileInputBindingsFromStaticPipeline(playDetail.play.staticPipeline)
|
|
5967
|
+
];
|
|
5968
|
+
applyCsvShortcutInput({
|
|
5969
|
+
runtimeInput,
|
|
5970
|
+
bindings: fileInputBindings
|
|
5971
|
+
});
|
|
5528
5972
|
const stagedFileInputs = await stageFileInputArgs({
|
|
5529
5973
|
client,
|
|
5530
5974
|
runtimeInput,
|
|
5531
|
-
bindings:
|
|
5532
|
-
...fileInputBindingsFromPlaySchema(playDetail.play.inputSchema),
|
|
5533
|
-
...fileInputBindingsFromStaticPipeline(playDetail.play.staticPipeline)
|
|
5534
|
-
],
|
|
5975
|
+
bindings: fileInputBindings,
|
|
5535
5976
|
progress
|
|
5536
5977
|
});
|
|
5537
5978
|
const startRequest = {
|
|
@@ -5609,80 +6050,101 @@ async function handlePlayRun(args) {
|
|
|
5609
6050
|
}
|
|
5610
6051
|
return handleNamedRun(options);
|
|
5611
6052
|
}
|
|
5612
|
-
|
|
5613
|
-
const usage = "Usage: deepline play tail --run-id <run-id> [--interval-ms 1000] [--json]\n deepline play tail --name <name> [--interval-ms 1000] [--json]";
|
|
5614
|
-
let target;
|
|
5615
|
-
try {
|
|
5616
|
-
target = parsePlayRunTarget({ args, usage, allowName: true });
|
|
5617
|
-
} catch (error) {
|
|
5618
|
-
console.error(error instanceof Error ? error.message : usage);
|
|
5619
|
-
return 1;
|
|
5620
|
-
}
|
|
5621
|
-
const client = new DeeplineClient();
|
|
5622
|
-
const jsonOutput = argsWantJson(args);
|
|
5623
|
-
const emitLogs = !jsonOutput || args.includes("--logs");
|
|
5624
|
-
let intervalMs = 500;
|
|
6053
|
+
function parseRunIdPositional(args, usage) {
|
|
5625
6054
|
for (let index = 0; index < args.length; index += 1) {
|
|
5626
6055
|
const arg = args[index];
|
|
5627
|
-
if (
|
|
5628
|
-
|
|
6056
|
+
if (arg === "--json" || arg === "--full" || arg === "--logs" || arg === "--compact" || arg === "--limit") {
|
|
6057
|
+
if (arg === "--limit" && args[index + 1]) {
|
|
6058
|
+
index += 1;
|
|
6059
|
+
}
|
|
6060
|
+
continue;
|
|
6061
|
+
}
|
|
6062
|
+
if ((arg === "--out" || arg === "--cursor" || arg === "--reason" || arg === "--interval-ms" || arg === "--poll-interval-ms") && args[index + 1]) {
|
|
6063
|
+
index += 1;
|
|
6064
|
+
continue;
|
|
6065
|
+
}
|
|
6066
|
+
if (!arg.startsWith("--")) {
|
|
6067
|
+
return arg;
|
|
5629
6068
|
}
|
|
5630
6069
|
}
|
|
5631
|
-
|
|
5632
|
-
const progress = getActiveCliProgress() ?? createCliProgress(!jsonOutput);
|
|
5633
|
-
progress.phase(`tailing ${workflowId}`);
|
|
5634
|
-
const finalStatus = await waitForPlayCompletion({
|
|
5635
|
-
client,
|
|
5636
|
-
workflowId,
|
|
5637
|
-
pollIntervalMs: intervalMs,
|
|
5638
|
-
jsonOutput,
|
|
5639
|
-
emitLogs,
|
|
5640
|
-
waitTimeoutMs: null,
|
|
5641
|
-
progress
|
|
5642
|
-
});
|
|
5643
|
-
if (finalStatus.status === "completed") {
|
|
5644
|
-
progress.complete();
|
|
5645
|
-
} else {
|
|
5646
|
-
progress.fail();
|
|
5647
|
-
}
|
|
5648
|
-
writePlayResult(finalStatus, jsonOutput);
|
|
5649
|
-
return finalStatus.status === "completed" ? 0 : 1;
|
|
6070
|
+
throw new DeeplineError(usage);
|
|
5650
6071
|
}
|
|
5651
|
-
async function
|
|
5652
|
-
const usage = "Usage: deepline
|
|
5653
|
-
let
|
|
6072
|
+
async function handleRunGet(args) {
|
|
6073
|
+
const usage = "Usage: deepline runs get <run-id> [--json] [--full]";
|
|
6074
|
+
let runId;
|
|
5654
6075
|
try {
|
|
5655
|
-
|
|
6076
|
+
runId = parseRunIdPositional(args, usage);
|
|
5656
6077
|
} catch (error) {
|
|
5657
6078
|
console.error(error instanceof Error ? error.message : usage);
|
|
5658
6079
|
return 1;
|
|
5659
6080
|
}
|
|
5660
6081
|
const client = new DeeplineClient();
|
|
5661
|
-
const
|
|
5662
|
-
const status = await client.getPlayStatus(workflowId);
|
|
6082
|
+
const status = await client.runs.get(runId);
|
|
5663
6083
|
writePlayResult(status, argsWantJson(args), {
|
|
5664
6084
|
fullJson: args.includes("--full")
|
|
5665
6085
|
});
|
|
5666
6086
|
return 0;
|
|
5667
6087
|
}
|
|
5668
|
-
function
|
|
6088
|
+
async function handleRunsList(args) {
|
|
6089
|
+
const usage = "Usage: deepline runs list --play <play-name> [--status <status>] [--json]";
|
|
6090
|
+
let playName = null;
|
|
6091
|
+
let statusFilter = null;
|
|
5669
6092
|
for (let index = 0; index < args.length; index += 1) {
|
|
5670
6093
|
const arg = args[index];
|
|
5671
|
-
if (arg === "--
|
|
6094
|
+
if ((arg === "--play" || arg === "--name") && args[index + 1]) {
|
|
6095
|
+
playName = parseReferencedPlayTarget(args[++index]).playName;
|
|
5672
6096
|
continue;
|
|
5673
6097
|
}
|
|
5674
|
-
if (arg === "--
|
|
5675
|
-
|
|
6098
|
+
if (arg === "--status" && args[index + 1]) {
|
|
6099
|
+
statusFilter = args[++index].trim().toLowerCase();
|
|
5676
6100
|
continue;
|
|
5677
6101
|
}
|
|
5678
|
-
if (
|
|
5679
|
-
|
|
6102
|
+
if (arg === "--json" || arg === "--compact") {
|
|
6103
|
+
continue;
|
|
5680
6104
|
}
|
|
5681
6105
|
}
|
|
5682
|
-
|
|
6106
|
+
if (!playName) {
|
|
6107
|
+
console.error(usage);
|
|
6108
|
+
return 1;
|
|
6109
|
+
}
|
|
6110
|
+
const client = new DeeplineClient();
|
|
6111
|
+
const runs = (await client.runs.list({
|
|
6112
|
+
play: playName,
|
|
6113
|
+
...statusFilter ? { status: statusFilter } : {}
|
|
6114
|
+
})).map((run) => ({
|
|
6115
|
+
runId: run.workflowId,
|
|
6116
|
+
workflowId: run.workflowId,
|
|
6117
|
+
temporalRunId: run.runId,
|
|
6118
|
+
status: String(run.status ?? "").toLowerCase(),
|
|
6119
|
+
startedAt: run.startTime,
|
|
6120
|
+
finishedAt: run.closeTime,
|
|
6121
|
+
executionTime: run.executionTime,
|
|
6122
|
+
playName: run.memo?.playName ?? playName
|
|
6123
|
+
}));
|
|
6124
|
+
if (argsWantJson(args)) {
|
|
6125
|
+
process.stdout.write(
|
|
6126
|
+
`${JSON.stringify({
|
|
6127
|
+
runs,
|
|
6128
|
+
count: runs.length,
|
|
6129
|
+
next: {
|
|
6130
|
+
get: runs[0]?.runId ? `deepline runs get ${runs[0].runId} --json` : null
|
|
6131
|
+
}
|
|
6132
|
+
})}
|
|
6133
|
+
`
|
|
6134
|
+
);
|
|
6135
|
+
} else {
|
|
6136
|
+
if (runs.length === 0) {
|
|
6137
|
+
console.log(`No runs found for ${playName}.`);
|
|
6138
|
+
} else {
|
|
6139
|
+
for (const run of runs) {
|
|
6140
|
+
console.log(`${run.runId} ${run.status} ${formatTimestamp(run.startedAt)}`);
|
|
6141
|
+
}
|
|
6142
|
+
}
|
|
6143
|
+
}
|
|
6144
|
+
return 0;
|
|
5683
6145
|
}
|
|
5684
|
-
async function
|
|
5685
|
-
const usage = "Usage: deepline runs
|
|
6146
|
+
async function handleRunTail(args) {
|
|
6147
|
+
const usage = "Usage: deepline runs tail <run-id> [--json] [--compact] [--cursor <cursor>]";
|
|
5686
6148
|
let runId;
|
|
5687
6149
|
try {
|
|
5688
6150
|
runId = parseRunIdPositional(args, usage);
|
|
@@ -5691,14 +6153,24 @@ async function handleRunStatus(args) {
|
|
|
5691
6153
|
return 1;
|
|
5692
6154
|
}
|
|
5693
6155
|
const client = new DeeplineClient();
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
6156
|
+
let afterLogIndex;
|
|
6157
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
6158
|
+
const arg = args[index];
|
|
6159
|
+
if (arg === "--cursor" && args[index + 1]) {
|
|
6160
|
+
const parsed = Number(args[++index]);
|
|
6161
|
+
if (Number.isInteger(parsed) && parsed >= 0) {
|
|
6162
|
+
afterLogIndex = parsed;
|
|
6163
|
+
}
|
|
6164
|
+
}
|
|
6165
|
+
}
|
|
6166
|
+
const status = await client.runs.tail(runId, {
|
|
6167
|
+
...afterLogIndex !== void 0 ? { afterLogIndex } : {}
|
|
5697
6168
|
});
|
|
5698
|
-
|
|
6169
|
+
writePlayResult(status, argsWantJson(args));
|
|
6170
|
+
return status.status === "failed" ? 1 : 0;
|
|
5699
6171
|
}
|
|
5700
6172
|
async function handleRunLogs(args) {
|
|
5701
|
-
const usage = "Usage: deepline runs logs <run-id> [--json]";
|
|
6173
|
+
const usage = "Usage: deepline runs logs <run-id> [--limit 200] [--out run.log] [--json]";
|
|
5702
6174
|
let runId;
|
|
5703
6175
|
try {
|
|
5704
6176
|
runId = parseRunIdPositional(args, usage);
|
|
@@ -5706,14 +6178,86 @@ async function handleRunLogs(args) {
|
|
|
5706
6178
|
console.error(error instanceof Error ? error.message : usage);
|
|
5707
6179
|
return 1;
|
|
5708
6180
|
}
|
|
6181
|
+
let limit = 200;
|
|
6182
|
+
let outPath = null;
|
|
6183
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
6184
|
+
const arg = args[index];
|
|
6185
|
+
if (arg === "--limit" && args[index + 1]) {
|
|
6186
|
+
limit = parsePositiveInteger2(args[++index], "--limit");
|
|
6187
|
+
continue;
|
|
6188
|
+
}
|
|
6189
|
+
if (arg === "--out" && args[index + 1]) {
|
|
6190
|
+
outPath = (0, import_node_path8.resolve)(args[++index]);
|
|
6191
|
+
}
|
|
6192
|
+
}
|
|
5709
6193
|
const client = new DeeplineClient();
|
|
5710
|
-
const status = await client.
|
|
6194
|
+
const status = await client.runs.get(runId);
|
|
5711
6195
|
const logs = status.progress?.logs ?? [];
|
|
6196
|
+
if (outPath) {
|
|
6197
|
+
(0, import_node_fs6.writeFileSync)(outPath, `${logs.join("\n")}${logs.length > 0 ? "\n" : ""}`);
|
|
6198
|
+
if (argsWantJson(args)) {
|
|
6199
|
+
process.stdout.write(
|
|
6200
|
+
`${JSON.stringify({
|
|
6201
|
+
runId: status.runId,
|
|
6202
|
+
log_path: outPath,
|
|
6203
|
+
lineCount: logs.length
|
|
6204
|
+
})}
|
|
6205
|
+
`
|
|
6206
|
+
);
|
|
6207
|
+
} else {
|
|
6208
|
+
console.log(`Wrote ${logs.length} log lines to ${outPath}`);
|
|
6209
|
+
}
|
|
6210
|
+
return 0;
|
|
6211
|
+
}
|
|
6212
|
+
const entries = logs.slice(Math.max(0, logs.length - limit));
|
|
5712
6213
|
if (argsWantJson(args)) {
|
|
5713
|
-
process.stdout.write(
|
|
6214
|
+
process.stdout.write(
|
|
6215
|
+
`${JSON.stringify({
|
|
6216
|
+
runId: status.runId,
|
|
6217
|
+
totalCount: logs.length,
|
|
6218
|
+
returnedCount: entries.length,
|
|
6219
|
+
firstSequence: logs.length === 0 ? null : logs.length - entries.length + 1,
|
|
6220
|
+
lastSequence: logs.length === 0 ? null : logs.length,
|
|
6221
|
+
truncated: logs.length > entries.length,
|
|
6222
|
+
hasMore: logs.length > entries.length,
|
|
6223
|
+
entries,
|
|
6224
|
+
next: {
|
|
6225
|
+
export: `deepline runs logs ${status.runId} --out run.log --json`
|
|
6226
|
+
}
|
|
6227
|
+
})}
|
|
6228
|
+
`
|
|
6229
|
+
);
|
|
6230
|
+
} else {
|
|
6231
|
+
process.stdout.write(`${entries.join("\n")}${entries.length > 0 ? "\n" : ""}`);
|
|
6232
|
+
}
|
|
6233
|
+
return 0;
|
|
6234
|
+
}
|
|
6235
|
+
async function handleRunStop(args) {
|
|
6236
|
+
const usage = 'Usage: deepline runs stop <run-id> [--reason "text"] [--json]';
|
|
6237
|
+
let runId;
|
|
6238
|
+
try {
|
|
6239
|
+
runId = parseRunIdPositional(args, usage);
|
|
6240
|
+
} catch (error) {
|
|
6241
|
+
console.error(error instanceof Error ? error.message : usage);
|
|
6242
|
+
return 1;
|
|
6243
|
+
}
|
|
6244
|
+
let reason;
|
|
6245
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
6246
|
+
const arg = args[index];
|
|
6247
|
+
if (arg === "--reason" && args[index + 1]) {
|
|
6248
|
+
reason = args[++index];
|
|
6249
|
+
}
|
|
6250
|
+
}
|
|
6251
|
+
const client = new DeeplineClient();
|
|
6252
|
+
const result = await client.runs.stop(runId, { reason });
|
|
6253
|
+
if (argsWantJson(args)) {
|
|
6254
|
+
process.stdout.write(`${JSON.stringify(result)}
|
|
5714
6255
|
`);
|
|
5715
6256
|
} else {
|
|
5716
|
-
|
|
6257
|
+
console.log(`Stopped ${result.runId}`);
|
|
6258
|
+
if (result.hitlCancelledCount > 0) {
|
|
6259
|
+
console.log(` cancelled HITL waits: ${result.hitlCancelledCount}`);
|
|
6260
|
+
}
|
|
5717
6261
|
}
|
|
5718
6262
|
return 0;
|
|
5719
6263
|
}
|
|
@@ -5756,37 +6300,6 @@ async function handleRunExport(args) {
|
|
|
5756
6300
|
}
|
|
5757
6301
|
return 0;
|
|
5758
6302
|
}
|
|
5759
|
-
async function handlePlayStop(args) {
|
|
5760
|
-
const usage = 'Usage: deepline play stop --run-id <run-id> [--reason "text"] [--json]';
|
|
5761
|
-
let target;
|
|
5762
|
-
try {
|
|
5763
|
-
target = parsePlayRunTarget({ args, usage, allowName: false });
|
|
5764
|
-
} catch (error) {
|
|
5765
|
-
console.error(error instanceof Error ? error.message : usage);
|
|
5766
|
-
return 1;
|
|
5767
|
-
}
|
|
5768
|
-
const client = new DeeplineClient();
|
|
5769
|
-
const jsonOutput = argsWantJson(args);
|
|
5770
|
-
let reason;
|
|
5771
|
-
for (let index = 0; index < args.length; index += 1) {
|
|
5772
|
-
const arg = args[index];
|
|
5773
|
-
if (arg === "--reason" && args[index + 1]) {
|
|
5774
|
-
reason = args[++index];
|
|
5775
|
-
}
|
|
5776
|
-
}
|
|
5777
|
-
const workflowId = await resolvePlayRunId(client, target);
|
|
5778
|
-
const result = await client.stopPlay(workflowId, { reason });
|
|
5779
|
-
if (jsonOutput) {
|
|
5780
|
-
process.stdout.write(`${JSON.stringify(result)}
|
|
5781
|
-
`);
|
|
5782
|
-
} else {
|
|
5783
|
-
console.log(`Stopped ${result.runId}`);
|
|
5784
|
-
if (result.hitlCancelledCount > 0) {
|
|
5785
|
-
console.log(` cancelled HITL waits: ${result.hitlCancelledCount}`);
|
|
5786
|
-
}
|
|
5787
|
-
}
|
|
5788
|
-
return 0;
|
|
5789
|
-
}
|
|
5790
6303
|
async function handlePlayGet(args) {
|
|
5791
6304
|
const target = args[0];
|
|
5792
6305
|
if (!target) {
|
|
@@ -5874,33 +6387,6 @@ async function handlePlayGet(args) {
|
|
|
5874
6387
|
}
|
|
5875
6388
|
return 0;
|
|
5876
6389
|
}
|
|
5877
|
-
async function handlePlayRuns(args) {
|
|
5878
|
-
const nameIndex = args.indexOf("--name");
|
|
5879
|
-
const name = nameIndex >= 0 ? args[nameIndex + 1] : void 0;
|
|
5880
|
-
if (!name) {
|
|
5881
|
-
console.error("Usage: deepline play runs --name <name> [--json]");
|
|
5882
|
-
return 1;
|
|
5883
|
-
}
|
|
5884
|
-
const client = new DeeplineClient();
|
|
5885
|
-
const jsonOutput = argsWantJson(args);
|
|
5886
|
-
await assertCanonicalNamedPlayReference(client, name);
|
|
5887
|
-
const runs = await client.listPlayRuns(
|
|
5888
|
-
parseReferencedPlayTarget(name).playName
|
|
5889
|
-
);
|
|
5890
|
-
if (jsonOutput) {
|
|
5891
|
-
process.stdout.write(`${JSON.stringify({ runs })}
|
|
5892
|
-
`);
|
|
5893
|
-
return 0;
|
|
5894
|
-
}
|
|
5895
|
-
if (runs.length === 0) {
|
|
5896
|
-
console.log(`No runs found for ${name}.`);
|
|
5897
|
-
return 0;
|
|
5898
|
-
}
|
|
5899
|
-
for (const run of runs) {
|
|
5900
|
-
console.log(formatRunLine(run));
|
|
5901
|
-
}
|
|
5902
|
-
return 0;
|
|
5903
|
-
}
|
|
5904
6390
|
function formatVersionLine(version) {
|
|
5905
6391
|
const revisionLabel = version.artifactHash?.slice(0, 12) ?? "unknown-revision";
|
|
5906
6392
|
return `v${version.version} ${revisionLabel} ${formatTimestamp(version.createdAt)}`;
|
|
@@ -6032,6 +6518,11 @@ function printPlayDescription(play) {
|
|
|
6032
6518
|
}
|
|
6033
6519
|
}
|
|
6034
6520
|
console.log(` Run: ${play.runCommand}`);
|
|
6521
|
+
if (play.origin === "prebuilt" && !play.canEdit) {
|
|
6522
|
+
console.log(
|
|
6523
|
+
` Customize: deepline plays get ${reference} --source --out ./my-play.play.ts`
|
|
6524
|
+
);
|
|
6525
|
+
}
|
|
6035
6526
|
}
|
|
6036
6527
|
async function handlePlaySearch(args) {
|
|
6037
6528
|
let options;
|
|
@@ -6129,6 +6620,7 @@ async function handlePlayPublish(args) {
|
|
|
6129
6620
|
const published = await client.registerPlayArtifact({
|
|
6130
6621
|
name: rootPlayName,
|
|
6131
6622
|
sourceCode: graph.root.sourceCode,
|
|
6623
|
+
sourceFiles: graph.root.sourceFiles,
|
|
6132
6624
|
artifact: graph.root.artifact,
|
|
6133
6625
|
compilerManifest: requireCompilerManifest(graph.root),
|
|
6134
6626
|
publish: true
|
|
@@ -6349,50 +6841,12 @@ Examples:
|
|
|
6349
6841
|
...options.json ? ["--json"] : []
|
|
6350
6842
|
]);
|
|
6351
6843
|
});
|
|
6352
|
-
play.command("runs").description("List runs for a named play.").option("--name <name>", "Saved play name").option("--json", "Emit JSON output").action(async (options) => {
|
|
6353
|
-
process.exitCode = await handlePlayRuns([
|
|
6354
|
-
...options.name ? ["--name", options.name] : [],
|
|
6355
|
-
...options.json ? ["--json"] : []
|
|
6356
|
-
]);
|
|
6357
|
-
});
|
|
6358
6844
|
play.command("versions").description("List revisions for a named play.").option("--name <name>", "Saved play name").option("--json", "Emit JSON output").action(async (options) => {
|
|
6359
6845
|
process.exitCode = await handlePlayVersions([
|
|
6360
6846
|
...options.name ? ["--name", options.name] : [],
|
|
6361
6847
|
...options.json ? ["--json"] : []
|
|
6362
6848
|
]);
|
|
6363
6849
|
});
|
|
6364
|
-
play.command("tail").description("Tail events for a play run.").option("--run-id <runId>", "Run id to tail").option("--name <name>", "Tail the latest run for a named play").option("--interval-ms <ms>", "Polling interval while tailing").option("--logs", "With --json, stream play logs to stderr while waiting").option("--json", "Emit JSON output").action(async (options) => {
|
|
6365
|
-
process.exitCode = await handlePlayTail([
|
|
6366
|
-
...options.runId ? ["--run-id", options.runId] : [],
|
|
6367
|
-
...options.name ? ["--name", options.name] : [],
|
|
6368
|
-
...options.intervalMs ? ["--interval-ms", options.intervalMs] : [],
|
|
6369
|
-
...options.logs ? ["--logs"] : [],
|
|
6370
|
-
...options.json ? ["--json"] : []
|
|
6371
|
-
]);
|
|
6372
|
-
});
|
|
6373
|
-
play.command("status").description("Show status for a play run.").option("--run-id <runId>", "Run id to inspect").option("--name <name>", "Inspect the latest run for a named play").option("--json", "Emit JSON output").option("--full", "Debug only: with --json, emit the raw status payload").action(async (options) => {
|
|
6374
|
-
process.exitCode = await handlePlayStatus([
|
|
6375
|
-
...options.runId ? ["--run-id", options.runId] : [],
|
|
6376
|
-
...options.name ? ["--name", options.name] : [],
|
|
6377
|
-
...options.json ? ["--json"] : [],
|
|
6378
|
-
...options.full ? ["--full"] : []
|
|
6379
|
-
]);
|
|
6380
|
-
});
|
|
6381
|
-
play.command("export").description("Export a completed play run to CSV.").requiredOption("--run-id <runId>", "Run id to export").requiredOption("--out <path>", "Output CSV path").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
|
|
6382
|
-
process.exitCode = await handleRunExport([
|
|
6383
|
-
options.runId,
|
|
6384
|
-
"--out",
|
|
6385
|
-
options.out,
|
|
6386
|
-
...options.json ? ["--json"] : []
|
|
6387
|
-
]);
|
|
6388
|
-
});
|
|
6389
|
-
play.command("stop").description("Stop a play run.").option("--run-id <runId>", "Run id to stop").option("--reason <text>", "Reason to include with the stop request").option("--json", "Emit JSON output").action(async (options) => {
|
|
6390
|
-
process.exitCode = await handlePlayStop([
|
|
6391
|
-
...options.runId ? ["--run-id", options.runId] : [],
|
|
6392
|
-
...options.reason ? ["--reason", options.reason] : [],
|
|
6393
|
-
...options.json ? ["--json"] : []
|
|
6394
|
-
]);
|
|
6395
|
-
});
|
|
6396
6850
|
play.command("publish <target>").description("Bundle, validate, save, and publish a play.").option("--latest", "Promote the newest saved revision").option("--revision-id <id>", "Revision to promote").option("--json", "Emit JSON output").action(async (target, options) => {
|
|
6397
6851
|
process.exitCode = await handlePlayPublish([
|
|
6398
6852
|
target,
|
|
@@ -6408,38 +6862,72 @@ Examples:
|
|
|
6408
6862
|
...options.json ? ["--json"] : []
|
|
6409
6863
|
]);
|
|
6410
6864
|
});
|
|
6411
|
-
const runs = program.command("runs").description("Inspect and export play runs.").addHelpText(
|
|
6865
|
+
const runs = program.command("runs").description("Inspect, tail, stop, and export play runs.").addHelpText(
|
|
6412
6866
|
"after",
|
|
6413
6867
|
`
|
|
6414
6868
|
Examples:
|
|
6415
|
-
deepline runs
|
|
6869
|
+
deepline runs get play/my-play/run/20260501t000000-000 --json
|
|
6870
|
+
deepline runs tail play/my-play/run/20260501t000000-000
|
|
6871
|
+
deepline runs logs play/my-play/run/20260501t000000-000 --out run.log --json
|
|
6872
|
+
deepline runs list --play my-play --status failed --json
|
|
6873
|
+
deepline runs stop play/my-play/run/20260501t000000-000 --reason "stale lock" --json
|
|
6416
6874
|
deepline runs export play/my-play/run/20260501t000000-000 --out output.csv
|
|
6417
|
-
deepline runs logs play/my-play/run/20260501t000000-000
|
|
6418
6875
|
`
|
|
6419
6876
|
);
|
|
6420
|
-
runs.command("
|
|
6421
|
-
process.exitCode = await
|
|
6877
|
+
runs.command("get <runId>").description("Get status, progress, outputs, errors, and recovery metadata for a play run.").option("--json", "Emit JSON output. Also automatic when stdout is piped").option("--full", "Debug only: with --json, emit the raw status payload").action(async (runId, options) => {
|
|
6878
|
+
process.exitCode = await handleRunGet([
|
|
6422
6879
|
runId,
|
|
6423
6880
|
...options.json ? ["--json"] : [],
|
|
6424
6881
|
...options.full ? ["--full"] : []
|
|
6425
6882
|
]);
|
|
6426
6883
|
});
|
|
6427
|
-
runs.command("
|
|
6428
|
-
process.exitCode = await
|
|
6429
|
-
|
|
6430
|
-
|
|
6431
|
-
options.
|
|
6884
|
+
runs.command("list").description("List play runs.").requiredOption("--play <name>", "Play name to filter runs").option("--status <status>", "Filter by run status").option("--compact", "Drop verbose fields from JSON output").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
|
|
6885
|
+
process.exitCode = await handleRunsList([
|
|
6886
|
+
"--play",
|
|
6887
|
+
options.play,
|
|
6888
|
+
...options.status ? ["--status", options.status] : [],
|
|
6889
|
+
...options.compact ? ["--compact"] : [],
|
|
6432
6890
|
...options.json ? ["--json"] : []
|
|
6433
6891
|
]);
|
|
6434
6892
|
});
|
|
6435
|
-
runs.command("
|
|
6893
|
+
runs.command("tail <runId>").description("Tail or fetch recent live events for a play run.").option("--json", "Emit JSON output. Also automatic when stdout is piped").option("--compact", "Drop verbose fields from JSON output").option("--cursor <cursor>", "Resume after a previously returned event cursor").action(async (runId, options) => {
|
|
6894
|
+
process.exitCode = await handleRunTail([
|
|
6895
|
+
runId,
|
|
6896
|
+
...options.json ? ["--json"] : [],
|
|
6897
|
+
...options.compact ? ["--compact"] : [],
|
|
6898
|
+
...options.cursor ? ["--cursor", options.cursor] : []
|
|
6899
|
+
]);
|
|
6900
|
+
});
|
|
6901
|
+
runs.command("logs <runId>").description("Fetch persisted logs for a play run.").option("--limit <count>", "Maximum recent log lines to print without --out", "200").option("--out <path>", "Write the full persisted log stream to a file").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
|
|
6436
6902
|
process.exitCode = await handleRunLogs([
|
|
6437
6903
|
runId,
|
|
6904
|
+
...options.limit ? ["--limit", options.limit] : [],
|
|
6905
|
+
...options.out ? ["--out", options.out] : [],
|
|
6906
|
+
...options.json ? ["--json"] : []
|
|
6907
|
+
]);
|
|
6908
|
+
});
|
|
6909
|
+
runs.command("stop <runId>").description("Stop a play run.").option("--reason <text>", "Reason to include with the stop request").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
|
|
6910
|
+
process.exitCode = await handleRunStop([
|
|
6911
|
+
runId,
|
|
6912
|
+
...options.reason ? ["--reason", options.reason] : [],
|
|
6913
|
+
...options.json ? ["--json"] : []
|
|
6914
|
+
]);
|
|
6915
|
+
});
|
|
6916
|
+
runs.command("export <runId>").description("Export the completed row output for a play run to CSV.").requiredOption("--out <path>", "Output CSV path").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
|
|
6917
|
+
process.exitCode = await handleRunExport([
|
|
6918
|
+
runId,
|
|
6919
|
+
"--out",
|
|
6920
|
+
options.out,
|
|
6438
6921
|
...options.json ? ["--json"] : []
|
|
6439
6922
|
]);
|
|
6440
6923
|
});
|
|
6441
6924
|
}
|
|
6442
6925
|
|
|
6926
|
+
// src/cli/commands/tools.ts
|
|
6927
|
+
var import_node_fs8 = require("fs");
|
|
6928
|
+
var import_node_os7 = require("os");
|
|
6929
|
+
var import_node_path10 = require("path");
|
|
6930
|
+
|
|
6443
6931
|
// src/tool-output.ts
|
|
6444
6932
|
var import_node_fs7 = require("fs");
|
|
6445
6933
|
var import_node_os6 = require("os");
|
|
@@ -6608,31 +7096,23 @@ async function listTools(args) {
|
|
|
6608
7096
|
}
|
|
6609
7097
|
return 0;
|
|
6610
7098
|
}
|
|
6611
|
-
function
|
|
6612
|
-
const
|
|
6613
|
-
tool.toolId,
|
|
6614
|
-
tool.provider,
|
|
6615
|
-
tool.displayName,
|
|
6616
|
-
tool.description,
|
|
6617
|
-
tool.operation,
|
|
6618
|
-
tool.operationId,
|
|
6619
|
-
...tool.operationAliases ?? [],
|
|
6620
|
-
...tool.categories ?? [],
|
|
6621
|
-
tool.inputSchema ? JSON.stringify(tool.inputSchema) : ""
|
|
6622
|
-
].filter(Boolean).join(" ").toLowerCase();
|
|
6623
|
-
return terms.every((term) => haystack.includes(term));
|
|
6624
|
-
}
|
|
6625
|
-
async function searchTools(args) {
|
|
6626
|
-
const query = args[0]?.trim();
|
|
7099
|
+
async function searchTools(queryInput, options = {}) {
|
|
7100
|
+
const query = queryInput.trim();
|
|
6627
7101
|
if (!query) {
|
|
6628
7102
|
console.error("Usage: deepline tools search <query> [--json]");
|
|
6629
7103
|
return 1;
|
|
6630
7104
|
}
|
|
6631
|
-
const terms = query.toLowerCase().split(/\s+/).filter(Boolean);
|
|
6632
7105
|
const client = new DeeplineClient();
|
|
6633
|
-
const
|
|
6634
|
-
|
|
6635
|
-
|
|
7106
|
+
const result = await client.searchTools({
|
|
7107
|
+
query,
|
|
7108
|
+
categories: options.categories,
|
|
7109
|
+
searchTerms: options.searchTerms,
|
|
7110
|
+
searchMode: options.searchMode,
|
|
7111
|
+
includeSearchDebug: options.includeSearchDebug
|
|
7112
|
+
});
|
|
7113
|
+
const items = result.tools.map(toListedTool);
|
|
7114
|
+
if (options.json || shouldEmitJson()) {
|
|
7115
|
+
process.stdout.write(`${JSON.stringify({ ...result, tools: items })}
|
|
6636
7116
|
`);
|
|
6637
7117
|
return 0;
|
|
6638
7118
|
}
|
|
@@ -6686,11 +7166,14 @@ Common commands:
|
|
|
6686
7166
|
...options.json ? ["--json"] : []
|
|
6687
7167
|
]);
|
|
6688
7168
|
});
|
|
6689
|
-
tools.command("search <query>").description("Search available tools.").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
|
|
6690
|
-
process.exitCode = await searchTools(
|
|
6691
|
-
|
|
6692
|
-
|
|
6693
|
-
|
|
7169
|
+
tools.command("search <query>").description("Search available tools.").option("--categories <categories>", "Comma-separated categories to filter ranked search").option("--search_terms <terms>", "Structured search terms for ranked search").option("--search-terms <terms>", "Structured search terms for ranked search").option("--search-mode <mode>", "Ranked search mode: v1 or v2").option("--include-search-debug", "Include ranked search debug metadata").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
|
|
7170
|
+
process.exitCode = await searchTools(query, {
|
|
7171
|
+
json: options.json,
|
|
7172
|
+
categories: options.categories,
|
|
7173
|
+
searchTerms: options.searchTerms ?? options.search_terms,
|
|
7174
|
+
searchMode: options.searchMode === "v1" || options.searchMode === "v2" ? options.searchMode : void 0,
|
|
7175
|
+
includeSearchDebug: Boolean(options.includeSearchDebug)
|
|
7176
|
+
});
|
|
6694
7177
|
});
|
|
6695
7178
|
tools.command("get <toolId>").alias("describe").description("Show metadata for a tool.").addHelpText(
|
|
6696
7179
|
"after",
|
|
@@ -7048,6 +7531,61 @@ function parseExecuteOptions(args) {
|
|
|
7048
7531
|
}
|
|
7049
7532
|
return { toolId, params, outputFormat, noPreview };
|
|
7050
7533
|
}
|
|
7534
|
+
function safeFileStem(value) {
|
|
7535
|
+
return value.trim().replace(/[^a-zA-Z0-9_-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64) || "tool";
|
|
7536
|
+
}
|
|
7537
|
+
function shellQuote(value) {
|
|
7538
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
7539
|
+
}
|
|
7540
|
+
function powerShellQuote(value) {
|
|
7541
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
7542
|
+
}
|
|
7543
|
+
function seedToolListScript(input) {
|
|
7544
|
+
const stem = safeFileStem(input.toolId);
|
|
7545
|
+
const fileName = `${stem}-workflow-seed-${Date.now()}.play.ts`;
|
|
7546
|
+
const scriptDir = (0, import_node_fs8.mkdtempSync)((0, import_node_path10.join)((0, import_node_os7.tmpdir)(), "deepline-workflow-seed-"));
|
|
7547
|
+
(0, import_node_fs8.chmodSync)(scriptDir, 448);
|
|
7548
|
+
const scriptPath = (0, import_node_path10.join)(scriptDir, fileName);
|
|
7549
|
+
const projectDir = `deepline/projects/${stem}-workflow`;
|
|
7550
|
+
const playName = `${stem}-workflow`;
|
|
7551
|
+
const sampleRows = input.rows.length > 0 ? `${JSON.stringify(input.rows.slice(0, 2)).replace(/\]$/, "")}, ...]` : "[]";
|
|
7552
|
+
const columns = Object.keys(input.rows[0] ?? {}).join(", ");
|
|
7553
|
+
const rowKey = Object.prototype.hasOwnProperty.call(input.rows[0] ?? {}, "id") ? '"id"' : "(row) => JSON.stringify(row)";
|
|
7554
|
+
const script = `import { definePlay } from 'deepline';
|
|
7555
|
+
|
|
7556
|
+
export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
7557
|
+
const result = await ctx.tools.execute({
|
|
7558
|
+
id: ${JSON.stringify(input.toolId)},
|
|
7559
|
+
tool: ${JSON.stringify(input.toolId)},
|
|
7560
|
+
input: ${JSON.stringify(input.payload)},
|
|
7561
|
+
description: ${JSON.stringify(`Seed ${input.toolId} rows for workflow expansion.`)},
|
|
7562
|
+
});
|
|
7563
|
+
|
|
7564
|
+
const list = Object.values(result.lists)[0];
|
|
7565
|
+
const rows = (list?.get() ?? []).slice(0, 100);
|
|
7566
|
+
// ${sampleRows}
|
|
7567
|
+
// columns: ${columns}
|
|
7568
|
+
// .step('email_waterfall', (row, rowCtx) => rowCtx.runPlay('name_domain_email', 'name-and-domain-to-email', { first_name: String(row.first_name ?? ''), last_name: String(row.last_name ?? ''), domain: String(row.domain ?? '') }, { description: 'Resolve email.' }))
|
|
7569
|
+
// .step('phone_waterfall', (row, rowCtx) => rowCtx.runPlay('contact_phone', 'contact-to-phone', { first_name: String(row.first_name ?? ''), last_name: String(row.last_name ?? ''), email: String(row.email ?? '') }, { description: 'Resolve phone.' }))
|
|
7570
|
+
// ctx.map is idempotent by map key + row key; reruns reuse completed rows.
|
|
7571
|
+
const enrichedData = await ctx
|
|
7572
|
+
.map('enriched_data', rows, { key: ${rowKey} })
|
|
7573
|
+
.run({ description: 'Enrich seeded rows.' });
|
|
7574
|
+
|
|
7575
|
+
return {
|
|
7576
|
+
rows: enrichedData,
|
|
7577
|
+
count: await enrichedData.count(),
|
|
7578
|
+
};
|
|
7579
|
+
});
|
|
7580
|
+
`;
|
|
7581
|
+
(0, import_node_fs8.writeFileSync)(scriptPath, script, { encoding: "utf-8", mode: 384 });
|
|
7582
|
+
return {
|
|
7583
|
+
path: scriptPath,
|
|
7584
|
+
projectDir,
|
|
7585
|
+
macCopyCommand: `mkdir -p ${shellQuote(projectDir)} && cp ${shellQuote(scriptPath)} ${shellQuote(`${projectDir}/${fileName}`)}`,
|
|
7586
|
+
windowsCopyCommand: `New-Item -ItemType Directory -Force -Path ${powerShellQuote(projectDir.replace(/\//g, "\\"))} | Out-Null; Copy-Item -LiteralPath ${powerShellQuote(scriptPath)} -Destination ${powerShellQuote(`${projectDir.replace(/\//g, "\\")}\\${fileName}`)}`
|
|
7587
|
+
};
|
|
7588
|
+
}
|
|
7051
7589
|
async function executeTool(args) {
|
|
7052
7590
|
let parsed;
|
|
7053
7591
|
try {
|
|
@@ -7101,6 +7639,11 @@ async function executeTool(args) {
|
|
|
7101
7639
|
return 0;
|
|
7102
7640
|
}
|
|
7103
7641
|
const csv = writeCsvOutputFile(listConversion.rows, `${parsed.toolId}_output`);
|
|
7642
|
+
const seededScript = seedToolListScript({
|
|
7643
|
+
toolId: parsed.toolId,
|
|
7644
|
+
payload: parsed.params,
|
|
7645
|
+
rows: listConversion.rows
|
|
7646
|
+
});
|
|
7104
7647
|
if (parsed.outputFormat === "csv_file") {
|
|
7105
7648
|
process.stdout.write(`${JSON.stringify({
|
|
7106
7649
|
extracted_csv: csv.path,
|
|
@@ -7109,6 +7652,12 @@ async function executeTool(args) {
|
|
|
7109
7652
|
preview: csv.preview,
|
|
7110
7653
|
list_strategy: listConversion.strategy,
|
|
7111
7654
|
list_source_path: listConversion.sourcePath,
|
|
7655
|
+
starter_script: seededScript.path,
|
|
7656
|
+
project_dir: seededScript.projectDir,
|
|
7657
|
+
copy_to_project: {
|
|
7658
|
+
macos_linux: seededScript.macCopyCommand,
|
|
7659
|
+
windows_powershell: seededScript.windowsCopyCommand
|
|
7660
|
+
},
|
|
7112
7661
|
summary
|
|
7113
7662
|
})}
|
|
7114
7663
|
`);
|
|
@@ -7126,14 +7675,20 @@ async function executeTool(args) {
|
|
|
7126
7675
|
console.log(`summary: ${Object.entries(summary).map(([key, value]) => `${key}=${String(value)}`).join(", ")}`);
|
|
7127
7676
|
}
|
|
7128
7677
|
console.log(`preview: ${JSON.stringify(csv.preview)}`);
|
|
7678
|
+
console.log(`starter script: ${seededScript.path}`);
|
|
7679
|
+
console.log(
|
|
7680
|
+
"next: Move the script into a project folder and expand it into a Deepline play. Use stable map and step keys so reruns are idempotent: completed rows are reused, and only missing or stale work runs again."
|
|
7681
|
+
);
|
|
7682
|
+
console.log(`macOS/Linux: ${seededScript.macCopyCommand}`);
|
|
7683
|
+
console.log(`Windows PowerShell: ${seededScript.windowsCopyCommand}`);
|
|
7129
7684
|
return 0;
|
|
7130
7685
|
}
|
|
7131
7686
|
|
|
7132
7687
|
// src/cli/skills-sync.ts
|
|
7133
7688
|
var import_node_child_process2 = require("child_process");
|
|
7134
|
-
var
|
|
7135
|
-
var
|
|
7136
|
-
var
|
|
7689
|
+
var import_node_fs9 = require("fs");
|
|
7690
|
+
var import_node_os8 = require("os");
|
|
7691
|
+
var import_node_path11 = require("path");
|
|
7137
7692
|
var CHECK_TIMEOUT_MS2 = 3e3;
|
|
7138
7693
|
var SDK_SKILL_NAME = "deepline-sdk";
|
|
7139
7694
|
var SKILL_AGENTS = ["codex", "claude-code", "cursor"];
|
|
@@ -7143,22 +7698,22 @@ function shouldSkipSkillsSync() {
|
|
|
7143
7698
|
return value === "1" || value === "true" || value === "yes" || value === "on";
|
|
7144
7699
|
}
|
|
7145
7700
|
function sdkSkillsVersionPath(baseUrl) {
|
|
7146
|
-
const home = process.env.HOME?.trim() || (0,
|
|
7147
|
-
return (0,
|
|
7701
|
+
const home = process.env.HOME?.trim() || (0, import_node_os8.homedir)();
|
|
7702
|
+
return (0, import_node_path11.join)(home, ".local", "deepline", baseUrlSlug(baseUrl), "sdk-skills", ".version");
|
|
7148
7703
|
}
|
|
7149
7704
|
function readLocalSkillsVersion(baseUrl) {
|
|
7150
7705
|
const path = sdkSkillsVersionPath(baseUrl);
|
|
7151
|
-
if (!(0,
|
|
7706
|
+
if (!(0, import_node_fs9.existsSync)(path)) return "";
|
|
7152
7707
|
try {
|
|
7153
|
-
return (0,
|
|
7708
|
+
return (0, import_node_fs9.readFileSync)(path, "utf-8").trim();
|
|
7154
7709
|
} catch {
|
|
7155
7710
|
return "";
|
|
7156
7711
|
}
|
|
7157
7712
|
}
|
|
7158
7713
|
function writeLocalSkillsVersion(baseUrl, version) {
|
|
7159
7714
|
const path = sdkSkillsVersionPath(baseUrl);
|
|
7160
|
-
(0,
|
|
7161
|
-
(0,
|
|
7715
|
+
(0, import_node_fs9.mkdirSync)((0, import_node_path11.dirname)(path), { recursive: true });
|
|
7716
|
+
(0, import_node_fs9.writeFileSync)(path, `${version}
|
|
7162
7717
|
`, "utf-8");
|
|
7163
7718
|
}
|
|
7164
7719
|
async function fetchSkillsUpdate(baseUrl, localVersion) {
|
|
@@ -7189,9 +7744,26 @@ async function fetchSkillsUpdate(baseUrl, localVersion) {
|
|
|
7189
7744
|
clearTimeout(timeout);
|
|
7190
7745
|
}
|
|
7191
7746
|
}
|
|
7192
|
-
function
|
|
7747
|
+
function buildSkillsInstallArgs(baseUrl) {
|
|
7748
|
+
const packageUrl = new URL("/.well-known/skills/index.json", baseUrl).toString();
|
|
7749
|
+
return [
|
|
7750
|
+
"--yes",
|
|
7751
|
+
"skills",
|
|
7752
|
+
"add",
|
|
7753
|
+
packageUrl,
|
|
7754
|
+
"--agents",
|
|
7755
|
+
...SKILL_AGENTS,
|
|
7756
|
+
"--global",
|
|
7757
|
+
"--yes",
|
|
7758
|
+
"--skill",
|
|
7759
|
+
SDK_SKILL_NAME,
|
|
7760
|
+
"--full-depth"
|
|
7761
|
+
];
|
|
7762
|
+
}
|
|
7763
|
+
function buildBunxSkillsInstallArgs(baseUrl) {
|
|
7193
7764
|
const packageUrl = new URL("/.well-known/skills/index.json", baseUrl).toString();
|
|
7194
|
-
|
|
7765
|
+
return [
|
|
7766
|
+
"--bun",
|
|
7195
7767
|
"skills",
|
|
7196
7768
|
"add",
|
|
7197
7769
|
packageUrl,
|
|
@@ -7203,8 +7775,40 @@ function runSkillsInstall(baseUrl) {
|
|
|
7203
7775
|
SDK_SKILL_NAME,
|
|
7204
7776
|
"--full-depth"
|
|
7205
7777
|
];
|
|
7778
|
+
}
|
|
7779
|
+
function hasCommand(command) {
|
|
7780
|
+
const result = (0, import_node_child_process2.spawnSync)(command, ["--version"], {
|
|
7781
|
+
stdio: "ignore",
|
|
7782
|
+
shell: process.platform === "win32"
|
|
7783
|
+
});
|
|
7784
|
+
return result.status === 0;
|
|
7785
|
+
}
|
|
7786
|
+
function shellQuote2(arg) {
|
|
7787
|
+
return `'${arg.replace(/'/g, `'\\''`)}'`;
|
|
7788
|
+
}
|
|
7789
|
+
function resolveSkillsInstallCommands(baseUrl) {
|
|
7790
|
+
const npxArgs = buildSkillsInstallArgs(baseUrl);
|
|
7791
|
+
const npxInstall = {
|
|
7792
|
+
command: "npx",
|
|
7793
|
+
args: npxArgs,
|
|
7794
|
+
manualCommand: `npx ${npxArgs.map(shellQuote2).join(" ")}`
|
|
7795
|
+
};
|
|
7796
|
+
if (hasCommand("bunx")) {
|
|
7797
|
+
const bunxArgs = buildBunxSkillsInstallArgs(baseUrl);
|
|
7798
|
+
return [
|
|
7799
|
+
{
|
|
7800
|
+
command: "bunx",
|
|
7801
|
+
args: bunxArgs,
|
|
7802
|
+
manualCommand: `bunx ${bunxArgs.map(shellQuote2).join(" ")}`
|
|
7803
|
+
},
|
|
7804
|
+
npxInstall
|
|
7805
|
+
];
|
|
7806
|
+
}
|
|
7807
|
+
return [npxInstall];
|
|
7808
|
+
}
|
|
7809
|
+
function runOneSkillsInstall(install) {
|
|
7206
7810
|
return new Promise((resolve8) => {
|
|
7207
|
-
const child = (0, import_node_child_process2.spawn)(
|
|
7811
|
+
const child = (0, import_node_child_process2.spawn)(install.command, install.args, {
|
|
7208
7812
|
stdio: ["ignore", "ignore", "pipe"],
|
|
7209
7813
|
env: process.env
|
|
7210
7814
|
});
|
|
@@ -7213,37 +7817,63 @@ function runSkillsInstall(baseUrl) {
|
|
|
7213
7817
|
stderr += chunk.toString("utf-8");
|
|
7214
7818
|
});
|
|
7215
7819
|
child.on("error", (error) => {
|
|
7216
|
-
|
|
7217
|
-
|
|
7218
|
-
|
|
7820
|
+
resolve8({
|
|
7821
|
+
ok: false,
|
|
7822
|
+
detail: `failed to start ${install.command}: ${error.message}`,
|
|
7823
|
+
manualCommand: install.manualCommand
|
|
7824
|
+
});
|
|
7219
7825
|
});
|
|
7220
7826
|
child.on("close", (code) => {
|
|
7221
7827
|
if (code === 0) {
|
|
7222
|
-
resolve8(true);
|
|
7828
|
+
resolve8({ ok: true, detail: "", manualCommand: install.manualCommand });
|
|
7223
7829
|
return;
|
|
7224
7830
|
}
|
|
7225
7831
|
const detail = stderr.trim();
|
|
7226
|
-
|
|
7227
|
-
|
|
7228
|
-
|
|
7229
|
-
|
|
7230
|
-
);
|
|
7231
|
-
resolve8(false);
|
|
7832
|
+
resolve8({
|
|
7833
|
+
ok: false,
|
|
7834
|
+
detail: detail ? `${install.command}: ${detail}` : `${install.command} exited ${code}`,
|
|
7835
|
+
manualCommand: install.manualCommand
|
|
7836
|
+
});
|
|
7232
7837
|
});
|
|
7233
7838
|
});
|
|
7234
7839
|
}
|
|
7840
|
+
async function runSkillsInstall(baseUrl) {
|
|
7841
|
+
const failures = [];
|
|
7842
|
+
for (const install of resolveSkillsInstallCommands(baseUrl)) {
|
|
7843
|
+
const result = await runOneSkillsInstall(install);
|
|
7844
|
+
if (result.ok) return true;
|
|
7845
|
+
failures.push(result);
|
|
7846
|
+
}
|
|
7847
|
+
const details = failures.map((failure) => failure.detail).filter(Boolean).join("\n");
|
|
7848
|
+
const manualCommand = failures.at(-1)?.manualCommand;
|
|
7849
|
+
process.stderr.write(
|
|
7850
|
+
`SDK skills sync failed${details ? `:
|
|
7851
|
+
${details}` : ""}
|
|
7852
|
+
` + (manualCommand ? `Run manually: ${manualCommand}
|
|
7853
|
+
` : "")
|
|
7854
|
+
);
|
|
7855
|
+
return false;
|
|
7856
|
+
}
|
|
7857
|
+
function writeSdkSkillsStatusLine(line) {
|
|
7858
|
+
const progress = getActiveCliProgress();
|
|
7859
|
+
if (progress) {
|
|
7860
|
+
progress.writeLine(line);
|
|
7861
|
+
return;
|
|
7862
|
+
}
|
|
7863
|
+
process.stderr.write(`${line}
|
|
7864
|
+
`);
|
|
7865
|
+
}
|
|
7235
7866
|
async function syncSdkSkillsIfNeeded(baseUrl) {
|
|
7236
7867
|
if (attemptedSync || shouldSkipSkillsSync()) return;
|
|
7237
7868
|
attemptedSync = true;
|
|
7238
7869
|
const localVersion = readLocalSkillsVersion(baseUrl);
|
|
7239
7870
|
const update = await fetchSkillsUpdate(baseUrl, localVersion);
|
|
7240
7871
|
if (!update?.needsUpdate || !update.remoteVersion) return;
|
|
7241
|
-
|
|
7242
|
-
progress?.writeLine("SDK skills changed; syncing deepline-sdk skill...") ?? process.stderr.write("SDK skills changed; syncing deepline-sdk skill...\n");
|
|
7872
|
+
writeSdkSkillsStatusLine("SDK skills changed; syncing deepline-sdk skill...");
|
|
7243
7873
|
const installed = await runSkillsInstall(baseUrl);
|
|
7244
7874
|
if (!installed) return;
|
|
7245
7875
|
writeLocalSkillsVersion(baseUrl, update.remoteVersion);
|
|
7246
|
-
|
|
7876
|
+
writeSdkSkillsStatusLine("SDK skills are up to date.");
|
|
7247
7877
|
}
|
|
7248
7878
|
|
|
7249
7879
|
// src/cli/trace.ts
|
|
@@ -7405,4 +8035,3 @@ Output:
|
|
|
7405
8035
|
process.exit(process.exitCode ?? 0);
|
|
7406
8036
|
}
|
|
7407
8037
|
main();
|
|
7408
|
-
//# sourceMappingURL=index.js.map
|