deepline 0.1.143 → 0.1.145
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/apps/play-runner-workers/src/coordinator-entry.ts +36 -4
- package/dist/bundling-sources/apps/play-runner-workers/src/entry.ts +5 -2
- package/dist/bundling-sources/sdk/src/client.ts +5 -0
- package/dist/bundling-sources/sdk/src/config.ts +310 -13
- package/dist/bundling-sources/sdk/src/release.ts +2 -2
- package/dist/bundling-sources/shared_libs/temporal/constants.ts +4 -3
- package/dist/cli/index.js +865 -82
- package/dist/cli/index.mjs +889 -98
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +151 -14
- package/dist/index.mjs +160 -15
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -237,6 +237,22 @@ var PROD_URL = "https://code.deepline.com";
|
|
|
237
237
|
var DEFAULT_TIMEOUT = 6e4;
|
|
238
238
|
var DEFAULT_MAX_RETRIES = 3;
|
|
239
239
|
var PROJECT_DEEPLINE_ENV_FILE = ".env.deepline";
|
|
240
|
+
var COWORK_IGNORED_WORKSPACE_DIRS = /* @__PURE__ */ new Set([
|
|
241
|
+
".auto-memory",
|
|
242
|
+
".claude",
|
|
243
|
+
".remote-plugins",
|
|
244
|
+
"outputs",
|
|
245
|
+
"plugins",
|
|
246
|
+
"uploads"
|
|
247
|
+
]);
|
|
248
|
+
var COWORK_PROJECT_MARKERS = [
|
|
249
|
+
".deepline",
|
|
250
|
+
".env.deepline",
|
|
251
|
+
".git",
|
|
252
|
+
"AGENTS.md",
|
|
253
|
+
"package.json",
|
|
254
|
+
"pyproject.toml"
|
|
255
|
+
];
|
|
240
256
|
function baseUrlSlug(baseUrl) {
|
|
241
257
|
let url;
|
|
242
258
|
try {
|
|
@@ -282,9 +298,124 @@ function findNearestEnvFile(name, startDir = process.cwd()) {
|
|
|
282
298
|
current = parent;
|
|
283
299
|
}
|
|
284
300
|
}
|
|
285
|
-
function
|
|
286
|
-
|
|
287
|
-
|
|
301
|
+
function isDirectory(path) {
|
|
302
|
+
try {
|
|
303
|
+
return (0, import_node_fs.statSync)(path).isDirectory();
|
|
304
|
+
} catch {
|
|
305
|
+
return false;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
function canonicalPath(path) {
|
|
309
|
+
try {
|
|
310
|
+
return (0, import_node_fs.realpathSync)(path);
|
|
311
|
+
} catch {
|
|
312
|
+
return (0, import_node_path.resolve)(path);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
function isTruthy(value) {
|
|
316
|
+
return /^(1|true|yes|on)$/i.test(value?.trim() ?? "");
|
|
317
|
+
}
|
|
318
|
+
function sessionRootFromPath(path) {
|
|
319
|
+
const trimmed = path?.trim();
|
|
320
|
+
if (!trimmed) return null;
|
|
321
|
+
const match = /^\/sessions\/[^/]+(?=\/|$)/.exec(trimmed);
|
|
322
|
+
return match?.[0] ?? null;
|
|
323
|
+
}
|
|
324
|
+
function coworkSessionRoot() {
|
|
325
|
+
const home = process.env.HOME?.trim();
|
|
326
|
+
const homeSessionRoot = sessionRootFromPath(home);
|
|
327
|
+
if (homeSessionRoot && isDirectory((0, import_node_path.join)(homeSessionRoot, "mnt"))) {
|
|
328
|
+
return homeSessionRoot;
|
|
329
|
+
}
|
|
330
|
+
const cwdSessionRoot = sessionRootFromPath(process.cwd());
|
|
331
|
+
if (cwdSessionRoot && isDirectory((0, import_node_path.join)(cwdSessionRoot, "mnt"))) {
|
|
332
|
+
return cwdSessionRoot;
|
|
333
|
+
}
|
|
334
|
+
if (isTruthy(process.env.CLAUDE_CODE_REMOTE) && home) {
|
|
335
|
+
const mountedRoot = (0, import_node_path.join)(home, "mnt");
|
|
336
|
+
if (isDirectory(mountedRoot)) return (0, import_node_path.resolve)(home);
|
|
337
|
+
}
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
340
|
+
function isCoworkLikeSandbox() {
|
|
341
|
+
const home = process.env.HOME?.trim();
|
|
342
|
+
return isTruthy(process.env.CLAUDE_CODE_REMOTE) || sessionRootFromPath(home) !== null || sessionRootFromPath(process.cwd()) !== null;
|
|
343
|
+
}
|
|
344
|
+
function coworkProjectScore(path) {
|
|
345
|
+
let score = 0;
|
|
346
|
+
for (const marker of COWORK_PROJECT_MARKERS) {
|
|
347
|
+
if ((0, import_node_fs.existsSync)((0, import_node_path.join)(path, marker))) score += 1;
|
|
348
|
+
}
|
|
349
|
+
return score;
|
|
350
|
+
}
|
|
351
|
+
function listCoworkWorkspaceDirCandidates() {
|
|
352
|
+
if (!isCoworkLikeSandbox()) {
|
|
353
|
+
return [];
|
|
354
|
+
}
|
|
355
|
+
const explicitProjectDir = process.env.CLAUDE_PROJECT_DIR?.trim();
|
|
356
|
+
if (explicitProjectDir && isDirectory(explicitProjectDir)) {
|
|
357
|
+
return [(0, import_node_path.resolve)(explicitProjectDir)];
|
|
358
|
+
}
|
|
359
|
+
const sessionRoot = coworkSessionRoot();
|
|
360
|
+
if (!sessionRoot) return [];
|
|
361
|
+
const mountedRoot = (0, import_node_path.join)(sessionRoot, "mnt");
|
|
362
|
+
if (!isDirectory(mountedRoot)) return [];
|
|
363
|
+
let names;
|
|
364
|
+
try {
|
|
365
|
+
names = (0, import_node_fs.readdirSync)(mountedRoot).sort();
|
|
366
|
+
} catch {
|
|
367
|
+
return [];
|
|
368
|
+
}
|
|
369
|
+
const candidates = [];
|
|
370
|
+
for (const name of names) {
|
|
371
|
+
if (name.startsWith(".") || COWORK_IGNORED_WORKSPACE_DIRS.has(name)) {
|
|
372
|
+
continue;
|
|
373
|
+
}
|
|
374
|
+
const candidate = (0, import_node_path.join)(mountedRoot, name);
|
|
375
|
+
if (isDirectory(candidate)) candidates.push(candidate);
|
|
376
|
+
}
|
|
377
|
+
if (candidates.length <= 1) return candidates;
|
|
378
|
+
const projectLike = candidates.filter(
|
|
379
|
+
(candidate) => coworkProjectScore(candidate) > 0
|
|
380
|
+
);
|
|
381
|
+
return projectLike.length > 0 ? projectLike : candidates;
|
|
382
|
+
}
|
|
383
|
+
function isInIgnoredCoworkMount(path) {
|
|
384
|
+
const sessionRoot = coworkSessionRoot();
|
|
385
|
+
if (!sessionRoot) return false;
|
|
386
|
+
const mountedRoot = canonicalPath((0, import_node_path.join)(sessionRoot, "mnt"));
|
|
387
|
+
const resolvedPath = canonicalPath(path);
|
|
388
|
+
const prefix = `${mountedRoot}/`;
|
|
389
|
+
if (!resolvedPath.startsWith(prefix)) return false;
|
|
390
|
+
const relativePath = resolvedPath.slice(prefix.length);
|
|
391
|
+
const mountName = relativePath.split("/")[0];
|
|
392
|
+
return mountName.startsWith(".") || COWORK_IGNORED_WORKSPACE_DIRS.has(mountName);
|
|
393
|
+
}
|
|
394
|
+
function detectCoworkWorkspaceDir() {
|
|
395
|
+
const candidates = listCoworkWorkspaceDirCandidates();
|
|
396
|
+
return candidates.length === 1 ? candidates[0] : null;
|
|
397
|
+
}
|
|
398
|
+
function loadProjectEnvCandidates(startDir = process.cwd()) {
|
|
399
|
+
const filePaths = [];
|
|
400
|
+
const sources = /* @__PURE__ */ new Map();
|
|
401
|
+
const nearestFile = findNearestEnvFile(PROJECT_DEEPLINE_ENV_FILE, startDir);
|
|
402
|
+
if (nearestFile && !isInIgnoredCoworkMount(nearestFile)) {
|
|
403
|
+
filePaths.push(nearestFile);
|
|
404
|
+
sources.set((0, import_node_path.resolve)(nearestFile), "nearest");
|
|
405
|
+
}
|
|
406
|
+
const coworkWorkspaceDir = detectCoworkWorkspaceDir();
|
|
407
|
+
if (coworkWorkspaceDir) {
|
|
408
|
+
const coworkFile = (0, import_node_path.join)(coworkWorkspaceDir, PROJECT_DEEPLINE_ENV_FILE);
|
|
409
|
+
if ((0, import_node_fs.existsSync)(coworkFile) && !filePaths.some((filePath) => (0, import_node_path.resolve)(filePath) === (0, import_node_path.resolve)(coworkFile))) {
|
|
410
|
+
filePaths.push(coworkFile);
|
|
411
|
+
sources.set((0, import_node_path.resolve)(coworkFile), "cowork");
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
return filePaths.map((filePath) => ({
|
|
415
|
+
filePath,
|
|
416
|
+
env: parseEnvFile(filePath),
|
|
417
|
+
source: sources.get((0, import_node_path.resolve)(filePath)) ?? "nearest"
|
|
418
|
+
}));
|
|
288
419
|
}
|
|
289
420
|
function normalizeBaseUrl(baseUrl) {
|
|
290
421
|
const trimmed = baseUrl.trim().replace(/\/+$/, "");
|
|
@@ -348,23 +479,35 @@ function loadGlobalCliEnv() {
|
|
|
348
479
|
return loadCliEnv(PROD_URL);
|
|
349
480
|
}
|
|
350
481
|
function autoDetectBaseUrl() {
|
|
351
|
-
const
|
|
482
|
+
const projectEnvs = loadProjectEnvCandidates();
|
|
352
483
|
const globalEnv = loadGlobalCliEnv();
|
|
353
|
-
return normalizeBaseUrl(process.env[HOST_URL_ENV] ?? "") ||
|
|
484
|
+
return normalizeBaseUrl(process.env[HOST_URL_ENV] ?? "") || firstNonEmpty(
|
|
485
|
+
...projectEnvs.map(({ env }) => normalizeBaseUrl(env[HOST_URL_ENV]))
|
|
486
|
+
) || normalizeBaseUrl(globalEnv[HOST_URL_ENV] ?? "") || PROD_URL;
|
|
354
487
|
}
|
|
355
488
|
function resolveApiKeyForBaseUrl(baseUrl, explicitApiKey) {
|
|
356
489
|
const normalizedBaseUrl = normalizeBaseUrl(baseUrl);
|
|
357
|
-
const
|
|
490
|
+
const projectEnvs = loadProjectEnvCandidates();
|
|
358
491
|
const cliEnv = loadCliEnv(normalizedBaseUrl || baseUrl);
|
|
359
|
-
const projectBaseUrl = normalizeBaseUrl(projectEnv[HOST_URL_ENV] ?? "");
|
|
360
|
-
const projectKeyApplies = projectBaseUrl === normalizedBaseUrl;
|
|
361
492
|
return firstNonEmpty(
|
|
362
493
|
explicitApiKey,
|
|
363
494
|
process.env[API_KEY_ENV],
|
|
364
|
-
|
|
495
|
+
...projectEnvs.map(({ env }) => {
|
|
496
|
+
const projectBaseUrl = normalizeBaseUrl(env[HOST_URL_ENV] ?? "");
|
|
497
|
+
return projectBaseUrl === normalizedBaseUrl ? env[API_KEY_ENV] : "";
|
|
498
|
+
}),
|
|
365
499
|
cliEnv[API_KEY_ENV]
|
|
366
500
|
);
|
|
367
501
|
}
|
|
502
|
+
function getResolvedProjectAuthSource(baseUrl, apiKey, startDir = process.cwd()) {
|
|
503
|
+
const normalizedBaseUrl = normalizeBaseUrl(baseUrl);
|
|
504
|
+
const normalizedApiKey = apiKey.trim();
|
|
505
|
+
if (!normalizedBaseUrl || !normalizedApiKey) return null;
|
|
506
|
+
return loadProjectEnvCandidates(startDir).find(({ env }) => {
|
|
507
|
+
const projectBaseUrl = normalizeBaseUrl(env[HOST_URL_ENV] ?? "");
|
|
508
|
+
return projectBaseUrl === normalizedBaseUrl && (env[API_KEY_ENV] ?? "").trim() === normalizedApiKey;
|
|
509
|
+
}) ?? null;
|
|
510
|
+
}
|
|
368
511
|
function resolveConfig(options) {
|
|
369
512
|
const baseUrl = normalizeBaseUrl(
|
|
370
513
|
options?.baseUrl?.trim() || autoDetectBaseUrl()
|
|
@@ -387,6 +530,69 @@ function resolveConfig(options) {
|
|
|
387
530
|
maxRetries: options?.maxRetries ?? DEFAULT_MAX_RETRIES
|
|
388
531
|
};
|
|
389
532
|
}
|
|
533
|
+
function mergeProjectEnvFile(filePath, values) {
|
|
534
|
+
const existing = parseEnvFile(filePath);
|
|
535
|
+
const merged = { ...existing, ...values };
|
|
536
|
+
const dir = (0, import_node_path.dirname)(filePath);
|
|
537
|
+
if (!(0, import_node_fs.existsSync)(dir)) (0, import_node_fs.mkdirSync)(dir, { recursive: true });
|
|
538
|
+
ensureProjectEnvIsIgnored(dir);
|
|
539
|
+
const allowedKeys = /* @__PURE__ */ new Set([HOST_URL_ENV, API_KEY_ENV]);
|
|
540
|
+
const lines = Object.entries(merged).filter(([key, value]) => allowedKeys.has(key) && value !== "").map(([key, value]) => `${key}=${value}`);
|
|
541
|
+
(0, import_node_fs.writeFileSync)(filePath, `${lines.join("\n")}
|
|
542
|
+
`, "utf-8");
|
|
543
|
+
}
|
|
544
|
+
function ensureProjectEnvIsIgnored(dir) {
|
|
545
|
+
const gitignorePath = (0, import_node_path.join)(dir, ".gitignore");
|
|
546
|
+
const entry = PROJECT_DEEPLINE_ENV_FILE;
|
|
547
|
+
const existing = (0, import_node_fs.existsSync)(gitignorePath) ? (0, import_node_fs.readFileSync)(gitignorePath, "utf-8") : "";
|
|
548
|
+
const alreadyIgnored = existing.split(/\r?\n/).map((line) => line.trim()).some((line) => line === entry || line === `/${entry}`);
|
|
549
|
+
if (alreadyIgnored) return;
|
|
550
|
+
const prefix = existing && !existing.endsWith("\n") ? "\n" : "";
|
|
551
|
+
(0, import_node_fs.writeFileSync)(gitignorePath, `${existing}${prefix}${entry}
|
|
552
|
+
`, "utf-8");
|
|
553
|
+
}
|
|
554
|
+
function saveProjectDeeplineEnvValues(values, startDir = process.cwd()) {
|
|
555
|
+
const target = resolveProjectPinTarget(startDir);
|
|
556
|
+
if (!target.ok) {
|
|
557
|
+
throw new ConfigError(
|
|
558
|
+
`Cowork project folder is ambiguous. Candidate folders: ${target.candidates.join(
|
|
559
|
+
", "
|
|
560
|
+
)}. Set CLAUDE_PROJECT_DIR or cd into the intended project folder before running this command.`
|
|
561
|
+
);
|
|
562
|
+
}
|
|
563
|
+
const filePath = (0, import_node_path.join)(target.dir, PROJECT_DEEPLINE_ENV_FILE);
|
|
564
|
+
mergeProjectEnvFile(filePath, values);
|
|
565
|
+
return [filePath];
|
|
566
|
+
}
|
|
567
|
+
function resolveProjectPinTarget(startDir = process.cwd()) {
|
|
568
|
+
const nearestFile = findNearestEnvFile(PROJECT_DEEPLINE_ENV_FILE, startDir);
|
|
569
|
+
if (nearestFile && !isInIgnoredCoworkMount(nearestFile)) {
|
|
570
|
+
return { ok: true, dir: (0, import_node_path.dirname)(nearestFile), source: "nearest" };
|
|
571
|
+
}
|
|
572
|
+
const coworkCandidates = listCoworkWorkspaceDirCandidates();
|
|
573
|
+
if (coworkCandidates.length === 1) {
|
|
574
|
+
return { ok: true, dir: coworkCandidates[0], source: "cowork" };
|
|
575
|
+
}
|
|
576
|
+
if (coworkCandidates.length > 1) {
|
|
577
|
+
const resolvedStartDir = canonicalPath(startDir);
|
|
578
|
+
const cwdCandidate = coworkCandidates.find((candidate) => {
|
|
579
|
+
const resolvedCandidate = canonicalPath(candidate);
|
|
580
|
+
return resolvedStartDir === resolvedCandidate || resolvedStartDir.startsWith(`${resolvedCandidate}/`);
|
|
581
|
+
});
|
|
582
|
+
if (cwdCandidate) {
|
|
583
|
+
return { ok: true, dir: cwdCandidate, source: "cowork" };
|
|
584
|
+
}
|
|
585
|
+
return {
|
|
586
|
+
ok: false,
|
|
587
|
+
reason: "ambiguous_cowork_project",
|
|
588
|
+
candidates: coworkCandidates
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
return { ok: true, dir: (0, import_node_path.resolve)(startDir), source: "cwd" };
|
|
592
|
+
}
|
|
593
|
+
function getActiveProjectAuthSource(startDir = process.cwd()) {
|
|
594
|
+
return loadProjectEnvCandidates(startDir)[0] ?? null;
|
|
595
|
+
}
|
|
390
596
|
|
|
391
597
|
// src/http.ts
|
|
392
598
|
var import_node_fs2 = require("fs");
|
|
@@ -413,10 +619,10 @@ var SDK_RELEASE = {
|
|
|
413
619
|
// 0.1.108 ships explicit dataset column/tool recompute policy and removes
|
|
414
620
|
// the SDK enrich generator's one-second stale policy.
|
|
415
621
|
// 0.1.110 ships authored V2 prebuilts and required top-level play descriptions.
|
|
416
|
-
version: "0.1.
|
|
622
|
+
version: "0.1.145",
|
|
417
623
|
apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
|
|
418
624
|
supportPolicy: {
|
|
419
|
-
latest: "0.1.
|
|
625
|
+
latest: "0.1.145",
|
|
420
626
|
minimumSupported: "0.1.53",
|
|
421
627
|
deprecatedBelow: "0.1.53",
|
|
422
628
|
commandMinimumSupported: [
|
|
@@ -507,7 +713,7 @@ function normalizeAgentRuntime(value) {
|
|
|
507
713
|
if (explicit === "gemini_cli") return "gemini";
|
|
508
714
|
return EXPLICIT_AGENT_RUNTIMES.has(explicit) ? explicit : null;
|
|
509
715
|
}
|
|
510
|
-
function
|
|
716
|
+
function isCoworkLikeSandbox2() {
|
|
511
717
|
const pluginMode = truthyEnv("DEEPLINE_PLUGIN_MODE");
|
|
512
718
|
const claudeRemote = truthyEnv("CLAUDE_CODE_REMOTE");
|
|
513
719
|
const projectDir = Boolean(process.env.CLAUDE_PROJECT_DIR?.trim());
|
|
@@ -520,7 +726,7 @@ function detectAgentRuntime(options = {}) {
|
|
|
520
726
|
const explicit = normalizeAgentRuntime(process.env.DEEPLINE_AGENT_RUNTIME);
|
|
521
727
|
if (explicit) return explicit;
|
|
522
728
|
if (process.env.CODEX_THREAD_ID?.trim()) return "codex";
|
|
523
|
-
if (options.detectCowork !== false &&
|
|
729
|
+
if (options.detectCowork !== false && isCoworkLikeSandbox2()) {
|
|
524
730
|
return "claude_cowork";
|
|
525
731
|
}
|
|
526
732
|
if (process.env.CLAUDECODE?.trim() === "1") return "claude_code";
|
|
@@ -986,7 +1192,7 @@ function sleep(ms) {
|
|
|
986
1192
|
return new Promise((resolve13) => setTimeout(resolve13, ms));
|
|
987
1193
|
}
|
|
988
1194
|
function withCoworkNetworkHint(message) {
|
|
989
|
-
if (!
|
|
1195
|
+
if (!isCoworkLikeSandbox2() || message.includes(COWORK_NETWORK_HINT)) {
|
|
990
1196
|
return message;
|
|
991
1197
|
}
|
|
992
1198
|
return `${message}
|
|
@@ -3293,6 +3499,9 @@ var DeeplineClient = class {
|
|
|
3293
3499
|
if (input2.runId?.trim()) {
|
|
3294
3500
|
params.set("runId", input2.runId.trim());
|
|
3295
3501
|
}
|
|
3502
|
+
if (input2.rowMode === "all") {
|
|
3503
|
+
params.set("rowMode", "all");
|
|
3504
|
+
}
|
|
3296
3505
|
return await this.http.get(
|
|
3297
3506
|
`/api/v2/plays/${encodeURIComponent(input2.playName)}/sheet?${params.toString()}`
|
|
3298
3507
|
);
|
|
@@ -11740,7 +11949,8 @@ async function fetchBackingDatasetRows(input2) {
|
|
|
11740
11949
|
tableNamespace,
|
|
11741
11950
|
runId: input2.status.runId,
|
|
11742
11951
|
limit: RUN_EXPORT_PAGE_SIZE,
|
|
11743
|
-
offset
|
|
11952
|
+
offset,
|
|
11953
|
+
rowMode: "all"
|
|
11744
11954
|
});
|
|
11745
11955
|
sheetRows.push(...page.rows);
|
|
11746
11956
|
const summaryTotal = page.summary?.stats?.total;
|
|
@@ -16080,8 +16290,10 @@ function helperSource() {
|
|
|
16080
16290
|
|
|
16081
16291
|
// src/cli/commands/enrich.ts
|
|
16082
16292
|
var ENRICH_EXPORT_PAGE_SIZE = 5e3;
|
|
16293
|
+
var ENRICH_AUTO_BATCH_ROWS = 250;
|
|
16083
16294
|
var EXIT_SERVER2 = 5;
|
|
16084
16295
|
var ENRICH_DEBUG_T0 = Date.now();
|
|
16296
|
+
var GENERATED_ENRICH_ROWS_TABLE_NAMESPACE = "deepline_enrich_rows";
|
|
16085
16297
|
var PLAN_SHAPING_OPTION_NAMES = [
|
|
16086
16298
|
"with",
|
|
16087
16299
|
"withWaterfall",
|
|
@@ -16745,7 +16957,12 @@ async function runGeneratedEnrichPlay(runArgs, options = {}) {
|
|
|
16745
16957
|
async function writeOutputCsv(outputPath, status, options) {
|
|
16746
16958
|
let rowsInfo = extractCanonicalRowsInfo(status);
|
|
16747
16959
|
if (!rowsInfo) {
|
|
16748
|
-
|
|
16960
|
+
rowsInfo = fallbackRowsInfoForGeneratedEnrichExport(status, options);
|
|
16961
|
+
}
|
|
16962
|
+
if (!rowsInfo) {
|
|
16963
|
+
throw new Error(
|
|
16964
|
+
"The generated play did not return row-shaped output, and no durable enrich rows were available to export."
|
|
16965
|
+
);
|
|
16749
16966
|
}
|
|
16750
16967
|
if (options?.client) {
|
|
16751
16968
|
rowsInfo = await fetchBackingRowsForCsvExport({
|
|
@@ -16808,6 +17025,98 @@ function extractPlayName2(status) {
|
|
|
16808
17025
|
}
|
|
16809
17026
|
return null;
|
|
16810
17027
|
}
|
|
17028
|
+
function selectedSourceCsvRange(sourceCsvPath, rows) {
|
|
17029
|
+
const sourceRows = readCsvRows(sourceCsvPath).length;
|
|
17030
|
+
if (sourceRows === 0) {
|
|
17031
|
+
return { start: 0, end: -1, count: 0, sourceRows };
|
|
17032
|
+
}
|
|
17033
|
+
const start = Math.max(0, rows?.rowStart ?? 0);
|
|
17034
|
+
if (start >= sourceRows) {
|
|
17035
|
+
return { start, end: start - 1, count: 0, sourceRows };
|
|
17036
|
+
}
|
|
17037
|
+
const maxEnd = sourceRows - 1;
|
|
17038
|
+
const end = rows?.rowEnd === null || rows?.rowEnd === void 0 ? maxEnd : Math.min(maxEnd, rows.rowEnd);
|
|
17039
|
+
return {
|
|
17040
|
+
start,
|
|
17041
|
+
end,
|
|
17042
|
+
count: Math.max(0, end - start + 1),
|
|
17043
|
+
sourceRows
|
|
17044
|
+
};
|
|
17045
|
+
}
|
|
17046
|
+
function selectedSourceCsvRowCount(options) {
|
|
17047
|
+
if (!options?.sourceCsvPath) {
|
|
17048
|
+
return null;
|
|
17049
|
+
}
|
|
17050
|
+
return selectedSourceCsvRange(options.sourceCsvPath, options.rows).count;
|
|
17051
|
+
}
|
|
17052
|
+
function collectStringFields(value, key, output2, depth = 0) {
|
|
17053
|
+
if (depth > 12 || !value || typeof value !== "object") {
|
|
17054
|
+
return;
|
|
17055
|
+
}
|
|
17056
|
+
if (Array.isArray(value)) {
|
|
17057
|
+
for (const item of value.slice(0, 50)) {
|
|
17058
|
+
collectStringFields(item, key, output2, depth + 1);
|
|
17059
|
+
}
|
|
17060
|
+
return;
|
|
17061
|
+
}
|
|
17062
|
+
const record = value;
|
|
17063
|
+
const direct = record[key];
|
|
17064
|
+
if (typeof direct === "string" && direct.trim()) {
|
|
17065
|
+
output2.add(direct.trim());
|
|
17066
|
+
}
|
|
17067
|
+
for (const child of Object.values(record)) {
|
|
17068
|
+
collectStringFields(child, key, output2, depth + 1);
|
|
17069
|
+
}
|
|
17070
|
+
}
|
|
17071
|
+
function fallbackRowsInfoForGeneratedEnrichExport(status, options) {
|
|
17072
|
+
if (!extractRunId(status) || !extractPlayName2(status)) {
|
|
17073
|
+
return null;
|
|
17074
|
+
}
|
|
17075
|
+
const totalRows = selectedSourceCsvRowCount(options);
|
|
17076
|
+
if (totalRows === null) {
|
|
17077
|
+
return null;
|
|
17078
|
+
}
|
|
17079
|
+
const tableNamespaces = /* @__PURE__ */ new Set();
|
|
17080
|
+
collectStringFields(status, "tableNamespace", tableNamespaces);
|
|
17081
|
+
collectStringFields(status, "artifactTableNamespace", tableNamespaces);
|
|
17082
|
+
const tableNamespace = tableNamespaces.values().next().value ?? GENERATED_ENRICH_ROWS_TABLE_NAMESPACE;
|
|
17083
|
+
return {
|
|
17084
|
+
rows: [],
|
|
17085
|
+
totalRows,
|
|
17086
|
+
columns: [],
|
|
17087
|
+
columnsExplicit: false,
|
|
17088
|
+
complete: false,
|
|
17089
|
+
source: tableNamespace,
|
|
17090
|
+
tableNamespace
|
|
17091
|
+
};
|
|
17092
|
+
}
|
|
17093
|
+
function firstCollectedStringField(value, key) {
|
|
17094
|
+
const fields = /* @__PURE__ */ new Set();
|
|
17095
|
+
collectStringFields(value, key, fields);
|
|
17096
|
+
return fields.values().next().value ?? null;
|
|
17097
|
+
}
|
|
17098
|
+
function emitPlainBatchRunFailure(input2) {
|
|
17099
|
+
process.stderr.write(
|
|
17100
|
+
`Batch ${input2.chunkIndex + 1}/${input2.chunkCount} failed for rows ${input2.rows.rowStart}:${input2.rows.rowEnd}.
|
|
17101
|
+
`
|
|
17102
|
+
);
|
|
17103
|
+
const runId = extractRunId(input2.status);
|
|
17104
|
+
const error = firstCollectedStringField(input2.status, "error") ?? firstCollectedStringField(input2.status, "message");
|
|
17105
|
+
if (runId) {
|
|
17106
|
+
process.stderr.write(`Run id: ${runId}
|
|
17107
|
+
`);
|
|
17108
|
+
}
|
|
17109
|
+
if (error) {
|
|
17110
|
+
process.stderr.write(`Error: ${error}
|
|
17111
|
+
`);
|
|
17112
|
+
}
|
|
17113
|
+
if (runId) {
|
|
17114
|
+
process.stderr.write(
|
|
17115
|
+
`Inspect run output: deepline runs get ${runId} --full --json
|
|
17116
|
+
`
|
|
17117
|
+
);
|
|
17118
|
+
}
|
|
17119
|
+
}
|
|
16811
17120
|
function exportableSheetRow2(row) {
|
|
16812
17121
|
if (!row || typeof row !== "object" || Array.isArray(row)) {
|
|
16813
17122
|
return null;
|
|
@@ -17175,7 +17484,8 @@ async function fetchBackingRowsForCsvExport(input2) {
|
|
|
17175
17484
|
tableNamespace,
|
|
17176
17485
|
runId,
|
|
17177
17486
|
limit: ENRICH_EXPORT_PAGE_SIZE,
|
|
17178
|
-
offset
|
|
17487
|
+
offset,
|
|
17488
|
+
rowMode: "all"
|
|
17179
17489
|
});
|
|
17180
17490
|
sheetRows.push(...page.rows);
|
|
17181
17491
|
const summaryTotal = page.summary?.stats?.total;
|
|
@@ -17543,41 +17853,177 @@ function registerEnrichCommand(program) {
|
|
|
17543
17853
|
const tempPlay = (0, import_node_path11.join)(tempDir, "deepline-enrich.play.ts");
|
|
17544
17854
|
try {
|
|
17545
17855
|
await (0, import_promises3.writeFile)(tempPlay, playSource, "utf8");
|
|
17546
|
-
const
|
|
17547
|
-
|
|
17548
|
-
|
|
17549
|
-
|
|
17856
|
+
const runOne = async (input2) => {
|
|
17857
|
+
const runtimeInput = {
|
|
17858
|
+
file: (0, import_node_path11.resolve)(input2.sourceCsvPath),
|
|
17859
|
+
...input2.rows.rowStart !== null ? { rowStart: input2.rows.rowStart } : {},
|
|
17860
|
+
...input2.rows.rowEnd !== null ? { rowEnd: input2.rows.rowEnd } : {}
|
|
17861
|
+
};
|
|
17862
|
+
const runArgs = [
|
|
17863
|
+
"--file",
|
|
17864
|
+
tempPlay,
|
|
17865
|
+
"--input",
|
|
17866
|
+
JSON.stringify(runtimeInput),
|
|
17867
|
+
"--watch"
|
|
17868
|
+
];
|
|
17869
|
+
if (options.profile) {
|
|
17870
|
+
runArgs.push("--profile", options.profile);
|
|
17871
|
+
}
|
|
17872
|
+
if (options.noOpen || input2.suppressOpen) {
|
|
17873
|
+
runArgs.push("--no-open");
|
|
17874
|
+
}
|
|
17875
|
+
if (input2.json) {
|
|
17876
|
+
runArgs.push("--json");
|
|
17877
|
+
} else {
|
|
17878
|
+
runArgs.push("--logs");
|
|
17879
|
+
}
|
|
17880
|
+
const timeoutSeconds = options.timeout ? Number.parseInt(options.timeout, 10) : null;
|
|
17881
|
+
if (timeoutSeconds !== null && Number.isFinite(timeoutSeconds) && timeoutSeconds > 0) {
|
|
17882
|
+
runArgs.push("--tail-timeout-ms", String(timeoutSeconds * 1e3));
|
|
17883
|
+
}
|
|
17884
|
+
const captured2 = await runGeneratedEnrichPlay(runArgs, {
|
|
17885
|
+
passthroughStdout: input2.passthroughStdout
|
|
17886
|
+
});
|
|
17887
|
+
const status2 = input2.json ? parseJsonOutput(captured2.stdout) : await resolveWatchedGeneratedPlayStatus({
|
|
17888
|
+
client: client2,
|
|
17889
|
+
stdout: captured2.stdout,
|
|
17890
|
+
exitCode: captured2.result
|
|
17891
|
+
});
|
|
17892
|
+
const exportResult2 = captured2.result === 0 && outputPath ? await writeOutputCsv(outputPath, status2, {
|
|
17893
|
+
client: client2,
|
|
17894
|
+
config,
|
|
17895
|
+
sourceCsvPath: input2.sourceCsvPath,
|
|
17896
|
+
rows: input2.rows,
|
|
17897
|
+
inPlace: Boolean(options.inPlace)
|
|
17898
|
+
}) : null;
|
|
17899
|
+
return { captured: captured2, status: status2, exportResult: exportResult2 };
|
|
17550
17900
|
};
|
|
17551
|
-
const
|
|
17552
|
-
|
|
17553
|
-
|
|
17554
|
-
|
|
17555
|
-
|
|
17556
|
-
|
|
17557
|
-
|
|
17558
|
-
|
|
17559
|
-
|
|
17560
|
-
|
|
17561
|
-
|
|
17562
|
-
|
|
17563
|
-
|
|
17564
|
-
|
|
17565
|
-
|
|
17566
|
-
|
|
17567
|
-
|
|
17568
|
-
|
|
17569
|
-
|
|
17570
|
-
|
|
17571
|
-
|
|
17901
|
+
const selectedRange = selectedSourceCsvRange(sourceCsvPath, rows);
|
|
17902
|
+
if (outputPath && selectedRange.count > ENRICH_AUTO_BATCH_ROWS) {
|
|
17903
|
+
const chunkCount = Math.ceil(
|
|
17904
|
+
selectedRange.count / ENRICH_AUTO_BATCH_ROWS
|
|
17905
|
+
);
|
|
17906
|
+
if (!options.json) {
|
|
17907
|
+
process.stderr.write(
|
|
17908
|
+
`Large enrich input selected ${selectedRange.count.toLocaleString()} rows. Running ${chunkCount.toLocaleString()} sequential batch runs of up to ${ENRICH_AUTO_BATCH_ROWS.toLocaleString()} rows and merging ${(0, import_node_path11.resolve)(outputPath)}.
|
|
17909
|
+
`
|
|
17910
|
+
);
|
|
17911
|
+
}
|
|
17912
|
+
let workingSourceCsvPath = sourceCsvPath;
|
|
17913
|
+
let lastStatus = null;
|
|
17914
|
+
let finalExportResult = null;
|
|
17915
|
+
let totalEnrichedRows = 0;
|
|
17916
|
+
const batchFailureRows = [];
|
|
17917
|
+
for (let chunkStart = selectedRange.start, chunkIndex = 0; chunkStart <= selectedRange.end; chunkStart += ENRICH_AUTO_BATCH_ROWS, chunkIndex += 1) {
|
|
17918
|
+
const chunkRows = {
|
|
17919
|
+
rowStart: chunkStart,
|
|
17920
|
+
rowEnd: Math.min(
|
|
17921
|
+
selectedRange.end,
|
|
17922
|
+
chunkStart + ENRICH_AUTO_BATCH_ROWS - 1
|
|
17923
|
+
)
|
|
17924
|
+
};
|
|
17925
|
+
if (!options.json) {
|
|
17926
|
+
process.stderr.write(
|
|
17927
|
+
`Batch ${chunkIndex + 1}/${chunkCount}: rows ${chunkRows.rowStart}:${chunkRows.rowEnd}
|
|
17928
|
+
`
|
|
17929
|
+
);
|
|
17930
|
+
}
|
|
17931
|
+
const chunk = await runOne({
|
|
17932
|
+
sourceCsvPath: workingSourceCsvPath,
|
|
17933
|
+
rows: chunkRows,
|
|
17934
|
+
json: true,
|
|
17935
|
+
passthroughStdout: false,
|
|
17936
|
+
suppressOpen: true
|
|
17937
|
+
});
|
|
17938
|
+
lastStatus = chunk.status;
|
|
17939
|
+
if (chunk.captured.result !== 0) {
|
|
17940
|
+
if (options.json) {
|
|
17941
|
+
printJson({
|
|
17942
|
+
ok: false,
|
|
17943
|
+
batch: {
|
|
17944
|
+
chunk: chunkIndex + 1,
|
|
17945
|
+
chunks: chunkCount,
|
|
17946
|
+
rows: chunkRows
|
|
17947
|
+
},
|
|
17948
|
+
result: chunk.status
|
|
17949
|
+
});
|
|
17950
|
+
} else {
|
|
17951
|
+
emitPlainBatchRunFailure({
|
|
17952
|
+
chunkIndex,
|
|
17953
|
+
chunkCount,
|
|
17954
|
+
rows: chunkRows,
|
|
17955
|
+
status: chunk.status
|
|
17956
|
+
});
|
|
17957
|
+
}
|
|
17958
|
+
process.exitCode = chunk.captured.result;
|
|
17959
|
+
return;
|
|
17960
|
+
}
|
|
17961
|
+
if (chunk.exportResult) {
|
|
17962
|
+
finalExportResult = chunk.exportResult;
|
|
17963
|
+
totalEnrichedRows += chunk.exportResult.enrichedRows;
|
|
17964
|
+
batchFailureRows.push(...chunk.exportResult.enrichedDataRows);
|
|
17965
|
+
workingSourceCsvPath = outputPath;
|
|
17966
|
+
}
|
|
17967
|
+
}
|
|
17968
|
+
const outputRows = readCsvRows(outputPath);
|
|
17969
|
+
const failureReport2 = await maybeEmitEnrichFailureReport({
|
|
17970
|
+
config,
|
|
17971
|
+
rows: batchFailureRows,
|
|
17972
|
+
rowRange: {
|
|
17973
|
+
rowStart: selectedRange.start,
|
|
17974
|
+
rowEnd: selectedRange.end
|
|
17975
|
+
},
|
|
17976
|
+
client: client2,
|
|
17977
|
+
outputPath
|
|
17978
|
+
});
|
|
17979
|
+
if (options.json) {
|
|
17980
|
+
const run = rewriteEnrichJsonStatus({
|
|
17981
|
+
status: lastStatus,
|
|
17982
|
+
config,
|
|
17983
|
+
forceAliases,
|
|
17984
|
+
output: finalExportResult ? {
|
|
17985
|
+
...finalExportResult,
|
|
17986
|
+
sourceCsvRows: selectedRange.sourceRows,
|
|
17987
|
+
selectedRows: selectedRange.count,
|
|
17988
|
+
enrichedRows: totalEnrichedRows,
|
|
17989
|
+
rows: outputRows.length,
|
|
17990
|
+
enrichedDataRows: outputRows
|
|
17991
|
+
} : null,
|
|
17992
|
+
failureReport: failureReport2
|
|
17993
|
+
});
|
|
17994
|
+
printJson({
|
|
17995
|
+
ok: !failureReport2,
|
|
17996
|
+
run,
|
|
17997
|
+
batch: {
|
|
17998
|
+
chunks: chunkCount,
|
|
17999
|
+
chunkRows: ENRICH_AUTO_BATCH_ROWS,
|
|
18000
|
+
selectedRows: selectedRange.count
|
|
18001
|
+
},
|
|
18002
|
+
output: finalExportResult ? {
|
|
18003
|
+
sourceCsvRows: selectedRange.sourceRows,
|
|
18004
|
+
selectedRows: selectedRange.count,
|
|
18005
|
+
enrichedRows: totalEnrichedRows,
|
|
18006
|
+
path: finalExportResult.path
|
|
18007
|
+
} : null,
|
|
18008
|
+
...failureReport2 ? {
|
|
18009
|
+
failure_report: {
|
|
18010
|
+
path: failureReport2.path,
|
|
18011
|
+
jobs: failureReport2.jobs.length
|
|
18012
|
+
}
|
|
18013
|
+
} : {}
|
|
18014
|
+
});
|
|
18015
|
+
}
|
|
18016
|
+
if (failureReport2) {
|
|
18017
|
+
process.exitCode = EXIT_SERVER2;
|
|
18018
|
+
}
|
|
18019
|
+
return;
|
|
17572
18020
|
}
|
|
17573
|
-
const captured = await
|
|
18021
|
+
const { captured, status, exportResult } = await runOne({
|
|
18022
|
+
sourceCsvPath,
|
|
18023
|
+
rows,
|
|
18024
|
+
json: Boolean(options.json),
|
|
17574
18025
|
passthroughStdout: !options.json
|
|
17575
18026
|
});
|
|
17576
|
-
const status = options.json ? parseJsonOutput(captured.stdout) : await resolveWatchedGeneratedPlayStatus({
|
|
17577
|
-
client: client2,
|
|
17578
|
-
stdout: captured.stdout,
|
|
17579
|
-
exitCode: captured.result
|
|
17580
|
-
});
|
|
17581
18027
|
if (captured.result !== 0) {
|
|
17582
18028
|
if (options.json) {
|
|
17583
18029
|
printJson({
|
|
@@ -17587,13 +18033,6 @@ function registerEnrichCommand(program) {
|
|
|
17587
18033
|
process.exitCode = captured.result;
|
|
17588
18034
|
return;
|
|
17589
18035
|
}
|
|
17590
|
-
const exportResult = outputPath ? await writeOutputCsv(outputPath, status, {
|
|
17591
|
-
client: client2,
|
|
17592
|
-
config,
|
|
17593
|
-
sourceCsvPath,
|
|
17594
|
-
rows,
|
|
17595
|
-
inPlace: Boolean(options.inPlace)
|
|
17596
|
-
}) : null;
|
|
17597
18036
|
const rowsForFailureReport = exportResult?.enrichedDataRows ?? extractCanonicalRowsInfo(status)?.rows ?? [];
|
|
17598
18037
|
if (options.json) {
|
|
17599
18038
|
const failureReport2 = await maybeEmitEnrichFailureReport({
|
|
@@ -18511,6 +18950,15 @@ Examples:
|
|
|
18511
18950
|
async function fetchOrganizations(http, apiKey) {
|
|
18512
18951
|
return http.post("/api/v2/auth/cli/organizations", { api_key: apiKey });
|
|
18513
18952
|
}
|
|
18953
|
+
function normalizeAuthScope(value) {
|
|
18954
|
+
if (!value) return "auto";
|
|
18955
|
+
if (value === "auto" || value === "folder" || value === "global") {
|
|
18956
|
+
return value;
|
|
18957
|
+
}
|
|
18958
|
+
throw new Error(
|
|
18959
|
+
`Invalid --auth-scope "${value}". Expected one of: auto, folder, global.`
|
|
18960
|
+
);
|
|
18961
|
+
}
|
|
18514
18962
|
function orgListLines(orgs) {
|
|
18515
18963
|
return orgs.map((org, index) => {
|
|
18516
18964
|
const current = org.is_current ? " (current)" : "";
|
|
@@ -18518,6 +18966,90 @@ function orgListLines(orgs) {
|
|
|
18518
18966
|
return `${index + 1}. ${org.name}${role}${current}`;
|
|
18519
18967
|
});
|
|
18520
18968
|
}
|
|
18969
|
+
function redactApiKey(value) {
|
|
18970
|
+
if (!value) return null;
|
|
18971
|
+
if (value.length <= 10) return `${value.slice(0, 3)}...`;
|
|
18972
|
+
return `${value.slice(0, 8)}...${value.slice(-4)}`;
|
|
18973
|
+
}
|
|
18974
|
+
function processEnvValue(name) {
|
|
18975
|
+
return process.env[name]?.trim() ?? "";
|
|
18976
|
+
}
|
|
18977
|
+
function resolveOrgSwitchAuthTarget(scope, config) {
|
|
18978
|
+
const activeProject = getResolvedProjectAuthSource(
|
|
18979
|
+
config.baseUrl,
|
|
18980
|
+
config.apiKey
|
|
18981
|
+
);
|
|
18982
|
+
const folderTarget = resolveProjectPinTarget();
|
|
18983
|
+
const globalOverrideWarning = activeProject && scope === "global" ? [
|
|
18984
|
+
`Folder auth in ${activeProject.filePath} overrides global auth for commands run here.`
|
|
18985
|
+
] : [];
|
|
18986
|
+
if (scope === "folder") {
|
|
18987
|
+
if (!folderTarget.ok) {
|
|
18988
|
+
throw new Error(
|
|
18989
|
+
`Cowork project folder is ambiguous. Candidate folders: ${folderTarget.candidates.join(
|
|
18990
|
+
", "
|
|
18991
|
+
)}. Set CLAUDE_PROJECT_DIR or cd into the intended project folder before running this command.`
|
|
18992
|
+
);
|
|
18993
|
+
}
|
|
18994
|
+
return {
|
|
18995
|
+
kind: "folder",
|
|
18996
|
+
requested_scope: scope,
|
|
18997
|
+
effective_scope: "folder",
|
|
18998
|
+
reason: "explicit_folder",
|
|
18999
|
+
source: folderTarget.source,
|
|
19000
|
+
warnings: []
|
|
19001
|
+
};
|
|
19002
|
+
}
|
|
19003
|
+
if (scope === "global") {
|
|
19004
|
+
return {
|
|
19005
|
+
kind: "global",
|
|
19006
|
+
requested_scope: scope,
|
|
19007
|
+
effective_scope: "global",
|
|
19008
|
+
reason: "explicit_global",
|
|
19009
|
+
warnings: globalOverrideWarning
|
|
19010
|
+
};
|
|
19011
|
+
}
|
|
19012
|
+
if (activeProject) {
|
|
19013
|
+
return {
|
|
19014
|
+
kind: "folder",
|
|
19015
|
+
requested_scope: scope,
|
|
19016
|
+
effective_scope: "folder",
|
|
19017
|
+
reason: "existing_folder_auth",
|
|
19018
|
+
source: activeProject.source,
|
|
19019
|
+
warnings: []
|
|
19020
|
+
};
|
|
19021
|
+
}
|
|
19022
|
+
if (folderTarget.ok && folderTarget.source === "cowork") {
|
|
19023
|
+
return {
|
|
19024
|
+
kind: "folder",
|
|
19025
|
+
requested_scope: scope,
|
|
19026
|
+
effective_scope: "folder",
|
|
19027
|
+
reason: "detected_cowork_project",
|
|
19028
|
+
source: "cowork",
|
|
19029
|
+
warnings: []
|
|
19030
|
+
};
|
|
19031
|
+
}
|
|
19032
|
+
if (!folderTarget.ok) {
|
|
19033
|
+
return {
|
|
19034
|
+
kind: "global",
|
|
19035
|
+
requested_scope: scope,
|
|
19036
|
+
effective_scope: "global",
|
|
19037
|
+
reason: "ambiguous_cowork_fell_back_global",
|
|
19038
|
+
warnings: [
|
|
19039
|
+
`Cowork project folder is ambiguous, so global auth was updated. Candidate folders: ${folderTarget.candidates.join(
|
|
19040
|
+
", "
|
|
19041
|
+
)}. Set CLAUDE_PROJECT_DIR or cd into the intended project folder to update folder auth.`
|
|
19042
|
+
]
|
|
19043
|
+
};
|
|
19044
|
+
}
|
|
19045
|
+
return {
|
|
19046
|
+
kind: "global",
|
|
19047
|
+
requested_scope: scope,
|
|
19048
|
+
effective_scope: "global",
|
|
19049
|
+
reason: "default_global",
|
|
19050
|
+
warnings: []
|
|
19051
|
+
};
|
|
19052
|
+
}
|
|
18521
19053
|
async function handleOrgList(options) {
|
|
18522
19054
|
const config = resolveConfig();
|
|
18523
19055
|
const http = new HttpClient(config);
|
|
@@ -18537,7 +19069,89 @@ async function handleOrgList(options) {
|
|
|
18537
19069
|
{ json: options.json }
|
|
18538
19070
|
);
|
|
18539
19071
|
}
|
|
19072
|
+
async function handleOrgStatus(options) {
|
|
19073
|
+
const config = resolveConfig();
|
|
19074
|
+
const http = new HttpClient(config);
|
|
19075
|
+
const payload = await fetchOrganizations(http, config.apiKey);
|
|
19076
|
+
const current = payload.organizations.find((org) => org.is_current) ?? payload.organizations.find((org) => org.org_id === payload.current_org_id) ?? null;
|
|
19077
|
+
const projectCandidate = getActiveProjectAuthSource();
|
|
19078
|
+
const activeProject = getResolvedProjectAuthSource(
|
|
19079
|
+
config.baseUrl,
|
|
19080
|
+
config.apiKey
|
|
19081
|
+
);
|
|
19082
|
+
const folderTarget = resolveProjectPinTarget();
|
|
19083
|
+
const hostPath = hostEnvFilePath(config.baseUrl);
|
|
19084
|
+
const envApiKey = processEnvValue(API_KEY_ENV);
|
|
19085
|
+
const envHostUrl = processEnvValue(HOST_URL_ENV);
|
|
19086
|
+
const authSource = envApiKey ? {
|
|
19087
|
+
scope: "env",
|
|
19088
|
+
source: "process",
|
|
19089
|
+
path: null,
|
|
19090
|
+
api_key: redactApiKey(envApiKey),
|
|
19091
|
+
host: envHostUrl || null,
|
|
19092
|
+
overrides_global: true,
|
|
19093
|
+
overrides_folder: Boolean(projectCandidate)
|
|
19094
|
+
} : activeProject ? {
|
|
19095
|
+
scope: "folder",
|
|
19096
|
+
source: activeProject.source,
|
|
19097
|
+
path: activeProject.filePath,
|
|
19098
|
+
api_key: redactApiKey(activeProject.env.DEEPLINE_API_KEY),
|
|
19099
|
+
overrides_global: true
|
|
19100
|
+
} : {
|
|
19101
|
+
scope: "global",
|
|
19102
|
+
source: "host",
|
|
19103
|
+
path: hostPath,
|
|
19104
|
+
api_key: redactApiKey(config.apiKey),
|
|
19105
|
+
overrides_global: false
|
|
19106
|
+
};
|
|
19107
|
+
const folderTargetPayload = folderTarget.ok ? {
|
|
19108
|
+
ok: true,
|
|
19109
|
+
source: folderTarget.source,
|
|
19110
|
+
dir: folderTarget.dir,
|
|
19111
|
+
env_path: `${folderTarget.dir}/.env.deepline`
|
|
19112
|
+
} : {
|
|
19113
|
+
ok: false,
|
|
19114
|
+
reason: folderTarget.reason,
|
|
19115
|
+
candidates: folderTarget.candidates
|
|
19116
|
+
};
|
|
19117
|
+
const lines = [
|
|
19118
|
+
`Organization: ${current?.name ?? "(unknown)"}`,
|
|
19119
|
+
`Host: ${config.baseUrl}`,
|
|
19120
|
+
`Auth scope: ${authSource.scope}`
|
|
19121
|
+
];
|
|
19122
|
+
if (authSource.path) {
|
|
19123
|
+
lines.push(`Auth file: ${authSource.path}`);
|
|
19124
|
+
} else {
|
|
19125
|
+
lines.push(`Auth source: ${API_KEY_ENV} process environment`);
|
|
19126
|
+
}
|
|
19127
|
+
if (envApiKey) {
|
|
19128
|
+
lines.push(`${API_KEY_ENV} overrides saved auth for this process.`);
|
|
19129
|
+
} else if (activeProject) {
|
|
19130
|
+
lines.push("Global auth is overridden in this folder.");
|
|
19131
|
+
}
|
|
19132
|
+
printCommandEnvelope(
|
|
19133
|
+
{
|
|
19134
|
+
ok: true,
|
|
19135
|
+
host: config.baseUrl,
|
|
19136
|
+
organization: current,
|
|
19137
|
+
current_org_id: payload.current_org_id,
|
|
19138
|
+
auth_source: authSource,
|
|
19139
|
+
host_env_path: hostPath,
|
|
19140
|
+
folder_target: folderTargetPayload,
|
|
19141
|
+
next: {
|
|
19142
|
+
set_auto: "deepline org set <org>",
|
|
19143
|
+
set_folder: "deepline org set <org> --auth-scope folder",
|
|
19144
|
+
set_global: "deepline org set <org> --auth-scope global"
|
|
19145
|
+
},
|
|
19146
|
+
render: {
|
|
19147
|
+
sections: [{ title: "org status", lines }]
|
|
19148
|
+
}
|
|
19149
|
+
},
|
|
19150
|
+
{ json: options.json }
|
|
19151
|
+
);
|
|
19152
|
+
}
|
|
18540
19153
|
async function handleOrgSwitch(selection, options) {
|
|
19154
|
+
const authScope = normalizeAuthScope(options.authScope);
|
|
18541
19155
|
const config = resolveConfig();
|
|
18542
19156
|
const http = new HttpClient(config);
|
|
18543
19157
|
const payload = await fetchOrganizations(http, config.apiKey);
|
|
@@ -18545,7 +19159,10 @@ async function handleOrgSwitch(selection, options) {
|
|
|
18545
19159
|
printCommandEnvelope(
|
|
18546
19160
|
{
|
|
18547
19161
|
...payload,
|
|
18548
|
-
next: {
|
|
19162
|
+
next: { set: "deepline org set <number>" },
|
|
19163
|
+
deprecated_command: options.deprecatedSwitch ? "org switch" : null,
|
|
19164
|
+
replacement_command: options.deprecatedSwitch ? "deepline org set" : null,
|
|
19165
|
+
warnings: options.deprecatedSwitch ? ["org switch is deprecated; use org set."] : [],
|
|
18549
19166
|
render: {
|
|
18550
19167
|
sections: [
|
|
18551
19168
|
{
|
|
@@ -18553,7 +19170,7 @@ async function handleOrgSwitch(selection, options) {
|
|
|
18553
19170
|
lines: orgListLines(payload.organizations)
|
|
18554
19171
|
}
|
|
18555
19172
|
],
|
|
18556
|
-
actions: [{ label: "Run", command: "deepline org
|
|
19173
|
+
actions: [{ label: "Run", command: "deepline org set <number>" }]
|
|
18557
19174
|
}
|
|
18558
19175
|
},
|
|
18559
19176
|
{ json: options.json }
|
|
@@ -18576,16 +19193,56 @@ async function handleOrgSwitch(selection, options) {
|
|
|
18576
19193
|
if (!target) {
|
|
18577
19194
|
throw new Error("Could not resolve the selected organization.");
|
|
18578
19195
|
}
|
|
19196
|
+
const authTarget = resolveOrgSwitchAuthTarget(authScope, config);
|
|
18579
19197
|
if (target.is_current) {
|
|
19198
|
+
let project_env_paths2 = [];
|
|
19199
|
+
if (authTarget.kind === "folder") {
|
|
19200
|
+
project_env_paths2 = saveProjectDeeplineEnvValues({
|
|
19201
|
+
DEEPLINE_HOST_URL: config.baseUrl,
|
|
19202
|
+
DEEPLINE_API_KEY: config.apiKey
|
|
19203
|
+
});
|
|
19204
|
+
} else {
|
|
19205
|
+
saveHostEnvValues(config.baseUrl, {
|
|
19206
|
+
DEEPLINE_HOST_URL: config.baseUrl,
|
|
19207
|
+
DEEPLINE_API_KEY: config.apiKey
|
|
19208
|
+
});
|
|
19209
|
+
}
|
|
19210
|
+
const renderLines2 = [`Already on ${target.name}.`];
|
|
19211
|
+
for (const projectPath of project_env_paths2) {
|
|
19212
|
+
renderLines2.push(`Saved folder auth in ${projectPath}`);
|
|
19213
|
+
}
|
|
19214
|
+
if (authTarget.kind === "global") {
|
|
19215
|
+
renderLines2.push(`Saved global auth in ${hostEnvFilePath(config.baseUrl)}`);
|
|
19216
|
+
}
|
|
19217
|
+
renderLines2.push(
|
|
19218
|
+
`Scope: ${authTarget.requested_scope} -> ${authTarget.effective_scope} (${authTarget.reason})`
|
|
19219
|
+
);
|
|
19220
|
+
if (options.deprecatedSwitch) {
|
|
19221
|
+
renderLines2.push("Warning: org switch is deprecated; use org set.");
|
|
19222
|
+
}
|
|
19223
|
+
for (const warning of authTarget.warnings) {
|
|
19224
|
+
renderLines2.push(`Warning: ${warning}`);
|
|
19225
|
+
}
|
|
19226
|
+
const warnings2 = [
|
|
19227
|
+
...options.deprecatedSwitch ? ["org switch is deprecated; use org set."] : [],
|
|
19228
|
+
...authTarget.warnings
|
|
19229
|
+
];
|
|
18580
19230
|
printCommandEnvelope(
|
|
18581
19231
|
{
|
|
18582
19232
|
ok: true,
|
|
18583
19233
|
unchanged: true,
|
|
18584
19234
|
organization: target,
|
|
19235
|
+
requested_auth_scope: authTarget.requested_scope,
|
|
19236
|
+
effective_auth_scope: authTarget.effective_scope,
|
|
19237
|
+
auth_scope_reason: authTarget.reason,
|
|
19238
|
+
auth_scope: authTarget.effective_scope,
|
|
19239
|
+
host_env_path: authTarget.kind === "global" ? hostEnvFilePath(config.baseUrl) : null,
|
|
19240
|
+
project_env_paths: project_env_paths2,
|
|
19241
|
+
deprecated_command: options.deprecatedSwitch ? "org switch" : null,
|
|
19242
|
+
replacement_command: options.deprecatedSwitch ? "deepline org set" : null,
|
|
19243
|
+
warnings: warnings2,
|
|
18585
19244
|
render: {
|
|
18586
|
-
sections: [
|
|
18587
|
-
{ title: "org switch", lines: [`Already on ${target.name}.`] }
|
|
18588
|
-
]
|
|
19245
|
+
sections: [{ title: "org set", lines: renderLines2 }]
|
|
18589
19246
|
}
|
|
18590
19247
|
},
|
|
18591
19248
|
{ json: options.json }
|
|
@@ -18596,26 +19253,61 @@ async function handleOrgSwitch(selection, options) {
|
|
|
18596
19253
|
api_key: config.apiKey,
|
|
18597
19254
|
org_id: target.org_id
|
|
18598
19255
|
});
|
|
18599
|
-
|
|
18600
|
-
|
|
18601
|
-
|
|
18602
|
-
|
|
18603
|
-
|
|
19256
|
+
let project_env_paths = [];
|
|
19257
|
+
if (authTarget.kind === "folder") {
|
|
19258
|
+
project_env_paths = saveProjectDeeplineEnvValues({
|
|
19259
|
+
DEEPLINE_HOST_URL: config.baseUrl,
|
|
19260
|
+
DEEPLINE_API_KEY: switched.api_key
|
|
19261
|
+
});
|
|
19262
|
+
} else {
|
|
19263
|
+
saveHostEnvValues(config.baseUrl, {
|
|
19264
|
+
DEEPLINE_HOST_URL: config.baseUrl,
|
|
19265
|
+
DEEPLINE_API_KEY: switched.api_key,
|
|
19266
|
+
DEEPLINE_ACTIVE_ORG_ID: switched.org_id,
|
|
19267
|
+
DEEPLINE_ACTIVE_ORG_NAME: switched.org_name
|
|
19268
|
+
});
|
|
19269
|
+
}
|
|
18604
19270
|
const { api_key: _apiKey, ...publicSwitched } = switched;
|
|
19271
|
+
const renderLines = [`Switched to ${switched.org_name}.`];
|
|
19272
|
+
if (authTarget.kind === "folder") {
|
|
19273
|
+
for (const projectPath of project_env_paths) {
|
|
19274
|
+
renderLines.push(`Saved folder auth in ${projectPath}`);
|
|
19275
|
+
}
|
|
19276
|
+
} else {
|
|
19277
|
+
renderLines.push(`Saved global auth in ${hostEnvFilePath(config.baseUrl)}`);
|
|
19278
|
+
}
|
|
19279
|
+
renderLines.push(
|
|
19280
|
+
`Scope: ${authTarget.requested_scope} -> ${authTarget.effective_scope} (${authTarget.reason})`
|
|
19281
|
+
);
|
|
19282
|
+
if (options.deprecatedSwitch) {
|
|
19283
|
+
renderLines.push("Warning: org switch is deprecated; use org set.");
|
|
19284
|
+
}
|
|
19285
|
+
for (const warning of authTarget.warnings) {
|
|
19286
|
+
renderLines.push(`Warning: ${warning}`);
|
|
19287
|
+
}
|
|
19288
|
+
const warnings = [
|
|
19289
|
+
...options.deprecatedSwitch ? ["org switch is deprecated; use org set."] : [],
|
|
19290
|
+
...authTarget.warnings
|
|
19291
|
+
];
|
|
18605
19292
|
printCommandEnvelope(
|
|
18606
19293
|
{
|
|
18607
19294
|
ok: true,
|
|
18608
|
-
host_env_path: hostEnvFilePath(config.baseUrl),
|
|
19295
|
+
host_env_path: authTarget.kind === "global" ? hostEnvFilePath(config.baseUrl) : null,
|
|
19296
|
+
project_env_paths,
|
|
18609
19297
|
...publicSwitched,
|
|
18610
19298
|
api_key_saved: true,
|
|
19299
|
+
requested_auth_scope: authTarget.requested_scope,
|
|
19300
|
+
effective_auth_scope: authTarget.effective_scope,
|
|
19301
|
+
auth_scope_reason: authTarget.reason,
|
|
19302
|
+
auth_scope: authTarget.effective_scope,
|
|
19303
|
+
deprecated_command: options.deprecatedSwitch ? "org switch" : null,
|
|
19304
|
+
replacement_command: options.deprecatedSwitch ? "deepline org set" : null,
|
|
19305
|
+
warnings,
|
|
18611
19306
|
render: {
|
|
18612
19307
|
sections: [
|
|
18613
19308
|
{
|
|
18614
|
-
title: "org
|
|
18615
|
-
lines:
|
|
18616
|
-
`Switched to ${switched.org_name}.`,
|
|
18617
|
-
`Saved host auth in ${hostEnvFilePath(config.baseUrl)}`
|
|
18618
|
-
]
|
|
19309
|
+
title: "org set",
|
|
19310
|
+
lines: renderLines
|
|
18619
19311
|
}
|
|
18620
19312
|
]
|
|
18621
19313
|
}
|
|
@@ -18631,6 +19323,7 @@ async function handleOrgCreate(name, options) {
|
|
|
18631
19323
|
name
|
|
18632
19324
|
});
|
|
18633
19325
|
saveHostEnvValues(config.baseUrl, {
|
|
19326
|
+
DEEPLINE_HOST_URL: config.baseUrl,
|
|
18634
19327
|
DEEPLINE_API_KEY: created.api_key,
|
|
18635
19328
|
DEEPLINE_ACTIVE_ORG_ID: created.org_id,
|
|
18636
19329
|
DEEPLINE_ACTIVE_ORG_NAME: created.org_name
|
|
@@ -18660,18 +19353,41 @@ async function handleOrgCreate(name, options) {
|
|
|
18660
19353
|
);
|
|
18661
19354
|
}
|
|
18662
19355
|
function registerOrgCommands(program) {
|
|
18663
|
-
const org = program.command("org").description("List, create, and
|
|
19356
|
+
const org = program.command("org").description("List, create, and set organizations.").addHelpText(
|
|
18664
19357
|
"after",
|
|
18665
19358
|
`
|
|
18666
19359
|
Notes:
|
|
18667
|
-
Organizations are workspaces.
|
|
18668
|
-
|
|
19360
|
+
Organizations are workspaces. Auth is stored as an API key scoped to one
|
|
19361
|
+
organization, so setting an org saves a key for the selected auth scope.
|
|
19362
|
+
|
|
19363
|
+
Auth scopes:
|
|
19364
|
+
auto Update the folder pin that already controls this command; in
|
|
19365
|
+
Cowork, write the mounted project folder; otherwise update global
|
|
19366
|
+
host auth.
|
|
19367
|
+
folder Write .env.deepline in the current project/Cowork project and make
|
|
19368
|
+
sure .env.deepline is gitignored. Commands below that folder use
|
|
19369
|
+
this org; sibling folders can pin different orgs.
|
|
19370
|
+
global Write ~/.local/deepline/<host>/.env. Commands outside folder pins
|
|
19371
|
+
use this org. Existing folder pins still override global auth.
|
|
19372
|
+
|
|
19373
|
+
Process env DEEPLINE_API_KEY overrides saved auth for that command only.
|
|
19374
|
+
|
|
19375
|
+
Agent loop:
|
|
19376
|
+
deepline org list --json
|
|
19377
|
+
deepline org set <number-or-org-id> --auth-scope folder --json
|
|
19378
|
+
deepline org status --json
|
|
19379
|
+
deepline auth status --json
|
|
18669
19380
|
|
|
18670
19381
|
Examples:
|
|
18671
19382
|
deepline org list --json
|
|
19383
|
+
deepline org status --json
|
|
18672
19384
|
deepline org create Acme --json
|
|
18673
|
-
deepline org
|
|
18674
|
-
deepline org
|
|
19385
|
+
deepline org set 2
|
|
19386
|
+
deepline org set 2 --auth-scope folder
|
|
19387
|
+
deepline org set --org-id org_123 --json
|
|
19388
|
+
cd path/to/project-a && deepline org set Prove --auth-scope folder --json
|
|
19389
|
+
cd path/to/project-b && deepline org set Mixmax --auth-scope folder --json
|
|
19390
|
+
cd .. && deepline org status --json
|
|
18675
19391
|
`
|
|
18676
19392
|
);
|
|
18677
19393
|
org.command("list").description("List your organizations.").addHelpText(
|
|
@@ -18698,21 +19414,88 @@ Examples:
|
|
|
18698
19414
|
deepline org create "Acme Sales" --json
|
|
18699
19415
|
`
|
|
18700
19416
|
).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleOrgCreate);
|
|
18701
|
-
org.command("
|
|
18702
|
-
"Switch to another organization and save the new API key in the host auth file."
|
|
18703
|
-
).addHelpText(
|
|
19417
|
+
org.command("status").description("Show the current organization and auth source.").addHelpText(
|
|
18704
19418
|
"after",
|
|
18705
19419
|
`
|
|
18706
19420
|
Notes:
|
|
18707
|
-
|
|
18708
|
-
|
|
19421
|
+
Read-only. Shows the current org plus auth_source.scope, auth_source.path,
|
|
19422
|
+
folder_target, host_env_path, and next commands.
|
|
19423
|
+
|
|
19424
|
+
Scopes are env, folder, or global. env means DEEPLINE_API_KEY/
|
|
19425
|
+
DEEPLINE_HOST_URL in process env wins. folder means nearest/Cowork
|
|
19426
|
+
.env.deepline wins. global means host config wins.
|
|
19427
|
+
|
|
19428
|
+
Run before and after org set to verify what future commands will use.
|
|
19429
|
+
|
|
19430
|
+
Examples:
|
|
19431
|
+
deepline org status
|
|
19432
|
+
deepline org status --json
|
|
19433
|
+
`
|
|
19434
|
+
).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleOrgStatus);
|
|
19435
|
+
const addOrgSetOptions = (command) => command.option("--org-id <id>", "Set using an explicit organization id").option(
|
|
19436
|
+
"--auth-scope <scope>",
|
|
19437
|
+
"Where to save auth: auto, folder, or global",
|
|
19438
|
+
"auto"
|
|
19439
|
+
).option("--json", "Emit JSON output. Also automatic when stdout is piped");
|
|
19440
|
+
addOrgSetOptions(
|
|
19441
|
+
org.command("set [selection]").description("Set the organization for the selected auth scope.").addHelpText(
|
|
19442
|
+
"after",
|
|
19443
|
+
`
|
|
19444
|
+
Notes:
|
|
19445
|
+
Selection can be a list number, exact organization name, or organization id.
|
|
19446
|
+
Without a selection, prints choices.
|
|
19447
|
+
|
|
19448
|
+
Mutates local auth state and asks Deepline for an org-scoped API key. It
|
|
19449
|
+
writes only the selected scope:
|
|
19450
|
+
auto Update the folder pin that already controls this command; in
|
|
19451
|
+
Cowork, write the mounted project folder; otherwise update global
|
|
19452
|
+
host auth.
|
|
19453
|
+
folder Write .env.deepline in the current project/Cowork project and make
|
|
19454
|
+
sure .env.deepline is gitignored.
|
|
19455
|
+
global Write ~/.local/deepline/<host>/.env.
|
|
19456
|
+
|
|
19457
|
+
Folder auth shadows global auth. If you set --auth-scope global from a pinned
|
|
19458
|
+
folder, commands in that folder still use the folder pin until it is changed
|
|
19459
|
+
or removed.
|
|
19460
|
+
|
|
19461
|
+
Use --json for stable fields including effective_auth_scope,
|
|
19462
|
+
auth_scope_reason, host_env_path, project_env_paths, warnings, org_id, and
|
|
19463
|
+
org_name.
|
|
19464
|
+
|
|
19465
|
+
Examples:
|
|
19466
|
+
deepline org set
|
|
19467
|
+
deepline org set 2
|
|
19468
|
+
deepline org set 2 --auth-scope folder
|
|
19469
|
+
deepline org set 2 --auth-scope global
|
|
19470
|
+
deepline org set --org-id org_123 --json
|
|
19471
|
+
deepline org status --json
|
|
19472
|
+
`
|
|
19473
|
+
)
|
|
19474
|
+
).action(handleOrgSwitch);
|
|
19475
|
+
addOrgSetOptions(
|
|
19476
|
+
org.command("switch [selection]").description(
|
|
19477
|
+
"Deprecated alias for org set. Set the organization for the selected auth scope."
|
|
19478
|
+
).addHelpText(
|
|
19479
|
+
"after",
|
|
19480
|
+
`
|
|
19481
|
+
Notes:
|
|
19482
|
+
Deprecated alias. Use deepline org set instead. The command still mutates
|
|
19483
|
+
local auth state with the same --auth-scope behavior as org set.
|
|
19484
|
+
|
|
19485
|
+
Run deepline org set --help for scope definitions and the agent verification
|
|
19486
|
+
loop.
|
|
18709
19487
|
|
|
18710
19488
|
Examples:
|
|
18711
19489
|
deepline org switch
|
|
18712
19490
|
deepline org switch 2
|
|
19491
|
+
deepline org switch 2 --auth-scope folder
|
|
19492
|
+
deepline org switch 2 --auth-scope global
|
|
18713
19493
|
deepline org switch --org-id org_123 --json
|
|
18714
19494
|
`
|
|
18715
|
-
|
|
19495
|
+
)
|
|
19496
|
+
).action(
|
|
19497
|
+
(selection, options) => handleOrgSwitch(selection, { ...options, deprecatedSwitch: true })
|
|
19498
|
+
);
|
|
18716
19499
|
}
|
|
18717
19500
|
|
|
18718
19501
|
// src/cli/commands/quickstart.ts
|