deepline 0.1.3 → 0.1.7
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 +235 -9
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +238 -11
- 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/auth.ts +25 -7
- package/dist/repo/sdk/src/cli/commands/play.ts +92 -0
- package/dist/repo/sdk/src/cli/index.ts +10 -0
- package/dist/repo/sdk/src/cli/skills-sync.ts +137 -0
- 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
|
@@ -98,6 +98,29 @@ function sleep(ms: number): Promise<void> {
|
|
|
98
98
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
function printDeeplineLogo(): void {
|
|
102
|
+
if (process.stdout.isTTY && (process.stdout.columns ?? 80) >= 70) {
|
|
103
|
+
console.log(' ██████╗ ███████╗ ███████╗ ██████╗ ██╗ ██╗ ███╗ ██╗ ███████╗');
|
|
104
|
+
console.log(' ██╔══██╗ ██╔════╝ ██╔════╝ ██╔══██╗ ██║ ██║ ████╗ ██║ ██╔════╝');
|
|
105
|
+
console.log(' ██║ ██║ █████╗ █████╗ ██████╔╝ ██║ ██║ ██╔██╗ ██║ █████╗');
|
|
106
|
+
console.log(' ██║ ██║ ██╔══╝ ██╔══╝ ██╔═══╝ ██║ ██║ ██║╚██╗██║ ██╔══╝');
|
|
107
|
+
console.log(' ██████╔╝ ███████╗ ███████╗ ██║ ███████╗ ██║ ██║ ╚████║ ███████╗');
|
|
108
|
+
console.log(' ╚═════╝ ╚══════╝ ╚══════╝ ╚═╝ ╚══════╝ ╚═╝ ╚═╝ ╚═══╝ ╚══════╝');
|
|
109
|
+
console.log('');
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
console.log('DEEPLINE');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function printClaimSuccessBanner(statusData: Record<string, unknown>): void {
|
|
116
|
+
console.log('');
|
|
117
|
+
printDeeplineLogo();
|
|
118
|
+
console.log('✓ All set! Your CLI is connected.');
|
|
119
|
+
if (statusData.org_name) {
|
|
120
|
+
console.log(` • Signed in with organization: ${statusData.org_name}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
101
124
|
export async function handleRegister(args: string[]): Promise<number> {
|
|
102
125
|
const baseUrl = autoDetectBaseUrl().replace(/\/$/, '');
|
|
103
126
|
|
|
@@ -189,12 +212,7 @@ export async function handleRegister(args: string[]): Promise<number> {
|
|
|
189
212
|
DEEPLINE_API_KEY: apiKey,
|
|
190
213
|
DEEPLINE_CLAIM_TOKEN: '',
|
|
191
214
|
}, baseUrl);
|
|
192
|
-
|
|
193
|
-
console.log('DEEPLINE');
|
|
194
|
-
console.log('All set! Your CLI is connected.');
|
|
195
|
-
if (statusData.org_name) {
|
|
196
|
-
console.log(` Signed in with organization: ${statusData.org_name}`);
|
|
197
|
-
}
|
|
215
|
+
printClaimSuccessBanner(statusData);
|
|
198
216
|
return EXIT_OK;
|
|
199
217
|
}
|
|
200
218
|
}
|
|
@@ -262,7 +280,7 @@ export async function handleWait(args: string[]): Promise<number> {
|
|
|
262
280
|
DEEPLINE_API_KEY: apiKey,
|
|
263
281
|
DEEPLINE_CLAIM_TOKEN: '',
|
|
264
282
|
}, baseUrl);
|
|
265
|
-
|
|
283
|
+
printClaimSuccessBanner(data);
|
|
266
284
|
return EXIT_OK;
|
|
267
285
|
}
|
|
268
286
|
}
|
|
@@ -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';
|
|
@@ -2184,6 +2260,22 @@ async function handleNamedRun(options: PlayRunCommandOptions): Promise<number> {
|
|
|
2184
2260
|
waitTimeoutMs: options.waitTimeoutMs,
|
|
2185
2261
|
progress,
|
|
2186
2262
|
});
|
|
2263
|
+
if (finalStatus.status !== 'completed' && options.csvPath) {
|
|
2264
|
+
progress.phase('generating csv wrapper play');
|
|
2265
|
+
const generatedPlayPath = writeGeneratedCsvWrapperPlay(
|
|
2266
|
+
options.target.name,
|
|
2267
|
+
);
|
|
2268
|
+
progress.writeLogLine(
|
|
2269
|
+
`Generated CSV wrapper play: ${generatedPlayPath}`,
|
|
2270
|
+
);
|
|
2271
|
+
progress.phase('running generated csv wrapper play');
|
|
2272
|
+
return handleFileBackedRun({
|
|
2273
|
+
...options,
|
|
2274
|
+
target: { kind: 'file', path: generatedPlayPath },
|
|
2275
|
+
revisionId: null,
|
|
2276
|
+
revisionSelector: null,
|
|
2277
|
+
});
|
|
2278
|
+
}
|
|
2187
2279
|
const exportedPath = exportPlayStatusRows(finalStatus, options.outPath);
|
|
2188
2280
|
if (finalStatus.status === 'completed') {
|
|
2189
2281
|
progress.complete();
|
|
@@ -14,6 +14,7 @@ import { registerOrgCommands } from './commands/org.js';
|
|
|
14
14
|
import { registerPlayCommands } from './commands/play.js';
|
|
15
15
|
import { registerToolsCommands } from './commands/tools.js';
|
|
16
16
|
import { createCliProgress } from './progress.js';
|
|
17
|
+
import { syncSdkSkillsIfNeeded } from './skills-sync.js';
|
|
17
18
|
import { recordCliTrace, traceCliSpan } from './trace.js';
|
|
18
19
|
import { printJsonError } from './utils.js';
|
|
19
20
|
|
|
@@ -75,6 +76,14 @@ Output:
|
|
|
75
76
|
{ baseUrl },
|
|
76
77
|
() => enforceSdkCompatibility(baseUrl),
|
|
77
78
|
);
|
|
79
|
+
if (printStartupPhase) {
|
|
80
|
+
progress?.phase('checking sdk skills');
|
|
81
|
+
}
|
|
82
|
+
await traceCliSpan(
|
|
83
|
+
'cli.sdk_skills_sync',
|
|
84
|
+
{ baseUrl },
|
|
85
|
+
() => syncSdkSkillsIfNeeded(baseUrl),
|
|
86
|
+
);
|
|
78
87
|
});
|
|
79
88
|
|
|
80
89
|
registerAuthCommands(program);
|
|
@@ -122,6 +131,7 @@ Output:
|
|
|
122
131
|
ok: false,
|
|
123
132
|
error: error instanceof Error ? error.message : String(error),
|
|
124
133
|
});
|
|
134
|
+
progress?.fail();
|
|
125
135
|
if (process.argv.includes('--json')) {
|
|
126
136
|
printJsonError(error);
|
|
127
137
|
} else if (error instanceof Error) {
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { dirname, join } from 'node:path';
|
|
5
|
+
import { baseUrlSlug } from '../config.js';
|
|
6
|
+
|
|
7
|
+
const CHECK_TIMEOUT_MS = 3_000;
|
|
8
|
+
const SDK_SKILL_NAME = 'deepline-sdk';
|
|
9
|
+
const SKILL_AGENTS = ['codex', 'claude-code', 'cursor'] as const;
|
|
10
|
+
|
|
11
|
+
type UpdateCheckResponse = {
|
|
12
|
+
skills?: {
|
|
13
|
+
needs_update?: unknown;
|
|
14
|
+
remote?: {
|
|
15
|
+
version?: unknown;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
let attemptedSync = false;
|
|
21
|
+
|
|
22
|
+
function shouldSkipSkillsSync(): boolean {
|
|
23
|
+
const value = process.env.DEEPLINE_SKIP_SKILLS_SYNC?.trim().toLowerCase();
|
|
24
|
+
return value === '1' || value === 'true' || value === 'yes' || value === 'on';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function sdkSkillsVersionPath(baseUrl: string): string {
|
|
28
|
+
const home = process.env.HOME?.trim() || homedir();
|
|
29
|
+
return join(home, '.local', 'deepline', baseUrlSlug(baseUrl), 'sdk-skills', '.version');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function readLocalSkillsVersion(baseUrl: string): string {
|
|
33
|
+
const path = sdkSkillsVersionPath(baseUrl);
|
|
34
|
+
if (!existsSync(path)) return '';
|
|
35
|
+
try {
|
|
36
|
+
return readFileSync(path, 'utf-8').trim();
|
|
37
|
+
} catch {
|
|
38
|
+
return '';
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function writeLocalSkillsVersion(baseUrl: string, version: string): void {
|
|
43
|
+
const path = sdkSkillsVersionPath(baseUrl);
|
|
44
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
45
|
+
writeFileSync(path, `${version}\n`, 'utf-8');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function fetchSkillsUpdate(baseUrl: string, localVersion: string): Promise<{
|
|
49
|
+
needsUpdate: boolean;
|
|
50
|
+
remoteVersion: string;
|
|
51
|
+
} | null> {
|
|
52
|
+
const controller = new AbortController();
|
|
53
|
+
const timeout = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS);
|
|
54
|
+
try {
|
|
55
|
+
const response = await fetch(new URL('/api/v2/cli/update-check', baseUrl), {
|
|
56
|
+
method: 'POST',
|
|
57
|
+
headers: { 'Content-Type': 'application/json' },
|
|
58
|
+
body: JSON.stringify({
|
|
59
|
+
skills: {
|
|
60
|
+
version: localVersion,
|
|
61
|
+
},
|
|
62
|
+
}),
|
|
63
|
+
signal: controller.signal,
|
|
64
|
+
});
|
|
65
|
+
if (!response.ok) return null;
|
|
66
|
+
const data = (await response.json().catch(() => null)) as UpdateCheckResponse | null;
|
|
67
|
+
const skills = data?.skills;
|
|
68
|
+
if (!skills) return null;
|
|
69
|
+
return {
|
|
70
|
+
needsUpdate: skills.needs_update === true,
|
|
71
|
+
remoteVersion: typeof skills.remote?.version === 'string' ? skills.remote.version.trim() : '',
|
|
72
|
+
};
|
|
73
|
+
} catch {
|
|
74
|
+
return null;
|
|
75
|
+
} finally {
|
|
76
|
+
clearTimeout(timeout);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function runSkillsInstall(baseUrl: string): Promise<boolean> {
|
|
81
|
+
const packageUrl = new URL('/.well-known/skills/index.json', baseUrl).toString();
|
|
82
|
+
const args = [
|
|
83
|
+
'skills',
|
|
84
|
+
'add',
|
|
85
|
+
packageUrl,
|
|
86
|
+
'--agents',
|
|
87
|
+
...SKILL_AGENTS,
|
|
88
|
+
'--global',
|
|
89
|
+
'--yes',
|
|
90
|
+
'--skill',
|
|
91
|
+
SDK_SKILL_NAME,
|
|
92
|
+
'--full-depth',
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
return new Promise((resolve) => {
|
|
96
|
+
const child = spawn('npx', args, {
|
|
97
|
+
stdio: ['ignore', 'ignore', 'pipe'],
|
|
98
|
+
env: process.env,
|
|
99
|
+
});
|
|
100
|
+
let stderr = '';
|
|
101
|
+
child.stderr.on('data', (chunk: Buffer) => {
|
|
102
|
+
stderr += chunk.toString('utf-8');
|
|
103
|
+
});
|
|
104
|
+
child.on('error', (error) => {
|
|
105
|
+
process.stderr.write(`SDK skills sync failed to start: ${error.message}\n`);
|
|
106
|
+
resolve(false);
|
|
107
|
+
});
|
|
108
|
+
child.on('close', (code) => {
|
|
109
|
+
if (code === 0) {
|
|
110
|
+
resolve(true);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const detail = stderr.trim();
|
|
114
|
+
process.stderr.write(
|
|
115
|
+
`SDK skills sync failed${detail ? `: ${detail}` : ''}\n` +
|
|
116
|
+
`Run manually: npx ${args.map((arg) => (arg.includes(' ') ? JSON.stringify(arg) : arg)).join(' ')}\n`,
|
|
117
|
+
);
|
|
118
|
+
resolve(false);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export async function syncSdkSkillsIfNeeded(baseUrl: string): Promise<void> {
|
|
124
|
+
if (attemptedSync || shouldSkipSkillsSync()) return;
|
|
125
|
+
attemptedSync = true;
|
|
126
|
+
|
|
127
|
+
const localVersion = readLocalSkillsVersion(baseUrl);
|
|
128
|
+
const update = await fetchSkillsUpdate(baseUrl, localVersion);
|
|
129
|
+
if (!update?.needsUpdate || !update.remoteVersion) return;
|
|
130
|
+
|
|
131
|
+
process.stderr.write('SDK skills changed; syncing deepline-sdk skill...\n');
|
|
132
|
+
const installed = await runSkillsInstall(baseUrl);
|
|
133
|
+
if (!installed) return;
|
|
134
|
+
|
|
135
|
+
writeLocalSkillsVersion(baseUrl, update.remoteVersion);
|
|
136
|
+
process.stderr.write('SDK skills are up to date.\n');
|
|
137
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const SDK_VERSION = "0.1.
|
|
1
|
+
export const SDK_VERSION = "0.1.7";
|
|
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.7",
|
|
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"
|