deepline 0.1.4 → 0.1.8
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/dist/cli/index.js +128 -13
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +133 -17
- package/dist/cli/index.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/repo/sdk/src/cli/commands/play.ts +113 -6
- package/dist/repo/sdk/src/cli/index.ts +1 -0
- package/dist/repo/sdk/src/cli/progress.ts +14 -0
- package/dist/repo/sdk/src/cli/skills-sync.ts +6 -2
- package/dist/repo/sdk/src/version.ts +1 -1
- package/dist/repo/shared_libs/plays/bundling/index.ts +9 -0
- package/package.json +5 -3
package/dist/index.d.mts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import {
|
|
3
3
|
existsSync,
|
|
4
|
+
mkdirSync,
|
|
4
5
|
readFileSync,
|
|
5
6
|
readdirSync,
|
|
6
7
|
realpathSync,
|
|
@@ -140,6 +141,81 @@ function defaultMaterializedPlayPath(reference: string): string {
|
|
|
140
141
|
return resolve(`${safeName || 'play'}.play.ts`);
|
|
141
142
|
}
|
|
142
143
|
|
|
144
|
+
function sanitizeGeneratedPlayName(value: string): string {
|
|
145
|
+
return (
|
|
146
|
+
value
|
|
147
|
+
.trim()
|
|
148
|
+
.toLowerCase()
|
|
149
|
+
.replace(/^prebuilt\//, '')
|
|
150
|
+
.replace(/[^a-z0-9-]/g, '-')
|
|
151
|
+
.replace(/-+/g, '-')
|
|
152
|
+
.replace(/^-|-$/g, '') || 'play'
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function buildGeneratedCsvWrapperSource(input: {
|
|
157
|
+
wrapperName: string;
|
|
158
|
+
playRef: string;
|
|
159
|
+
}): string {
|
|
160
|
+
return `import { definePlay } from 'deepline';
|
|
161
|
+
|
|
162
|
+
export default definePlay(
|
|
163
|
+
${JSON.stringify(input.wrapperName)},
|
|
164
|
+
async (ctx, input: Record<string, unknown> & { file: string }) => {
|
|
165
|
+
const rows = await ctx.csv<Record<string, unknown>>(input.file);
|
|
166
|
+
const constants = Object.fromEntries(
|
|
167
|
+
Object.entries(input).filter(([key]) => key !== 'file'),
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
const mappedRows = await ctx
|
|
171
|
+
.map('csv_rows', rows, {
|
|
172
|
+
key: (row, index) =>
|
|
173
|
+
String(
|
|
174
|
+
row.id ??
|
|
175
|
+
row.lead_id ??
|
|
176
|
+
row.email ??
|
|
177
|
+
row.linkedin_url ??
|
|
178
|
+
row.domain ??
|
|
179
|
+
index,
|
|
180
|
+
),
|
|
181
|
+
})
|
|
182
|
+
.step('result', (row, rowCtx) =>
|
|
183
|
+
rowCtx.runPlay(
|
|
184
|
+
'row_play',
|
|
185
|
+
${JSON.stringify(input.playRef)},
|
|
186
|
+
{
|
|
187
|
+
...constants,
|
|
188
|
+
...row,
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
description: 'Run the source play for this CSV row.',
|
|
192
|
+
},
|
|
193
|
+
),
|
|
194
|
+
)
|
|
195
|
+
.run({ description: 'Run the source play once per CSV row.' });
|
|
196
|
+
|
|
197
|
+
return { rows: mappedRows };
|
|
198
|
+
},
|
|
199
|
+
);
|
|
200
|
+
`;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function writeGeneratedCsvWrapperPlay(playRef: string): string {
|
|
204
|
+
const baseName = sanitizeGeneratedPlayName(
|
|
205
|
+
parseReferencedPlayTarget(playRef).unqualifiedPlayName,
|
|
206
|
+
);
|
|
207
|
+
const wrapperName = `${baseName}-csv`;
|
|
208
|
+
const outputDir = resolve('.deepline', 'generated');
|
|
209
|
+
const outputPath = join(outputDir, `${wrapperName}.play.ts`);
|
|
210
|
+
mkdirSync(outputDir, { recursive: true });
|
|
211
|
+
writeFileSync(
|
|
212
|
+
outputPath,
|
|
213
|
+
buildGeneratedCsvWrapperSource({ wrapperName, playRef }),
|
|
214
|
+
'utf-8',
|
|
215
|
+
);
|
|
216
|
+
return outputPath;
|
|
217
|
+
}
|
|
218
|
+
|
|
143
219
|
type MaterializedRemotePlaySource = {
|
|
144
220
|
path: string;
|
|
145
221
|
status: 'created' | 'updated' | 'unchanged';
|
|
@@ -892,9 +968,16 @@ async function startAndWaitForPlayCompletionByStream(input: {
|
|
|
892
968
|
const dashboardUrl =
|
|
893
969
|
getDashboardUrlFromLiveEvent(event) ??
|
|
894
970
|
buildPlayDashboardUrl(input.client.baseUrl, input.playName);
|
|
895
|
-
input.
|
|
896
|
-
|
|
897
|
-
|
|
971
|
+
if (!input.jsonOutput) {
|
|
972
|
+
writeStartedPlayRun({
|
|
973
|
+
runId: workflowId,
|
|
974
|
+
playName: input.playName,
|
|
975
|
+
dashboardUrl,
|
|
976
|
+
jsonOutput: false,
|
|
977
|
+
progress: input.progress,
|
|
978
|
+
});
|
|
979
|
+
}
|
|
980
|
+
input.progress.phase(`loading play on ${dashboardUrl}`);
|
|
898
981
|
emittedDashboardUrl = true;
|
|
899
982
|
}
|
|
900
983
|
assertPlayWaitNotTimedOut({
|
|
@@ -1024,8 +1107,8 @@ async function waitForPlayCompletionByPolling(input: {
|
|
|
1024
1107
|
const now = Date.now();
|
|
1025
1108
|
if (now - lastTransientPollWarningAt >= 30_000) {
|
|
1026
1109
|
const message = error instanceof Error ? error.message : String(error);
|
|
1027
|
-
|
|
1028
|
-
`[play tail] transient status poll failed; retrying: ${message}
|
|
1110
|
+
input.progress.writeLine(
|
|
1111
|
+
`[play tail] transient status poll failed; retrying: ${message}`,
|
|
1029
1112
|
);
|
|
1030
1113
|
lastTransientPollWarningAt = now;
|
|
1031
1114
|
}
|
|
@@ -1711,6 +1794,7 @@ function writeStartedPlayRun(input: {
|
|
|
1711
1794
|
statusUrl?: string;
|
|
1712
1795
|
dashboardUrl?: string;
|
|
1713
1796
|
jsonOutput: boolean;
|
|
1797
|
+
progress?: CliProgress;
|
|
1714
1798
|
}): void {
|
|
1715
1799
|
const payload = {
|
|
1716
1800
|
runId: input.runId,
|
|
@@ -1739,7 +1823,12 @@ function writeStartedPlayRun(input: {
|
|
|
1739
1823
|
lines.push(` play page: ${input.dashboardUrl}`);
|
|
1740
1824
|
}
|
|
1741
1825
|
|
|
1742
|
-
|
|
1826
|
+
const output = lines.join('\n');
|
|
1827
|
+
if (input.progress) {
|
|
1828
|
+
input.progress.writeLine(output, process.stdout);
|
|
1829
|
+
return;
|
|
1830
|
+
}
|
|
1831
|
+
console.log(output);
|
|
1743
1832
|
}
|
|
1744
1833
|
|
|
1745
1834
|
function parsePlayRunOptions(args: string[]): PlayRunCommandOptions {
|
|
@@ -2112,6 +2201,7 @@ async function handleFileBackedRun(
|
|
|
2112
2201
|
statusUrl: started.statusUrl,
|
|
2113
2202
|
dashboardUrl,
|
|
2114
2203
|
jsonOutput: options.jsonOutput,
|
|
2204
|
+
progress,
|
|
2115
2205
|
});
|
|
2116
2206
|
return 0;
|
|
2117
2207
|
}
|
|
@@ -2184,6 +2274,22 @@ async function handleNamedRun(options: PlayRunCommandOptions): Promise<number> {
|
|
|
2184
2274
|
waitTimeoutMs: options.waitTimeoutMs,
|
|
2185
2275
|
progress,
|
|
2186
2276
|
});
|
|
2277
|
+
if (finalStatus.status !== 'completed' && options.csvPath) {
|
|
2278
|
+
progress.phase('generating csv wrapper play');
|
|
2279
|
+
const generatedPlayPath = writeGeneratedCsvWrapperPlay(
|
|
2280
|
+
options.target.name,
|
|
2281
|
+
);
|
|
2282
|
+
progress.writeLogLine(
|
|
2283
|
+
`Generated CSV wrapper play: ${generatedPlayPath}`,
|
|
2284
|
+
);
|
|
2285
|
+
progress.phase('running generated csv wrapper play');
|
|
2286
|
+
return handleFileBackedRun({
|
|
2287
|
+
...options,
|
|
2288
|
+
target: { kind: 'file', path: generatedPlayPath },
|
|
2289
|
+
revisionId: null,
|
|
2290
|
+
revisionSelector: null,
|
|
2291
|
+
});
|
|
2292
|
+
}
|
|
2187
2293
|
const exportedPath = exportPlayStatusRows(finalStatus, options.outPath);
|
|
2188
2294
|
if (finalStatus.status === 'completed') {
|
|
2189
2295
|
progress.complete();
|
|
@@ -2211,6 +2317,7 @@ async function handleNamedRun(options: PlayRunCommandOptions): Promise<number> {
|
|
|
2211
2317
|
statusUrl: started.statusUrl,
|
|
2212
2318
|
dashboardUrl,
|
|
2213
2319
|
jsonOutput: options.jsonOutput,
|
|
2320
|
+
progress,
|
|
2214
2321
|
});
|
|
2215
2322
|
return 0;
|
|
2216
2323
|
}
|
|
@@ -56,6 +56,20 @@ export class CliProgress {
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
writeLine(line: string, stream: NodeJS.WriteStream = process.stderr): void {
|
|
60
|
+
if (!this.enabled || !this.interactive) {
|
|
61
|
+
stream.write(`${line}\n`);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const activeMessage = this.lastMessage;
|
|
65
|
+
this.worker?.terminate().catch(() => undefined);
|
|
66
|
+
this.worker = null;
|
|
67
|
+
stream.write(`\r\x1b[2K${line}\n`);
|
|
68
|
+
if (activeMessage) {
|
|
69
|
+
this.startWorker().postMessage({ type: 'phase', message: activeMessage });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
59
73
|
private settle(mark: '✓' | '✗'): void {
|
|
60
74
|
if (!this.enabled || !this.lastMessage) {
|
|
61
75
|
return;
|
|
@@ -2,6 +2,7 @@ import { spawn } from 'node:child_process';
|
|
|
2
2
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
import { dirname, join } from 'node:path';
|
|
5
|
+
import { getActiveCliProgress } from './progress.js';
|
|
5
6
|
import { baseUrlSlug } from '../config.js';
|
|
6
7
|
|
|
7
8
|
const CHECK_TIMEOUT_MS = 3_000;
|
|
@@ -128,10 +129,13 @@ export async function syncSdkSkillsIfNeeded(baseUrl: string): Promise<void> {
|
|
|
128
129
|
const update = await fetchSkillsUpdate(baseUrl, localVersion);
|
|
129
130
|
if (!update?.needsUpdate || !update.remoteVersion) return;
|
|
130
131
|
|
|
131
|
-
|
|
132
|
+
const progress = getActiveCliProgress();
|
|
133
|
+
progress?.writeLine('SDK skills changed; syncing deepline-sdk skill...') ??
|
|
134
|
+
process.stderr.write('SDK skills changed; syncing deepline-sdk skill...\n');
|
|
132
135
|
const installed = await runSkillsInstall(baseUrl);
|
|
133
136
|
if (!installed) return;
|
|
134
137
|
|
|
135
138
|
writeLocalSkillsVersion(baseUrl, update.remoteVersion);
|
|
136
|
-
|
|
139
|
+
progress?.writeLine('SDK skills are up to date.') ??
|
|
140
|
+
process.stderr.write('SDK skills are up to date.\n');
|
|
137
141
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const SDK_VERSION = "0.1.
|
|
1
|
+
export const SDK_VERSION = "0.1.8";
|
|
2
2
|
export const SDK_API_CONTRACT = "2026-04-plays-v1";
|
|
@@ -165,6 +165,14 @@ function formatTypeScriptDiagnostic(diagnostic: ts.Diagnostic): string | null {
|
|
|
165
165
|
return `${diagnostic.file.fileName}:${line + 1}:${character + 1} ${message}`;
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
+
function resolveBundledTypeRoots(): string[] {
|
|
169
|
+
try {
|
|
170
|
+
return [dirname(dirname(playArtifactRequire.resolve('@types/node/package.json')))];
|
|
171
|
+
} catch {
|
|
172
|
+
return [];
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
168
176
|
function typecheckPlaySource(
|
|
169
177
|
input: SourceGraphAnalysis,
|
|
170
178
|
adapter: PlayBundlingAdapter,
|
|
@@ -196,6 +204,7 @@ function typecheckPlaySource(
|
|
|
196
204
|
allowJs: true,
|
|
197
205
|
resolveJsonModule: true,
|
|
198
206
|
types: ['node'],
|
|
207
|
+
typeRoots: resolveBundledTypeRoots(),
|
|
199
208
|
});
|
|
200
209
|
return ts
|
|
201
210
|
.getPreEmitDiagnostics(program)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deepline",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "Deepline SDK + CLI — B2B data enrichment powered by durable cloud execution",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -44,12 +44,14 @@
|
|
|
44
44
|
"prepublishOnly": "tsup"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
+
"@types/node": "^20.0.0",
|
|
48
|
+
"acorn": "^8.16.0",
|
|
49
|
+
"acorn-walk": "^8.3.5",
|
|
47
50
|
"commander": "^14.0.3",
|
|
48
51
|
"csv-parse": "^5.6.0",
|
|
49
52
|
"csv-stringify": "^6.5.0",
|
|
50
53
|
"esbuild": "^0.25.11",
|
|
51
|
-
"typescript": "^5.9.3"
|
|
52
|
-
"@types/node": "^20.0.0"
|
|
54
|
+
"typescript": "^5.9.3"
|
|
53
55
|
},
|
|
54
56
|
"devDependencies": {
|
|
55
57
|
"tsup": "^8.0.0"
|