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.
@@ -164,7 +164,15 @@ import { tmpdir as tmpdir4 } from "os";
164
164
  import { Command as Command3 } from "commander";
165
165
 
166
166
  // src/config.ts
167
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
167
+ import {
168
+ existsSync,
169
+ mkdirSync,
170
+ readdirSync,
171
+ realpathSync,
172
+ readFileSync,
173
+ statSync,
174
+ writeFileSync
175
+ } from "fs";
168
176
  import { homedir } from "os";
169
177
  import { dirname, join, resolve } from "path";
170
178
 
@@ -214,6 +222,22 @@ var PROD_URL = "https://code.deepline.com";
214
222
  var DEFAULT_TIMEOUT = 6e4;
215
223
  var DEFAULT_MAX_RETRIES = 3;
216
224
  var PROJECT_DEEPLINE_ENV_FILE = ".env.deepline";
225
+ var COWORK_IGNORED_WORKSPACE_DIRS = /* @__PURE__ */ new Set([
226
+ ".auto-memory",
227
+ ".claude",
228
+ ".remote-plugins",
229
+ "outputs",
230
+ "plugins",
231
+ "uploads"
232
+ ]);
233
+ var COWORK_PROJECT_MARKERS = [
234
+ ".deepline",
235
+ ".env.deepline",
236
+ ".git",
237
+ "AGENTS.md",
238
+ "package.json",
239
+ "pyproject.toml"
240
+ ];
217
241
  function baseUrlSlug(baseUrl) {
218
242
  let url;
219
243
  try {
@@ -259,9 +283,124 @@ function findNearestEnvFile(name, startDir = process.cwd()) {
259
283
  current = parent;
260
284
  }
261
285
  }
262
- function loadProjectDeeplineEnv(startDir = process.cwd()) {
263
- const filePath = findNearestEnvFile(PROJECT_DEEPLINE_ENV_FILE, startDir);
264
- return filePath ? parseEnvFile(filePath) : {};
286
+ function isDirectory(path) {
287
+ try {
288
+ return statSync(path).isDirectory();
289
+ } catch {
290
+ return false;
291
+ }
292
+ }
293
+ function canonicalPath(path) {
294
+ try {
295
+ return realpathSync(path);
296
+ } catch {
297
+ return resolve(path);
298
+ }
299
+ }
300
+ function isTruthy(value) {
301
+ return /^(1|true|yes|on)$/i.test(value?.trim() ?? "");
302
+ }
303
+ function sessionRootFromPath(path) {
304
+ const trimmed = path?.trim();
305
+ if (!trimmed) return null;
306
+ const match = /^\/sessions\/[^/]+(?=\/|$)/.exec(trimmed);
307
+ return match?.[0] ?? null;
308
+ }
309
+ function coworkSessionRoot() {
310
+ const home = process.env.HOME?.trim();
311
+ const homeSessionRoot = sessionRootFromPath(home);
312
+ if (homeSessionRoot && isDirectory(join(homeSessionRoot, "mnt"))) {
313
+ return homeSessionRoot;
314
+ }
315
+ const cwdSessionRoot = sessionRootFromPath(process.cwd());
316
+ if (cwdSessionRoot && isDirectory(join(cwdSessionRoot, "mnt"))) {
317
+ return cwdSessionRoot;
318
+ }
319
+ if (isTruthy(process.env.CLAUDE_CODE_REMOTE) && home) {
320
+ const mountedRoot = join(home, "mnt");
321
+ if (isDirectory(mountedRoot)) return resolve(home);
322
+ }
323
+ return null;
324
+ }
325
+ function isCoworkLikeSandbox() {
326
+ const home = process.env.HOME?.trim();
327
+ return isTruthy(process.env.CLAUDE_CODE_REMOTE) || sessionRootFromPath(home) !== null || sessionRootFromPath(process.cwd()) !== null;
328
+ }
329
+ function coworkProjectScore(path) {
330
+ let score = 0;
331
+ for (const marker of COWORK_PROJECT_MARKERS) {
332
+ if (existsSync(join(path, marker))) score += 1;
333
+ }
334
+ return score;
335
+ }
336
+ function listCoworkWorkspaceDirCandidates() {
337
+ if (!isCoworkLikeSandbox()) {
338
+ return [];
339
+ }
340
+ const explicitProjectDir = process.env.CLAUDE_PROJECT_DIR?.trim();
341
+ if (explicitProjectDir && isDirectory(explicitProjectDir)) {
342
+ return [resolve(explicitProjectDir)];
343
+ }
344
+ const sessionRoot = coworkSessionRoot();
345
+ if (!sessionRoot) return [];
346
+ const mountedRoot = join(sessionRoot, "mnt");
347
+ if (!isDirectory(mountedRoot)) return [];
348
+ let names;
349
+ try {
350
+ names = readdirSync(mountedRoot).sort();
351
+ } catch {
352
+ return [];
353
+ }
354
+ const candidates = [];
355
+ for (const name of names) {
356
+ if (name.startsWith(".") || COWORK_IGNORED_WORKSPACE_DIRS.has(name)) {
357
+ continue;
358
+ }
359
+ const candidate = join(mountedRoot, name);
360
+ if (isDirectory(candidate)) candidates.push(candidate);
361
+ }
362
+ if (candidates.length <= 1) return candidates;
363
+ const projectLike = candidates.filter(
364
+ (candidate) => coworkProjectScore(candidate) > 0
365
+ );
366
+ return projectLike.length > 0 ? projectLike : candidates;
367
+ }
368
+ function isInIgnoredCoworkMount(path) {
369
+ const sessionRoot = coworkSessionRoot();
370
+ if (!sessionRoot) return false;
371
+ const mountedRoot = canonicalPath(join(sessionRoot, "mnt"));
372
+ const resolvedPath = canonicalPath(path);
373
+ const prefix = `${mountedRoot}/`;
374
+ if (!resolvedPath.startsWith(prefix)) return false;
375
+ const relativePath = resolvedPath.slice(prefix.length);
376
+ const mountName = relativePath.split("/")[0];
377
+ return mountName.startsWith(".") || COWORK_IGNORED_WORKSPACE_DIRS.has(mountName);
378
+ }
379
+ function detectCoworkWorkspaceDir() {
380
+ const candidates = listCoworkWorkspaceDirCandidates();
381
+ return candidates.length === 1 ? candidates[0] : null;
382
+ }
383
+ function loadProjectEnvCandidates(startDir = process.cwd()) {
384
+ const filePaths = [];
385
+ const sources = /* @__PURE__ */ new Map();
386
+ const nearestFile = findNearestEnvFile(PROJECT_DEEPLINE_ENV_FILE, startDir);
387
+ if (nearestFile && !isInIgnoredCoworkMount(nearestFile)) {
388
+ filePaths.push(nearestFile);
389
+ sources.set(resolve(nearestFile), "nearest");
390
+ }
391
+ const coworkWorkspaceDir = detectCoworkWorkspaceDir();
392
+ if (coworkWorkspaceDir) {
393
+ const coworkFile = join(coworkWorkspaceDir, PROJECT_DEEPLINE_ENV_FILE);
394
+ if (existsSync(coworkFile) && !filePaths.some((filePath) => resolve(filePath) === resolve(coworkFile))) {
395
+ filePaths.push(coworkFile);
396
+ sources.set(resolve(coworkFile), "cowork");
397
+ }
398
+ }
399
+ return filePaths.map((filePath) => ({
400
+ filePath,
401
+ env: parseEnvFile(filePath),
402
+ source: sources.get(resolve(filePath)) ?? "nearest"
403
+ }));
265
404
  }
266
405
  function normalizeBaseUrl(baseUrl) {
267
406
  const trimmed = baseUrl.trim().replace(/\/+$/, "");
@@ -325,23 +464,35 @@ function loadGlobalCliEnv() {
325
464
  return loadCliEnv(PROD_URL);
326
465
  }
327
466
  function autoDetectBaseUrl() {
328
- const projectEnv = loadProjectDeeplineEnv();
467
+ const projectEnvs = loadProjectEnvCandidates();
329
468
  const globalEnv = loadGlobalCliEnv();
330
- return normalizeBaseUrl(process.env[HOST_URL_ENV] ?? "") || normalizeBaseUrl(projectEnv[HOST_URL_ENV] ?? "") || normalizeBaseUrl(globalEnv[HOST_URL_ENV] ?? "") || PROD_URL;
469
+ return normalizeBaseUrl(process.env[HOST_URL_ENV] ?? "") || firstNonEmpty(
470
+ ...projectEnvs.map(({ env }) => normalizeBaseUrl(env[HOST_URL_ENV]))
471
+ ) || normalizeBaseUrl(globalEnv[HOST_URL_ENV] ?? "") || PROD_URL;
331
472
  }
332
473
  function resolveApiKeyForBaseUrl(baseUrl, explicitApiKey) {
333
474
  const normalizedBaseUrl = normalizeBaseUrl(baseUrl);
334
- const projectEnv = loadProjectDeeplineEnv();
475
+ const projectEnvs = loadProjectEnvCandidates();
335
476
  const cliEnv = loadCliEnv(normalizedBaseUrl || baseUrl);
336
- const projectBaseUrl = normalizeBaseUrl(projectEnv[HOST_URL_ENV] ?? "");
337
- const projectKeyApplies = projectBaseUrl === normalizedBaseUrl;
338
477
  return firstNonEmpty(
339
478
  explicitApiKey,
340
479
  process.env[API_KEY_ENV],
341
- projectKeyApplies ? projectEnv[API_KEY_ENV] : "",
480
+ ...projectEnvs.map(({ env }) => {
481
+ const projectBaseUrl = normalizeBaseUrl(env[HOST_URL_ENV] ?? "");
482
+ return projectBaseUrl === normalizedBaseUrl ? env[API_KEY_ENV] : "";
483
+ }),
342
484
  cliEnv[API_KEY_ENV]
343
485
  );
344
486
  }
487
+ function getResolvedProjectAuthSource(baseUrl, apiKey, startDir = process.cwd()) {
488
+ const normalizedBaseUrl = normalizeBaseUrl(baseUrl);
489
+ const normalizedApiKey = apiKey.trim();
490
+ if (!normalizedBaseUrl || !normalizedApiKey) return null;
491
+ return loadProjectEnvCandidates(startDir).find(({ env }) => {
492
+ const projectBaseUrl = normalizeBaseUrl(env[HOST_URL_ENV] ?? "");
493
+ return projectBaseUrl === normalizedBaseUrl && (env[API_KEY_ENV] ?? "").trim() === normalizedApiKey;
494
+ }) ?? null;
495
+ }
345
496
  function resolveConfig(options) {
346
497
  const baseUrl = normalizeBaseUrl(
347
498
  options?.baseUrl?.trim() || autoDetectBaseUrl()
@@ -364,6 +515,69 @@ function resolveConfig(options) {
364
515
  maxRetries: options?.maxRetries ?? DEFAULT_MAX_RETRIES
365
516
  };
366
517
  }
518
+ function mergeProjectEnvFile(filePath, values) {
519
+ const existing = parseEnvFile(filePath);
520
+ const merged = { ...existing, ...values };
521
+ const dir = dirname(filePath);
522
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
523
+ ensureProjectEnvIsIgnored(dir);
524
+ const allowedKeys = /* @__PURE__ */ new Set([HOST_URL_ENV, API_KEY_ENV]);
525
+ const lines = Object.entries(merged).filter(([key, value]) => allowedKeys.has(key) && value !== "").map(([key, value]) => `${key}=${value}`);
526
+ writeFileSync(filePath, `${lines.join("\n")}
527
+ `, "utf-8");
528
+ }
529
+ function ensureProjectEnvIsIgnored(dir) {
530
+ const gitignorePath = join(dir, ".gitignore");
531
+ const entry = PROJECT_DEEPLINE_ENV_FILE;
532
+ const existing = existsSync(gitignorePath) ? readFileSync(gitignorePath, "utf-8") : "";
533
+ const alreadyIgnored = existing.split(/\r?\n/).map((line) => line.trim()).some((line) => line === entry || line === `/${entry}`);
534
+ if (alreadyIgnored) return;
535
+ const prefix = existing && !existing.endsWith("\n") ? "\n" : "";
536
+ writeFileSync(gitignorePath, `${existing}${prefix}${entry}
537
+ `, "utf-8");
538
+ }
539
+ function saveProjectDeeplineEnvValues(values, startDir = process.cwd()) {
540
+ const target = resolveProjectPinTarget(startDir);
541
+ if (!target.ok) {
542
+ throw new ConfigError(
543
+ `Cowork project folder is ambiguous. Candidate folders: ${target.candidates.join(
544
+ ", "
545
+ )}. Set CLAUDE_PROJECT_DIR or cd into the intended project folder before running this command.`
546
+ );
547
+ }
548
+ const filePath = join(target.dir, PROJECT_DEEPLINE_ENV_FILE);
549
+ mergeProjectEnvFile(filePath, values);
550
+ return [filePath];
551
+ }
552
+ function resolveProjectPinTarget(startDir = process.cwd()) {
553
+ const nearestFile = findNearestEnvFile(PROJECT_DEEPLINE_ENV_FILE, startDir);
554
+ if (nearestFile && !isInIgnoredCoworkMount(nearestFile)) {
555
+ return { ok: true, dir: dirname(nearestFile), source: "nearest" };
556
+ }
557
+ const coworkCandidates = listCoworkWorkspaceDirCandidates();
558
+ if (coworkCandidates.length === 1) {
559
+ return { ok: true, dir: coworkCandidates[0], source: "cowork" };
560
+ }
561
+ if (coworkCandidates.length > 1) {
562
+ const resolvedStartDir = canonicalPath(startDir);
563
+ const cwdCandidate = coworkCandidates.find((candidate) => {
564
+ const resolvedCandidate = canonicalPath(candidate);
565
+ return resolvedStartDir === resolvedCandidate || resolvedStartDir.startsWith(`${resolvedCandidate}/`);
566
+ });
567
+ if (cwdCandidate) {
568
+ return { ok: true, dir: cwdCandidate, source: "cowork" };
569
+ }
570
+ return {
571
+ ok: false,
572
+ reason: "ambiguous_cowork_project",
573
+ candidates: coworkCandidates
574
+ };
575
+ }
576
+ return { ok: true, dir: resolve(startDir), source: "cwd" };
577
+ }
578
+ function getActiveProjectAuthSource(startDir = process.cwd()) {
579
+ return loadProjectEnvCandidates(startDir)[0] ?? null;
580
+ }
367
581
 
368
582
  // src/http.ts
369
583
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
@@ -390,10 +604,10 @@ var SDK_RELEASE = {
390
604
  // 0.1.108 ships explicit dataset column/tool recompute policy and removes
391
605
  // the SDK enrich generator's one-second stale policy.
392
606
  // 0.1.110 ships authored V2 prebuilts and required top-level play descriptions.
393
- version: "0.1.143",
607
+ version: "0.1.145",
394
608
  apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
395
609
  supportPolicy: {
396
- latest: "0.1.143",
610
+ latest: "0.1.145",
397
611
  minimumSupported: "0.1.53",
398
612
  deprecatedBelow: "0.1.53",
399
613
  commandMinimumSupported: [
@@ -484,7 +698,7 @@ function normalizeAgentRuntime(value) {
484
698
  if (explicit === "gemini_cli") return "gemini";
485
699
  return EXPLICIT_AGENT_RUNTIMES.has(explicit) ? explicit : null;
486
700
  }
487
- function isCoworkLikeSandbox() {
701
+ function isCoworkLikeSandbox2() {
488
702
  const pluginMode = truthyEnv("DEEPLINE_PLUGIN_MODE");
489
703
  const claudeRemote = truthyEnv("CLAUDE_CODE_REMOTE");
490
704
  const projectDir = Boolean(process.env.CLAUDE_PROJECT_DIR?.trim());
@@ -497,7 +711,7 @@ function detectAgentRuntime(options = {}) {
497
711
  const explicit = normalizeAgentRuntime(process.env.DEEPLINE_AGENT_RUNTIME);
498
712
  if (explicit) return explicit;
499
713
  if (process.env.CODEX_THREAD_ID?.trim()) return "codex";
500
- if (options.detectCowork !== false && isCoworkLikeSandbox()) {
714
+ if (options.detectCowork !== false && isCoworkLikeSandbox2()) {
501
715
  return "claude_cowork";
502
716
  }
503
717
  if (process.env.CLAUDECODE?.trim() === "1") return "claude_code";
@@ -963,7 +1177,7 @@ function sleep(ms) {
963
1177
  return new Promise((resolve13) => setTimeout(resolve13, ms));
964
1178
  }
965
1179
  function withCoworkNetworkHint(message) {
966
- if (!isCoworkLikeSandbox() || message.includes(COWORK_NETWORK_HINT)) {
1180
+ if (!isCoworkLikeSandbox2() || message.includes(COWORK_NETWORK_HINT)) {
967
1181
  return message;
968
1182
  }
969
1183
  return `${message}
@@ -3270,6 +3484,9 @@ var DeeplineClient = class {
3270
3484
  if (input2.runId?.trim()) {
3271
3485
  params.set("runId", input2.runId.trim());
3272
3486
  }
3487
+ if (input2.rowMode === "all") {
3488
+ params.set("rowMode", "all");
3489
+ }
3273
3490
  return await this.http.get(
3274
3491
  `/api/v2/plays/${encodeURIComponent(input2.playName)}/sheet?${params.toString()}`
3275
3492
  );
@@ -7017,9 +7234,9 @@ import { createHash as createHash2 } from "crypto";
7017
7234
  import {
7018
7235
  existsSync as existsSync6,
7019
7236
  readFileSync as readFileSync6,
7020
- readdirSync,
7021
- realpathSync,
7022
- statSync as statSync2,
7237
+ readdirSync as readdirSync2,
7238
+ realpathSync as realpathSync2,
7239
+ statSync as statSync3,
7023
7240
  writeFileSync as writeFileSync8
7024
7241
  } from "fs";
7025
7242
  import { basename, dirname as dirname6, join as join5, resolve as resolve7 } from "path";
@@ -7030,7 +7247,7 @@ import {
7030
7247
  closeSync,
7031
7248
  openSync,
7032
7249
  readSync,
7033
- statSync,
7250
+ statSync as statSync2,
7034
7251
  writeFileSync as writeFileSync7
7035
7252
  } from "fs";
7036
7253
  import { isAbsolute, relative, resolve as resolve6 } from "path";
@@ -7463,7 +7680,7 @@ function inferCsvColumnSpecs(headers, rows) {
7463
7680
  }
7464
7681
  function readCsvSample(csvPath) {
7465
7682
  const resolvedPath = resolve6(csvPath);
7466
- const size = statSync(resolvedPath).size;
7683
+ const size = statSync2(resolvedPath).size;
7467
7684
  const fd = openSync(resolvedPath, "r");
7468
7685
  const byteLength = Math.min(size, CSV_HEADER_SAMPLE_BYTES);
7469
7686
  const buffer = Buffer.alloc(byteLength);
@@ -9499,7 +9716,7 @@ function preflightLocalFileInputs(runtimeInput) {
9499
9716
  }
9500
9717
  let stat2;
9501
9718
  try {
9502
- stat2 = statSync2(absolutePath);
9719
+ stat2 = statSync3(absolutePath);
9503
9720
  } catch (error) {
9504
9721
  throw new DeeplineError(
9505
9722
  `Input ${ref.inputPath} references a local file that is not readable: ${ref.value} (${error instanceof Error ? error.message : String(error)}). No run was created.`,
@@ -9651,7 +9868,7 @@ function stageFile(logicalPath, absolutePath) {
9651
9868
  }
9652
9869
  function normalizePlayPath(filePath) {
9653
9870
  try {
9654
- return realpathSync.native(resolve7(filePath));
9871
+ return realpathSync2.native(resolve7(filePath));
9655
9872
  } catch {
9656
9873
  return resolve7(filePath);
9657
9874
  }
@@ -11749,7 +11966,8 @@ async function fetchBackingDatasetRows(input2) {
11749
11966
  tableNamespace,
11750
11967
  runId: input2.status.runId,
11751
11968
  limit: RUN_EXPORT_PAGE_SIZE,
11752
- offset
11969
+ offset,
11970
+ rowMode: "all"
11753
11971
  });
11754
11972
  sheetRows.push(...page.rows);
11755
11973
  const summaryTotal = page.summary?.stats?.total;
@@ -12913,7 +13131,7 @@ async function handlePlayRun(args) {
12913
13131
  if (existsSync6(dir)) {
12914
13132
  const base = basename(resolved);
12915
13133
  try {
12916
- const siblings = readdirSync(dir).filter(
13134
+ const siblings = readdirSync2(dir).filter(
12917
13135
  (f) => f.includes(base.replace(/\.(play\.)?ts$/, "")) || f.endsWith(".play.ts")
12918
13136
  );
12919
13137
  if (siblings.length > 0) {
@@ -16089,8 +16307,10 @@ function helperSource() {
16089
16307
 
16090
16308
  // src/cli/commands/enrich.ts
16091
16309
  var ENRICH_EXPORT_PAGE_SIZE = 5e3;
16310
+ var ENRICH_AUTO_BATCH_ROWS = 250;
16092
16311
  var EXIT_SERVER2 = 5;
16093
16312
  var ENRICH_DEBUG_T0 = Date.now();
16313
+ var GENERATED_ENRICH_ROWS_TABLE_NAMESPACE = "deepline_enrich_rows";
16094
16314
  var PLAN_SHAPING_OPTION_NAMES = [
16095
16315
  "with",
16096
16316
  "withWaterfall",
@@ -16754,7 +16974,12 @@ async function runGeneratedEnrichPlay(runArgs, options = {}) {
16754
16974
  async function writeOutputCsv(outputPath, status, options) {
16755
16975
  let rowsInfo = extractCanonicalRowsInfo(status);
16756
16976
  if (!rowsInfo) {
16757
- throw new Error("The generated play did not return row-shaped output.");
16977
+ rowsInfo = fallbackRowsInfoForGeneratedEnrichExport(status, options);
16978
+ }
16979
+ if (!rowsInfo) {
16980
+ throw new Error(
16981
+ "The generated play did not return row-shaped output, and no durable enrich rows were available to export."
16982
+ );
16758
16983
  }
16759
16984
  if (options?.client) {
16760
16985
  rowsInfo = await fetchBackingRowsForCsvExport({
@@ -16817,6 +17042,98 @@ function extractPlayName2(status) {
16817
17042
  }
16818
17043
  return null;
16819
17044
  }
17045
+ function selectedSourceCsvRange(sourceCsvPath, rows) {
17046
+ const sourceRows = readCsvRows(sourceCsvPath).length;
17047
+ if (sourceRows === 0) {
17048
+ return { start: 0, end: -1, count: 0, sourceRows };
17049
+ }
17050
+ const start = Math.max(0, rows?.rowStart ?? 0);
17051
+ if (start >= sourceRows) {
17052
+ return { start, end: start - 1, count: 0, sourceRows };
17053
+ }
17054
+ const maxEnd = sourceRows - 1;
17055
+ const end = rows?.rowEnd === null || rows?.rowEnd === void 0 ? maxEnd : Math.min(maxEnd, rows.rowEnd);
17056
+ return {
17057
+ start,
17058
+ end,
17059
+ count: Math.max(0, end - start + 1),
17060
+ sourceRows
17061
+ };
17062
+ }
17063
+ function selectedSourceCsvRowCount(options) {
17064
+ if (!options?.sourceCsvPath) {
17065
+ return null;
17066
+ }
17067
+ return selectedSourceCsvRange(options.sourceCsvPath, options.rows).count;
17068
+ }
17069
+ function collectStringFields(value, key, output2, depth = 0) {
17070
+ if (depth > 12 || !value || typeof value !== "object") {
17071
+ return;
17072
+ }
17073
+ if (Array.isArray(value)) {
17074
+ for (const item of value.slice(0, 50)) {
17075
+ collectStringFields(item, key, output2, depth + 1);
17076
+ }
17077
+ return;
17078
+ }
17079
+ const record = value;
17080
+ const direct = record[key];
17081
+ if (typeof direct === "string" && direct.trim()) {
17082
+ output2.add(direct.trim());
17083
+ }
17084
+ for (const child of Object.values(record)) {
17085
+ collectStringFields(child, key, output2, depth + 1);
17086
+ }
17087
+ }
17088
+ function fallbackRowsInfoForGeneratedEnrichExport(status, options) {
17089
+ if (!extractRunId(status) || !extractPlayName2(status)) {
17090
+ return null;
17091
+ }
17092
+ const totalRows = selectedSourceCsvRowCount(options);
17093
+ if (totalRows === null) {
17094
+ return null;
17095
+ }
17096
+ const tableNamespaces = /* @__PURE__ */ new Set();
17097
+ collectStringFields(status, "tableNamespace", tableNamespaces);
17098
+ collectStringFields(status, "artifactTableNamespace", tableNamespaces);
17099
+ const tableNamespace = tableNamespaces.values().next().value ?? GENERATED_ENRICH_ROWS_TABLE_NAMESPACE;
17100
+ return {
17101
+ rows: [],
17102
+ totalRows,
17103
+ columns: [],
17104
+ columnsExplicit: false,
17105
+ complete: false,
17106
+ source: tableNamespace,
17107
+ tableNamespace
17108
+ };
17109
+ }
17110
+ function firstCollectedStringField(value, key) {
17111
+ const fields = /* @__PURE__ */ new Set();
17112
+ collectStringFields(value, key, fields);
17113
+ return fields.values().next().value ?? null;
17114
+ }
17115
+ function emitPlainBatchRunFailure(input2) {
17116
+ process.stderr.write(
17117
+ `Batch ${input2.chunkIndex + 1}/${input2.chunkCount} failed for rows ${input2.rows.rowStart}:${input2.rows.rowEnd}.
17118
+ `
17119
+ );
17120
+ const runId = extractRunId(input2.status);
17121
+ const error = firstCollectedStringField(input2.status, "error") ?? firstCollectedStringField(input2.status, "message");
17122
+ if (runId) {
17123
+ process.stderr.write(`Run id: ${runId}
17124
+ `);
17125
+ }
17126
+ if (error) {
17127
+ process.stderr.write(`Error: ${error}
17128
+ `);
17129
+ }
17130
+ if (runId) {
17131
+ process.stderr.write(
17132
+ `Inspect run output: deepline runs get ${runId} --full --json
17133
+ `
17134
+ );
17135
+ }
17136
+ }
16820
17137
  function exportableSheetRow2(row) {
16821
17138
  if (!row || typeof row !== "object" || Array.isArray(row)) {
16822
17139
  return null;
@@ -17184,7 +17501,8 @@ async function fetchBackingRowsForCsvExport(input2) {
17184
17501
  tableNamespace,
17185
17502
  runId,
17186
17503
  limit: ENRICH_EXPORT_PAGE_SIZE,
17187
- offset
17504
+ offset,
17505
+ rowMode: "all"
17188
17506
  });
17189
17507
  sheetRows.push(...page.rows);
17190
17508
  const summaryTotal = page.summary?.stats?.total;
@@ -17552,41 +17870,177 @@ function registerEnrichCommand(program) {
17552
17870
  const tempPlay = join6(tempDir, "deepline-enrich.play.ts");
17553
17871
  try {
17554
17872
  await writeFile3(tempPlay, playSource, "utf8");
17555
- const runtimeInput = {
17556
- file: resolve8(sourceCsvPath),
17557
- ...rows.rowStart !== null ? { rowStart: rows.rowStart } : {},
17558
- ...rows.rowEnd !== null ? { rowEnd: rows.rowEnd } : {}
17873
+ const runOne = async (input2) => {
17874
+ const runtimeInput = {
17875
+ file: resolve8(input2.sourceCsvPath),
17876
+ ...input2.rows.rowStart !== null ? { rowStart: input2.rows.rowStart } : {},
17877
+ ...input2.rows.rowEnd !== null ? { rowEnd: input2.rows.rowEnd } : {}
17878
+ };
17879
+ const runArgs = [
17880
+ "--file",
17881
+ tempPlay,
17882
+ "--input",
17883
+ JSON.stringify(runtimeInput),
17884
+ "--watch"
17885
+ ];
17886
+ if (options.profile) {
17887
+ runArgs.push("--profile", options.profile);
17888
+ }
17889
+ if (options.noOpen || input2.suppressOpen) {
17890
+ runArgs.push("--no-open");
17891
+ }
17892
+ if (input2.json) {
17893
+ runArgs.push("--json");
17894
+ } else {
17895
+ runArgs.push("--logs");
17896
+ }
17897
+ const timeoutSeconds = options.timeout ? Number.parseInt(options.timeout, 10) : null;
17898
+ if (timeoutSeconds !== null && Number.isFinite(timeoutSeconds) && timeoutSeconds > 0) {
17899
+ runArgs.push("--tail-timeout-ms", String(timeoutSeconds * 1e3));
17900
+ }
17901
+ const captured2 = await runGeneratedEnrichPlay(runArgs, {
17902
+ passthroughStdout: input2.passthroughStdout
17903
+ });
17904
+ const status2 = input2.json ? parseJsonOutput(captured2.stdout) : await resolveWatchedGeneratedPlayStatus({
17905
+ client: client2,
17906
+ stdout: captured2.stdout,
17907
+ exitCode: captured2.result
17908
+ });
17909
+ const exportResult2 = captured2.result === 0 && outputPath ? await writeOutputCsv(outputPath, status2, {
17910
+ client: client2,
17911
+ config,
17912
+ sourceCsvPath: input2.sourceCsvPath,
17913
+ rows: input2.rows,
17914
+ inPlace: Boolean(options.inPlace)
17915
+ }) : null;
17916
+ return { captured: captured2, status: status2, exportResult: exportResult2 };
17559
17917
  };
17560
- const runArgs = [
17561
- "--file",
17562
- tempPlay,
17563
- "--input",
17564
- JSON.stringify(runtimeInput),
17565
- "--watch"
17566
- ];
17567
- if (options.profile) {
17568
- runArgs.push("--profile", options.profile);
17569
- }
17570
- if (options.noOpen) {
17571
- runArgs.push("--no-open");
17572
- }
17573
- if (options.json) {
17574
- runArgs.push("--json");
17575
- } else {
17576
- runArgs.push("--logs");
17577
- }
17578
- const timeoutSeconds = options.timeout ? Number.parseInt(options.timeout, 10) : null;
17579
- if (timeoutSeconds !== null && Number.isFinite(timeoutSeconds) && timeoutSeconds > 0) {
17580
- runArgs.push("--tail-timeout-ms", String(timeoutSeconds * 1e3));
17918
+ const selectedRange = selectedSourceCsvRange(sourceCsvPath, rows);
17919
+ if (outputPath && selectedRange.count > ENRICH_AUTO_BATCH_ROWS) {
17920
+ const chunkCount = Math.ceil(
17921
+ selectedRange.count / ENRICH_AUTO_BATCH_ROWS
17922
+ );
17923
+ if (!options.json) {
17924
+ process.stderr.write(
17925
+ `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 ${resolve8(outputPath)}.
17926
+ `
17927
+ );
17928
+ }
17929
+ let workingSourceCsvPath = sourceCsvPath;
17930
+ let lastStatus = null;
17931
+ let finalExportResult = null;
17932
+ let totalEnrichedRows = 0;
17933
+ const batchFailureRows = [];
17934
+ for (let chunkStart = selectedRange.start, chunkIndex = 0; chunkStart <= selectedRange.end; chunkStart += ENRICH_AUTO_BATCH_ROWS, chunkIndex += 1) {
17935
+ const chunkRows = {
17936
+ rowStart: chunkStart,
17937
+ rowEnd: Math.min(
17938
+ selectedRange.end,
17939
+ chunkStart + ENRICH_AUTO_BATCH_ROWS - 1
17940
+ )
17941
+ };
17942
+ if (!options.json) {
17943
+ process.stderr.write(
17944
+ `Batch ${chunkIndex + 1}/${chunkCount}: rows ${chunkRows.rowStart}:${chunkRows.rowEnd}
17945
+ `
17946
+ );
17947
+ }
17948
+ const chunk = await runOne({
17949
+ sourceCsvPath: workingSourceCsvPath,
17950
+ rows: chunkRows,
17951
+ json: true,
17952
+ passthroughStdout: false,
17953
+ suppressOpen: true
17954
+ });
17955
+ lastStatus = chunk.status;
17956
+ if (chunk.captured.result !== 0) {
17957
+ if (options.json) {
17958
+ printJson({
17959
+ ok: false,
17960
+ batch: {
17961
+ chunk: chunkIndex + 1,
17962
+ chunks: chunkCount,
17963
+ rows: chunkRows
17964
+ },
17965
+ result: chunk.status
17966
+ });
17967
+ } else {
17968
+ emitPlainBatchRunFailure({
17969
+ chunkIndex,
17970
+ chunkCount,
17971
+ rows: chunkRows,
17972
+ status: chunk.status
17973
+ });
17974
+ }
17975
+ process.exitCode = chunk.captured.result;
17976
+ return;
17977
+ }
17978
+ if (chunk.exportResult) {
17979
+ finalExportResult = chunk.exportResult;
17980
+ totalEnrichedRows += chunk.exportResult.enrichedRows;
17981
+ batchFailureRows.push(...chunk.exportResult.enrichedDataRows);
17982
+ workingSourceCsvPath = outputPath;
17983
+ }
17984
+ }
17985
+ const outputRows = readCsvRows(outputPath);
17986
+ const failureReport2 = await maybeEmitEnrichFailureReport({
17987
+ config,
17988
+ rows: batchFailureRows,
17989
+ rowRange: {
17990
+ rowStart: selectedRange.start,
17991
+ rowEnd: selectedRange.end
17992
+ },
17993
+ client: client2,
17994
+ outputPath
17995
+ });
17996
+ if (options.json) {
17997
+ const run = rewriteEnrichJsonStatus({
17998
+ status: lastStatus,
17999
+ config,
18000
+ forceAliases,
18001
+ output: finalExportResult ? {
18002
+ ...finalExportResult,
18003
+ sourceCsvRows: selectedRange.sourceRows,
18004
+ selectedRows: selectedRange.count,
18005
+ enrichedRows: totalEnrichedRows,
18006
+ rows: outputRows.length,
18007
+ enrichedDataRows: outputRows
18008
+ } : null,
18009
+ failureReport: failureReport2
18010
+ });
18011
+ printJson({
18012
+ ok: !failureReport2,
18013
+ run,
18014
+ batch: {
18015
+ chunks: chunkCount,
18016
+ chunkRows: ENRICH_AUTO_BATCH_ROWS,
18017
+ selectedRows: selectedRange.count
18018
+ },
18019
+ output: finalExportResult ? {
18020
+ sourceCsvRows: selectedRange.sourceRows,
18021
+ selectedRows: selectedRange.count,
18022
+ enrichedRows: totalEnrichedRows,
18023
+ path: finalExportResult.path
18024
+ } : null,
18025
+ ...failureReport2 ? {
18026
+ failure_report: {
18027
+ path: failureReport2.path,
18028
+ jobs: failureReport2.jobs.length
18029
+ }
18030
+ } : {}
18031
+ });
18032
+ }
18033
+ if (failureReport2) {
18034
+ process.exitCode = EXIT_SERVER2;
18035
+ }
18036
+ return;
17581
18037
  }
17582
- const captured = await runGeneratedEnrichPlay(runArgs, {
18038
+ const { captured, status, exportResult } = await runOne({
18039
+ sourceCsvPath,
18040
+ rows,
18041
+ json: Boolean(options.json),
17583
18042
  passthroughStdout: !options.json
17584
18043
  });
17585
- const status = options.json ? parseJsonOutput(captured.stdout) : await resolveWatchedGeneratedPlayStatus({
17586
- client: client2,
17587
- stdout: captured.stdout,
17588
- exitCode: captured.result
17589
- });
17590
18044
  if (captured.result !== 0) {
17591
18045
  if (options.json) {
17592
18046
  printJson({
@@ -17596,13 +18050,6 @@ function registerEnrichCommand(program) {
17596
18050
  process.exitCode = captured.result;
17597
18051
  return;
17598
18052
  }
17599
- const exportResult = outputPath ? await writeOutputCsv(outputPath, status, {
17600
- client: client2,
17601
- config,
17602
- sourceCsvPath,
17603
- rows,
17604
- inPlace: Boolean(options.inPlace)
17605
- }) : null;
17606
18053
  const rowsForFailureReport = exportResult?.enrichedDataRows ?? extractCanonicalRowsInfo(status)?.rows ?? [];
17607
18054
  if (options.json) {
17608
18055
  const failureReport2 = await maybeEmitEnrichFailureReport({
@@ -17718,9 +18165,9 @@ Examples:
17718
18165
  import {
17719
18166
  existsSync as existsSync7,
17720
18167
  mkdirSync as mkdirSync5,
17721
- readdirSync as readdirSync2,
18168
+ readdirSync as readdirSync3,
17722
18169
  readFileSync as readFileSync7,
17723
- statSync as statSync3,
18170
+ statSync as statSync4,
17724
18171
  writeFileSync as writeFileSync9
17725
18172
  } from "fs";
17726
18173
  import { homedir as homedir7, platform } from "os";
@@ -17805,7 +18252,7 @@ function listSessionFiles(agent) {
17805
18252
  }
17806
18253
  function readDirectoryNames(dir) {
17807
18254
  try {
17808
- return readdirSync2(dir);
18255
+ return readdirSync3(dir);
17809
18256
  } catch {
17810
18257
  return [];
17811
18258
  }
@@ -17816,7 +18263,7 @@ function listJsonlFilesRecursive(root, maxDepth) {
17816
18263
  if (depth > maxDepth) return;
17817
18264
  let entries;
17818
18265
  try {
17819
- entries = readdirSync2(dir, { withFileTypes: true });
18266
+ entries = readdirSync3(dir, { withFileTypes: true });
17820
18267
  } catch {
17821
18268
  return;
17822
18269
  }
@@ -17834,7 +18281,7 @@ function listJsonlFilesRecursive(root, maxDepth) {
17834
18281
  }
17835
18282
  function statIfReadable(filePath) {
17836
18283
  try {
17837
- return statSync3(filePath);
18284
+ return statSync4(filePath);
17838
18285
  } catch {
17839
18286
  return null;
17840
18287
  }
@@ -18527,6 +18974,15 @@ Examples:
18527
18974
  async function fetchOrganizations(http, apiKey) {
18528
18975
  return http.post("/api/v2/auth/cli/organizations", { api_key: apiKey });
18529
18976
  }
18977
+ function normalizeAuthScope(value) {
18978
+ if (!value) return "auto";
18979
+ if (value === "auto" || value === "folder" || value === "global") {
18980
+ return value;
18981
+ }
18982
+ throw new Error(
18983
+ `Invalid --auth-scope "${value}". Expected one of: auto, folder, global.`
18984
+ );
18985
+ }
18530
18986
  function orgListLines(orgs) {
18531
18987
  return orgs.map((org, index) => {
18532
18988
  const current = org.is_current ? " (current)" : "";
@@ -18534,6 +18990,90 @@ function orgListLines(orgs) {
18534
18990
  return `${index + 1}. ${org.name}${role}${current}`;
18535
18991
  });
18536
18992
  }
18993
+ function redactApiKey(value) {
18994
+ if (!value) return null;
18995
+ if (value.length <= 10) return `${value.slice(0, 3)}...`;
18996
+ return `${value.slice(0, 8)}...${value.slice(-4)}`;
18997
+ }
18998
+ function processEnvValue(name) {
18999
+ return process.env[name]?.trim() ?? "";
19000
+ }
19001
+ function resolveOrgSwitchAuthTarget(scope, config) {
19002
+ const activeProject = getResolvedProjectAuthSource(
19003
+ config.baseUrl,
19004
+ config.apiKey
19005
+ );
19006
+ const folderTarget = resolveProjectPinTarget();
19007
+ const globalOverrideWarning = activeProject && scope === "global" ? [
19008
+ `Folder auth in ${activeProject.filePath} overrides global auth for commands run here.`
19009
+ ] : [];
19010
+ if (scope === "folder") {
19011
+ if (!folderTarget.ok) {
19012
+ throw new Error(
19013
+ `Cowork project folder is ambiguous. Candidate folders: ${folderTarget.candidates.join(
19014
+ ", "
19015
+ )}. Set CLAUDE_PROJECT_DIR or cd into the intended project folder before running this command.`
19016
+ );
19017
+ }
19018
+ return {
19019
+ kind: "folder",
19020
+ requested_scope: scope,
19021
+ effective_scope: "folder",
19022
+ reason: "explicit_folder",
19023
+ source: folderTarget.source,
19024
+ warnings: []
19025
+ };
19026
+ }
19027
+ if (scope === "global") {
19028
+ return {
19029
+ kind: "global",
19030
+ requested_scope: scope,
19031
+ effective_scope: "global",
19032
+ reason: "explicit_global",
19033
+ warnings: globalOverrideWarning
19034
+ };
19035
+ }
19036
+ if (activeProject) {
19037
+ return {
19038
+ kind: "folder",
19039
+ requested_scope: scope,
19040
+ effective_scope: "folder",
19041
+ reason: "existing_folder_auth",
19042
+ source: activeProject.source,
19043
+ warnings: []
19044
+ };
19045
+ }
19046
+ if (folderTarget.ok && folderTarget.source === "cowork") {
19047
+ return {
19048
+ kind: "folder",
19049
+ requested_scope: scope,
19050
+ effective_scope: "folder",
19051
+ reason: "detected_cowork_project",
19052
+ source: "cowork",
19053
+ warnings: []
19054
+ };
19055
+ }
19056
+ if (!folderTarget.ok) {
19057
+ return {
19058
+ kind: "global",
19059
+ requested_scope: scope,
19060
+ effective_scope: "global",
19061
+ reason: "ambiguous_cowork_fell_back_global",
19062
+ warnings: [
19063
+ `Cowork project folder is ambiguous, so global auth was updated. Candidate folders: ${folderTarget.candidates.join(
19064
+ ", "
19065
+ )}. Set CLAUDE_PROJECT_DIR or cd into the intended project folder to update folder auth.`
19066
+ ]
19067
+ };
19068
+ }
19069
+ return {
19070
+ kind: "global",
19071
+ requested_scope: scope,
19072
+ effective_scope: "global",
19073
+ reason: "default_global",
19074
+ warnings: []
19075
+ };
19076
+ }
18537
19077
  async function handleOrgList(options) {
18538
19078
  const config = resolveConfig();
18539
19079
  const http = new HttpClient(config);
@@ -18553,7 +19093,89 @@ async function handleOrgList(options) {
18553
19093
  { json: options.json }
18554
19094
  );
18555
19095
  }
19096
+ async function handleOrgStatus(options) {
19097
+ const config = resolveConfig();
19098
+ const http = new HttpClient(config);
19099
+ const payload = await fetchOrganizations(http, config.apiKey);
19100
+ const current = payload.organizations.find((org) => org.is_current) ?? payload.organizations.find((org) => org.org_id === payload.current_org_id) ?? null;
19101
+ const projectCandidate = getActiveProjectAuthSource();
19102
+ const activeProject = getResolvedProjectAuthSource(
19103
+ config.baseUrl,
19104
+ config.apiKey
19105
+ );
19106
+ const folderTarget = resolveProjectPinTarget();
19107
+ const hostPath = hostEnvFilePath(config.baseUrl);
19108
+ const envApiKey = processEnvValue(API_KEY_ENV);
19109
+ const envHostUrl = processEnvValue(HOST_URL_ENV);
19110
+ const authSource = envApiKey ? {
19111
+ scope: "env",
19112
+ source: "process",
19113
+ path: null,
19114
+ api_key: redactApiKey(envApiKey),
19115
+ host: envHostUrl || null,
19116
+ overrides_global: true,
19117
+ overrides_folder: Boolean(projectCandidate)
19118
+ } : activeProject ? {
19119
+ scope: "folder",
19120
+ source: activeProject.source,
19121
+ path: activeProject.filePath,
19122
+ api_key: redactApiKey(activeProject.env.DEEPLINE_API_KEY),
19123
+ overrides_global: true
19124
+ } : {
19125
+ scope: "global",
19126
+ source: "host",
19127
+ path: hostPath,
19128
+ api_key: redactApiKey(config.apiKey),
19129
+ overrides_global: false
19130
+ };
19131
+ const folderTargetPayload = folderTarget.ok ? {
19132
+ ok: true,
19133
+ source: folderTarget.source,
19134
+ dir: folderTarget.dir,
19135
+ env_path: `${folderTarget.dir}/.env.deepline`
19136
+ } : {
19137
+ ok: false,
19138
+ reason: folderTarget.reason,
19139
+ candidates: folderTarget.candidates
19140
+ };
19141
+ const lines = [
19142
+ `Organization: ${current?.name ?? "(unknown)"}`,
19143
+ `Host: ${config.baseUrl}`,
19144
+ `Auth scope: ${authSource.scope}`
19145
+ ];
19146
+ if (authSource.path) {
19147
+ lines.push(`Auth file: ${authSource.path}`);
19148
+ } else {
19149
+ lines.push(`Auth source: ${API_KEY_ENV} process environment`);
19150
+ }
19151
+ if (envApiKey) {
19152
+ lines.push(`${API_KEY_ENV} overrides saved auth for this process.`);
19153
+ } else if (activeProject) {
19154
+ lines.push("Global auth is overridden in this folder.");
19155
+ }
19156
+ printCommandEnvelope(
19157
+ {
19158
+ ok: true,
19159
+ host: config.baseUrl,
19160
+ organization: current,
19161
+ current_org_id: payload.current_org_id,
19162
+ auth_source: authSource,
19163
+ host_env_path: hostPath,
19164
+ folder_target: folderTargetPayload,
19165
+ next: {
19166
+ set_auto: "deepline org set <org>",
19167
+ set_folder: "deepline org set <org> --auth-scope folder",
19168
+ set_global: "deepline org set <org> --auth-scope global"
19169
+ },
19170
+ render: {
19171
+ sections: [{ title: "org status", lines }]
19172
+ }
19173
+ },
19174
+ { json: options.json }
19175
+ );
19176
+ }
18556
19177
  async function handleOrgSwitch(selection, options) {
19178
+ const authScope = normalizeAuthScope(options.authScope);
18557
19179
  const config = resolveConfig();
18558
19180
  const http = new HttpClient(config);
18559
19181
  const payload = await fetchOrganizations(http, config.apiKey);
@@ -18561,7 +19183,10 @@ async function handleOrgSwitch(selection, options) {
18561
19183
  printCommandEnvelope(
18562
19184
  {
18563
19185
  ...payload,
18564
- next: { switch: "deepline org switch <number>" },
19186
+ next: { set: "deepline org set <number>" },
19187
+ deprecated_command: options.deprecatedSwitch ? "org switch" : null,
19188
+ replacement_command: options.deprecatedSwitch ? "deepline org set" : null,
19189
+ warnings: options.deprecatedSwitch ? ["org switch is deprecated; use org set."] : [],
18565
19190
  render: {
18566
19191
  sections: [
18567
19192
  {
@@ -18569,7 +19194,7 @@ async function handleOrgSwitch(selection, options) {
18569
19194
  lines: orgListLines(payload.organizations)
18570
19195
  }
18571
19196
  ],
18572
- actions: [{ label: "Run", command: "deepline org switch <number>" }]
19197
+ actions: [{ label: "Run", command: "deepline org set <number>" }]
18573
19198
  }
18574
19199
  },
18575
19200
  { json: options.json }
@@ -18592,16 +19217,56 @@ async function handleOrgSwitch(selection, options) {
18592
19217
  if (!target) {
18593
19218
  throw new Error("Could not resolve the selected organization.");
18594
19219
  }
19220
+ const authTarget = resolveOrgSwitchAuthTarget(authScope, config);
18595
19221
  if (target.is_current) {
19222
+ let project_env_paths2 = [];
19223
+ if (authTarget.kind === "folder") {
19224
+ project_env_paths2 = saveProjectDeeplineEnvValues({
19225
+ DEEPLINE_HOST_URL: config.baseUrl,
19226
+ DEEPLINE_API_KEY: config.apiKey
19227
+ });
19228
+ } else {
19229
+ saveHostEnvValues(config.baseUrl, {
19230
+ DEEPLINE_HOST_URL: config.baseUrl,
19231
+ DEEPLINE_API_KEY: config.apiKey
19232
+ });
19233
+ }
19234
+ const renderLines2 = [`Already on ${target.name}.`];
19235
+ for (const projectPath of project_env_paths2) {
19236
+ renderLines2.push(`Saved folder auth in ${projectPath}`);
19237
+ }
19238
+ if (authTarget.kind === "global") {
19239
+ renderLines2.push(`Saved global auth in ${hostEnvFilePath(config.baseUrl)}`);
19240
+ }
19241
+ renderLines2.push(
19242
+ `Scope: ${authTarget.requested_scope} -> ${authTarget.effective_scope} (${authTarget.reason})`
19243
+ );
19244
+ if (options.deprecatedSwitch) {
19245
+ renderLines2.push("Warning: org switch is deprecated; use org set.");
19246
+ }
19247
+ for (const warning of authTarget.warnings) {
19248
+ renderLines2.push(`Warning: ${warning}`);
19249
+ }
19250
+ const warnings2 = [
19251
+ ...options.deprecatedSwitch ? ["org switch is deprecated; use org set."] : [],
19252
+ ...authTarget.warnings
19253
+ ];
18596
19254
  printCommandEnvelope(
18597
19255
  {
18598
19256
  ok: true,
18599
19257
  unchanged: true,
18600
19258
  organization: target,
19259
+ requested_auth_scope: authTarget.requested_scope,
19260
+ effective_auth_scope: authTarget.effective_scope,
19261
+ auth_scope_reason: authTarget.reason,
19262
+ auth_scope: authTarget.effective_scope,
19263
+ host_env_path: authTarget.kind === "global" ? hostEnvFilePath(config.baseUrl) : null,
19264
+ project_env_paths: project_env_paths2,
19265
+ deprecated_command: options.deprecatedSwitch ? "org switch" : null,
19266
+ replacement_command: options.deprecatedSwitch ? "deepline org set" : null,
19267
+ warnings: warnings2,
18601
19268
  render: {
18602
- sections: [
18603
- { title: "org switch", lines: [`Already on ${target.name}.`] }
18604
- ]
19269
+ sections: [{ title: "org set", lines: renderLines2 }]
18605
19270
  }
18606
19271
  },
18607
19272
  { json: options.json }
@@ -18612,26 +19277,61 @@ async function handleOrgSwitch(selection, options) {
18612
19277
  api_key: config.apiKey,
18613
19278
  org_id: target.org_id
18614
19279
  });
18615
- saveHostEnvValues(config.baseUrl, {
18616
- DEEPLINE_API_KEY: switched.api_key,
18617
- DEEPLINE_ACTIVE_ORG_ID: switched.org_id,
18618
- DEEPLINE_ACTIVE_ORG_NAME: switched.org_name
18619
- });
19280
+ let project_env_paths = [];
19281
+ if (authTarget.kind === "folder") {
19282
+ project_env_paths = saveProjectDeeplineEnvValues({
19283
+ DEEPLINE_HOST_URL: config.baseUrl,
19284
+ DEEPLINE_API_KEY: switched.api_key
19285
+ });
19286
+ } else {
19287
+ saveHostEnvValues(config.baseUrl, {
19288
+ DEEPLINE_HOST_URL: config.baseUrl,
19289
+ DEEPLINE_API_KEY: switched.api_key,
19290
+ DEEPLINE_ACTIVE_ORG_ID: switched.org_id,
19291
+ DEEPLINE_ACTIVE_ORG_NAME: switched.org_name
19292
+ });
19293
+ }
18620
19294
  const { api_key: _apiKey, ...publicSwitched } = switched;
19295
+ const renderLines = [`Switched to ${switched.org_name}.`];
19296
+ if (authTarget.kind === "folder") {
19297
+ for (const projectPath of project_env_paths) {
19298
+ renderLines.push(`Saved folder auth in ${projectPath}`);
19299
+ }
19300
+ } else {
19301
+ renderLines.push(`Saved global auth in ${hostEnvFilePath(config.baseUrl)}`);
19302
+ }
19303
+ renderLines.push(
19304
+ `Scope: ${authTarget.requested_scope} -> ${authTarget.effective_scope} (${authTarget.reason})`
19305
+ );
19306
+ if (options.deprecatedSwitch) {
19307
+ renderLines.push("Warning: org switch is deprecated; use org set.");
19308
+ }
19309
+ for (const warning of authTarget.warnings) {
19310
+ renderLines.push(`Warning: ${warning}`);
19311
+ }
19312
+ const warnings = [
19313
+ ...options.deprecatedSwitch ? ["org switch is deprecated; use org set."] : [],
19314
+ ...authTarget.warnings
19315
+ ];
18621
19316
  printCommandEnvelope(
18622
19317
  {
18623
19318
  ok: true,
18624
- host_env_path: hostEnvFilePath(config.baseUrl),
19319
+ host_env_path: authTarget.kind === "global" ? hostEnvFilePath(config.baseUrl) : null,
19320
+ project_env_paths,
18625
19321
  ...publicSwitched,
18626
19322
  api_key_saved: true,
19323
+ requested_auth_scope: authTarget.requested_scope,
19324
+ effective_auth_scope: authTarget.effective_scope,
19325
+ auth_scope_reason: authTarget.reason,
19326
+ auth_scope: authTarget.effective_scope,
19327
+ deprecated_command: options.deprecatedSwitch ? "org switch" : null,
19328
+ replacement_command: options.deprecatedSwitch ? "deepline org set" : null,
19329
+ warnings,
18627
19330
  render: {
18628
19331
  sections: [
18629
19332
  {
18630
- title: "org switch",
18631
- lines: [
18632
- `Switched to ${switched.org_name}.`,
18633
- `Saved host auth in ${hostEnvFilePath(config.baseUrl)}`
18634
- ]
19333
+ title: "org set",
19334
+ lines: renderLines
18635
19335
  }
18636
19336
  ]
18637
19337
  }
@@ -18647,6 +19347,7 @@ async function handleOrgCreate(name, options) {
18647
19347
  name
18648
19348
  });
18649
19349
  saveHostEnvValues(config.baseUrl, {
19350
+ DEEPLINE_HOST_URL: config.baseUrl,
18650
19351
  DEEPLINE_API_KEY: created.api_key,
18651
19352
  DEEPLINE_ACTIVE_ORG_ID: created.org_id,
18652
19353
  DEEPLINE_ACTIVE_ORG_NAME: created.org_name
@@ -18676,18 +19377,41 @@ async function handleOrgCreate(name, options) {
18676
19377
  );
18677
19378
  }
18678
19379
  function registerOrgCommands(program) {
18679
- const org = program.command("org").description("List, create, and switch organizations.").addHelpText(
19380
+ const org = program.command("org").description("List, create, and set organizations.").addHelpText(
18680
19381
  "after",
18681
19382
  `
18682
19383
  Notes:
18683
- Organizations are workspaces. Switching organizations mutates the saved host
18684
- auth file so later CLI commands target the selected workspace.
19384
+ Organizations are workspaces. Auth is stored as an API key scoped to one
19385
+ organization, so setting an org saves a key for the selected auth scope.
19386
+
19387
+ Auth scopes:
19388
+ auto Update the folder pin that already controls this command; in
19389
+ Cowork, write the mounted project folder; otherwise update global
19390
+ host auth.
19391
+ folder Write .env.deepline in the current project/Cowork project and make
19392
+ sure .env.deepline is gitignored. Commands below that folder use
19393
+ this org; sibling folders can pin different orgs.
19394
+ global Write ~/.local/deepline/<host>/.env. Commands outside folder pins
19395
+ use this org. Existing folder pins still override global auth.
19396
+
19397
+ Process env DEEPLINE_API_KEY overrides saved auth for that command only.
19398
+
19399
+ Agent loop:
19400
+ deepline org list --json
19401
+ deepline org set <number-or-org-id> --auth-scope folder --json
19402
+ deepline org status --json
19403
+ deepline auth status --json
18685
19404
 
18686
19405
  Examples:
18687
19406
  deepline org list --json
19407
+ deepline org status --json
18688
19408
  deepline org create Acme --json
18689
- deepline org switch 2
18690
- deepline org switch --org-id org_123 --json
19409
+ deepline org set 2
19410
+ deepline org set 2 --auth-scope folder
19411
+ deepline org set --org-id org_123 --json
19412
+ cd path/to/project-a && deepline org set Prove --auth-scope folder --json
19413
+ cd path/to/project-b && deepline org set Mixmax --auth-scope folder --json
19414
+ cd .. && deepline org status --json
18691
19415
  `
18692
19416
  );
18693
19417
  org.command("list").description("List your organizations.").addHelpText(
@@ -18714,21 +19438,88 @@ Examples:
18714
19438
  deepline org create "Acme Sales" --json
18715
19439
  `
18716
19440
  ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleOrgCreate);
18717
- org.command("switch [selection]").description(
18718
- "Switch to another organization and save the new API key in the host auth file."
18719
- ).addHelpText(
19441
+ org.command("status").description("Show the current organization and auth source.").addHelpText(
18720
19442
  "after",
18721
19443
  `
18722
19444
  Notes:
18723
- Mutates the saved host auth file. Selection can be a list number, exact
18724
- organization name, or organization id. Without a selection, prints choices.
19445
+ Read-only. Shows the current org plus auth_source.scope, auth_source.path,
19446
+ folder_target, host_env_path, and next commands.
19447
+
19448
+ Scopes are env, folder, or global. env means DEEPLINE_API_KEY/
19449
+ DEEPLINE_HOST_URL in process env wins. folder means nearest/Cowork
19450
+ .env.deepline wins. global means host config wins.
19451
+
19452
+ Run before and after org set to verify what future commands will use.
19453
+
19454
+ Examples:
19455
+ deepline org status
19456
+ deepline org status --json
19457
+ `
19458
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleOrgStatus);
19459
+ const addOrgSetOptions = (command) => command.option("--org-id <id>", "Set using an explicit organization id").option(
19460
+ "--auth-scope <scope>",
19461
+ "Where to save auth: auto, folder, or global",
19462
+ "auto"
19463
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped");
19464
+ addOrgSetOptions(
19465
+ org.command("set [selection]").description("Set the organization for the selected auth scope.").addHelpText(
19466
+ "after",
19467
+ `
19468
+ Notes:
19469
+ Selection can be a list number, exact organization name, or organization id.
19470
+ Without a selection, prints choices.
19471
+
19472
+ Mutates local auth state and asks Deepline for an org-scoped API key. It
19473
+ writes only the selected scope:
19474
+ auto Update the folder pin that already controls this command; in
19475
+ Cowork, write the mounted project folder; otherwise update global
19476
+ host auth.
19477
+ folder Write .env.deepline in the current project/Cowork project and make
19478
+ sure .env.deepline is gitignored.
19479
+ global Write ~/.local/deepline/<host>/.env.
19480
+
19481
+ Folder auth shadows global auth. If you set --auth-scope global from a pinned
19482
+ folder, commands in that folder still use the folder pin until it is changed
19483
+ or removed.
19484
+
19485
+ Use --json for stable fields including effective_auth_scope,
19486
+ auth_scope_reason, host_env_path, project_env_paths, warnings, org_id, and
19487
+ org_name.
19488
+
19489
+ Examples:
19490
+ deepline org set
19491
+ deepline org set 2
19492
+ deepline org set 2 --auth-scope folder
19493
+ deepline org set 2 --auth-scope global
19494
+ deepline org set --org-id org_123 --json
19495
+ deepline org status --json
19496
+ `
19497
+ )
19498
+ ).action(handleOrgSwitch);
19499
+ addOrgSetOptions(
19500
+ org.command("switch [selection]").description(
19501
+ "Deprecated alias for org set. Set the organization for the selected auth scope."
19502
+ ).addHelpText(
19503
+ "after",
19504
+ `
19505
+ Notes:
19506
+ Deprecated alias. Use deepline org set instead. The command still mutates
19507
+ local auth state with the same --auth-scope behavior as org set.
19508
+
19509
+ Run deepline org set --help for scope definitions and the agent verification
19510
+ loop.
18725
19511
 
18726
19512
  Examples:
18727
19513
  deepline org switch
18728
19514
  deepline org switch 2
19515
+ deepline org switch 2 --auth-scope folder
19516
+ deepline org switch 2 --auth-scope global
18729
19517
  deepline org switch --org-id org_123 --json
18730
19518
  `
18731
- ).option("--org-id <id>", "Switch using an explicit organization id").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleOrgSwitch);
19519
+ )
19520
+ ).action(
19521
+ (selection, options) => handleOrgSwitch(selection, { ...options, deprecatedSwitch: true })
19522
+ );
18732
19523
  }
18733
19524
 
18734
19525
  // src/cli/commands/quickstart.ts
@@ -21595,7 +22386,7 @@ import { spawn as spawn3 } from "child_process";
21595
22386
  import {
21596
22387
  existsSync as existsSync11,
21597
22388
  mkdirSync as mkdirSync9,
21598
- realpathSync as realpathSync2,
22389
+ realpathSync as realpathSync3,
21599
22390
  readFileSync as readFileSync11,
21600
22391
  renameSync,
21601
22392
  rmSync as rmSync3,
@@ -22094,7 +22885,7 @@ function findRepoBackedSdkRoot(startPath) {
22094
22885
  function inferNpmGlobalPrefixFromEntrypoint(entrypoint) {
22095
22886
  const normalized = (() => {
22096
22887
  try {
22097
- return realpathSync2(entrypoint);
22888
+ return realpathSync3(entrypoint);
22098
22889
  } catch {
22099
22890
  return resolve12(entrypoint);
22100
22891
  }