deepline 0.1.12 → 0.1.19
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 +1298 -711
- package/dist/cli/index.mjs +1294 -707
- package/dist/index.d.mts +199 -23
- package/dist/index.d.ts +199 -23
- package/dist/index.js +219 -13
- package/dist/index.mjs +219 -13
- package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +68 -12
- package/dist/repo/apps/play-runner-workers/src/entry.ts +241 -51
- 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 +10 -2
- 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/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.19";
|
|
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";
|
|
@@ -386,8 +460,12 @@ var HttpClient = class {
|
|
|
386
460
|
* @param path - API path
|
|
387
461
|
* @param body - Request body (will be JSON-serialized)
|
|
388
462
|
*/
|
|
389
|
-
async post(path, body) {
|
|
390
|
-
return this.request(path, {
|
|
463
|
+
async post(path, body, headers) {
|
|
464
|
+
return this.request(path, {
|
|
465
|
+
method: "POST",
|
|
466
|
+
body,
|
|
467
|
+
headers
|
|
468
|
+
});
|
|
391
469
|
}
|
|
392
470
|
/**
|
|
393
471
|
* Send a DELETE request.
|
|
@@ -467,6 +545,7 @@ function sleep(ms) {
|
|
|
467
545
|
|
|
468
546
|
// src/client.ts
|
|
469
547
|
var TERMINAL_PLAY_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
|
|
548
|
+
var INCLUDE_TOOL_METADATA_HEADER = "x-deepline-include-tool-metadata";
|
|
470
549
|
function isRecord(value) {
|
|
471
550
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
472
551
|
}
|
|
@@ -499,6 +578,7 @@ function mapLegacyTemporalStatus(status) {
|
|
|
499
578
|
var DeeplineClient = class {
|
|
500
579
|
http;
|
|
501
580
|
config;
|
|
581
|
+
runs;
|
|
502
582
|
/**
|
|
503
583
|
* @param options - Optional overrides for API key, base URL, timeout, and retries.
|
|
504
584
|
* @throws {@link ConfigError} if no API key can be resolved from any source.
|
|
@@ -506,6 +586,13 @@ var DeeplineClient = class {
|
|
|
506
586
|
constructor(options) {
|
|
507
587
|
this.config = resolveConfig(options);
|
|
508
588
|
this.http = new HttpClient(this.config);
|
|
589
|
+
this.runs = {
|
|
590
|
+
get: (runId) => this.getRunStatus(runId),
|
|
591
|
+
list: (options2) => this.listRuns(options2),
|
|
592
|
+
tail: (runId, options2) => this.tailRun(runId, options2),
|
|
593
|
+
logs: (runId, options2) => this.getRunLogs(runId, options2),
|
|
594
|
+
stop: (runId, options2) => this.stopRun(runId, options2)
|
|
595
|
+
};
|
|
509
596
|
}
|
|
510
597
|
/** The resolved base URL this client is targeting (e.g. `"http://localhost:3000"`). */
|
|
511
598
|
get baseUrl() {
|
|
@@ -594,6 +681,31 @@ var DeeplineClient = class {
|
|
|
594
681
|
);
|
|
595
682
|
return res.tools;
|
|
596
683
|
}
|
|
684
|
+
/**
|
|
685
|
+
* Search available tools using Deepline's ranked backend search.
|
|
686
|
+
*
|
|
687
|
+
* This is the same discovery surface used by the legacy CLI: it ranks across
|
|
688
|
+
* tool metadata, categories, agent guidance, and input schema fields.
|
|
689
|
+
*/
|
|
690
|
+
async searchTools(options = {}) {
|
|
691
|
+
const params = new URLSearchParams();
|
|
692
|
+
const query = options.query?.trim() ?? "";
|
|
693
|
+
params.set("q", query);
|
|
694
|
+
params.set(
|
|
695
|
+
"include_search_debug",
|
|
696
|
+
options.includeSearchDebug ? "true" : "false"
|
|
697
|
+
);
|
|
698
|
+
params.set("search_mode", options.searchMode ?? "v2");
|
|
699
|
+
if (options.categories?.trim()) {
|
|
700
|
+
params.set("categories", options.categories.trim());
|
|
701
|
+
}
|
|
702
|
+
if (options.searchTerms?.trim()) {
|
|
703
|
+
params.set("search_terms", options.searchTerms.trim());
|
|
704
|
+
}
|
|
705
|
+
return this.http.get(
|
|
706
|
+
`/api/v2/integrations/list?${params.toString()}`
|
|
707
|
+
);
|
|
708
|
+
}
|
|
597
709
|
/**
|
|
598
710
|
* Get detailed metadata for a single tool.
|
|
599
711
|
*
|
|
@@ -629,12 +741,17 @@ var DeeplineClient = class {
|
|
|
629
741
|
* Top-level fields such as `status`, `job_id`, and `billing` describe the
|
|
630
742
|
* Deepline execution.
|
|
631
743
|
*/
|
|
632
|
-
async executeTool(toolId, input) {
|
|
744
|
+
async executeTool(toolId, input, options) {
|
|
745
|
+
const headers = options?.includeToolMetadata ? { [INCLUDE_TOOL_METADATA_HEADER]: "true" } : void 0;
|
|
633
746
|
return this.http.post(
|
|
634
747
|
`/api/v2/integrations/${encodeURIComponent(toolId)}/execute`,
|
|
635
|
-
{ payload: input }
|
|
748
|
+
{ payload: input },
|
|
749
|
+
headers
|
|
636
750
|
);
|
|
637
751
|
}
|
|
752
|
+
async executeToolRaw(toolId, input, options) {
|
|
753
|
+
return this.executeTool(toolId, input, options);
|
|
754
|
+
}
|
|
638
755
|
async queryCustomerDb(input) {
|
|
639
756
|
return this.http.post("/api/v2/db/query", {
|
|
640
757
|
sql: input.sql,
|
|
@@ -683,6 +800,7 @@ var DeeplineClient = class {
|
|
|
683
800
|
...request.revisionId ? { revisionId: request.revisionId } : {},
|
|
684
801
|
...request.artifactStorageKey ? { artifactStorageKey: request.artifactStorageKey } : {},
|
|
685
802
|
...request.sourceCode ? { sourceCode: request.sourceCode } : {},
|
|
803
|
+
...request.sourceFiles ? { sourceFiles: request.sourceFiles } : {},
|
|
686
804
|
..."staticPipeline" in request ? { staticPipeline: request.staticPipeline } : {},
|
|
687
805
|
...request.artifactHash ? { artifactHash: request.artifactHash } : {},
|
|
688
806
|
...request.graphHash ? { graphHash: request.graphHash } : {},
|
|
@@ -707,6 +825,7 @@ var DeeplineClient = class {
|
|
|
707
825
|
...request.revisionId ? { revisionId: request.revisionId } : {},
|
|
708
826
|
...request.artifactStorageKey ? { artifactStorageKey: request.artifactStorageKey } : {},
|
|
709
827
|
...request.sourceCode ? { sourceCode: request.sourceCode } : {},
|
|
828
|
+
...request.sourceFiles ? { sourceFiles: request.sourceFiles } : {},
|
|
710
829
|
..."staticPipeline" in request ? { staticPipeline: request.staticPipeline } : {},
|
|
711
830
|
...request.artifactHash ? { artifactHash: request.artifactHash } : {},
|
|
712
831
|
...request.graphHash ? { graphHash: request.graphHash } : {},
|
|
@@ -743,6 +862,7 @@ var DeeplineClient = class {
|
|
|
743
862
|
const compilerManifest = input.compilerManifest ?? await this.compilePlayManifest({
|
|
744
863
|
name: input.name,
|
|
745
864
|
sourceCode: input.sourceCode,
|
|
865
|
+
sourceFiles: input.sourceFiles,
|
|
746
866
|
artifact: input.artifact
|
|
747
867
|
});
|
|
748
868
|
return this.http.post("/api/v2/plays/artifacts", {
|
|
@@ -757,6 +877,7 @@ var DeeplineClient = class {
|
|
|
757
877
|
compilerManifest: artifact.compilerManifest ?? await this.compilePlayManifest({
|
|
758
878
|
name: artifact.name,
|
|
759
879
|
sourceCode: artifact.sourceCode,
|
|
880
|
+
sourceFiles: artifact.sourceFiles,
|
|
760
881
|
artifact: artifact.artifact
|
|
761
882
|
})
|
|
762
883
|
}))
|
|
@@ -783,11 +904,13 @@ var DeeplineClient = class {
|
|
|
783
904
|
const compilerManifest = input.compilerManifest ?? await this.compilePlayManifest({
|
|
784
905
|
name: input.name,
|
|
785
906
|
sourceCode: input.sourceCode,
|
|
907
|
+
sourceFiles: input.sourceFiles,
|
|
786
908
|
artifact: input.artifact
|
|
787
909
|
});
|
|
788
910
|
const registeredArtifact = await this.registerPlayArtifact({
|
|
789
911
|
name: input.name,
|
|
790
912
|
sourceCode: input.sourceCode,
|
|
913
|
+
sourceFiles: input.sourceFiles,
|
|
791
914
|
artifact: input.artifact,
|
|
792
915
|
compilerManifest,
|
|
793
916
|
publish: false
|
|
@@ -847,11 +970,13 @@ var DeeplineClient = class {
|
|
|
847
970
|
const compilerManifest = options?.compilerManifest ?? await this.compilePlayManifest({
|
|
848
971
|
name,
|
|
849
972
|
sourceCode,
|
|
973
|
+
sourceFiles: options?.sourceFiles,
|
|
850
974
|
artifact
|
|
851
975
|
});
|
|
852
976
|
const registeredArtifact = await this.registerPlayArtifact({
|
|
853
977
|
name,
|
|
854
978
|
sourceCode,
|
|
979
|
+
sourceFiles: options?.sourceFiles,
|
|
855
980
|
artifact,
|
|
856
981
|
compilerManifest,
|
|
857
982
|
publish: false
|
|
@@ -1035,6 +1160,112 @@ var DeeplineClient = class {
|
|
|
1035
1160
|
);
|
|
1036
1161
|
return response.runs ?? [];
|
|
1037
1162
|
}
|
|
1163
|
+
/**
|
|
1164
|
+
* Get a run by id using the public runs resource model.
|
|
1165
|
+
*
|
|
1166
|
+
* This is the SDK equivalent of:
|
|
1167
|
+
*
|
|
1168
|
+
* ```bash
|
|
1169
|
+
* deepline runs get <run-id> --json
|
|
1170
|
+
* ```
|
|
1171
|
+
*/
|
|
1172
|
+
async getRunStatus(runId) {
|
|
1173
|
+
const response = await this.http.get(
|
|
1174
|
+
`/api/v2/runs/${encodeURIComponent(runId)}`
|
|
1175
|
+
);
|
|
1176
|
+
return normalizePlayStatus(response);
|
|
1177
|
+
}
|
|
1178
|
+
/**
|
|
1179
|
+
* List play runs using the public runs resource model.
|
|
1180
|
+
*
|
|
1181
|
+
* This is the SDK equivalent of:
|
|
1182
|
+
*
|
|
1183
|
+
* ```bash
|
|
1184
|
+
* deepline runs list --play <play-name> --status failed --json
|
|
1185
|
+
* ```
|
|
1186
|
+
*/
|
|
1187
|
+
async listRuns(options) {
|
|
1188
|
+
const playName = options.play.trim();
|
|
1189
|
+
if (!playName) {
|
|
1190
|
+
throw new Error("runs.list requires options.play.");
|
|
1191
|
+
}
|
|
1192
|
+
const params = new URLSearchParams({ play: playName });
|
|
1193
|
+
const status = options.status?.trim();
|
|
1194
|
+
if (status) {
|
|
1195
|
+
params.set("status", status);
|
|
1196
|
+
}
|
|
1197
|
+
const response = await this.http.get(
|
|
1198
|
+
`/api/v2/runs?${params.toString()}`
|
|
1199
|
+
);
|
|
1200
|
+
return response.runs ?? [];
|
|
1201
|
+
}
|
|
1202
|
+
/**
|
|
1203
|
+
* Fetch the lightweight tail status for a run using the public runs resource model.
|
|
1204
|
+
*
|
|
1205
|
+
* This is the SDK equivalent of:
|
|
1206
|
+
*
|
|
1207
|
+
* ```bash
|
|
1208
|
+
* deepline runs tail <run-id> --json
|
|
1209
|
+
* ```
|
|
1210
|
+
*/
|
|
1211
|
+
async tailRun(runId, options) {
|
|
1212
|
+
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;
|
|
1213
|
+
const params = new URLSearchParams();
|
|
1214
|
+
if (Number.isFinite(afterLogIndex)) {
|
|
1215
|
+
params.set("afterLogIndex", String(Number(afterLogIndex)));
|
|
1216
|
+
}
|
|
1217
|
+
if (typeof options?.waitMs === "number") {
|
|
1218
|
+
params.set("waitMs", String(options.waitMs));
|
|
1219
|
+
}
|
|
1220
|
+
if (options?.terminalOnly) {
|
|
1221
|
+
params.set("terminalOnly", "true");
|
|
1222
|
+
}
|
|
1223
|
+
const suffix = params.toString() ? `?${params.toString()}` : "";
|
|
1224
|
+
const response = await this.http.get(
|
|
1225
|
+
`/api/v2/runs/${encodeURIComponent(runId)}/tail${suffix}`
|
|
1226
|
+
);
|
|
1227
|
+
return normalizePlayStatus(response);
|
|
1228
|
+
}
|
|
1229
|
+
/**
|
|
1230
|
+
* Fetch persisted logs for a run using the public runs resource model.
|
|
1231
|
+
*
|
|
1232
|
+
* This is the SDK equivalent of:
|
|
1233
|
+
*
|
|
1234
|
+
* ```bash
|
|
1235
|
+
* deepline runs logs <run-id> --limit 200 --json
|
|
1236
|
+
* ```
|
|
1237
|
+
*/
|
|
1238
|
+
async getRunLogs(runId, options) {
|
|
1239
|
+
const status = await this.getRunStatus(runId);
|
|
1240
|
+
const logs = status.progress?.logs ?? [];
|
|
1241
|
+
const limit = typeof options?.limit === "number" && Number.isFinite(options.limit) ? Math.max(0, Math.trunc(options.limit)) : 200;
|
|
1242
|
+
const entries = logs.slice(Math.max(0, logs.length - limit));
|
|
1243
|
+
return {
|
|
1244
|
+
runId: status.runId,
|
|
1245
|
+
totalCount: logs.length,
|
|
1246
|
+
returnedCount: entries.length,
|
|
1247
|
+
firstSequence: logs.length === 0 ? null : logs.length - entries.length + 1,
|
|
1248
|
+
lastSequence: logs.length === 0 ? null : logs.length,
|
|
1249
|
+
truncated: logs.length > entries.length,
|
|
1250
|
+
hasMore: logs.length > entries.length,
|
|
1251
|
+
entries
|
|
1252
|
+
};
|
|
1253
|
+
}
|
|
1254
|
+
/**
|
|
1255
|
+
* Stop a run by id using the public runs resource model.
|
|
1256
|
+
*
|
|
1257
|
+
* This is the SDK equivalent of:
|
|
1258
|
+
*
|
|
1259
|
+
* ```bash
|
|
1260
|
+
* deepline runs stop <run-id> --reason "stale lock" --json
|
|
1261
|
+
* ```
|
|
1262
|
+
*/
|
|
1263
|
+
async stopRun(runId, options) {
|
|
1264
|
+
return this.http.post(
|
|
1265
|
+
`/api/v2/runs/${encodeURIComponent(runId)}/stop`,
|
|
1266
|
+
options?.reason ? { reason: options.reason } : {}
|
|
1267
|
+
);
|
|
1268
|
+
}
|
|
1038
1269
|
async listPlays() {
|
|
1039
1270
|
const response = await this.http.get(
|
|
1040
1271
|
"/api/v2/plays"
|
|
@@ -1421,6 +1652,7 @@ function saveEnvValues(values, baseUrl) {
|
|
|
1421
1652
|
const merged = { ...existing, ...values };
|
|
1422
1653
|
const lines = Object.entries(merged).filter(([, v]) => v !== "").map(([k, v]) => `${k}=${v}`);
|
|
1423
1654
|
(0, import_node_fs3.writeFileSync)(filePath, lines.join("\n") + "\n", "utf-8");
|
|
1655
|
+
saveProjectDeeplineEnvValues(baseUrl, values);
|
|
1424
1656
|
}
|
|
1425
1657
|
async function httpJson(method, url, apiKey, body) {
|
|
1426
1658
|
const headers = { "Content-Type": "application/json" };
|
|
@@ -2021,6 +2253,9 @@ function rowArray(value) {
|
|
|
2021
2253
|
function readNumber(value) {
|
|
2022
2254
|
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.trunc(value) : null;
|
|
2023
2255
|
}
|
|
2256
|
+
function numericStat(value) {
|
|
2257
|
+
return readNumber(value) ?? 0;
|
|
2258
|
+
}
|
|
2024
2259
|
function inferColumns(rows) {
|
|
2025
2260
|
const columns = [];
|
|
2026
2261
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -2100,6 +2335,31 @@ function extractCanonicalRowsInfo(statusOrResult) {
|
|
|
2100
2335
|
function percentText(numerator, denominator) {
|
|
2101
2336
|
return denominator > 0 ? `${numerator}/${denominator} (${Math.round(100 * numerator / denominator)}%)` : "0/0 (0%)";
|
|
2102
2337
|
}
|
|
2338
|
+
function isDatasetExecutionStatsInput(value) {
|
|
2339
|
+
return isRecord2(value) && isRecord2(value.columnStats) && Object.values(value.columnStats).every(isRecord2);
|
|
2340
|
+
}
|
|
2341
|
+
function extractDatasetExecutionStats(statusOrResult) {
|
|
2342
|
+
if (!isRecord2(statusOrResult)) {
|
|
2343
|
+
return null;
|
|
2344
|
+
}
|
|
2345
|
+
const direct = statusOrResult.dataset_execution_stats;
|
|
2346
|
+
if (isDatasetExecutionStatsInput(direct)) {
|
|
2347
|
+
return direct;
|
|
2348
|
+
}
|
|
2349
|
+
const nested = isRecord2(statusOrResult.result) ? statusOrResult.result.dataset_execution_stats : null;
|
|
2350
|
+
return isDatasetExecutionStatsInput(nested) ? nested : null;
|
|
2351
|
+
}
|
|
2352
|
+
function formatExecutionStats(raw, denominator) {
|
|
2353
|
+
return {
|
|
2354
|
+
queued: percentText(numericStat(raw.queued), denominator),
|
|
2355
|
+
running: percentText(numericStat(raw.running), denominator),
|
|
2356
|
+
"completed:executed": percentText(numericStat(raw.completed), denominator),
|
|
2357
|
+
"completed:reused": percentText(numericStat(raw.cached), denominator),
|
|
2358
|
+
"skipped:condition": percentText(numericStat(raw.skipped), denominator),
|
|
2359
|
+
"skipped:missed": percentText(numericStat(raw.missed), denominator),
|
|
2360
|
+
failed: percentText(numericStat(raw.failed), denominator)
|
|
2361
|
+
};
|
|
2362
|
+
}
|
|
2103
2363
|
function countPercentText(count, denominator) {
|
|
2104
2364
|
return denominator > 0 ? `${count} (${Math.round(100 * count / denominator)}%)` : "0 (0%)";
|
|
2105
2365
|
}
|
|
@@ -2192,7 +2452,7 @@ function compactCell(value) {
|
|
|
2192
2452
|
}
|
|
2193
2453
|
return compactScalar(parsed, 120);
|
|
2194
2454
|
}
|
|
2195
|
-
function buildDatasetStats(rows, totalRows = rows.length, columns = inferColumns(rows)) {
|
|
2455
|
+
function buildDatasetStats(rows, totalRows = rows.length, columns = inferColumns(rows), executionStats) {
|
|
2196
2456
|
const sanitized = sanitizeCsvProjectionInfo({ rows, columns });
|
|
2197
2457
|
const columnStats = {};
|
|
2198
2458
|
for (const column of sanitized.columns) {
|
|
@@ -2220,6 +2480,10 @@ function buildDatasetStats(rows, totalRows = rows.length, columns = inferColumns
|
|
|
2220
2480
|
non_empty: percentText(nonEmpty, denominator),
|
|
2221
2481
|
unique: valueCounts.size
|
|
2222
2482
|
};
|
|
2483
|
+
const rawExecutionStats = executionStats?.columnStats[column];
|
|
2484
|
+
if (rawExecutionStats) {
|
|
2485
|
+
stat3.execution = formatExecutionStats(rawExecutionStats, totalRows);
|
|
2486
|
+
}
|
|
2223
2487
|
if (sampleValue !== void 0 && sampleValueType) {
|
|
2224
2488
|
stat3.sample_value = sampleValue;
|
|
2225
2489
|
stat3.sample_type = sampleValueType;
|
|
@@ -2566,7 +2830,6 @@ var import_node_os4 = require("os");
|
|
|
2566
2830
|
var import_node_path5 = require("path");
|
|
2567
2831
|
var import_node_module = require("module");
|
|
2568
2832
|
var import_esbuild = require("esbuild");
|
|
2569
|
-
var import_typescript = __toESM(require("typescript"));
|
|
2570
2833
|
|
|
2571
2834
|
// ../shared_libs/play-runtime/backend.ts
|
|
2572
2835
|
var PLAY_RUNTIME_BACKENDS = {
|
|
@@ -2651,56 +2914,6 @@ function formatEsbuildMessage(message) {
|
|
|
2651
2914
|
const location = message.location ? `${message.location.file}:${message.location.line}:${message.location.column}` : null;
|
|
2652
2915
|
return location ? `${location} ${message.text}` : message.text;
|
|
2653
2916
|
}
|
|
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
2917
|
function isLocalSpecifier(specifier) {
|
|
2705
2918
|
return specifier.startsWith("./") || specifier.startsWith("../") || specifier.startsWith("/") || specifier.startsWith("file:");
|
|
2706
2919
|
}
|
|
@@ -2724,11 +2937,8 @@ function assertWithinPlayWorkspace(input) {
|
|
|
2724
2937
|
if (isPathInsideDirectory(input.resolvedPath, input.workspace.rootDir)) {
|
|
2725
2938
|
return;
|
|
2726
2939
|
}
|
|
2727
|
-
const position = input.sourceFile.getLineAndCharacterOfPosition(
|
|
2728
|
-
input.node.getStart(input.sourceFile)
|
|
2729
|
-
);
|
|
2730
2940
|
throw new Error(
|
|
2731
|
-
`${input.importer}:${
|
|
2941
|
+
`${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
2942
|
);
|
|
2733
2943
|
}
|
|
2734
2944
|
function getPackageName(specifier) {
|
|
@@ -2738,72 +2948,135 @@ function getPackageName(specifier) {
|
|
|
2738
2948
|
}
|
|
2739
2949
|
return specifier.split("/")[0] ?? specifier;
|
|
2740
2950
|
}
|
|
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
2951
|
function isPlaySourceFile(filePath) {
|
|
2759
2952
|
return PLAY_SOURCE_FILE_PATTERN.test(filePath);
|
|
2760
2953
|
}
|
|
2761
|
-
function
|
|
2762
|
-
|
|
2763
|
-
|
|
2954
|
+
function stripCommentsToSpaces(source) {
|
|
2955
|
+
return source.replace(/\/\*[\s\S]*?\*\//g, (match) => match.replace(/[^\n]/g, " ")).replace(
|
|
2956
|
+
/(^|[^:])\/\/.*$/gm,
|
|
2957
|
+
(match, prefix) => prefix + " ".repeat(Math.max(0, match.length - prefix.length))
|
|
2958
|
+
);
|
|
2959
|
+
}
|
|
2960
|
+
function lineAndColumnAt(source, index) {
|
|
2961
|
+
const prefix = source.slice(0, index);
|
|
2962
|
+
const lines = prefix.split("\n");
|
|
2963
|
+
return { line: lines.length, column: lines[lines.length - 1].length + 1 };
|
|
2964
|
+
}
|
|
2965
|
+
function findSourceImportReferences(sourceCode) {
|
|
2966
|
+
const source = stripCommentsToSpaces(sourceCode);
|
|
2967
|
+
const references = [];
|
|
2968
|
+
const addReference = (specifier, specifierIndex, kind) => {
|
|
2969
|
+
if (!specifier) return;
|
|
2970
|
+
const position = lineAndColumnAt(sourceCode, specifierIndex);
|
|
2971
|
+
references.push({
|
|
2972
|
+
specifier,
|
|
2973
|
+
line: position.line,
|
|
2974
|
+
column: position.column,
|
|
2975
|
+
kind
|
|
2976
|
+
});
|
|
2977
|
+
};
|
|
2978
|
+
const staticImportPattern = /\b(?:import|export)\s+(?!type\b)(?:[\s\S]*?\s+from\s*)?(['"])([^'"\n]+)\1/g;
|
|
2979
|
+
for (const match of source.matchAll(staticImportPattern)) {
|
|
2980
|
+
addReference(match[2], match.index + match[0].lastIndexOf(match[1]), "static");
|
|
2981
|
+
}
|
|
2982
|
+
const dynamicImportPattern = /\bimport\s*\(\s*(['"])([^'"\n]+)\1/g;
|
|
2983
|
+
for (const match of source.matchAll(dynamicImportPattern)) {
|
|
2984
|
+
addReference(match[2], match.index + match[0].lastIndexOf(match[1]), "dynamic-import");
|
|
2985
|
+
}
|
|
2986
|
+
const requirePattern = /\brequire\s*\(\s*(['"])([^'"\n]+)\1/g;
|
|
2987
|
+
for (const match of source.matchAll(requirePattern)) {
|
|
2988
|
+
addReference(match[2], match.index + match[0].lastIndexOf(match[1]), "require");
|
|
2989
|
+
}
|
|
2990
|
+
const literalDynamicImportIndexes = new Set(
|
|
2991
|
+
[...source.matchAll(dynamicImportPattern)].map((match) => match.index)
|
|
2992
|
+
);
|
|
2993
|
+
for (const match of source.matchAll(/\bimport\s*\(/g)) {
|
|
2994
|
+
if (literalDynamicImportIndexes.has(match.index)) continue;
|
|
2995
|
+
const position = lineAndColumnAt(sourceCode, match.index);
|
|
2996
|
+
throw new Error(
|
|
2997
|
+
`:${position.line}:${position.column} Dynamic import() is not allowed in plays. Use static imports instead.`
|
|
2998
|
+
);
|
|
2999
|
+
}
|
|
3000
|
+
const literalRequireIndexes = new Set(
|
|
3001
|
+
[...source.matchAll(requirePattern)].map((match) => match.index)
|
|
3002
|
+
);
|
|
3003
|
+
for (const match of source.matchAll(/\brequire\s*\(/g)) {
|
|
3004
|
+
if (literalRequireIndexes.has(match.index)) continue;
|
|
3005
|
+
const position = lineAndColumnAt(sourceCode, match.index);
|
|
3006
|
+
throw new Error(
|
|
3007
|
+
`:${position.line}:${position.column} Dynamic require() is not allowed in plays. Use static imports or require("literal") only.`
|
|
3008
|
+
);
|
|
3009
|
+
}
|
|
3010
|
+
return references.sort(
|
|
3011
|
+
(left, right) => left.line === right.line ? left.column - right.column : left.line - right.line
|
|
3012
|
+
);
|
|
3013
|
+
}
|
|
3014
|
+
function unquoteStringLiteral(literal) {
|
|
3015
|
+
const trimmed = literal.trim();
|
|
3016
|
+
const quote = trimmed[0];
|
|
3017
|
+
if (quote !== '"' && quote !== "'" || trimmed[trimmed.length - 1] !== quote) {
|
|
3018
|
+
return null;
|
|
3019
|
+
}
|
|
3020
|
+
try {
|
|
3021
|
+
return JSON.parse(quote === '"' ? trimmed : `"${trimmed.slice(1, -1).replace(/"/g, '\\"')}"`);
|
|
3022
|
+
} catch {
|
|
3023
|
+
return trimmed.slice(1, -1);
|
|
3024
|
+
}
|
|
3025
|
+
}
|
|
3026
|
+
function findMatchingBrace(source, openIndex) {
|
|
3027
|
+
let depth = 0;
|
|
3028
|
+
let quote = null;
|
|
3029
|
+
let escaped = false;
|
|
3030
|
+
for (let index = openIndex; index < source.length; index += 1) {
|
|
3031
|
+
const char = source[index];
|
|
3032
|
+
if (quote) {
|
|
3033
|
+
if (escaped) {
|
|
3034
|
+
escaped = false;
|
|
3035
|
+
} else if (char === "\\") {
|
|
3036
|
+
escaped = true;
|
|
3037
|
+
} else if (char === quote) {
|
|
3038
|
+
quote = null;
|
|
3039
|
+
}
|
|
2764
3040
|
continue;
|
|
2765
3041
|
}
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
if (!matches) {
|
|
3042
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
3043
|
+
quote = char;
|
|
2769
3044
|
continue;
|
|
2770
3045
|
}
|
|
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
|
-
|
|
3046
|
+
if (char === "{") depth += 1;
|
|
3047
|
+
if (char === "}") {
|
|
3048
|
+
depth -= 1;
|
|
3049
|
+
if (depth === 0) return index;
|
|
3050
|
+
}
|
|
3051
|
+
}
|
|
3052
|
+
return -1;
|
|
3053
|
+
}
|
|
3054
|
+
function extractDefinedPlayName(sourceCode, _filePath) {
|
|
3055
|
+
const source = stripCommentsToSpaces(sourceCode);
|
|
3056
|
+
const callPattern = /(?:\b[A-Za-z_$][\w$]*\s*\.\s*)?\b(?:definePlay|defineWorkflow)\s*\(/g;
|
|
3057
|
+
for (const match of source.matchAll(callPattern)) {
|
|
3058
|
+
const openParen = match.index + match[0].length - 1;
|
|
3059
|
+
const firstArgStart = openParen + 1;
|
|
3060
|
+
const firstNonSpace = source.slice(firstArgStart).search(/\S/);
|
|
3061
|
+
if (firstNonSpace < 0) continue;
|
|
3062
|
+
const argIndex = firstArgStart + firstNonSpace;
|
|
3063
|
+
const quote = source[argIndex];
|
|
3064
|
+
if (quote === '"' || quote === "'") {
|
|
3065
|
+
const literalMatch = source.slice(argIndex).match(/^(['"])(?:\\.|(?!\1)[\s\S])*\1/);
|
|
3066
|
+
const value = literalMatch ? unquoteStringLiteral(literalMatch[0]) : null;
|
|
3067
|
+
if (value?.trim()) return value.trim();
|
|
3068
|
+
}
|
|
3069
|
+
if (quote === "{") {
|
|
3070
|
+
const closeBrace = findMatchingBrace(source, argIndex);
|
|
3071
|
+
if (closeBrace < 0) continue;
|
|
3072
|
+
const objectSource = source.slice(argIndex + 1, closeBrace);
|
|
3073
|
+
const idMatch = objectSource.match(/(?:^|[,{\s])(?:id|['"]id['"])\s*:\s*(['"])([\s\S]*?)\1/);
|
|
3074
|
+
if (idMatch?.[2]?.trim()) {
|
|
3075
|
+
return idMatch[2].trim();
|
|
2801
3076
|
}
|
|
2802
3077
|
}
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
visit(sourceFile);
|
|
2806
|
-
return detectedPlayName;
|
|
3078
|
+
}
|
|
3079
|
+
return null;
|
|
2807
3080
|
}
|
|
2808
3081
|
function getPackageRequireCandidates(fromFile) {
|
|
2809
3082
|
const candidates = [
|
|
@@ -3113,18 +3386,10 @@ async function analyzeSourceGraph(entryFile, adapter) {
|
|
|
3113
3386
|
if ((0, import_node_path5.extname)(absolutePath).toLowerCase() === ".json") {
|
|
3114
3387
|
return;
|
|
3115
3388
|
}
|
|
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) => {
|
|
3389
|
+
const handleSpecifier = async (specifier, line, column, kind) => {
|
|
3124
3390
|
if (kind === "dynamic-import") {
|
|
3125
|
-
const position = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
3126
3391
|
throw new Error(
|
|
3127
|
-
`${absolutePath}:${
|
|
3392
|
+
`${absolutePath}:${line}:${column} Dynamic import() is not allowed in plays. Use static imports instead.`
|
|
3128
3393
|
);
|
|
3129
3394
|
}
|
|
3130
3395
|
if (NODE_BUILTIN_SET.has(specifier)) {
|
|
@@ -3138,16 +3403,15 @@ async function analyzeSourceGraph(entryFile, adapter) {
|
|
|
3138
3403
|
specifier,
|
|
3139
3404
|
resolvedPath: resolved,
|
|
3140
3405
|
workspace,
|
|
3141
|
-
|
|
3142
|
-
|
|
3406
|
+
line,
|
|
3407
|
+
column
|
|
3143
3408
|
});
|
|
3144
3409
|
if (resolved !== absoluteEntryFile && isPlaySourceFile(resolved)) {
|
|
3145
3410
|
const importedSource = await (0, import_promises2.readFile)(resolved, "utf-8");
|
|
3146
3411
|
const importedPlayName = extractDefinedPlayName(importedSource, resolved);
|
|
3147
3412
|
if (!importedPlayName) {
|
|
3148
|
-
const position = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
3149
3413
|
throw new Error(
|
|
3150
|
-
`${absolutePath}:${
|
|
3414
|
+
`${absolutePath}:${line}:${column} Imported play file "${specifier}" must export definePlay(...) so it can be runtime-composed.`
|
|
3151
3415
|
);
|
|
3152
3416
|
}
|
|
3153
3417
|
importedPlayDependencies.set(resolved, {
|
|
@@ -3160,44 +3424,28 @@ async function analyzeSourceGraph(entryFile, adapter) {
|
|
|
3160
3424
|
return;
|
|
3161
3425
|
}
|
|
3162
3426
|
if (specifier.includes(":")) {
|
|
3163
|
-
const position = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
3164
3427
|
throw new Error(
|
|
3165
|
-
`${absolutePath}:${
|
|
3428
|
+
`${absolutePath}:${line}:${column} Unsupported import specifier "${specifier}". Allowed imports are relative files, Node builtins, and installed packages.`
|
|
3166
3429
|
);
|
|
3167
3430
|
}
|
|
3168
3431
|
const packageImport = resolvePackageImport(specifier, absolutePath, adapter);
|
|
3169
3432
|
packages.set(packageImport.name, packageImport.version);
|
|
3170
3433
|
};
|
|
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
|
-
}
|
|
3434
|
+
try {
|
|
3435
|
+
for (const reference of findSourceImportReferences(sourceCode2)) {
|
|
3436
|
+
await handleSpecifier(
|
|
3437
|
+
reference.specifier,
|
|
3438
|
+
reference.line,
|
|
3439
|
+
reference.column,
|
|
3440
|
+
reference.kind
|
|
3441
|
+
);
|
|
3195
3442
|
}
|
|
3196
|
-
|
|
3197
|
-
|
|
3443
|
+
} catch (error) {
|
|
3444
|
+
if (error instanceof Error && error.message.startsWith(":")) {
|
|
3445
|
+
throw new Error(`${absolutePath}${error.message}`);
|
|
3198
3446
|
}
|
|
3199
|
-
|
|
3200
|
-
|
|
3447
|
+
throw error;
|
|
3448
|
+
}
|
|
3201
3449
|
};
|
|
3202
3450
|
await visitFile(absoluteEntryFile);
|
|
3203
3451
|
const sourceCode = localFiles.get(absoluteEntryFile) ?? "";
|
|
@@ -3217,6 +3465,11 @@ async function analyzeSourceGraph(entryFile, adapter) {
|
|
|
3217
3465
|
const playName = extractDefinedPlayName(sourceCode, absoluteEntryFile);
|
|
3218
3466
|
return {
|
|
3219
3467
|
sourceCode,
|
|
3468
|
+
sourceFiles: Object.fromEntries(
|
|
3469
|
+
[...localFiles.entries()].sort(
|
|
3470
|
+
(left, right) => left[0].localeCompare(right[0])
|
|
3471
|
+
)
|
|
3472
|
+
),
|
|
3220
3473
|
sourceHash,
|
|
3221
3474
|
graphHash,
|
|
3222
3475
|
importPolicy: {
|
|
@@ -3280,8 +3533,7 @@ function normalizeSourceMapForRuntime(sourceMapText) {
|
|
|
3280
3533
|
parsed.sourceRoot = void 0;
|
|
3281
3534
|
return JSON.stringify(parsed);
|
|
3282
3535
|
}
|
|
3283
|
-
function
|
|
3284
|
-
const bundleBytes = Buffer.byteLength(bundledCode, "utf8");
|
|
3536
|
+
function getBundleSizeErrorForBytes(filePath, bundleBytes, artifactKind) {
|
|
3285
3537
|
if (bundleBytes > MAX_PLAY_BUNDLE_BYTES) {
|
|
3286
3538
|
return `${filePath} Play bundle exceeds the 30 MiB limit (${bundleBytes} bytes > ${MAX_PLAY_BUNDLE_BYTES} bytes).`;
|
|
3287
3539
|
}
|
|
@@ -3292,6 +3544,13 @@ function getBundleSizeError(filePath, bundledCode, artifactKind) {
|
|
|
3292
3544
|
}
|
|
3293
3545
|
return null;
|
|
3294
3546
|
}
|
|
3547
|
+
function getBundleSizeError(filePath, bundledCode, artifactKind) {
|
|
3548
|
+
return getBundleSizeErrorForBytes(
|
|
3549
|
+
filePath,
|
|
3550
|
+
Buffer.byteLength(bundledCode, "utf8"),
|
|
3551
|
+
artifactKind
|
|
3552
|
+
);
|
|
3553
|
+
}
|
|
3295
3554
|
async function runEsbuildForCjsNode(entryFile, importedPlayDependencies, adapter, exportName) {
|
|
3296
3555
|
const sdkAliasPlugin = localSdkAliasPlugin(adapter);
|
|
3297
3556
|
const playProxyPlugin = importedPlayProxyPlugin(importedPlayDependencies);
|
|
@@ -3424,6 +3683,23 @@ entry-export:${exportName}`
|
|
|
3424
3683
|
workers-harness:${harnessFingerprint}`
|
|
3425
3684
|
);
|
|
3426
3685
|
}
|
|
3686
|
+
const typecheckErrors = [
|
|
3687
|
+
...await adapter.typecheckPlaySource?.({
|
|
3688
|
+
sourceCode: analysis.sourceCode,
|
|
3689
|
+
sourcePath: absolutePath,
|
|
3690
|
+
importedFilePaths: [
|
|
3691
|
+
...analysis.importPolicy.localFiles,
|
|
3692
|
+
...analysis.importedPlayDependencies.map((dependency) => dependency.filePath)
|
|
3693
|
+
]
|
|
3694
|
+
}) ?? []
|
|
3695
|
+
];
|
|
3696
|
+
if (typecheckErrors.length > 0) {
|
|
3697
|
+
return {
|
|
3698
|
+
success: false,
|
|
3699
|
+
filePath: absolutePath,
|
|
3700
|
+
errors: typecheckErrors
|
|
3701
|
+
};
|
|
3702
|
+
}
|
|
3427
3703
|
const cachedArtifact = await readArtifactCache(analysis.graphHash, target, adapter);
|
|
3428
3704
|
const discoveredFiles = await adapter.discoverPackagedLocalFiles(absolutePath);
|
|
3429
3705
|
if (cachedArtifact) {
|
|
@@ -3443,6 +3719,7 @@ workers-harness:${harnessFingerprint}`
|
|
|
3443
3719
|
success: true,
|
|
3444
3720
|
artifact: { ...cachedArtifact, cacheHit: true },
|
|
3445
3721
|
sourceCode: analysis.sourceCode,
|
|
3722
|
+
sourceFiles: analysis.sourceFiles,
|
|
3446
3723
|
filePath: absolutePath,
|
|
3447
3724
|
playName: analysis.playName,
|
|
3448
3725
|
packagedFiles: discoveredFiles.files,
|
|
@@ -3450,24 +3727,6 @@ workers-harness:${harnessFingerprint}`
|
|
|
3450
3727
|
importedPlayDependencies: analysis.importedPlayDependencies
|
|
3451
3728
|
};
|
|
3452
3729
|
}
|
|
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
3730
|
const buildOutcome = target === PLAY_ARTIFACT_KINDS.esmWorkers ? await runEsbuildForEsmWorkers(absolutePath, analysis.importedPlayDependencies, adapter, exportName) : await runEsbuildForCjsNode(absolutePath, analysis.importedPlayDependencies, adapter, exportName);
|
|
3472
3731
|
if (Array.isArray(buildOutcome)) {
|
|
3473
3732
|
return {
|
|
@@ -3517,6 +3776,7 @@ workers-harness:${harnessFingerprint}`
|
|
|
3517
3776
|
success: true,
|
|
3518
3777
|
artifact,
|
|
3519
3778
|
sourceCode: analysis.sourceCode,
|
|
3779
|
+
sourceFiles: analysis.sourceFiles,
|
|
3520
3780
|
filePath: absolutePath,
|
|
3521
3781
|
playName: analysis.playName,
|
|
3522
3782
|
packagedFiles: discoveredFiles.files,
|
|
@@ -3598,7 +3858,6 @@ function resolveExecutionProfile(override) {
|
|
|
3598
3858
|
var import_node_crypto2 = require("crypto");
|
|
3599
3859
|
var import_promises3 = require("fs/promises");
|
|
3600
3860
|
var import_node_path6 = require("path");
|
|
3601
|
-
var import_typescript2 = __toESM(require("typescript"));
|
|
3602
3861
|
var SOURCE_EXTENSIONS2 = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs", ".json"];
|
|
3603
3862
|
function sha2562(buffer) {
|
|
3604
3863
|
return (0, import_node_crypto2.createHash)("sha256").update(buffer).digest("hex");
|
|
@@ -3610,94 +3869,181 @@ function contentTypeForFile(filePath) {
|
|
|
3610
3869
|
if (extension === ".txt") return "text/plain";
|
|
3611
3870
|
return "application/octet-stream";
|
|
3612
3871
|
}
|
|
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));
|
|
3872
|
+
function stripCommentsToSpaces2(source) {
|
|
3873
|
+
return source.replace(/\/\*[\s\S]*?\*\//g, (match) => match.replace(/[^\n]/g, " ")).replace(
|
|
3874
|
+
/(^|[^:])\/\/.*$/gm,
|
|
3875
|
+
(match, prefix) => prefix + " ".repeat(Math.max(0, match.length - prefix.length))
|
|
3876
|
+
);
|
|
3628
3877
|
}
|
|
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);
|
|
3878
|
+
function unquoteStringLiteral2(literal) {
|
|
3879
|
+
const trimmed = literal.trim();
|
|
3880
|
+
const quote = trimmed[0];
|
|
3881
|
+
if (quote !== '"' && quote !== "'" || trimmed[trimmed.length - 1] !== quote) {
|
|
3882
|
+
return null;
|
|
3641
3883
|
}
|
|
3642
|
-
|
|
3643
|
-
return
|
|
3884
|
+
try {
|
|
3885
|
+
return JSON.parse(quote === '"' ? trimmed : `"${trimmed.slice(1, -1).replace(/"/g, '\\"')}"`);
|
|
3886
|
+
} catch {
|
|
3887
|
+
return trimmed.slice(1, -1);
|
|
3644
3888
|
}
|
|
3645
|
-
|
|
3646
|
-
|
|
3889
|
+
}
|
|
3890
|
+
function splitTopLevelPlus(expression) {
|
|
3891
|
+
const parts = [];
|
|
3892
|
+
let start = 0;
|
|
3893
|
+
let depth = 0;
|
|
3894
|
+
let quote = null;
|
|
3895
|
+
let escaped = false;
|
|
3896
|
+
for (let index = 0; index < expression.length; index += 1) {
|
|
3897
|
+
const char = expression[index];
|
|
3898
|
+
if (quote) {
|
|
3899
|
+
if (escaped) {
|
|
3900
|
+
escaped = false;
|
|
3901
|
+
} else if (char === "\\") {
|
|
3902
|
+
escaped = true;
|
|
3903
|
+
} else if (char === quote) {
|
|
3904
|
+
quote = null;
|
|
3905
|
+
}
|
|
3906
|
+
continue;
|
|
3907
|
+
}
|
|
3908
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
3909
|
+
quote = char;
|
|
3910
|
+
continue;
|
|
3911
|
+
}
|
|
3912
|
+
if (char === "(" || char === "[" || char === "{") depth += 1;
|
|
3913
|
+
if (char === ")" || char === "]" || char === "}") depth -= 1;
|
|
3914
|
+
if (char === "+" && depth === 0) {
|
|
3915
|
+
parts.push(expression.slice(start, index));
|
|
3916
|
+
start = index + 1;
|
|
3917
|
+
}
|
|
3647
3918
|
}
|
|
3648
|
-
|
|
3919
|
+
if (parts.length === 0) return null;
|
|
3920
|
+
parts.push(expression.slice(start));
|
|
3921
|
+
return parts;
|
|
3649
3922
|
}
|
|
3650
|
-
function
|
|
3651
|
-
|
|
3652
|
-
|
|
3923
|
+
function stripOuterParens(expression) {
|
|
3924
|
+
let value = expression.trim();
|
|
3925
|
+
while (value.startsWith("(") && value.endsWith(")")) {
|
|
3926
|
+
value = value.slice(1, -1).trim();
|
|
3653
3927
|
}
|
|
3654
|
-
|
|
3655
|
-
|
|
3928
|
+
return value;
|
|
3929
|
+
}
|
|
3930
|
+
function isRuntimeInputExpression(expression) {
|
|
3931
|
+
return /(^|[^\w$])input([^\w$]|$)/.test(expression);
|
|
3932
|
+
}
|
|
3933
|
+
function resolveStringExpression(expression, constants) {
|
|
3934
|
+
const value = stripOuterParens(expression);
|
|
3935
|
+
if (/^(['"])(?:\\.|(?!\1)[\s\S])*\1$/.test(value)) {
|
|
3936
|
+
return unquoteStringLiteral2(value);
|
|
3656
3937
|
}
|
|
3657
|
-
if (
|
|
3658
|
-
return
|
|
3938
|
+
if (/^`(?:\\.|[^`$]|\$(?!\{))*`$/.test(value)) {
|
|
3939
|
+
return value.slice(1, -1);
|
|
3659
3940
|
}
|
|
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;
|
|
3941
|
+
if (/^[A-Za-z_$][\w$]*$/.test(value)) {
|
|
3942
|
+
return constants.get(value) ?? null;
|
|
3670
3943
|
}
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
const
|
|
3674
|
-
|
|
3675
|
-
return null;
|
|
3676
|
-
}
|
|
3677
|
-
return left + right;
|
|
3944
|
+
const parts = splitTopLevelPlus(value);
|
|
3945
|
+
if (parts) {
|
|
3946
|
+
const resolved = parts.map((part) => resolveStringExpression(part, constants));
|
|
3947
|
+
return resolved.every((part) => part != null) ? resolved.join("") : null;
|
|
3678
3948
|
}
|
|
3679
3949
|
return null;
|
|
3680
3950
|
}
|
|
3681
|
-
function collectTopLevelStringConstants(
|
|
3951
|
+
function collectTopLevelStringConstants(sourceCode) {
|
|
3682
3952
|
const constants = /* @__PURE__ */ new Map();
|
|
3683
|
-
|
|
3684
|
-
|
|
3953
|
+
const source = stripCommentsToSpaces2(sourceCode);
|
|
3954
|
+
for (const match of source.matchAll(/(?:^|\n)\s*const\s+([A-Za-z_$][\w$]*)\s*=\s*([^;\n]+)/g)) {
|
|
3955
|
+
const resolved = resolveStringExpression(match[2], constants);
|
|
3956
|
+
if (resolved != null) {
|
|
3957
|
+
constants.set(match[1], resolved);
|
|
3958
|
+
}
|
|
3959
|
+
}
|
|
3960
|
+
return constants;
|
|
3961
|
+
}
|
|
3962
|
+
function findMatchingGenericEnd(source, openIndex) {
|
|
3963
|
+
let depth = 0;
|
|
3964
|
+
let quote = null;
|
|
3965
|
+
let escaped = false;
|
|
3966
|
+
for (let index = openIndex; index < source.length; index += 1) {
|
|
3967
|
+
const char = source[index];
|
|
3968
|
+
if (quote) {
|
|
3969
|
+
if (escaped) {
|
|
3970
|
+
escaped = false;
|
|
3971
|
+
} else if (char === "\\") {
|
|
3972
|
+
escaped = true;
|
|
3973
|
+
} else if (char === quote) {
|
|
3974
|
+
quote = null;
|
|
3975
|
+
}
|
|
3685
3976
|
continue;
|
|
3686
3977
|
}
|
|
3687
|
-
if (
|
|
3978
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
3979
|
+
quote = char;
|
|
3688
3980
|
continue;
|
|
3689
3981
|
}
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3982
|
+
if (char === "<") depth += 1;
|
|
3983
|
+
if (char === ">") {
|
|
3984
|
+
depth -= 1;
|
|
3985
|
+
if (depth === 0) return index;
|
|
3986
|
+
}
|
|
3987
|
+
}
|
|
3988
|
+
return -1;
|
|
3989
|
+
}
|
|
3990
|
+
function findCallOpenParen(source, afterCsvIndex) {
|
|
3991
|
+
let index = afterCsvIndex;
|
|
3992
|
+
while (/\s/.test(source[index] ?? "")) index += 1;
|
|
3993
|
+
if (source[index] === "<") {
|
|
3994
|
+
const genericEnd = findMatchingGenericEnd(source, index);
|
|
3995
|
+
if (genericEnd < 0) return -1;
|
|
3996
|
+
index = genericEnd + 1;
|
|
3997
|
+
while (/\s/.test(source[index] ?? "")) index += 1;
|
|
3998
|
+
}
|
|
3999
|
+
return source[index] === "(" ? index : -1;
|
|
4000
|
+
}
|
|
4001
|
+
function firstCallArgument(source, openParen) {
|
|
4002
|
+
let depth = 0;
|
|
4003
|
+
let quote = null;
|
|
4004
|
+
let escaped = false;
|
|
4005
|
+
const start = openParen + 1;
|
|
4006
|
+
for (let index = start; index < source.length; index += 1) {
|
|
4007
|
+
const char = source[index];
|
|
4008
|
+
if (quote) {
|
|
4009
|
+
if (escaped) {
|
|
4010
|
+
escaped = false;
|
|
4011
|
+
} else if (char === "\\") {
|
|
4012
|
+
escaped = true;
|
|
4013
|
+
} else if (char === quote) {
|
|
4014
|
+
quote = null;
|
|
3697
4015
|
}
|
|
4016
|
+
continue;
|
|
4017
|
+
}
|
|
4018
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
4019
|
+
quote = char;
|
|
4020
|
+
continue;
|
|
4021
|
+
}
|
|
4022
|
+
if (char === "(" || char === "[" || char === "{") depth += 1;
|
|
4023
|
+
if (char === ")" && depth === 0) {
|
|
4024
|
+
const text = source.slice(start, index).trim();
|
|
4025
|
+
return text ? { text, start, end: index } : null;
|
|
3698
4026
|
}
|
|
4027
|
+
if (char === "," && depth === 0) {
|
|
4028
|
+
const text = source.slice(start, index).trim();
|
|
4029
|
+
return text ? { text, start, end: index } : null;
|
|
4030
|
+
}
|
|
4031
|
+
if (char === ")" || char === "]" || char === "}") depth -= 1;
|
|
3699
4032
|
}
|
|
3700
|
-
return
|
|
4033
|
+
return null;
|
|
4034
|
+
}
|
|
4035
|
+
function localImportSpecifiers(sourceCode) {
|
|
4036
|
+
const source = stripCommentsToSpaces2(sourceCode);
|
|
4037
|
+
const specifiers = [];
|
|
4038
|
+
for (const match of source.matchAll(
|
|
4039
|
+
/\b(?:import|export)\s+(?!type\b)(?:[\s\S]*?\s+from\s*)?['"]([^'"]+)['"]/g
|
|
4040
|
+
)) {
|
|
4041
|
+
if (match[1]?.startsWith(".")) specifiers.push(match[1]);
|
|
4042
|
+
}
|
|
4043
|
+
for (const match of source.matchAll(/\brequire\s*\(\s*(['"])(\.[^'"]*)\1\s*\)/g)) {
|
|
4044
|
+
specifiers.push(match[2]);
|
|
4045
|
+
}
|
|
4046
|
+
return specifiers;
|
|
3701
4047
|
}
|
|
3702
4048
|
async function fileExists2(filePath) {
|
|
3703
4049
|
try {
|
|
@@ -3742,69 +4088,60 @@ async function discoverPackagedLocalFiles(entryFile) {
|
|
|
3742
4088
|
}
|
|
3743
4089
|
visitedFiles.add(absolutePath);
|
|
3744
4090
|
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);
|
|
4091
|
+
const scanSource = stripCommentsToSpaces2(sourceCode);
|
|
4092
|
+
const constants = collectTopLevelStringConstants(sourceCode);
|
|
3753
4093
|
const childVisits = [];
|
|
3754
|
-
const
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
4094
|
+
for (const match of scanSource.matchAll(/\b([A-Za-z_$][\w$]*)\s*\.\s*csv\b/g)) {
|
|
4095
|
+
const target = match[1];
|
|
4096
|
+
if (target !== "ctx" && !target.endsWith("Ctx")) {
|
|
4097
|
+
continue;
|
|
4098
|
+
}
|
|
4099
|
+
const openParen = findCallOpenParen(scanSource, match.index + match[0].length);
|
|
4100
|
+
if (openParen < 0) {
|
|
4101
|
+
continue;
|
|
4102
|
+
}
|
|
4103
|
+
const argument = firstCallArgument(scanSource, openParen);
|
|
4104
|
+
if (!argument) {
|
|
4105
|
+
unresolved.push({
|
|
4106
|
+
sourceFragment: "ctx.csv()",
|
|
4107
|
+
message: "ctx.csv() requires a file path string or input reference."
|
|
4108
|
+
});
|
|
4109
|
+
} else if (!isRuntimeInputExpression(argument.text)) {
|
|
4110
|
+
const resolvedPath = resolveStringExpression(argument.text, constants);
|
|
4111
|
+
if (resolvedPath == null) {
|
|
3758
4112
|
unresolved.push({
|
|
3759
|
-
sourceFragment:
|
|
3760
|
-
message: "ctx.csv()
|
|
4113
|
+
sourceFragment: sourceCode.slice(argument.start, argument.end).trim(),
|
|
4114
|
+
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
4115
|
});
|
|
3762
|
-
} else
|
|
3763
|
-
const
|
|
3764
|
-
if (resolvedPath
|
|
4116
|
+
} else {
|
|
4117
|
+
const absoluteCsvPath = (0, import_node_path6.resolve)((0, import_node_path6.dirname)(absolutePath), resolvedPath);
|
|
4118
|
+
if ((0, import_node_path6.isAbsolute)(resolvedPath) || !isPathInsideDirectory2(absoluteCsvPath, packagingRoot)) {
|
|
3765
4119
|
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)
|
|
4120
|
+
sourceFragment: sourceCode.slice(argument.start, argument.end).trim(),
|
|
4121
|
+
message: "ctx.csv(...) packaged file paths must be relative paths inside the play directory. Pass external files at runtime with input.file instead."
|
|
3787
4122
|
});
|
|
4123
|
+
continue;
|
|
3788
4124
|
}
|
|
4125
|
+
const buffer = await (0, import_promises3.readFile)(absoluteCsvPath);
|
|
4126
|
+
const stats = await (0, import_promises3.stat)(absoluteCsvPath);
|
|
4127
|
+
files.set(absoluteCsvPath, {
|
|
4128
|
+
sourceFragment: sourceCode.slice(argument.start, argument.end).trim(),
|
|
4129
|
+
logicalPath: resolvedPath,
|
|
4130
|
+
absolutePath: absoluteCsvPath,
|
|
4131
|
+
bytes: stats.size,
|
|
4132
|
+
contentHash: sha2562(buffer),
|
|
4133
|
+
contentType: contentTypeForFile(absoluteCsvPath)
|
|
4134
|
+
});
|
|
3789
4135
|
}
|
|
3790
4136
|
}
|
|
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);
|
|
4137
|
+
}
|
|
4138
|
+
for (const specifier of localImportSpecifiers(sourceCode)) {
|
|
4139
|
+
childVisits.push(
|
|
4140
|
+
resolveLocalImport2(absolutePath, specifier).then(
|
|
4141
|
+
(resolvedImport) => visitSourceFile(resolvedImport)
|
|
4142
|
+
)
|
|
4143
|
+
);
|
|
4144
|
+
}
|
|
3808
4145
|
await Promise.all(childVisits);
|
|
3809
4146
|
};
|
|
3810
4147
|
await visitSourceFile(absoluteEntryFile);
|
|
@@ -3816,7 +4153,7 @@ async function discoverPackagedLocalFiles(entryFile) {
|
|
|
3816
4153
|
|
|
3817
4154
|
// src/plays/bundle-play-file.ts
|
|
3818
4155
|
var import_meta2 = {};
|
|
3819
|
-
var PLAY_BUNDLE_CACHE_VERSION2 =
|
|
4156
|
+
var PLAY_BUNDLE_CACHE_VERSION2 = 26;
|
|
3820
4157
|
var MODULE_DIR = (0, import_node_path7.dirname)((0, import_node_url.fileURLToPath)(import_meta2.url));
|
|
3821
4158
|
var SDK_PACKAGE_ROOT = (0, import_node_path7.resolve)(MODULE_DIR, "..", "..");
|
|
3822
4159
|
var SOURCE_REPO_ROOT = (0, import_node_path7.resolve)(SDK_PACKAGE_ROOT, "..");
|
|
@@ -3831,7 +4168,7 @@ var PROJECT_ROOT = HAS_SOURCE_BUNDLING_SOURCES ? SOURCE_REPO_ROOT : HAS_PACKAGED
|
|
|
3831
4168
|
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
4169
|
var SDK_PACKAGE_JSON = (0, import_node_path7.resolve)(SDK_PACKAGE_ROOT, "package.json");
|
|
3833
4170
|
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");
|
|
4171
|
+
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
4172
|
var SDK_WORKERS_ENTRY_FILE = (0, import_node_path7.resolve)(SDK_SOURCE_ROOT, "worker-play-entry.ts");
|
|
3836
4173
|
var WORKERS_HARNESS_ENTRY_FILE = (0, import_node_path7.resolve)(PROJECT_ROOT, "apps", "play-runner-workers", "src", "entry.ts");
|
|
3837
4174
|
var WORKERS_HARNESS_FILES_DIR = (0, import_node_path7.resolve)(PROJECT_ROOT, "apps", "play-runner-workers", "src");
|
|
@@ -3863,7 +4200,7 @@ function createSdkPlayBundlingAdapter() {
|
|
|
3863
4200
|
sdkSourceRoot: SDK_SOURCE_ROOT,
|
|
3864
4201
|
sdkPackageJson: SDK_PACKAGE_JSON,
|
|
3865
4202
|
sdkEntryFile: SDK_ENTRY_FILE,
|
|
3866
|
-
sdkTypesEntryFile: HAS_SOURCE_BUNDLING_SOURCES
|
|
4203
|
+
sdkTypesEntryFile: HAS_SOURCE_BUNDLING_SOURCES || !(0, import_node_fs5.existsSync)(SDK_TYPES_ENTRY_FILE) ? SDK_ENTRY_FILE : SDK_TYPES_ENTRY_FILE,
|
|
3867
4204
|
sdkWorkersEntryFile: SDK_WORKERS_ENTRY_FILE,
|
|
3868
4205
|
workersHarnessEntryFile: WORKERS_HARNESS_ENTRY_FILE,
|
|
3869
4206
|
workersHarnessFilesDir: WORKERS_HARNESS_FILES_DIR,
|
|
@@ -4100,13 +4437,15 @@ function formatLoadedPlayMessage(materializedFile) {
|
|
|
4100
4437
|
return `Loaded play here: ${materializedFile.path}`;
|
|
4101
4438
|
}
|
|
4102
4439
|
function buildReadonlyPrebuiltPlayError(reference) {
|
|
4440
|
+
const localName = reference.split("/").slice(1).join("/") || "custom-play";
|
|
4103
4441
|
return new Error(
|
|
4104
4442
|
`Cannot edit or push ${reference} because Deepline prebuilt plays are read-only.
|
|
4105
4443
|
To make your own version:
|
|
4106
|
-
1.
|
|
4107
|
-
2. Change definePlay('${
|
|
4108
|
-
3. Run: deepline plays
|
|
4109
|
-
4.
|
|
4444
|
+
1. Run: deepline plays get ${reference} --source --out ./${localName}.play.ts
|
|
4445
|
+
2. Change definePlay('${localName}', ...) to a new play name you own.
|
|
4446
|
+
3. Run: deepline plays check ./${localName}.play.ts
|
|
4447
|
+
4. Run: deepline plays publish ./${localName}.play.ts
|
|
4448
|
+
5. Your play will then live under your workspace namespace.`
|
|
4110
4449
|
);
|
|
4111
4450
|
}
|
|
4112
4451
|
async function ensureEditableRemotePlay(client, target) {
|
|
@@ -4247,6 +4586,15 @@ function fileInputBindingsFromStaticPipeline(staticPipeline) {
|
|
|
4247
4586
|
);
|
|
4248
4587
|
return inputField ? [{ inputPath: inputField }] : [];
|
|
4249
4588
|
}
|
|
4589
|
+
function applyCsvShortcutInput(input) {
|
|
4590
|
+
const csvValue = getDottedInputValue(input.runtimeInput, "csv");
|
|
4591
|
+
if (csvValue == null || csvValue === "") return;
|
|
4592
|
+
const candidate = input.bindings.find((binding) => binding.inputPath !== "csv")?.inputPath ?? input.fallbackInputPath ?? null;
|
|
4593
|
+
if (!candidate || candidate === "csv") return;
|
|
4594
|
+
const existing = getDottedInputValue(input.runtimeInput, candidate);
|
|
4595
|
+
if (existing != null && existing !== "") return;
|
|
4596
|
+
setDottedInputValue(input.runtimeInput, candidate, csvValue);
|
|
4597
|
+
}
|
|
4250
4598
|
function isLocalFilePathValue(value) {
|
|
4251
4599
|
if (typeof value !== "string" || !value.trim()) return false;
|
|
4252
4600
|
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(value.trim())) return false;
|
|
@@ -4370,6 +4718,7 @@ async function compileBundledPlayGraphManifests(client, graph) {
|
|
|
4370
4718
|
node.compilerManifest = await client.compilePlayManifest({
|
|
4371
4719
|
name,
|
|
4372
4720
|
sourceCode: node.sourceCode,
|
|
4721
|
+
sourceFiles: node.sourceFiles,
|
|
4373
4722
|
artifact: node.artifact,
|
|
4374
4723
|
importedPlayDependencies: node.importedPlayDependencies.map(
|
|
4375
4724
|
(dependency) => {
|
|
@@ -4419,6 +4768,7 @@ async function publishImportedPlayDependencies(client, graph) {
|
|
|
4419
4768
|
await client.registerPlayArtifact({
|
|
4420
4769
|
name: node.playName,
|
|
4421
4770
|
sourceCode: node.sourceCode,
|
|
4771
|
+
sourceFiles: node.sourceFiles,
|
|
4422
4772
|
artifact: node.artifact,
|
|
4423
4773
|
compilerManifest: requireCompilerManifest(node),
|
|
4424
4774
|
publish: true
|
|
@@ -4436,67 +4786,6 @@ function formatTimestamp(value) {
|
|
|
4436
4786
|
function formatRunLine(run) {
|
|
4437
4787
|
return `${run.workflowId} ${run.status} ${formatTimestamp(run.startTime)}`;
|
|
4438
4788
|
}
|
|
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
4789
|
function isTransientPlayStatusPollError(error) {
|
|
4501
4790
|
if (error instanceof DeeplineError && typeof error.statusCode === "number") {
|
|
4502
4791
|
return error.statusCode >= 500 && error.statusCode < 600;
|
|
@@ -4600,7 +4889,7 @@ function assertPlayWaitNotTimedOut(input) {
|
|
|
4600
4889
|
if (input.waitTimeoutMs !== null && Date.now() - input.startedAt >= input.waitTimeoutMs) {
|
|
4601
4890
|
const hasRealRunId = input.workflowId.length > 0 && input.workflowId !== "pending";
|
|
4602
4891
|
const phaseSuffix = input.lastPhase && input.lastPhase.trim() ? ` (last observed phase: ${input.lastPhase.trim()})` : "";
|
|
4603
|
-
const tailHint = hasRealRunId ? ` Run 'deepline
|
|
4892
|
+
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
4893
|
throw new DeeplineError(
|
|
4605
4894
|
`Timed out waiting for play ${hasRealRunId ? input.workflowId : "<no run id>"} after ${Math.ceil(input.waitTimeoutMs / 1e3)}s${phaseSuffix}.${tailHint}`,
|
|
4606
4895
|
void 0,
|
|
@@ -4613,66 +4902,6 @@ function assertPlayWaitNotTimedOut(input) {
|
|
|
4613
4902
|
);
|
|
4614
4903
|
}
|
|
4615
4904
|
}
|
|
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
4905
|
async function startAndWaitForPlayCompletionByStream(input) {
|
|
4677
4906
|
const startedAt = Date.now();
|
|
4678
4907
|
const state = {
|
|
@@ -4752,10 +4981,12 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
4752
4981
|
clearTimeout(timeout);
|
|
4753
4982
|
}
|
|
4754
4983
|
const reason = error instanceof Error ? error.message : String(error);
|
|
4755
|
-
|
|
4756
|
-
|
|
4984
|
+
if (!input.jsonOutput) {
|
|
4985
|
+
process.stderr.write(
|
|
4986
|
+
`[play watch] start stream failed after run ${lastKnownWorkflowId}; falling back to polling (${reason})
|
|
4757
4987
|
`
|
|
4758
|
-
|
|
4988
|
+
);
|
|
4989
|
+
}
|
|
4759
4990
|
return waitForPlayCompletionByPolling({
|
|
4760
4991
|
client: input.client,
|
|
4761
4992
|
workflowId: lastKnownWorkflowId,
|
|
@@ -4774,6 +5005,24 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
4774
5005
|
clearTimeout(timeout);
|
|
4775
5006
|
}
|
|
4776
5007
|
}
|
|
5008
|
+
if (lastKnownWorkflowId) {
|
|
5009
|
+
if (!input.jsonOutput) {
|
|
5010
|
+
input.progress.writeLine(
|
|
5011
|
+
`[play watch] start stream ended after run ${lastKnownWorkflowId}; falling back to polling`
|
|
5012
|
+
);
|
|
5013
|
+
}
|
|
5014
|
+
return waitForPlayCompletionByPolling({
|
|
5015
|
+
client: input.client,
|
|
5016
|
+
workflowId: lastKnownWorkflowId,
|
|
5017
|
+
pollIntervalMs: 500,
|
|
5018
|
+
jsonOutput: input.jsonOutput,
|
|
5019
|
+
emitLogs: input.emitLogs,
|
|
5020
|
+
waitTimeoutMs: input.waitTimeoutMs,
|
|
5021
|
+
startedAt,
|
|
5022
|
+
state,
|
|
5023
|
+
progress: input.progress
|
|
5024
|
+
});
|
|
5025
|
+
}
|
|
4777
5026
|
const phaseSuffix = lastPhase && lastPhase.trim() ? ` (last observed phase: ${lastPhase.trim()})` : "";
|
|
4778
5027
|
const idSuffix = lastKnownWorkflowId ? ` runId=${lastKnownWorkflowId}` : "";
|
|
4779
5028
|
throw new DeeplineError(
|
|
@@ -4851,38 +5100,6 @@ async function waitForPlayCompletionByPolling(input) {
|
|
|
4851
5100
|
}
|
|
4852
5101
|
}
|
|
4853
5102
|
}
|
|
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
5103
|
function formatInteger(value) {
|
|
4887
5104
|
return typeof value === "number" && Number.isFinite(value) ? value.toLocaleString("en-US") : String(value ?? "-");
|
|
4888
5105
|
}
|
|
@@ -5011,17 +5228,153 @@ function buildRunWarnings(status, rowsInfo) {
|
|
|
5011
5228
|
}
|
|
5012
5229
|
function buildRunNextCommands(runId) {
|
|
5013
5230
|
return {
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
5231
|
+
get: `deepline runs get ${runId} --json`,
|
|
5232
|
+
tail: `deepline runs tail ${runId} --json`,
|
|
5233
|
+
stop: `deepline runs stop ${runId} --reason "stale lock" --json`,
|
|
5234
|
+
logs: `deepline runs logs ${runId} --out run.log --json`,
|
|
5235
|
+
exportCsv: `deepline runs export ${runId} --out output.csv`
|
|
5236
|
+
};
|
|
5237
|
+
}
|
|
5238
|
+
var RUN_LOG_PREVIEW_LIMIT = 20;
|
|
5239
|
+
function getRecordField(value, key) {
|
|
5240
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value[key] : void 0;
|
|
5241
|
+
}
|
|
5242
|
+
function getNumericField(value, key) {
|
|
5243
|
+
const field = getRecordField(value, key);
|
|
5244
|
+
return typeof field === "number" && Number.isFinite(field) ? field : null;
|
|
5245
|
+
}
|
|
5246
|
+
function getStringField(value, key) {
|
|
5247
|
+
const field = getRecordField(value, key);
|
|
5248
|
+
return typeof field === "string" && field.trim() ? field : null;
|
|
5249
|
+
}
|
|
5250
|
+
function normalizeRunStatusForEnvelope(status) {
|
|
5251
|
+
const run = status.run ?? null;
|
|
5252
|
+
return {
|
|
5253
|
+
id: status.runId,
|
|
5254
|
+
playName: status.playName ?? status.name ?? getStringField(run, "playName") ?? null,
|
|
5255
|
+
status: status.status,
|
|
5256
|
+
runtime: getStringField(status, "runtime") ?? getStringField(status, "runtimeBackend") ?? getStringField(run, "runtime") ?? null,
|
|
5257
|
+
startedAt: getStringField(run, "startTime") ?? getStringField(run, "startedAt") ?? null,
|
|
5258
|
+
updatedAt: getStringField(status, "updatedAt") ?? getStringField(run, "updatedAt") ?? null,
|
|
5259
|
+
finishedAt: getStringField(run, "closeTime") ?? getStringField(run, "finishedAt") ?? null,
|
|
5260
|
+
source: getRecordField(status, "source") ?? getRecordField(status, "artifact") ?? null
|
|
5017
5261
|
};
|
|
5018
5262
|
}
|
|
5263
|
+
function normalizeProgressForEnvelope(status, rowsInfo) {
|
|
5264
|
+
const progress = status.progress;
|
|
5265
|
+
const total = getNumericField(progress, "totalRows") ?? getNumericField(progress, "total") ?? rowsInfo?.totalRows ?? null;
|
|
5266
|
+
const failed = getNumericField(progress, "failed") ?? getNumericField(progress, "failedRows") ?? null;
|
|
5267
|
+
const completed = getNumericField(progress, "completed") ?? getNumericField(progress, "completedRows") ?? (status.status === "completed" ? total : null);
|
|
5268
|
+
const pending = getNumericField(progress, "pending") ?? (typeof total === "number" && typeof completed === "number" && typeof failed === "number" ? Math.max(0, total - completed - failed) : null);
|
|
5269
|
+
return {
|
|
5270
|
+
total,
|
|
5271
|
+
completed,
|
|
5272
|
+
pending,
|
|
5273
|
+
failed,
|
|
5274
|
+
executed: getNumericField(progress, "executed"),
|
|
5275
|
+
reused: getNumericField(progress, "reused"),
|
|
5276
|
+
skipped: getNumericField(progress, "skipped"),
|
|
5277
|
+
retried: getNumericField(progress, "retried"),
|
|
5278
|
+
degraded: typeof getRecordField(progress, "degraded") === "boolean" ? getRecordField(progress, "degraded") : null,
|
|
5279
|
+
duplicates: getRecordField(progress, "duplicates") ?? null,
|
|
5280
|
+
active: getStringField(progress, "status") ?? getStringField(status, "activeStep") ?? getStringField(status, "activeNodeId") ?? null,
|
|
5281
|
+
wait: status.wait ?? null
|
|
5282
|
+
};
|
|
5283
|
+
}
|
|
5284
|
+
function normalizeOutputsForEnvelope(rowsInfo, exportedPath) {
|
|
5285
|
+
if (!rowsInfo) {
|
|
5286
|
+
return exportedPath ? [{ name: "output", kind: "file", path: exportedPath }] : [];
|
|
5287
|
+
}
|
|
5288
|
+
return [
|
|
5289
|
+
{
|
|
5290
|
+
name: "rows",
|
|
5291
|
+
kind: "dataset",
|
|
5292
|
+
rowCount: rowsInfo.totalRows,
|
|
5293
|
+
columns: rowsInfo.columns,
|
|
5294
|
+
preview: rowsInfo.rows.slice(0, 5),
|
|
5295
|
+
previewRowCount: Math.min(rowsInfo.rows.length, 5),
|
|
5296
|
+
previewLimit: 5,
|
|
5297
|
+
complete: rowsInfo.complete,
|
|
5298
|
+
source: rowsInfo.source,
|
|
5299
|
+
...exportedPath ? { csv_path: exportedPath } : {}
|
|
5300
|
+
}
|
|
5301
|
+
];
|
|
5302
|
+
}
|
|
5303
|
+
function normalizeStepsForEnvelope(status) {
|
|
5304
|
+
const directSteps = getRecordField(status, "steps");
|
|
5305
|
+
if (Array.isArray(directSteps)) {
|
|
5306
|
+
return directSteps;
|
|
5307
|
+
}
|
|
5308
|
+
const timeline = getRecordField(status, "timeline");
|
|
5309
|
+
if (Array.isArray(timeline)) {
|
|
5310
|
+
return timeline;
|
|
5311
|
+
}
|
|
5312
|
+
return [];
|
|
5313
|
+
}
|
|
5314
|
+
function normalizeErrorsForEnvelope(status, error) {
|
|
5315
|
+
const directErrors = getRecordField(status, "errors");
|
|
5316
|
+
if (Array.isArray(directErrors)) {
|
|
5317
|
+
return directErrors.filter(
|
|
5318
|
+
(entry) => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry)
|
|
5319
|
+
);
|
|
5320
|
+
}
|
|
5321
|
+
if (!error) {
|
|
5322
|
+
return [];
|
|
5323
|
+
}
|
|
5324
|
+
return [
|
|
5325
|
+
{
|
|
5326
|
+
code: getStringField(status, "errorCode") ?? "RUN_FAILED",
|
|
5327
|
+
phase: getStringField(status, "errorPhase") ?? "runtime",
|
|
5328
|
+
message: error,
|
|
5329
|
+
retryable: typeof getRecordField(status, "retryable") === "boolean" ? getRecordField(status, "retryable") : null,
|
|
5330
|
+
nextAction: `deepline runs get ${status.runId} --json`
|
|
5331
|
+
}
|
|
5332
|
+
];
|
|
5333
|
+
}
|
|
5334
|
+
function normalizeLogsForEnvelope(status) {
|
|
5335
|
+
const logs = Array.isArray(status.progress?.logs) ? status.progress.logs : [];
|
|
5336
|
+
const offset = typeof status.progress?.logOffset === "number" && Number.isFinite(status.progress.logOffset) ? Math.max(0, Math.trunc(status.progress.logOffset)) : 0;
|
|
5337
|
+
const totalCount = offset + logs.length;
|
|
5338
|
+
const entries = logs.slice(Math.max(0, logs.length - RUN_LOG_PREVIEW_LIMIT));
|
|
5339
|
+
const firstSequence = entries.length === 0 ? null : offset + logs.length - entries.length + 1;
|
|
5340
|
+
const lastSequence = totalCount === 0 ? null : totalCount;
|
|
5341
|
+
return {
|
|
5342
|
+
totalCount,
|
|
5343
|
+
returnedCount: entries.length,
|
|
5344
|
+
firstSequence,
|
|
5345
|
+
lastSequence,
|
|
5346
|
+
truncated: totalCount > entries.length,
|
|
5347
|
+
hasMore: totalCount > entries.length,
|
|
5348
|
+
entries,
|
|
5349
|
+
nextCursor: lastSequence
|
|
5350
|
+
};
|
|
5351
|
+
}
|
|
5352
|
+
function stripProviderSpendFromBilling(value) {
|
|
5353
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
5354
|
+
return value;
|
|
5355
|
+
}
|
|
5356
|
+
const next = {};
|
|
5357
|
+
for (const [key, item] of Object.entries(value)) {
|
|
5358
|
+
if (key === "providerCostUsd" || key === "totalProviderCostUsd") {
|
|
5359
|
+
continue;
|
|
5360
|
+
}
|
|
5361
|
+
next[key] = item;
|
|
5362
|
+
}
|
|
5363
|
+
return next;
|
|
5364
|
+
}
|
|
5019
5365
|
function compactPlayStatus(status, options) {
|
|
5020
5366
|
const rowsInfo = extractCanonicalRowsInfo(status);
|
|
5021
5367
|
const result = status && typeof status === "object" ? status.result : null;
|
|
5022
5368
|
const warnings = buildRunWarnings(status, rowsInfo);
|
|
5023
|
-
const datasetStats = rowsInfo && rowsInfo.complete ? buildDatasetStats(
|
|
5024
|
-
|
|
5369
|
+
const datasetStats = rowsInfo && rowsInfo.complete ? buildDatasetStats(
|
|
5370
|
+
rowsInfo.rows,
|
|
5371
|
+
rowsInfo.totalRows,
|
|
5372
|
+
rowsInfo.columns,
|
|
5373
|
+
extractDatasetExecutionStats(status)
|
|
5374
|
+
) : null;
|
|
5375
|
+
const billing = status && typeof status === "object" ? stripProviderSpendFromBilling(
|
|
5376
|
+
status.billing
|
|
5377
|
+
) : null;
|
|
5025
5378
|
const progressError = status.progress?.error;
|
|
5026
5379
|
const error = typeof progressError === "string" ? progressError : typeof status.error === "string" ? String(status.error) : null;
|
|
5027
5380
|
return {
|
|
@@ -5030,6 +5383,12 @@ function compactPlayStatus(status, options) {
|
|
|
5030
5383
|
...typeof status.name === "string" ? { name: status.name } : {},
|
|
5031
5384
|
...typeof status.playName === "string" ? { playName: status.playName } : {},
|
|
5032
5385
|
status: status.status,
|
|
5386
|
+
run: normalizeRunStatusForEnvelope(status),
|
|
5387
|
+
progress: normalizeProgressForEnvelope(status, rowsInfo),
|
|
5388
|
+
outputs: normalizeOutputsForEnvelope(rowsInfo, options?.exportedPath),
|
|
5389
|
+
steps: normalizeStepsForEnvelope(status),
|
|
5390
|
+
errors: normalizeErrorsForEnvelope(status, error),
|
|
5391
|
+
logs: normalizeLogsForEnvelope(status),
|
|
5033
5392
|
...error ? { error } : {},
|
|
5034
5393
|
...warnings.length > 0 ? { warnings } : {},
|
|
5035
5394
|
output: buildOutputSummary(rowsInfo, options?.exportedPath) ?? result ?? null,
|
|
@@ -5038,7 +5397,6 @@ function compactPlayStatus(status, options) {
|
|
|
5038
5397
|
...datasetStats ? { dataset_stats: datasetStats } : {},
|
|
5039
5398
|
...rowsInfo ? { previewRows: rowsInfo.rows.slice(0, 5) } : {},
|
|
5040
5399
|
...billing ? { billing } : {},
|
|
5041
|
-
...status.run ? { run: status.run } : {},
|
|
5042
5400
|
next: buildRunNextCommands(status.runId)
|
|
5043
5401
|
};
|
|
5044
5402
|
}
|
|
@@ -5052,7 +5410,8 @@ function enrichPlayStatusWithDatasetStats(status) {
|
|
|
5052
5410
|
dataset_stats: buildDatasetStats(
|
|
5053
5411
|
rowsInfo.rows,
|
|
5054
5412
|
rowsInfo.totalRows,
|
|
5055
|
-
rowsInfo.columns
|
|
5413
|
+
rowsInfo.columns,
|
|
5414
|
+
extractDatasetExecutionStats(status)
|
|
5056
5415
|
)
|
|
5057
5416
|
};
|
|
5058
5417
|
}
|
|
@@ -5067,8 +5426,9 @@ function formatDatasetStatsLines(datasetStats) {
|
|
|
5067
5426
|
)) {
|
|
5068
5427
|
const topValues = stat3.top_values ? `, top_values=${Object.entries(stat3.top_values).slice(0, 3).map(([value, count]) => `${value}=${count}`).join(", ")}` : "";
|
|
5069
5428
|
const sample = stat3.sample_value !== void 0 ? `, sample_value=${JSON.stringify(stat3.sample_value)}` : "";
|
|
5429
|
+
const execution = stat3.execution ? `, execution=${Object.entries(stat3.execution).map(([bucket, count]) => `${bucket}=${count}`).join(", ")}` : "";
|
|
5070
5430
|
lines.push(
|
|
5071
|
-
` ${column}: non_empty=${stat3.non_empty}, unique=${stat3.unique}${topValues}${sample}`
|
|
5431
|
+
` ${column}: non_empty=${stat3.non_empty}, unique=${stat3.unique}${topValues}${sample}${execution}`
|
|
5072
5432
|
);
|
|
5073
5433
|
}
|
|
5074
5434
|
return lines;
|
|
@@ -5091,7 +5451,12 @@ function writePlayResult(status, jsonOutput, options) {
|
|
|
5091
5451
|
lines.push(`${success ? "\u2713" : "\u2717"} ${publicStatus} ${runId}`);
|
|
5092
5452
|
const rowsInfo = extractCanonicalRowsInfo(status);
|
|
5093
5453
|
const warnings = buildRunWarnings(status, rowsInfo);
|
|
5094
|
-
const datasetStats = rowsInfo && rowsInfo.complete ? buildDatasetStats(
|
|
5454
|
+
const datasetStats = rowsInfo && rowsInfo.complete ? buildDatasetStats(
|
|
5455
|
+
rowsInfo.rows,
|
|
5456
|
+
rowsInfo.totalRows,
|
|
5457
|
+
rowsInfo.columns,
|
|
5458
|
+
extractDatasetExecutionStats(status)
|
|
5459
|
+
) : null;
|
|
5095
5460
|
const outputSummary = buildOutputSummary(rowsInfo, options?.exportedPath);
|
|
5096
5461
|
if (outputSummary) {
|
|
5097
5462
|
const columns = Array.isArray(outputSummary.columns) ? outputSummary.columns.length : 0;
|
|
@@ -5210,10 +5575,10 @@ function writeStartedPlayRun(input) {
|
|
|
5210
5575
|
const lines = [
|
|
5211
5576
|
`Started ${input.playName}`,
|
|
5212
5577
|
` run id: ${input.runId}`,
|
|
5213
|
-
`
|
|
5214
|
-
` tail logs: deepline
|
|
5215
|
-
` stop run: deepline
|
|
5216
|
-
` result JSON: deepline
|
|
5578
|
+
` get status: deepline runs get ${input.runId} --json`,
|
|
5579
|
+
` tail logs: deepline runs tail ${input.runId} --json`,
|
|
5580
|
+
` stop run: deepline runs stop ${input.runId} --reason "stale lock" --json`,
|
|
5581
|
+
` result JSON: deepline runs get ${input.runId} --json`
|
|
5217
5582
|
];
|
|
5218
5583
|
if (input.dashboardUrl) {
|
|
5219
5584
|
lines.push(` play page: ${input.dashboardUrl}`);
|
|
@@ -5360,6 +5725,10 @@ function parsePlayCheckOptions(args) {
|
|
|
5360
5725
|
const jsonOutput = argsWantJson(args);
|
|
5361
5726
|
return { target, jsonOutput };
|
|
5362
5727
|
}
|
|
5728
|
+
function shouldUseLocalOnlyPlayCheck() {
|
|
5729
|
+
const value = process.env.DEEPLINE_PLAY_CHECK_LOCAL_ONLY?.trim().toLowerCase();
|
|
5730
|
+
return value === "1" || value === "true" || value === "yes" || value === "on";
|
|
5731
|
+
}
|
|
5363
5732
|
async function handlePlayCheck(args) {
|
|
5364
5733
|
const options = parsePlayCheckOptions(args);
|
|
5365
5734
|
if (!isFileTarget(options.target)) {
|
|
@@ -5385,10 +5754,28 @@ async function handlePlayCheck(args) {
|
|
|
5385
5754
|
return 1;
|
|
5386
5755
|
}
|
|
5387
5756
|
const playName = graph.root.playName ?? extractPlayName(sourceCode, absolutePlayPath);
|
|
5757
|
+
if (shouldUseLocalOnlyPlayCheck()) {
|
|
5758
|
+
const result2 = {
|
|
5759
|
+
valid: true,
|
|
5760
|
+
errors: [],
|
|
5761
|
+
staticPipeline: graph.root.compilerManifest?.staticPipeline ?? null,
|
|
5762
|
+
artifactHash: graph.root.artifact.artifactHash,
|
|
5763
|
+
graphHash: graph.root.artifact.graphHash
|
|
5764
|
+
};
|
|
5765
|
+
if (options.jsonOutput) {
|
|
5766
|
+
process.stdout.write(`${JSON.stringify({ name: playName, ...result2 })}
|
|
5767
|
+
`);
|
|
5768
|
+
} else {
|
|
5769
|
+
console.log(`\u2713 ${playName} passed local play check`);
|
|
5770
|
+
console.log(` artifact: ${result2.artifactHash.slice(0, 12)}`);
|
|
5771
|
+
}
|
|
5772
|
+
return 0;
|
|
5773
|
+
}
|
|
5388
5774
|
const client = new DeeplineClient();
|
|
5389
5775
|
const result = await client.checkPlayArtifact({
|
|
5390
5776
|
name: playName,
|
|
5391
5777
|
sourceCode: graph.root.sourceCode,
|
|
5778
|
+
sourceFiles: graph.root.sourceFiles,
|
|
5392
5779
|
artifact: graph.root.artifact
|
|
5393
5780
|
});
|
|
5394
5781
|
if (options.jsonOutput) {
|
|
@@ -5440,17 +5827,24 @@ async function handleFileBackedRun(options) {
|
|
|
5440
5827
|
const packagedFileUploads = bundleResult.packagedFiles.map(
|
|
5441
5828
|
(file) => stageFile(file.logicalPath, file.absolutePath)
|
|
5442
5829
|
);
|
|
5830
|
+
const fileInputBindings = fileInputBindingsFromStaticPipeline(
|
|
5831
|
+
requireCompilerManifest(bundleResult).staticPipeline
|
|
5832
|
+
);
|
|
5833
|
+
applyCsvShortcutInput({
|
|
5834
|
+
runtimeInput,
|
|
5835
|
+
bindings: fileInputBindings,
|
|
5836
|
+
fallbackInputPath: "file"
|
|
5837
|
+
});
|
|
5443
5838
|
const stagedFileInputs = await stageFileInputArgs({
|
|
5444
5839
|
client,
|
|
5445
5840
|
runtimeInput,
|
|
5446
|
-
bindings:
|
|
5447
|
-
requireCompilerManifest(bundleResult).staticPipeline
|
|
5448
|
-
),
|
|
5841
|
+
bindings: fileInputBindings,
|
|
5449
5842
|
progress
|
|
5450
5843
|
});
|
|
5451
5844
|
const startRequest = {
|
|
5452
5845
|
name: playName,
|
|
5453
5846
|
sourceCode: bundleResult.sourceCode,
|
|
5847
|
+
sourceFiles: bundleResult.sourceFiles,
|
|
5454
5848
|
runtimeArtifact: bundleResult.artifact,
|
|
5455
5849
|
compilerManifest: requireCompilerManifest(bundleResult),
|
|
5456
5850
|
packagedFileUploads,
|
|
@@ -5525,13 +5919,18 @@ async function handleNamedRun(options) {
|
|
|
5525
5919
|
selector: options.revisionSelector
|
|
5526
5920
|
});
|
|
5527
5921
|
const runtimeInput = options.input ? { ...options.input } : {};
|
|
5922
|
+
const fileInputBindings = [
|
|
5923
|
+
...fileInputBindingsFromPlaySchema(playDetail.play.inputSchema),
|
|
5924
|
+
...fileInputBindingsFromStaticPipeline(playDetail.play.staticPipeline)
|
|
5925
|
+
];
|
|
5926
|
+
applyCsvShortcutInput({
|
|
5927
|
+
runtimeInput,
|
|
5928
|
+
bindings: fileInputBindings
|
|
5929
|
+
});
|
|
5528
5930
|
const stagedFileInputs = await stageFileInputArgs({
|
|
5529
5931
|
client,
|
|
5530
5932
|
runtimeInput,
|
|
5531
|
-
bindings:
|
|
5532
|
-
...fileInputBindingsFromPlaySchema(playDetail.play.inputSchema),
|
|
5533
|
-
...fileInputBindingsFromStaticPipeline(playDetail.play.staticPipeline)
|
|
5534
|
-
],
|
|
5933
|
+
bindings: fileInputBindings,
|
|
5535
5934
|
progress
|
|
5536
5935
|
});
|
|
5537
5936
|
const startRequest = {
|
|
@@ -5609,80 +6008,101 @@ async function handlePlayRun(args) {
|
|
|
5609
6008
|
}
|
|
5610
6009
|
return handleNamedRun(options);
|
|
5611
6010
|
}
|
|
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;
|
|
6011
|
+
function parseRunIdPositional(args, usage) {
|
|
5625
6012
|
for (let index = 0; index < args.length; index += 1) {
|
|
5626
6013
|
const arg = args[index];
|
|
5627
|
-
if (
|
|
5628
|
-
|
|
6014
|
+
if (arg === "--json" || arg === "--full" || arg === "--logs" || arg === "--compact" || arg === "--limit") {
|
|
6015
|
+
if (arg === "--limit" && args[index + 1]) {
|
|
6016
|
+
index += 1;
|
|
6017
|
+
}
|
|
6018
|
+
continue;
|
|
6019
|
+
}
|
|
6020
|
+
if ((arg === "--out" || arg === "--cursor" || arg === "--reason" || arg === "--interval-ms" || arg === "--poll-interval-ms") && args[index + 1]) {
|
|
6021
|
+
index += 1;
|
|
6022
|
+
continue;
|
|
6023
|
+
}
|
|
6024
|
+
if (!arg.startsWith("--")) {
|
|
6025
|
+
return arg;
|
|
5629
6026
|
}
|
|
5630
6027
|
}
|
|
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;
|
|
6028
|
+
throw new DeeplineError(usage);
|
|
5650
6029
|
}
|
|
5651
|
-
async function
|
|
5652
|
-
const usage = "Usage: deepline
|
|
5653
|
-
let
|
|
6030
|
+
async function handleRunGet(args) {
|
|
6031
|
+
const usage = "Usage: deepline runs get <run-id> [--json] [--full]";
|
|
6032
|
+
let runId;
|
|
5654
6033
|
try {
|
|
5655
|
-
|
|
6034
|
+
runId = parseRunIdPositional(args, usage);
|
|
5656
6035
|
} catch (error) {
|
|
5657
6036
|
console.error(error instanceof Error ? error.message : usage);
|
|
5658
6037
|
return 1;
|
|
5659
6038
|
}
|
|
5660
6039
|
const client = new DeeplineClient();
|
|
5661
|
-
const
|
|
5662
|
-
const status = await client.getPlayStatus(workflowId);
|
|
6040
|
+
const status = await client.runs.get(runId);
|
|
5663
6041
|
writePlayResult(status, argsWantJson(args), {
|
|
5664
6042
|
fullJson: args.includes("--full")
|
|
5665
6043
|
});
|
|
5666
6044
|
return 0;
|
|
5667
6045
|
}
|
|
5668
|
-
function
|
|
6046
|
+
async function handleRunsList(args) {
|
|
6047
|
+
const usage = "Usage: deepline runs list --play <play-name> [--status <status>] [--json]";
|
|
6048
|
+
let playName = null;
|
|
6049
|
+
let statusFilter = null;
|
|
5669
6050
|
for (let index = 0; index < args.length; index += 1) {
|
|
5670
6051
|
const arg = args[index];
|
|
5671
|
-
if (arg === "--
|
|
6052
|
+
if ((arg === "--play" || arg === "--name") && args[index + 1]) {
|
|
6053
|
+
playName = parseReferencedPlayTarget(args[++index]).playName;
|
|
5672
6054
|
continue;
|
|
5673
6055
|
}
|
|
5674
|
-
if (arg === "--
|
|
5675
|
-
|
|
6056
|
+
if (arg === "--status" && args[index + 1]) {
|
|
6057
|
+
statusFilter = args[++index].trim().toLowerCase();
|
|
5676
6058
|
continue;
|
|
5677
6059
|
}
|
|
5678
|
-
if (
|
|
5679
|
-
|
|
6060
|
+
if (arg === "--json" || arg === "--compact") {
|
|
6061
|
+
continue;
|
|
5680
6062
|
}
|
|
5681
6063
|
}
|
|
5682
|
-
|
|
6064
|
+
if (!playName) {
|
|
6065
|
+
console.error(usage);
|
|
6066
|
+
return 1;
|
|
6067
|
+
}
|
|
6068
|
+
const client = new DeeplineClient();
|
|
6069
|
+
const runs = (await client.runs.list({
|
|
6070
|
+
play: playName,
|
|
6071
|
+
...statusFilter ? { status: statusFilter } : {}
|
|
6072
|
+
})).map((run) => ({
|
|
6073
|
+
runId: run.workflowId,
|
|
6074
|
+
workflowId: run.workflowId,
|
|
6075
|
+
temporalRunId: run.runId,
|
|
6076
|
+
status: String(run.status ?? "").toLowerCase(),
|
|
6077
|
+
startedAt: run.startTime,
|
|
6078
|
+
finishedAt: run.closeTime,
|
|
6079
|
+
executionTime: run.executionTime,
|
|
6080
|
+
playName: run.memo?.playName ?? playName
|
|
6081
|
+
}));
|
|
6082
|
+
if (argsWantJson(args)) {
|
|
6083
|
+
process.stdout.write(
|
|
6084
|
+
`${JSON.stringify({
|
|
6085
|
+
runs,
|
|
6086
|
+
count: runs.length,
|
|
6087
|
+
next: {
|
|
6088
|
+
get: runs[0]?.runId ? `deepline runs get ${runs[0].runId} --json` : null
|
|
6089
|
+
}
|
|
6090
|
+
})}
|
|
6091
|
+
`
|
|
6092
|
+
);
|
|
6093
|
+
} else {
|
|
6094
|
+
if (runs.length === 0) {
|
|
6095
|
+
console.log(`No runs found for ${playName}.`);
|
|
6096
|
+
} else {
|
|
6097
|
+
for (const run of runs) {
|
|
6098
|
+
console.log(`${run.runId} ${run.status} ${formatTimestamp(run.startedAt)}`);
|
|
6099
|
+
}
|
|
6100
|
+
}
|
|
6101
|
+
}
|
|
6102
|
+
return 0;
|
|
5683
6103
|
}
|
|
5684
|
-
async function
|
|
5685
|
-
const usage = "Usage: deepline runs
|
|
6104
|
+
async function handleRunTail(args) {
|
|
6105
|
+
const usage = "Usage: deepline runs tail <run-id> [--json] [--compact] [--cursor <cursor>]";
|
|
5686
6106
|
let runId;
|
|
5687
6107
|
try {
|
|
5688
6108
|
runId = parseRunIdPositional(args, usage);
|
|
@@ -5691,14 +6111,24 @@ async function handleRunStatus(args) {
|
|
|
5691
6111
|
return 1;
|
|
5692
6112
|
}
|
|
5693
6113
|
const client = new DeeplineClient();
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
6114
|
+
let afterLogIndex;
|
|
6115
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
6116
|
+
const arg = args[index];
|
|
6117
|
+
if (arg === "--cursor" && args[index + 1]) {
|
|
6118
|
+
const parsed = Number(args[++index]);
|
|
6119
|
+
if (Number.isInteger(parsed) && parsed >= 0) {
|
|
6120
|
+
afterLogIndex = parsed;
|
|
6121
|
+
}
|
|
6122
|
+
}
|
|
6123
|
+
}
|
|
6124
|
+
const status = await client.runs.tail(runId, {
|
|
6125
|
+
...afterLogIndex !== void 0 ? { afterLogIndex } : {}
|
|
5697
6126
|
});
|
|
5698
|
-
|
|
6127
|
+
writePlayResult(status, argsWantJson(args));
|
|
6128
|
+
return status.status === "failed" ? 1 : 0;
|
|
5699
6129
|
}
|
|
5700
6130
|
async function handleRunLogs(args) {
|
|
5701
|
-
const usage = "Usage: deepline runs logs <run-id> [--json]";
|
|
6131
|
+
const usage = "Usage: deepline runs logs <run-id> [--limit 200] [--out run.log] [--json]";
|
|
5702
6132
|
let runId;
|
|
5703
6133
|
try {
|
|
5704
6134
|
runId = parseRunIdPositional(args, usage);
|
|
@@ -5706,14 +6136,86 @@ async function handleRunLogs(args) {
|
|
|
5706
6136
|
console.error(error instanceof Error ? error.message : usage);
|
|
5707
6137
|
return 1;
|
|
5708
6138
|
}
|
|
6139
|
+
let limit = 200;
|
|
6140
|
+
let outPath = null;
|
|
6141
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
6142
|
+
const arg = args[index];
|
|
6143
|
+
if (arg === "--limit" && args[index + 1]) {
|
|
6144
|
+
limit = parsePositiveInteger2(args[++index], "--limit");
|
|
6145
|
+
continue;
|
|
6146
|
+
}
|
|
6147
|
+
if (arg === "--out" && args[index + 1]) {
|
|
6148
|
+
outPath = (0, import_node_path8.resolve)(args[++index]);
|
|
6149
|
+
}
|
|
6150
|
+
}
|
|
5709
6151
|
const client = new DeeplineClient();
|
|
5710
|
-
const status = await client.
|
|
6152
|
+
const status = await client.runs.get(runId);
|
|
5711
6153
|
const logs = status.progress?.logs ?? [];
|
|
6154
|
+
if (outPath) {
|
|
6155
|
+
(0, import_node_fs6.writeFileSync)(outPath, `${logs.join("\n")}${logs.length > 0 ? "\n" : ""}`);
|
|
6156
|
+
if (argsWantJson(args)) {
|
|
6157
|
+
process.stdout.write(
|
|
6158
|
+
`${JSON.stringify({
|
|
6159
|
+
runId: status.runId,
|
|
6160
|
+
log_path: outPath,
|
|
6161
|
+
lineCount: logs.length
|
|
6162
|
+
})}
|
|
6163
|
+
`
|
|
6164
|
+
);
|
|
6165
|
+
} else {
|
|
6166
|
+
console.log(`Wrote ${logs.length} log lines to ${outPath}`);
|
|
6167
|
+
}
|
|
6168
|
+
return 0;
|
|
6169
|
+
}
|
|
6170
|
+
const entries = logs.slice(Math.max(0, logs.length - limit));
|
|
6171
|
+
if (argsWantJson(args)) {
|
|
6172
|
+
process.stdout.write(
|
|
6173
|
+
`${JSON.stringify({
|
|
6174
|
+
runId: status.runId,
|
|
6175
|
+
totalCount: logs.length,
|
|
6176
|
+
returnedCount: entries.length,
|
|
6177
|
+
firstSequence: logs.length === 0 ? null : logs.length - entries.length + 1,
|
|
6178
|
+
lastSequence: logs.length === 0 ? null : logs.length,
|
|
6179
|
+
truncated: logs.length > entries.length,
|
|
6180
|
+
hasMore: logs.length > entries.length,
|
|
6181
|
+
entries,
|
|
6182
|
+
next: {
|
|
6183
|
+
export: `deepline runs logs ${status.runId} --out run.log --json`
|
|
6184
|
+
}
|
|
6185
|
+
})}
|
|
6186
|
+
`
|
|
6187
|
+
);
|
|
6188
|
+
} else {
|
|
6189
|
+
process.stdout.write(`${entries.join("\n")}${entries.length > 0 ? "\n" : ""}`);
|
|
6190
|
+
}
|
|
6191
|
+
return 0;
|
|
6192
|
+
}
|
|
6193
|
+
async function handleRunStop(args) {
|
|
6194
|
+
const usage = 'Usage: deepline runs stop <run-id> [--reason "text"] [--json]';
|
|
6195
|
+
let runId;
|
|
6196
|
+
try {
|
|
6197
|
+
runId = parseRunIdPositional(args, usage);
|
|
6198
|
+
} catch (error) {
|
|
6199
|
+
console.error(error instanceof Error ? error.message : usage);
|
|
6200
|
+
return 1;
|
|
6201
|
+
}
|
|
6202
|
+
let reason;
|
|
6203
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
6204
|
+
const arg = args[index];
|
|
6205
|
+
if (arg === "--reason" && args[index + 1]) {
|
|
6206
|
+
reason = args[++index];
|
|
6207
|
+
}
|
|
6208
|
+
}
|
|
6209
|
+
const client = new DeeplineClient();
|
|
6210
|
+
const result = await client.runs.stop(runId, { reason });
|
|
5712
6211
|
if (argsWantJson(args)) {
|
|
5713
|
-
process.stdout.write(`${JSON.stringify(
|
|
6212
|
+
process.stdout.write(`${JSON.stringify(result)}
|
|
5714
6213
|
`);
|
|
5715
6214
|
} else {
|
|
5716
|
-
|
|
6215
|
+
console.log(`Stopped ${result.runId}`);
|
|
6216
|
+
if (result.hitlCancelledCount > 0) {
|
|
6217
|
+
console.log(` cancelled HITL waits: ${result.hitlCancelledCount}`);
|
|
6218
|
+
}
|
|
5717
6219
|
}
|
|
5718
6220
|
return 0;
|
|
5719
6221
|
}
|
|
@@ -5756,37 +6258,6 @@ async function handleRunExport(args) {
|
|
|
5756
6258
|
}
|
|
5757
6259
|
return 0;
|
|
5758
6260
|
}
|
|
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
6261
|
async function handlePlayGet(args) {
|
|
5791
6262
|
const target = args[0];
|
|
5792
6263
|
if (!target) {
|
|
@@ -5874,33 +6345,6 @@ async function handlePlayGet(args) {
|
|
|
5874
6345
|
}
|
|
5875
6346
|
return 0;
|
|
5876
6347
|
}
|
|
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
6348
|
function formatVersionLine(version) {
|
|
5905
6349
|
const revisionLabel = version.artifactHash?.slice(0, 12) ?? "unknown-revision";
|
|
5906
6350
|
return `v${version.version} ${revisionLabel} ${formatTimestamp(version.createdAt)}`;
|
|
@@ -6032,6 +6476,11 @@ function printPlayDescription(play) {
|
|
|
6032
6476
|
}
|
|
6033
6477
|
}
|
|
6034
6478
|
console.log(` Run: ${play.runCommand}`);
|
|
6479
|
+
if (play.origin === "prebuilt" && !play.canEdit) {
|
|
6480
|
+
console.log(
|
|
6481
|
+
` Customize: deepline plays get ${reference} --source --out ./my-play.play.ts`
|
|
6482
|
+
);
|
|
6483
|
+
}
|
|
6035
6484
|
}
|
|
6036
6485
|
async function handlePlaySearch(args) {
|
|
6037
6486
|
let options;
|
|
@@ -6129,6 +6578,7 @@ async function handlePlayPublish(args) {
|
|
|
6129
6578
|
const published = await client.registerPlayArtifact({
|
|
6130
6579
|
name: rootPlayName,
|
|
6131
6580
|
sourceCode: graph.root.sourceCode,
|
|
6581
|
+
sourceFiles: graph.root.sourceFiles,
|
|
6132
6582
|
artifact: graph.root.artifact,
|
|
6133
6583
|
compilerManifest: requireCompilerManifest(graph.root),
|
|
6134
6584
|
publish: true
|
|
@@ -6349,50 +6799,12 @@ Examples:
|
|
|
6349
6799
|
...options.json ? ["--json"] : []
|
|
6350
6800
|
]);
|
|
6351
6801
|
});
|
|
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
6802
|
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
6803
|
process.exitCode = await handlePlayVersions([
|
|
6360
6804
|
...options.name ? ["--name", options.name] : [],
|
|
6361
6805
|
...options.json ? ["--json"] : []
|
|
6362
6806
|
]);
|
|
6363
6807
|
});
|
|
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
6808
|
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
6809
|
process.exitCode = await handlePlayPublish([
|
|
6398
6810
|
target,
|
|
@@ -6408,38 +6820,72 @@ Examples:
|
|
|
6408
6820
|
...options.json ? ["--json"] : []
|
|
6409
6821
|
]);
|
|
6410
6822
|
});
|
|
6411
|
-
const runs = program.command("runs").description("Inspect and export play runs.").addHelpText(
|
|
6823
|
+
const runs = program.command("runs").description("Inspect, tail, stop, and export play runs.").addHelpText(
|
|
6412
6824
|
"after",
|
|
6413
6825
|
`
|
|
6414
6826
|
Examples:
|
|
6415
|
-
deepline runs
|
|
6827
|
+
deepline runs get play/my-play/run/20260501t000000-000 --json
|
|
6828
|
+
deepline runs tail play/my-play/run/20260501t000000-000
|
|
6829
|
+
deepline runs logs play/my-play/run/20260501t000000-000 --out run.log --json
|
|
6830
|
+
deepline runs list --play my-play --status failed --json
|
|
6831
|
+
deepline runs stop play/my-play/run/20260501t000000-000 --reason "stale lock" --json
|
|
6416
6832
|
deepline runs export play/my-play/run/20260501t000000-000 --out output.csv
|
|
6417
|
-
deepline runs logs play/my-play/run/20260501t000000-000
|
|
6418
6833
|
`
|
|
6419
6834
|
);
|
|
6420
|
-
runs.command("
|
|
6421
|
-
process.exitCode = await
|
|
6835
|
+
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) => {
|
|
6836
|
+
process.exitCode = await handleRunGet([
|
|
6422
6837
|
runId,
|
|
6423
6838
|
...options.json ? ["--json"] : [],
|
|
6424
6839
|
...options.full ? ["--full"] : []
|
|
6425
6840
|
]);
|
|
6426
6841
|
});
|
|
6427
|
-
runs.command("
|
|
6428
|
-
process.exitCode = await
|
|
6429
|
-
|
|
6430
|
-
|
|
6431
|
-
options.
|
|
6842
|
+
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) => {
|
|
6843
|
+
process.exitCode = await handleRunsList([
|
|
6844
|
+
"--play",
|
|
6845
|
+
options.play,
|
|
6846
|
+
...options.status ? ["--status", options.status] : [],
|
|
6847
|
+
...options.compact ? ["--compact"] : [],
|
|
6432
6848
|
...options.json ? ["--json"] : []
|
|
6433
6849
|
]);
|
|
6434
6850
|
});
|
|
6435
|
-
runs.command("
|
|
6851
|
+
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) => {
|
|
6852
|
+
process.exitCode = await handleRunTail([
|
|
6853
|
+
runId,
|
|
6854
|
+
...options.json ? ["--json"] : [],
|
|
6855
|
+
...options.compact ? ["--compact"] : [],
|
|
6856
|
+
...options.cursor ? ["--cursor", options.cursor] : []
|
|
6857
|
+
]);
|
|
6858
|
+
});
|
|
6859
|
+
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
6860
|
process.exitCode = await handleRunLogs([
|
|
6437
6861
|
runId,
|
|
6862
|
+
...options.limit ? ["--limit", options.limit] : [],
|
|
6863
|
+
...options.out ? ["--out", options.out] : [],
|
|
6864
|
+
...options.json ? ["--json"] : []
|
|
6865
|
+
]);
|
|
6866
|
+
});
|
|
6867
|
+
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) => {
|
|
6868
|
+
process.exitCode = await handleRunStop([
|
|
6869
|
+
runId,
|
|
6870
|
+
...options.reason ? ["--reason", options.reason] : [],
|
|
6871
|
+
...options.json ? ["--json"] : []
|
|
6872
|
+
]);
|
|
6873
|
+
});
|
|
6874
|
+
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) => {
|
|
6875
|
+
process.exitCode = await handleRunExport([
|
|
6876
|
+
runId,
|
|
6877
|
+
"--out",
|
|
6878
|
+
options.out,
|
|
6438
6879
|
...options.json ? ["--json"] : []
|
|
6439
6880
|
]);
|
|
6440
6881
|
});
|
|
6441
6882
|
}
|
|
6442
6883
|
|
|
6884
|
+
// src/cli/commands/tools.ts
|
|
6885
|
+
var import_node_fs8 = require("fs");
|
|
6886
|
+
var import_node_os7 = require("os");
|
|
6887
|
+
var import_node_path10 = require("path");
|
|
6888
|
+
|
|
6443
6889
|
// src/tool-output.ts
|
|
6444
6890
|
var import_node_fs7 = require("fs");
|
|
6445
6891
|
var import_node_os6 = require("os");
|
|
@@ -6608,31 +7054,23 @@ async function listTools(args) {
|
|
|
6608
7054
|
}
|
|
6609
7055
|
return 0;
|
|
6610
7056
|
}
|
|
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();
|
|
7057
|
+
async function searchTools(queryInput, options = {}) {
|
|
7058
|
+
const query = queryInput.trim();
|
|
6627
7059
|
if (!query) {
|
|
6628
7060
|
console.error("Usage: deepline tools search <query> [--json]");
|
|
6629
7061
|
return 1;
|
|
6630
7062
|
}
|
|
6631
|
-
const terms = query.toLowerCase().split(/\s+/).filter(Boolean);
|
|
6632
7063
|
const client = new DeeplineClient();
|
|
6633
|
-
const
|
|
6634
|
-
|
|
6635
|
-
|
|
7064
|
+
const result = await client.searchTools({
|
|
7065
|
+
query,
|
|
7066
|
+
categories: options.categories,
|
|
7067
|
+
searchTerms: options.searchTerms,
|
|
7068
|
+
searchMode: options.searchMode,
|
|
7069
|
+
includeSearchDebug: options.includeSearchDebug
|
|
7070
|
+
});
|
|
7071
|
+
const items = result.tools.map(toListedTool);
|
|
7072
|
+
if (options.json || shouldEmitJson()) {
|
|
7073
|
+
process.stdout.write(`${JSON.stringify({ ...result, tools: items })}
|
|
6636
7074
|
`);
|
|
6637
7075
|
return 0;
|
|
6638
7076
|
}
|
|
@@ -6686,11 +7124,14 @@ Common commands:
|
|
|
6686
7124
|
...options.json ? ["--json"] : []
|
|
6687
7125
|
]);
|
|
6688
7126
|
});
|
|
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
|
-
|
|
7127
|
+
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) => {
|
|
7128
|
+
process.exitCode = await searchTools(query, {
|
|
7129
|
+
json: options.json,
|
|
7130
|
+
categories: options.categories,
|
|
7131
|
+
searchTerms: options.searchTerms ?? options.search_terms,
|
|
7132
|
+
searchMode: options.searchMode === "v1" || options.searchMode === "v2" ? options.searchMode : void 0,
|
|
7133
|
+
includeSearchDebug: Boolean(options.includeSearchDebug)
|
|
7134
|
+
});
|
|
6694
7135
|
});
|
|
6695
7136
|
tools.command("get <toolId>").alias("describe").description("Show metadata for a tool.").addHelpText(
|
|
6696
7137
|
"after",
|
|
@@ -7048,6 +7489,61 @@ function parseExecuteOptions(args) {
|
|
|
7048
7489
|
}
|
|
7049
7490
|
return { toolId, params, outputFormat, noPreview };
|
|
7050
7491
|
}
|
|
7492
|
+
function safeFileStem(value) {
|
|
7493
|
+
return value.trim().replace(/[^a-zA-Z0-9_-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64) || "tool";
|
|
7494
|
+
}
|
|
7495
|
+
function shellQuote(value) {
|
|
7496
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
7497
|
+
}
|
|
7498
|
+
function powerShellQuote(value) {
|
|
7499
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
7500
|
+
}
|
|
7501
|
+
function seedToolListScript(input) {
|
|
7502
|
+
const stem = safeFileStem(input.toolId);
|
|
7503
|
+
const fileName = `${stem}-workflow-seed-${Date.now()}.play.ts`;
|
|
7504
|
+
const scriptDir = (0, import_node_fs8.mkdtempSync)((0, import_node_path10.join)((0, import_node_os7.tmpdir)(), "deepline-workflow-seed-"));
|
|
7505
|
+
(0, import_node_fs8.chmodSync)(scriptDir, 448);
|
|
7506
|
+
const scriptPath = (0, import_node_path10.join)(scriptDir, fileName);
|
|
7507
|
+
const projectDir = `deepline/projects/${stem}-workflow`;
|
|
7508
|
+
const playName = `${stem}-workflow`;
|
|
7509
|
+
const sampleRows = input.rows.length > 0 ? `${JSON.stringify(input.rows.slice(0, 2)).replace(/\]$/, "")}, ...]` : "[]";
|
|
7510
|
+
const columns = Object.keys(input.rows[0] ?? {}).join(", ");
|
|
7511
|
+
const rowKey = Object.prototype.hasOwnProperty.call(input.rows[0] ?? {}, "id") ? '"id"' : "(row) => JSON.stringify(row)";
|
|
7512
|
+
const script = `import { definePlay } from 'deepline';
|
|
7513
|
+
|
|
7514
|
+
export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
7515
|
+
const result = await ctx.tools.execute({
|
|
7516
|
+
id: ${JSON.stringify(input.toolId)},
|
|
7517
|
+
tool: ${JSON.stringify(input.toolId)},
|
|
7518
|
+
input: ${JSON.stringify(input.payload)},
|
|
7519
|
+
description: ${JSON.stringify(`Seed ${input.toolId} rows for workflow expansion.`)},
|
|
7520
|
+
});
|
|
7521
|
+
|
|
7522
|
+
const list = Object.values(result.lists)[0];
|
|
7523
|
+
const rows = (list?.get() ?? []).slice(0, 100);
|
|
7524
|
+
// ${sampleRows}
|
|
7525
|
+
// columns: ${columns}
|
|
7526
|
+
// .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.' }))
|
|
7527
|
+
// .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.' }))
|
|
7528
|
+
// ctx.map is idempotent by map key + row key; reruns reuse completed rows.
|
|
7529
|
+
const enrichedData = await ctx
|
|
7530
|
+
.map('enriched_data', rows, { key: ${rowKey} })
|
|
7531
|
+
.run({ description: 'Enrich seeded rows.' });
|
|
7532
|
+
|
|
7533
|
+
return {
|
|
7534
|
+
rows: enrichedData,
|
|
7535
|
+
count: await enrichedData.count(),
|
|
7536
|
+
};
|
|
7537
|
+
});
|
|
7538
|
+
`;
|
|
7539
|
+
(0, import_node_fs8.writeFileSync)(scriptPath, script, { encoding: "utf-8", mode: 384 });
|
|
7540
|
+
return {
|
|
7541
|
+
path: scriptPath,
|
|
7542
|
+
projectDir,
|
|
7543
|
+
macCopyCommand: `mkdir -p ${shellQuote(projectDir)} && cp ${shellQuote(scriptPath)} ${shellQuote(`${projectDir}/${fileName}`)}`,
|
|
7544
|
+
windowsCopyCommand: `New-Item -ItemType Directory -Force -Path ${powerShellQuote(projectDir.replace(/\//g, "\\"))} | Out-Null; Copy-Item -LiteralPath ${powerShellQuote(scriptPath)} -Destination ${powerShellQuote(`${projectDir.replace(/\//g, "\\")}\\${fileName}`)}`
|
|
7545
|
+
};
|
|
7546
|
+
}
|
|
7051
7547
|
async function executeTool(args) {
|
|
7052
7548
|
let parsed;
|
|
7053
7549
|
try {
|
|
@@ -7101,6 +7597,11 @@ async function executeTool(args) {
|
|
|
7101
7597
|
return 0;
|
|
7102
7598
|
}
|
|
7103
7599
|
const csv = writeCsvOutputFile(listConversion.rows, `${parsed.toolId}_output`);
|
|
7600
|
+
const seededScript = seedToolListScript({
|
|
7601
|
+
toolId: parsed.toolId,
|
|
7602
|
+
payload: parsed.params,
|
|
7603
|
+
rows: listConversion.rows
|
|
7604
|
+
});
|
|
7104
7605
|
if (parsed.outputFormat === "csv_file") {
|
|
7105
7606
|
process.stdout.write(`${JSON.stringify({
|
|
7106
7607
|
extracted_csv: csv.path,
|
|
@@ -7109,6 +7610,12 @@ async function executeTool(args) {
|
|
|
7109
7610
|
preview: csv.preview,
|
|
7110
7611
|
list_strategy: listConversion.strategy,
|
|
7111
7612
|
list_source_path: listConversion.sourcePath,
|
|
7613
|
+
starter_script: seededScript.path,
|
|
7614
|
+
project_dir: seededScript.projectDir,
|
|
7615
|
+
copy_to_project: {
|
|
7616
|
+
macos_linux: seededScript.macCopyCommand,
|
|
7617
|
+
windows_powershell: seededScript.windowsCopyCommand
|
|
7618
|
+
},
|
|
7112
7619
|
summary
|
|
7113
7620
|
})}
|
|
7114
7621
|
`);
|
|
@@ -7126,14 +7633,20 @@ async function executeTool(args) {
|
|
|
7126
7633
|
console.log(`summary: ${Object.entries(summary).map(([key, value]) => `${key}=${String(value)}`).join(", ")}`);
|
|
7127
7634
|
}
|
|
7128
7635
|
console.log(`preview: ${JSON.stringify(csv.preview)}`);
|
|
7636
|
+
console.log(`starter script: ${seededScript.path}`);
|
|
7637
|
+
console.log(
|
|
7638
|
+
"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."
|
|
7639
|
+
);
|
|
7640
|
+
console.log(`macOS/Linux: ${seededScript.macCopyCommand}`);
|
|
7641
|
+
console.log(`Windows PowerShell: ${seededScript.windowsCopyCommand}`);
|
|
7129
7642
|
return 0;
|
|
7130
7643
|
}
|
|
7131
7644
|
|
|
7132
7645
|
// src/cli/skills-sync.ts
|
|
7133
7646
|
var import_node_child_process2 = require("child_process");
|
|
7134
|
-
var
|
|
7135
|
-
var
|
|
7136
|
-
var
|
|
7647
|
+
var import_node_fs9 = require("fs");
|
|
7648
|
+
var import_node_os8 = require("os");
|
|
7649
|
+
var import_node_path11 = require("path");
|
|
7137
7650
|
var CHECK_TIMEOUT_MS2 = 3e3;
|
|
7138
7651
|
var SDK_SKILL_NAME = "deepline-sdk";
|
|
7139
7652
|
var SKILL_AGENTS = ["codex", "claude-code", "cursor"];
|
|
@@ -7143,22 +7656,22 @@ function shouldSkipSkillsSync() {
|
|
|
7143
7656
|
return value === "1" || value === "true" || value === "yes" || value === "on";
|
|
7144
7657
|
}
|
|
7145
7658
|
function sdkSkillsVersionPath(baseUrl) {
|
|
7146
|
-
const home = process.env.HOME?.trim() || (0,
|
|
7147
|
-
return (0,
|
|
7659
|
+
const home = process.env.HOME?.trim() || (0, import_node_os8.homedir)();
|
|
7660
|
+
return (0, import_node_path11.join)(home, ".local", "deepline", baseUrlSlug(baseUrl), "sdk-skills", ".version");
|
|
7148
7661
|
}
|
|
7149
7662
|
function readLocalSkillsVersion(baseUrl) {
|
|
7150
7663
|
const path = sdkSkillsVersionPath(baseUrl);
|
|
7151
|
-
if (!(0,
|
|
7664
|
+
if (!(0, import_node_fs9.existsSync)(path)) return "";
|
|
7152
7665
|
try {
|
|
7153
|
-
return (0,
|
|
7666
|
+
return (0, import_node_fs9.readFileSync)(path, "utf-8").trim();
|
|
7154
7667
|
} catch {
|
|
7155
7668
|
return "";
|
|
7156
7669
|
}
|
|
7157
7670
|
}
|
|
7158
7671
|
function writeLocalSkillsVersion(baseUrl, version) {
|
|
7159
7672
|
const path = sdkSkillsVersionPath(baseUrl);
|
|
7160
|
-
(0,
|
|
7161
|
-
(0,
|
|
7673
|
+
(0, import_node_fs9.mkdirSync)((0, import_node_path11.dirname)(path), { recursive: true });
|
|
7674
|
+
(0, import_node_fs9.writeFileSync)(path, `${version}
|
|
7162
7675
|
`, "utf-8");
|
|
7163
7676
|
}
|
|
7164
7677
|
async function fetchSkillsUpdate(baseUrl, localVersion) {
|
|
@@ -7189,9 +7702,26 @@ async function fetchSkillsUpdate(baseUrl, localVersion) {
|
|
|
7189
7702
|
clearTimeout(timeout);
|
|
7190
7703
|
}
|
|
7191
7704
|
}
|
|
7192
|
-
function
|
|
7705
|
+
function buildSkillsInstallArgs(baseUrl) {
|
|
7706
|
+
const packageUrl = new URL("/.well-known/skills/index.json", baseUrl).toString();
|
|
7707
|
+
return [
|
|
7708
|
+
"--yes",
|
|
7709
|
+
"skills",
|
|
7710
|
+
"add",
|
|
7711
|
+
packageUrl,
|
|
7712
|
+
"--agents",
|
|
7713
|
+
...SKILL_AGENTS,
|
|
7714
|
+
"--global",
|
|
7715
|
+
"--yes",
|
|
7716
|
+
"--skill",
|
|
7717
|
+
SDK_SKILL_NAME,
|
|
7718
|
+
"--full-depth"
|
|
7719
|
+
];
|
|
7720
|
+
}
|
|
7721
|
+
function buildBunxSkillsInstallArgs(baseUrl) {
|
|
7193
7722
|
const packageUrl = new URL("/.well-known/skills/index.json", baseUrl).toString();
|
|
7194
|
-
|
|
7723
|
+
return [
|
|
7724
|
+
"--bun",
|
|
7195
7725
|
"skills",
|
|
7196
7726
|
"add",
|
|
7197
7727
|
packageUrl,
|
|
@@ -7203,8 +7733,40 @@ function runSkillsInstall(baseUrl) {
|
|
|
7203
7733
|
SDK_SKILL_NAME,
|
|
7204
7734
|
"--full-depth"
|
|
7205
7735
|
];
|
|
7736
|
+
}
|
|
7737
|
+
function hasCommand(command) {
|
|
7738
|
+
const result = (0, import_node_child_process2.spawnSync)(command, ["--version"], {
|
|
7739
|
+
stdio: "ignore",
|
|
7740
|
+
shell: process.platform === "win32"
|
|
7741
|
+
});
|
|
7742
|
+
return result.status === 0;
|
|
7743
|
+
}
|
|
7744
|
+
function shellQuote2(arg) {
|
|
7745
|
+
return `'${arg.replace(/'/g, `'\\''`)}'`;
|
|
7746
|
+
}
|
|
7747
|
+
function resolveSkillsInstallCommands(baseUrl) {
|
|
7748
|
+
const npxArgs = buildSkillsInstallArgs(baseUrl);
|
|
7749
|
+
const npxInstall = {
|
|
7750
|
+
command: "npx",
|
|
7751
|
+
args: npxArgs,
|
|
7752
|
+
manualCommand: `npx ${npxArgs.map(shellQuote2).join(" ")}`
|
|
7753
|
+
};
|
|
7754
|
+
if (hasCommand("bunx")) {
|
|
7755
|
+
const bunxArgs = buildBunxSkillsInstallArgs(baseUrl);
|
|
7756
|
+
return [
|
|
7757
|
+
{
|
|
7758
|
+
command: "bunx",
|
|
7759
|
+
args: bunxArgs,
|
|
7760
|
+
manualCommand: `bunx ${bunxArgs.map(shellQuote2).join(" ")}`
|
|
7761
|
+
},
|
|
7762
|
+
npxInstall
|
|
7763
|
+
];
|
|
7764
|
+
}
|
|
7765
|
+
return [npxInstall];
|
|
7766
|
+
}
|
|
7767
|
+
function runOneSkillsInstall(install) {
|
|
7206
7768
|
return new Promise((resolve8) => {
|
|
7207
|
-
const child = (0, import_node_child_process2.spawn)(
|
|
7769
|
+
const child = (0, import_node_child_process2.spawn)(install.command, install.args, {
|
|
7208
7770
|
stdio: ["ignore", "ignore", "pipe"],
|
|
7209
7771
|
env: process.env
|
|
7210
7772
|
});
|
|
@@ -7213,37 +7775,63 @@ function runSkillsInstall(baseUrl) {
|
|
|
7213
7775
|
stderr += chunk.toString("utf-8");
|
|
7214
7776
|
});
|
|
7215
7777
|
child.on("error", (error) => {
|
|
7216
|
-
|
|
7217
|
-
|
|
7218
|
-
|
|
7778
|
+
resolve8({
|
|
7779
|
+
ok: false,
|
|
7780
|
+
detail: `failed to start ${install.command}: ${error.message}`,
|
|
7781
|
+
manualCommand: install.manualCommand
|
|
7782
|
+
});
|
|
7219
7783
|
});
|
|
7220
7784
|
child.on("close", (code) => {
|
|
7221
7785
|
if (code === 0) {
|
|
7222
|
-
resolve8(true);
|
|
7786
|
+
resolve8({ ok: true, detail: "", manualCommand: install.manualCommand });
|
|
7223
7787
|
return;
|
|
7224
7788
|
}
|
|
7225
7789
|
const detail = stderr.trim();
|
|
7226
|
-
|
|
7227
|
-
|
|
7228
|
-
|
|
7229
|
-
|
|
7230
|
-
);
|
|
7231
|
-
resolve8(false);
|
|
7790
|
+
resolve8({
|
|
7791
|
+
ok: false,
|
|
7792
|
+
detail: detail ? `${install.command}: ${detail}` : `${install.command} exited ${code}`,
|
|
7793
|
+
manualCommand: install.manualCommand
|
|
7794
|
+
});
|
|
7232
7795
|
});
|
|
7233
7796
|
});
|
|
7234
7797
|
}
|
|
7798
|
+
async function runSkillsInstall(baseUrl) {
|
|
7799
|
+
const failures = [];
|
|
7800
|
+
for (const install of resolveSkillsInstallCommands(baseUrl)) {
|
|
7801
|
+
const result = await runOneSkillsInstall(install);
|
|
7802
|
+
if (result.ok) return true;
|
|
7803
|
+
failures.push(result);
|
|
7804
|
+
}
|
|
7805
|
+
const details = failures.map((failure) => failure.detail).filter(Boolean).join("\n");
|
|
7806
|
+
const manualCommand = failures.at(-1)?.manualCommand;
|
|
7807
|
+
process.stderr.write(
|
|
7808
|
+
`SDK skills sync failed${details ? `:
|
|
7809
|
+
${details}` : ""}
|
|
7810
|
+
` + (manualCommand ? `Run manually: ${manualCommand}
|
|
7811
|
+
` : "")
|
|
7812
|
+
);
|
|
7813
|
+
return false;
|
|
7814
|
+
}
|
|
7815
|
+
function writeSdkSkillsStatusLine(line) {
|
|
7816
|
+
const progress = getActiveCliProgress();
|
|
7817
|
+
if (progress) {
|
|
7818
|
+
progress.writeLine(line);
|
|
7819
|
+
return;
|
|
7820
|
+
}
|
|
7821
|
+
process.stderr.write(`${line}
|
|
7822
|
+
`);
|
|
7823
|
+
}
|
|
7235
7824
|
async function syncSdkSkillsIfNeeded(baseUrl) {
|
|
7236
7825
|
if (attemptedSync || shouldSkipSkillsSync()) return;
|
|
7237
7826
|
attemptedSync = true;
|
|
7238
7827
|
const localVersion = readLocalSkillsVersion(baseUrl);
|
|
7239
7828
|
const update = await fetchSkillsUpdate(baseUrl, localVersion);
|
|
7240
7829
|
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");
|
|
7830
|
+
writeSdkSkillsStatusLine("SDK skills changed; syncing deepline-sdk skill...");
|
|
7243
7831
|
const installed = await runSkillsInstall(baseUrl);
|
|
7244
7832
|
if (!installed) return;
|
|
7245
7833
|
writeLocalSkillsVersion(baseUrl, update.remoteVersion);
|
|
7246
|
-
|
|
7834
|
+
writeSdkSkillsStatusLine("SDK skills are up to date.");
|
|
7247
7835
|
}
|
|
7248
7836
|
|
|
7249
7837
|
// src/cli/trace.ts
|
|
@@ -7405,4 +7993,3 @@ Output:
|
|
|
7405
7993
|
process.exit(process.exitCode ?? 0);
|
|
7406
7994
|
}
|
|
7407
7995
|
main();
|
|
7408
|
-
//# sourceMappingURL=index.js.map
|