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/index.d.mts CHANGED
@@ -1325,7 +1325,7 @@ declare class DeeplineClient {
1325
1325
  }>;
1326
1326
  }
1327
1327
 
1328
- declare const SDK_VERSION = "0.1.3";
1328
+ declare const SDK_VERSION = "0.1.7";
1329
1329
  declare const SDK_API_CONTRACT = "2026-04-plays-v1";
1330
1330
 
1331
1331
  /**
package/dist/index.d.ts CHANGED
@@ -1325,7 +1325,7 @@ declare class DeeplineClient {
1325
1325
  }>;
1326
1326
  }
1327
1327
 
1328
- declare const SDK_VERSION = "0.1.3";
1328
+ declare const SDK_VERSION = "0.1.7";
1329
1329
  declare const SDK_API_CONTRACT = "2026-04-plays-v1";
1330
1330
 
1331
1331
  /**
package/dist/index.js CHANGED
@@ -196,7 +196,7 @@ function resolveConfig(options) {
196
196
  }
197
197
 
198
198
  // src/version.ts
199
- var SDK_VERSION = "0.1.3";
199
+ var SDK_VERSION = "0.1.7";
200
200
  var SDK_API_CONTRACT = "2026-04-plays-v1";
201
201
 
202
202
  // ../shared_libs/play-runtime/coordinator-headers.ts
package/dist/index.mjs CHANGED
@@ -149,7 +149,7 @@ function resolveConfig(options) {
149
149
  }
150
150
 
151
151
  // src/version.ts
152
- var SDK_VERSION = "0.1.3";
152
+ var SDK_VERSION = "0.1.7";
153
153
  var SDK_API_CONTRACT = "2026-04-plays-v1";
154
154
 
155
155
  // ../shared_libs/play-runtime/coordinator-headers.ts
@@ -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
- console.log('');
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
- console.log('All set! Your CLI is connected.');
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.3";
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",
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"