deepline 0.1.143 → 0.1.144
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 +2 -2
- package/dist/bundling-sources/sdk/src/config.ts +310 -13
- package/dist/bundling-sources/sdk/src/release.ts +2 -2
- package/dist/cli/index.js +591 -41
- package/dist/cli/index.mjs +615 -57
- package/dist/index.js +148 -14
- package/dist/index.mjs +157 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -65,8 +65,8 @@ Do not route the SDK CLI through `.env`, `.env.local`, or `.env.worktree`.
|
|
|
65
65
|
Config resolution order:
|
|
66
66
|
|
|
67
67
|
```text
|
|
68
|
-
host: explicit SDK option -> DEEPLINE_HOST_URL -> nearest .env.deepline -> saved production auth -> https://code.deepline.com
|
|
69
|
-
key: explicit SDK option -> DEEPLINE_API_KEY -> matching nearest .env.deepline -> saved auth for the resolved host
|
|
68
|
+
host: explicit SDK option -> DEEPLINE_HOST_URL -> nearest .env.deepline -> Cowork workspace .env.deepline -> saved production auth -> https://code.deepline.com
|
|
69
|
+
key: explicit SDK option -> DEEPLINE_API_KEY -> matching nearest .env.deepline -> matching Cowork workspace .env.deepline -> saved auth for the resolved host
|
|
70
70
|
```
|
|
71
71
|
|
|
72
72
|
## CLI commands
|
|
@@ -15,21 +15,31 @@
|
|
|
15
15
|
* 1. `options.baseUrl`
|
|
16
16
|
* 2. `DEEPLINE_HOST_URL`
|
|
17
17
|
* 3. nearest project `.env.deepline`
|
|
18
|
-
* 4.
|
|
19
|
-
* 5. production
|
|
18
|
+
* 4. Cowork mounted workspace `.env.deepline`
|
|
19
|
+
* 5. production host auth file
|
|
20
|
+
* 6. production fallback: `https://code.deepline.com`
|
|
20
21
|
*
|
|
21
22
|
* API key:
|
|
22
23
|
* 1. `options.apiKey`
|
|
23
24
|
* 2. `DEEPLINE_API_KEY`
|
|
24
25
|
* 3. nearest project `.env.deepline`
|
|
25
|
-
* 4.
|
|
26
|
+
* 4. Cowork mounted workspace `.env.deepline`
|
|
27
|
+
* 5. host auth file for the resolved base URL
|
|
26
28
|
*
|
|
27
29
|
* App/runtime env files such as `.env`, `.env.local`, and `.env.worktree` do
|
|
28
30
|
* not route the SDK CLI. Put CLI routing in `.env.deepline`.
|
|
29
31
|
*
|
|
30
32
|
* @module
|
|
31
33
|
*/
|
|
32
|
-
import {
|
|
34
|
+
import {
|
|
35
|
+
existsSync,
|
|
36
|
+
mkdirSync,
|
|
37
|
+
readdirSync,
|
|
38
|
+
realpathSync,
|
|
39
|
+
readFileSync,
|
|
40
|
+
statSync,
|
|
41
|
+
writeFileSync,
|
|
42
|
+
} from 'node:fs';
|
|
33
43
|
import { homedir } from 'node:os';
|
|
34
44
|
import { dirname, join, resolve } from 'node:path';
|
|
35
45
|
import type { DeeplineClientOptions, ResolvedConfig } from './types.js';
|
|
@@ -48,8 +58,41 @@ const DEFAULT_TIMEOUT = 60_000;
|
|
|
48
58
|
const DEFAULT_MAX_RETRIES = 3;
|
|
49
59
|
|
|
50
60
|
const PROJECT_DEEPLINE_ENV_FILE = '.env.deepline';
|
|
61
|
+
const COWORK_IGNORED_WORKSPACE_DIRS = new Set([
|
|
62
|
+
'.auto-memory',
|
|
63
|
+
'.claude',
|
|
64
|
+
'.remote-plugins',
|
|
65
|
+
'outputs',
|
|
66
|
+
'plugins',
|
|
67
|
+
'uploads',
|
|
68
|
+
]);
|
|
69
|
+
const COWORK_PROJECT_MARKERS = [
|
|
70
|
+
'.deepline',
|
|
71
|
+
'.env.deepline',
|
|
72
|
+
'.git',
|
|
73
|
+
'AGENTS.md',
|
|
74
|
+
'package.json',
|
|
75
|
+
'pyproject.toml',
|
|
76
|
+
];
|
|
51
77
|
|
|
52
78
|
type EnvValues = Record<string, string>;
|
|
79
|
+
type ProjectEnvCandidate = {
|
|
80
|
+
filePath: string;
|
|
81
|
+
env: EnvValues;
|
|
82
|
+
source: 'nearest' | 'cowork';
|
|
83
|
+
};
|
|
84
|
+
export type ProjectAuthSource = ProjectEnvCandidate;
|
|
85
|
+
export type ProjectPinTarget =
|
|
86
|
+
| {
|
|
87
|
+
ok: true;
|
|
88
|
+
dir: string;
|
|
89
|
+
source: 'nearest' | 'cowork' | 'cwd';
|
|
90
|
+
}
|
|
91
|
+
| {
|
|
92
|
+
ok: false;
|
|
93
|
+
reason: 'ambiguous_cowork_project';
|
|
94
|
+
candidates: string[];
|
|
95
|
+
};
|
|
53
96
|
|
|
54
97
|
/**
|
|
55
98
|
* Convert a base URL to a filesystem-safe slug for per-host config storage.
|
|
@@ -119,9 +162,161 @@ function findNearestEnvFile(
|
|
|
119
162
|
}
|
|
120
163
|
}
|
|
121
164
|
|
|
165
|
+
function isDirectory(path: string): boolean {
|
|
166
|
+
try {
|
|
167
|
+
return statSync(path).isDirectory();
|
|
168
|
+
} catch {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function canonicalPath(path: string): string {
|
|
174
|
+
try {
|
|
175
|
+
return realpathSync(path);
|
|
176
|
+
} catch {
|
|
177
|
+
return resolve(path);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function isTruthy(value: string | undefined): boolean {
|
|
182
|
+
return /^(1|true|yes|on)$/i.test(value?.trim() ?? '');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function sessionRootFromPath(path: string | undefined): string | null {
|
|
186
|
+
const trimmed = path?.trim();
|
|
187
|
+
if (!trimmed) return null;
|
|
188
|
+
const match = /^\/sessions\/[^/]+(?=\/|$)/.exec(trimmed);
|
|
189
|
+
return match?.[0] ?? null;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function coworkSessionRoot(): string | null {
|
|
193
|
+
const home = process.env.HOME?.trim();
|
|
194
|
+
const homeSessionRoot = sessionRootFromPath(home);
|
|
195
|
+
if (homeSessionRoot && isDirectory(join(homeSessionRoot, 'mnt'))) {
|
|
196
|
+
return homeSessionRoot;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const cwdSessionRoot = sessionRootFromPath(process.cwd());
|
|
200
|
+
if (cwdSessionRoot && isDirectory(join(cwdSessionRoot, 'mnt'))) {
|
|
201
|
+
return cwdSessionRoot;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (isTruthy(process.env.CLAUDE_CODE_REMOTE) && home) {
|
|
205
|
+
const mountedRoot = join(home, 'mnt');
|
|
206
|
+
if (isDirectory(mountedRoot)) return resolve(home);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function isCoworkLikeSandbox(): boolean {
|
|
213
|
+
const home = process.env.HOME?.trim();
|
|
214
|
+
return (
|
|
215
|
+
isTruthy(process.env.CLAUDE_CODE_REMOTE) ||
|
|
216
|
+
sessionRootFromPath(home) !== null ||
|
|
217
|
+
sessionRootFromPath(process.cwd()) !== null
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function coworkProjectScore(path: string): number {
|
|
222
|
+
let score = 0;
|
|
223
|
+
for (const marker of COWORK_PROJECT_MARKERS) {
|
|
224
|
+
if (existsSync(join(path, marker))) score += 1;
|
|
225
|
+
}
|
|
226
|
+
return score;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function listCoworkWorkspaceDirCandidates(): string[] {
|
|
230
|
+
if (!isCoworkLikeSandbox()) {
|
|
231
|
+
return [];
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const explicitProjectDir = process.env.CLAUDE_PROJECT_DIR?.trim();
|
|
235
|
+
if (explicitProjectDir && isDirectory(explicitProjectDir)) {
|
|
236
|
+
return [resolve(explicitProjectDir)];
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const sessionRoot = coworkSessionRoot();
|
|
240
|
+
if (!sessionRoot) return [];
|
|
241
|
+
|
|
242
|
+
const mountedRoot = join(sessionRoot, 'mnt');
|
|
243
|
+
if (!isDirectory(mountedRoot)) return [];
|
|
244
|
+
|
|
245
|
+
let names: string[];
|
|
246
|
+
try {
|
|
247
|
+
names = readdirSync(mountedRoot).sort();
|
|
248
|
+
} catch {
|
|
249
|
+
return [];
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const candidates: string[] = [];
|
|
253
|
+
for (const name of names) {
|
|
254
|
+
if (name.startsWith('.') || COWORK_IGNORED_WORKSPACE_DIRS.has(name)) {
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
const candidate = join(mountedRoot, name);
|
|
258
|
+
if (isDirectory(candidate)) candidates.push(candidate);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (candidates.length <= 1) return candidates;
|
|
262
|
+
|
|
263
|
+
const projectLike = candidates.filter(
|
|
264
|
+
(candidate) => coworkProjectScore(candidate) > 0,
|
|
265
|
+
);
|
|
266
|
+
return projectLike.length > 0 ? projectLike : candidates;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function isInIgnoredCoworkMount(path: string): boolean {
|
|
270
|
+
const sessionRoot = coworkSessionRoot();
|
|
271
|
+
if (!sessionRoot) return false;
|
|
272
|
+
const mountedRoot = canonicalPath(join(sessionRoot, 'mnt'));
|
|
273
|
+
const resolvedPath = canonicalPath(path);
|
|
274
|
+
const prefix = `${mountedRoot}/`;
|
|
275
|
+
if (!resolvedPath.startsWith(prefix)) return false;
|
|
276
|
+
const relativePath = resolvedPath.slice(prefix.length);
|
|
277
|
+
const mountName = relativePath.split('/')[0];
|
|
278
|
+
return (
|
|
279
|
+
mountName.startsWith('.') || COWORK_IGNORED_WORKSPACE_DIRS.has(mountName)
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function detectCoworkWorkspaceDir(): string | null {
|
|
284
|
+
const candidates = listCoworkWorkspaceDirCandidates();
|
|
285
|
+
return candidates.length === 1 ? candidates[0] : null;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function loadProjectEnvCandidates(
|
|
289
|
+
startDir: string = process.cwd(),
|
|
290
|
+
): ProjectEnvCandidate[] {
|
|
291
|
+
const filePaths: string[] = [];
|
|
292
|
+
const sources = new Map<string, ProjectEnvCandidate['source']>();
|
|
293
|
+
const nearestFile = findNearestEnvFile(PROJECT_DEEPLINE_ENV_FILE, startDir);
|
|
294
|
+
if (nearestFile && !isInIgnoredCoworkMount(nearestFile)) {
|
|
295
|
+
filePaths.push(nearestFile);
|
|
296
|
+
sources.set(resolve(nearestFile), 'nearest');
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const coworkWorkspaceDir = detectCoworkWorkspaceDir();
|
|
300
|
+
if (coworkWorkspaceDir) {
|
|
301
|
+
const coworkFile = join(coworkWorkspaceDir, PROJECT_DEEPLINE_ENV_FILE);
|
|
302
|
+
if (
|
|
303
|
+
existsSync(coworkFile) &&
|
|
304
|
+
!filePaths.some((filePath) => resolve(filePath) === resolve(coworkFile))
|
|
305
|
+
) {
|
|
306
|
+
filePaths.push(coworkFile);
|
|
307
|
+
sources.set(resolve(coworkFile), 'cowork');
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
return filePaths.map((filePath) => ({
|
|
312
|
+
filePath,
|
|
313
|
+
env: parseEnvFile(filePath),
|
|
314
|
+
source: sources.get(resolve(filePath)) ?? 'nearest',
|
|
315
|
+
}));
|
|
316
|
+
}
|
|
317
|
+
|
|
122
318
|
function loadProjectDeeplineEnv(startDir = process.cwd()): EnvValues {
|
|
123
|
-
|
|
124
|
-
return filePath ? parseEnvFile(filePath) : {};
|
|
319
|
+
return loadProjectEnvCandidates(startDir)[0]?.env ?? {};
|
|
125
320
|
}
|
|
126
321
|
|
|
127
322
|
function normalizeBaseUrl(baseUrl: string): string {
|
|
@@ -204,11 +399,13 @@ function loadGlobalCliEnv(): EnvValues {
|
|
|
204
399
|
* Auto-detect the best base URL when none is explicitly provided.
|
|
205
400
|
*/
|
|
206
401
|
function autoDetectBaseUrl(): string {
|
|
207
|
-
const
|
|
402
|
+
const projectEnvs = loadProjectEnvCandidates();
|
|
208
403
|
const globalEnv = loadGlobalCliEnv();
|
|
209
404
|
return (
|
|
210
405
|
normalizeBaseUrl(process.env[HOST_URL_ENV] ?? '') ||
|
|
211
|
-
|
|
406
|
+
firstNonEmpty(
|
|
407
|
+
...projectEnvs.map(({ env }) => normalizeBaseUrl(env[HOST_URL_ENV])),
|
|
408
|
+
) ||
|
|
212
409
|
normalizeBaseUrl(globalEnv[HOST_URL_ENV] ?? '') ||
|
|
213
410
|
PROD_URL
|
|
214
411
|
);
|
|
@@ -219,18 +416,38 @@ export function resolveApiKeyForBaseUrl(
|
|
|
219
416
|
explicitApiKey?: string | null,
|
|
220
417
|
): string {
|
|
221
418
|
const normalizedBaseUrl = normalizeBaseUrl(baseUrl);
|
|
222
|
-
const
|
|
419
|
+
const projectEnvs = loadProjectEnvCandidates();
|
|
223
420
|
const cliEnv = loadCliEnv(normalizedBaseUrl || baseUrl);
|
|
224
|
-
const projectBaseUrl = normalizeBaseUrl(projectEnv[HOST_URL_ENV] ?? '');
|
|
225
|
-
const projectKeyApplies = projectBaseUrl === normalizedBaseUrl;
|
|
226
421
|
return firstNonEmpty(
|
|
227
422
|
explicitApiKey,
|
|
228
423
|
process.env[API_KEY_ENV],
|
|
229
|
-
|
|
424
|
+
...projectEnvs.map(({ env }) => {
|
|
425
|
+
const projectBaseUrl = normalizeBaseUrl(env[HOST_URL_ENV] ?? '');
|
|
426
|
+
return projectBaseUrl === normalizedBaseUrl ? env[API_KEY_ENV] : '';
|
|
427
|
+
}),
|
|
230
428
|
cliEnv[API_KEY_ENV],
|
|
231
429
|
);
|
|
232
430
|
}
|
|
233
431
|
|
|
432
|
+
function getResolvedProjectAuthSource(
|
|
433
|
+
baseUrl: string,
|
|
434
|
+
apiKey: string,
|
|
435
|
+
startDir: string = process.cwd(),
|
|
436
|
+
): ProjectAuthSource | null {
|
|
437
|
+
const normalizedBaseUrl = normalizeBaseUrl(baseUrl);
|
|
438
|
+
const normalizedApiKey = apiKey.trim();
|
|
439
|
+
if (!normalizedBaseUrl || !normalizedApiKey) return null;
|
|
440
|
+
return (
|
|
441
|
+
loadProjectEnvCandidates(startDir).find(({ env }) => {
|
|
442
|
+
const projectBaseUrl = normalizeBaseUrl(env[HOST_URL_ENV] ?? '');
|
|
443
|
+
return (
|
|
444
|
+
projectBaseUrl === normalizedBaseUrl &&
|
|
445
|
+
(env[API_KEY_ENV] ?? '').trim() === normalizedApiKey
|
|
446
|
+
);
|
|
447
|
+
}) ?? null
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
|
|
234
451
|
/**
|
|
235
452
|
* Resolve SDK configuration from the public SDK CLI env contract.
|
|
236
453
|
*/
|
|
@@ -265,6 +482,7 @@ function mergeProjectEnvFile(filePath: string, values: EnvValues): void {
|
|
|
265
482
|
const merged = { ...existing, ...values };
|
|
266
483
|
const dir = dirname(filePath);
|
|
267
484
|
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
485
|
+
ensureProjectEnvIsIgnored(dir);
|
|
268
486
|
const allowedKeys = new Set([HOST_URL_ENV, API_KEY_ENV]);
|
|
269
487
|
const lines = Object.entries(merged)
|
|
270
488
|
.filter(([key, value]) => allowedKeys.has(key) && value !== '')
|
|
@@ -272,20 +490,99 @@ function mergeProjectEnvFile(filePath: string, values: EnvValues): void {
|
|
|
272
490
|
writeFileSync(filePath, `${lines.join('\n')}\n`, 'utf-8');
|
|
273
491
|
}
|
|
274
492
|
|
|
493
|
+
function ensureProjectEnvIsIgnored(dir: string): void {
|
|
494
|
+
const gitignorePath = join(dir, '.gitignore');
|
|
495
|
+
const entry = PROJECT_DEEPLINE_ENV_FILE;
|
|
496
|
+
const existing = existsSync(gitignorePath)
|
|
497
|
+
? readFileSync(gitignorePath, 'utf-8')
|
|
498
|
+
: '';
|
|
499
|
+
const alreadyIgnored = existing
|
|
500
|
+
.split(/\r?\n/)
|
|
501
|
+
.map((line) => line.trim())
|
|
502
|
+
.some((line) => line === entry || line === `/${entry}`);
|
|
503
|
+
if (alreadyIgnored) return;
|
|
504
|
+
const prefix = existing && !existing.endsWith('\n') ? '\n' : '';
|
|
505
|
+
writeFileSync(gitignorePath, `${existing}${prefix}${entry}\n`, 'utf-8');
|
|
506
|
+
}
|
|
507
|
+
|
|
275
508
|
export function saveProjectDeeplineEnvValues(
|
|
276
509
|
values: EnvValues,
|
|
277
510
|
startDir: string = process.cwd(),
|
|
278
511
|
): string[] {
|
|
279
|
-
const
|
|
512
|
+
const target = resolveProjectPinTarget(startDir);
|
|
513
|
+
if (!target.ok) {
|
|
514
|
+
throw new ConfigError(
|
|
515
|
+
`Cowork project folder is ambiguous. Candidate folders: ${target.candidates.join(
|
|
516
|
+
', ',
|
|
517
|
+
)}. Set CLAUDE_PROJECT_DIR or cd into the intended project folder before running this command.`,
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
const filePath = join(target.dir, PROJECT_DEEPLINE_ENV_FILE);
|
|
280
521
|
mergeProjectEnvFile(filePath, values);
|
|
281
522
|
return [filePath];
|
|
282
523
|
}
|
|
283
524
|
|
|
525
|
+
export function resolveProjectPinDir(startDir: string = process.cwd()): string {
|
|
526
|
+
const target = resolveProjectPinTarget(startDir);
|
|
527
|
+
if (!target.ok) {
|
|
528
|
+
throw new ConfigError(
|
|
529
|
+
`Cowork project folder is ambiguous. Candidate folders: ${target.candidates.join(
|
|
530
|
+
', ',
|
|
531
|
+
)}. Set CLAUDE_PROJECT_DIR or cd into the intended project folder before running this command.`,
|
|
532
|
+
);
|
|
533
|
+
}
|
|
534
|
+
return target.dir;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
export function resolveProjectPinTarget(
|
|
538
|
+
startDir: string = process.cwd(),
|
|
539
|
+
): ProjectPinTarget {
|
|
540
|
+
const nearestFile = findNearestEnvFile(PROJECT_DEEPLINE_ENV_FILE, startDir);
|
|
541
|
+
if (nearestFile && !isInIgnoredCoworkMount(nearestFile)) {
|
|
542
|
+
return { ok: true, dir: dirname(nearestFile), source: 'nearest' };
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
const coworkCandidates = listCoworkWorkspaceDirCandidates();
|
|
546
|
+
if (coworkCandidates.length === 1) {
|
|
547
|
+
return { ok: true, dir: coworkCandidates[0], source: 'cowork' };
|
|
548
|
+
}
|
|
549
|
+
if (coworkCandidates.length > 1) {
|
|
550
|
+
const resolvedStartDir = canonicalPath(startDir);
|
|
551
|
+
const cwdCandidate = coworkCandidates.find((candidate) => {
|
|
552
|
+
const resolvedCandidate = canonicalPath(candidate);
|
|
553
|
+
return (
|
|
554
|
+
resolvedStartDir === resolvedCandidate ||
|
|
555
|
+
resolvedStartDir.startsWith(`${resolvedCandidate}/`)
|
|
556
|
+
);
|
|
557
|
+
});
|
|
558
|
+
if (cwdCandidate) {
|
|
559
|
+
return { ok: true, dir: cwdCandidate, source: 'cowork' };
|
|
560
|
+
}
|
|
561
|
+
return {
|
|
562
|
+
ok: false,
|
|
563
|
+
reason: 'ambiguous_cowork_project',
|
|
564
|
+
candidates: coworkCandidates,
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
return { ok: true, dir: resolve(startDir), source: 'cwd' };
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
export function getActiveProjectAuthSource(
|
|
572
|
+
startDir: string = process.cwd(),
|
|
573
|
+
): ProjectAuthSource | null {
|
|
574
|
+
return loadProjectEnvCandidates(startDir)[0] ?? null;
|
|
575
|
+
}
|
|
576
|
+
|
|
284
577
|
export {
|
|
285
578
|
baseUrlSlug,
|
|
286
579
|
loadCliEnv,
|
|
287
580
|
loadGlobalCliEnv,
|
|
581
|
+
loadProjectDeeplineEnv,
|
|
582
|
+
getResolvedProjectAuthSource,
|
|
583
|
+
listCoworkWorkspaceDirCandidates,
|
|
288
584
|
parseEnvFile,
|
|
585
|
+
detectCoworkWorkspaceDir,
|
|
289
586
|
autoDetectBaseUrl,
|
|
290
587
|
PROD_URL,
|
|
291
588
|
};
|
|
@@ -101,10 +101,10 @@ export const SDK_RELEASE = {
|
|
|
101
101
|
// 0.1.108 ships explicit dataset column/tool recompute policy and removes
|
|
102
102
|
// the SDK enrich generator's one-second stale policy.
|
|
103
103
|
// 0.1.110 ships authored V2 prebuilts and required top-level play descriptions.
|
|
104
|
-
version: '0.1.
|
|
104
|
+
version: '0.1.144',
|
|
105
105
|
apiContract: '2026-06-dataset-column-cell-stale-hard-cutover',
|
|
106
106
|
supportPolicy: {
|
|
107
|
-
latest: '0.1.
|
|
107
|
+
latest: '0.1.144',
|
|
108
108
|
minimumSupported: '0.1.53',
|
|
109
109
|
deprecatedBelow: '0.1.53',
|
|
110
110
|
commandMinimumSupported: [
|