deepline 0.1.136 → 0.1.137

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.136",
607
+ version: "0.1.137",
394
608
  apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
395
609
  supportPolicy: {
396
- latest: "0.1.136",
610
+ latest: "0.1.137",
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}
@@ -6983,9 +7197,9 @@ import { createHash as createHash2 } from "crypto";
6983
7197
  import {
6984
7198
  existsSync as existsSync6,
6985
7199
  readFileSync as readFileSync6,
6986
- readdirSync,
6987
- realpathSync,
6988
- statSync as statSync2,
7200
+ readdirSync as readdirSync2,
7201
+ realpathSync as realpathSync2,
7202
+ statSync as statSync3,
6989
7203
  writeFileSync as writeFileSync8
6990
7204
  } from "fs";
6991
7205
  import { basename, dirname as dirname6, join as join5, resolve as resolve7 } from "path";
@@ -6996,7 +7210,7 @@ import {
6996
7210
  closeSync,
6997
7211
  openSync,
6998
7212
  readSync,
6999
- statSync,
7213
+ statSync as statSync2,
7000
7214
  writeFileSync as writeFileSync7
7001
7215
  } from "fs";
7002
7216
  import { isAbsolute, relative, resolve as resolve6 } from "path";
@@ -7429,7 +7643,7 @@ function inferCsvColumnSpecs(headers, rows) {
7429
7643
  }
7430
7644
  function readCsvSample(csvPath) {
7431
7645
  const resolvedPath = resolve6(csvPath);
7432
- const size = statSync(resolvedPath).size;
7646
+ const size = statSync2(resolvedPath).size;
7433
7647
  const fd = openSync(resolvedPath, "r");
7434
7648
  const byteLength = Math.min(size, CSV_HEADER_SAMPLE_BYTES);
7435
7649
  const buffer = Buffer.alloc(byteLength);
@@ -9465,7 +9679,7 @@ function preflightLocalFileInputs(runtimeInput) {
9465
9679
  }
9466
9680
  let stat2;
9467
9681
  try {
9468
- stat2 = statSync2(absolutePath);
9682
+ stat2 = statSync3(absolutePath);
9469
9683
  } catch (error) {
9470
9684
  throw new DeeplineError(
9471
9685
  `Input ${ref.inputPath} references a local file that is not readable: ${ref.value} (${error instanceof Error ? error.message : String(error)}). No run was created.`,
@@ -9617,7 +9831,7 @@ function stageFile(logicalPath, absolutePath) {
9617
9831
  }
9618
9832
  function normalizePlayPath(filePath) {
9619
9833
  try {
9620
- return realpathSync.native(resolve7(filePath));
9834
+ return realpathSync2.native(resolve7(filePath));
9621
9835
  } catch {
9622
9836
  return resolve7(filePath);
9623
9837
  }
@@ -12879,7 +13093,7 @@ async function handlePlayRun(args) {
12879
13093
  if (existsSync6(dir)) {
12880
13094
  const base = basename(resolved);
12881
13095
  try {
12882
- const siblings = readdirSync(dir).filter(
13096
+ const siblings = readdirSync2(dir).filter(
12883
13097
  (f) => f.includes(base.replace(/\.(play\.)?ts$/, "")) || f.endsWith(".play.ts")
12884
13098
  );
12885
13099
  if (siblings.length > 0) {
@@ -17672,9 +17886,9 @@ Examples:
17672
17886
  import {
17673
17887
  existsSync as existsSync7,
17674
17888
  mkdirSync as mkdirSync5,
17675
- readdirSync as readdirSync2,
17889
+ readdirSync as readdirSync3,
17676
17890
  readFileSync as readFileSync7,
17677
- statSync as statSync3,
17891
+ statSync as statSync4,
17678
17892
  writeFileSync as writeFileSync9
17679
17893
  } from "fs";
17680
17894
  import { homedir as homedir7, platform } from "os";
@@ -17759,7 +17973,7 @@ function listSessionFiles(agent) {
17759
17973
  }
17760
17974
  function readDirectoryNames(dir) {
17761
17975
  try {
17762
- return readdirSync2(dir);
17976
+ return readdirSync3(dir);
17763
17977
  } catch {
17764
17978
  return [];
17765
17979
  }
@@ -17770,7 +17984,7 @@ function listJsonlFilesRecursive(root, maxDepth) {
17770
17984
  if (depth > maxDepth) return;
17771
17985
  let entries;
17772
17986
  try {
17773
- entries = readdirSync2(dir, { withFileTypes: true });
17987
+ entries = readdirSync3(dir, { withFileTypes: true });
17774
17988
  } catch {
17775
17989
  return;
17776
17990
  }
@@ -17788,7 +18002,7 @@ function listJsonlFilesRecursive(root, maxDepth) {
17788
18002
  }
17789
18003
  function statIfReadable(filePath) {
17790
18004
  try {
17791
- return statSync3(filePath);
18005
+ return statSync4(filePath);
17792
18006
  } catch {
17793
18007
  return null;
17794
18008
  }
@@ -18481,6 +18695,15 @@ Examples:
18481
18695
  async function fetchOrganizations(http, apiKey) {
18482
18696
  return http.post("/api/v2/auth/cli/organizations", { api_key: apiKey });
18483
18697
  }
18698
+ function normalizeAuthScope(value) {
18699
+ if (!value) return "auto";
18700
+ if (value === "auto" || value === "folder" || value === "global") {
18701
+ return value;
18702
+ }
18703
+ throw new Error(
18704
+ `Invalid --auth-scope "${value}". Expected one of: auto, folder, global.`
18705
+ );
18706
+ }
18484
18707
  function orgListLines(orgs) {
18485
18708
  return orgs.map((org, index) => {
18486
18709
  const current = org.is_current ? " (current)" : "";
@@ -18488,6 +18711,90 @@ function orgListLines(orgs) {
18488
18711
  return `${index + 1}. ${org.name}${role}${current}`;
18489
18712
  });
18490
18713
  }
18714
+ function redactApiKey(value) {
18715
+ if (!value) return null;
18716
+ if (value.length <= 10) return `${value.slice(0, 3)}...`;
18717
+ return `${value.slice(0, 8)}...${value.slice(-4)}`;
18718
+ }
18719
+ function processEnvValue(name) {
18720
+ return process.env[name]?.trim() ?? "";
18721
+ }
18722
+ function resolveOrgSwitchAuthTarget(scope, config) {
18723
+ const activeProject = getResolvedProjectAuthSource(
18724
+ config.baseUrl,
18725
+ config.apiKey
18726
+ );
18727
+ const folderTarget = resolveProjectPinTarget();
18728
+ const globalOverrideWarning = activeProject && scope === "global" ? [
18729
+ `Folder auth in ${activeProject.filePath} overrides global auth for commands run here.`
18730
+ ] : [];
18731
+ if (scope === "folder") {
18732
+ if (!folderTarget.ok) {
18733
+ throw new Error(
18734
+ `Cowork project folder is ambiguous. Candidate folders: ${folderTarget.candidates.join(
18735
+ ", "
18736
+ )}. Set CLAUDE_PROJECT_DIR or cd into the intended project folder before running this command.`
18737
+ );
18738
+ }
18739
+ return {
18740
+ kind: "folder",
18741
+ requested_scope: scope,
18742
+ effective_scope: "folder",
18743
+ reason: "explicit_folder",
18744
+ source: folderTarget.source,
18745
+ warnings: []
18746
+ };
18747
+ }
18748
+ if (scope === "global") {
18749
+ return {
18750
+ kind: "global",
18751
+ requested_scope: scope,
18752
+ effective_scope: "global",
18753
+ reason: "explicit_global",
18754
+ warnings: globalOverrideWarning
18755
+ };
18756
+ }
18757
+ if (activeProject) {
18758
+ return {
18759
+ kind: "folder",
18760
+ requested_scope: scope,
18761
+ effective_scope: "folder",
18762
+ reason: "existing_folder_auth",
18763
+ source: activeProject.source,
18764
+ warnings: []
18765
+ };
18766
+ }
18767
+ if (folderTarget.ok && folderTarget.source === "cowork") {
18768
+ return {
18769
+ kind: "folder",
18770
+ requested_scope: scope,
18771
+ effective_scope: "folder",
18772
+ reason: "detected_cowork_project",
18773
+ source: "cowork",
18774
+ warnings: []
18775
+ };
18776
+ }
18777
+ if (!folderTarget.ok) {
18778
+ return {
18779
+ kind: "global",
18780
+ requested_scope: scope,
18781
+ effective_scope: "global",
18782
+ reason: "ambiguous_cowork_fell_back_global",
18783
+ warnings: [
18784
+ `Cowork project folder is ambiguous, so global auth was updated. Candidate folders: ${folderTarget.candidates.join(
18785
+ ", "
18786
+ )}. Set CLAUDE_PROJECT_DIR or cd into the intended project folder to update folder auth.`
18787
+ ]
18788
+ };
18789
+ }
18790
+ return {
18791
+ kind: "global",
18792
+ requested_scope: scope,
18793
+ effective_scope: "global",
18794
+ reason: "default_global",
18795
+ warnings: []
18796
+ };
18797
+ }
18491
18798
  async function handleOrgList(options) {
18492
18799
  const config = resolveConfig();
18493
18800
  const http = new HttpClient(config);
@@ -18507,7 +18814,89 @@ async function handleOrgList(options) {
18507
18814
  { json: options.json }
18508
18815
  );
18509
18816
  }
18817
+ async function handleOrgStatus(options) {
18818
+ const config = resolveConfig();
18819
+ const http = new HttpClient(config);
18820
+ const payload = await fetchOrganizations(http, config.apiKey);
18821
+ const current = payload.organizations.find((org) => org.is_current) ?? payload.organizations.find((org) => org.org_id === payload.current_org_id) ?? null;
18822
+ const projectCandidate = getActiveProjectAuthSource();
18823
+ const activeProject = getResolvedProjectAuthSource(
18824
+ config.baseUrl,
18825
+ config.apiKey
18826
+ );
18827
+ const folderTarget = resolveProjectPinTarget();
18828
+ const hostPath = hostEnvFilePath(config.baseUrl);
18829
+ const envApiKey = processEnvValue(API_KEY_ENV);
18830
+ const envHostUrl = processEnvValue(HOST_URL_ENV);
18831
+ const authSource = envApiKey ? {
18832
+ scope: "env",
18833
+ source: "process",
18834
+ path: null,
18835
+ api_key: redactApiKey(envApiKey),
18836
+ host: envHostUrl || null,
18837
+ overrides_global: true,
18838
+ overrides_folder: Boolean(projectCandidate)
18839
+ } : activeProject ? {
18840
+ scope: "folder",
18841
+ source: activeProject.source,
18842
+ path: activeProject.filePath,
18843
+ api_key: redactApiKey(activeProject.env.DEEPLINE_API_KEY),
18844
+ overrides_global: true
18845
+ } : {
18846
+ scope: "global",
18847
+ source: "host",
18848
+ path: hostPath,
18849
+ api_key: redactApiKey(config.apiKey),
18850
+ overrides_global: false
18851
+ };
18852
+ const folderTargetPayload = folderTarget.ok ? {
18853
+ ok: true,
18854
+ source: folderTarget.source,
18855
+ dir: folderTarget.dir,
18856
+ env_path: `${folderTarget.dir}/.env.deepline`
18857
+ } : {
18858
+ ok: false,
18859
+ reason: folderTarget.reason,
18860
+ candidates: folderTarget.candidates
18861
+ };
18862
+ const lines = [
18863
+ `Organization: ${current?.name ?? "(unknown)"}`,
18864
+ `Host: ${config.baseUrl}`,
18865
+ `Auth scope: ${authSource.scope}`
18866
+ ];
18867
+ if (authSource.path) {
18868
+ lines.push(`Auth file: ${authSource.path}`);
18869
+ } else {
18870
+ lines.push(`Auth source: ${API_KEY_ENV} process environment`);
18871
+ }
18872
+ if (envApiKey) {
18873
+ lines.push(`${API_KEY_ENV} overrides saved auth for this process.`);
18874
+ } else if (activeProject) {
18875
+ lines.push("Global auth is overridden in this folder.");
18876
+ }
18877
+ printCommandEnvelope(
18878
+ {
18879
+ ok: true,
18880
+ host: config.baseUrl,
18881
+ organization: current,
18882
+ current_org_id: payload.current_org_id,
18883
+ auth_source: authSource,
18884
+ host_env_path: hostPath,
18885
+ folder_target: folderTargetPayload,
18886
+ next: {
18887
+ set_auto: "deepline org set <org>",
18888
+ set_folder: "deepline org set <org> --auth-scope folder",
18889
+ set_global: "deepline org set <org> --auth-scope global"
18890
+ },
18891
+ render: {
18892
+ sections: [{ title: "org status", lines }]
18893
+ }
18894
+ },
18895
+ { json: options.json }
18896
+ );
18897
+ }
18510
18898
  async function handleOrgSwitch(selection, options) {
18899
+ const authScope = normalizeAuthScope(options.authScope);
18511
18900
  const config = resolveConfig();
18512
18901
  const http = new HttpClient(config);
18513
18902
  const payload = await fetchOrganizations(http, config.apiKey);
@@ -18515,7 +18904,10 @@ async function handleOrgSwitch(selection, options) {
18515
18904
  printCommandEnvelope(
18516
18905
  {
18517
18906
  ...payload,
18518
- next: { switch: "deepline org switch <number>" },
18907
+ next: { set: "deepline org set <number>" },
18908
+ deprecated_command: options.deprecatedSwitch ? "org switch" : null,
18909
+ replacement_command: options.deprecatedSwitch ? "deepline org set" : null,
18910
+ warnings: options.deprecatedSwitch ? ["org switch is deprecated; use org set."] : [],
18519
18911
  render: {
18520
18912
  sections: [
18521
18913
  {
@@ -18523,7 +18915,7 @@ async function handleOrgSwitch(selection, options) {
18523
18915
  lines: orgListLines(payload.organizations)
18524
18916
  }
18525
18917
  ],
18526
- actions: [{ label: "Run", command: "deepline org switch <number>" }]
18918
+ actions: [{ label: "Run", command: "deepline org set <number>" }]
18527
18919
  }
18528
18920
  },
18529
18921
  { json: options.json }
@@ -18546,16 +18938,56 @@ async function handleOrgSwitch(selection, options) {
18546
18938
  if (!target) {
18547
18939
  throw new Error("Could not resolve the selected organization.");
18548
18940
  }
18941
+ const authTarget = resolveOrgSwitchAuthTarget(authScope, config);
18549
18942
  if (target.is_current) {
18943
+ let project_env_paths2 = [];
18944
+ if (authTarget.kind === "folder") {
18945
+ project_env_paths2 = saveProjectDeeplineEnvValues({
18946
+ DEEPLINE_HOST_URL: config.baseUrl,
18947
+ DEEPLINE_API_KEY: config.apiKey
18948
+ });
18949
+ } else {
18950
+ saveHostEnvValues(config.baseUrl, {
18951
+ DEEPLINE_HOST_URL: config.baseUrl,
18952
+ DEEPLINE_API_KEY: config.apiKey
18953
+ });
18954
+ }
18955
+ const renderLines2 = [`Already on ${target.name}.`];
18956
+ for (const projectPath of project_env_paths2) {
18957
+ renderLines2.push(`Saved folder auth in ${projectPath}`);
18958
+ }
18959
+ if (authTarget.kind === "global") {
18960
+ renderLines2.push(`Saved global auth in ${hostEnvFilePath(config.baseUrl)}`);
18961
+ }
18962
+ renderLines2.push(
18963
+ `Scope: ${authTarget.requested_scope} -> ${authTarget.effective_scope} (${authTarget.reason})`
18964
+ );
18965
+ if (options.deprecatedSwitch) {
18966
+ renderLines2.push("Warning: org switch is deprecated; use org set.");
18967
+ }
18968
+ for (const warning of authTarget.warnings) {
18969
+ renderLines2.push(`Warning: ${warning}`);
18970
+ }
18971
+ const warnings2 = [
18972
+ ...options.deprecatedSwitch ? ["org switch is deprecated; use org set."] : [],
18973
+ ...authTarget.warnings
18974
+ ];
18550
18975
  printCommandEnvelope(
18551
18976
  {
18552
18977
  ok: true,
18553
18978
  unchanged: true,
18554
18979
  organization: target,
18980
+ requested_auth_scope: authTarget.requested_scope,
18981
+ effective_auth_scope: authTarget.effective_scope,
18982
+ auth_scope_reason: authTarget.reason,
18983
+ auth_scope: authTarget.effective_scope,
18984
+ host_env_path: authTarget.kind === "global" ? hostEnvFilePath(config.baseUrl) : null,
18985
+ project_env_paths: project_env_paths2,
18986
+ deprecated_command: options.deprecatedSwitch ? "org switch" : null,
18987
+ replacement_command: options.deprecatedSwitch ? "deepline org set" : null,
18988
+ warnings: warnings2,
18555
18989
  render: {
18556
- sections: [
18557
- { title: "org switch", lines: [`Already on ${target.name}.`] }
18558
- ]
18990
+ sections: [{ title: "org set", lines: renderLines2 }]
18559
18991
  }
18560
18992
  },
18561
18993
  { json: options.json }
@@ -18566,26 +18998,61 @@ async function handleOrgSwitch(selection, options) {
18566
18998
  api_key: config.apiKey,
18567
18999
  org_id: target.org_id
18568
19000
  });
18569
- saveHostEnvValues(config.baseUrl, {
18570
- DEEPLINE_API_KEY: switched.api_key,
18571
- DEEPLINE_ACTIVE_ORG_ID: switched.org_id,
18572
- DEEPLINE_ACTIVE_ORG_NAME: switched.org_name
18573
- });
19001
+ let project_env_paths = [];
19002
+ if (authTarget.kind === "folder") {
19003
+ project_env_paths = saveProjectDeeplineEnvValues({
19004
+ DEEPLINE_HOST_URL: config.baseUrl,
19005
+ DEEPLINE_API_KEY: switched.api_key
19006
+ });
19007
+ } else {
19008
+ saveHostEnvValues(config.baseUrl, {
19009
+ DEEPLINE_HOST_URL: config.baseUrl,
19010
+ DEEPLINE_API_KEY: switched.api_key,
19011
+ DEEPLINE_ACTIVE_ORG_ID: switched.org_id,
19012
+ DEEPLINE_ACTIVE_ORG_NAME: switched.org_name
19013
+ });
19014
+ }
18574
19015
  const { api_key: _apiKey, ...publicSwitched } = switched;
19016
+ const renderLines = [`Switched to ${switched.org_name}.`];
19017
+ if (authTarget.kind === "folder") {
19018
+ for (const projectPath of project_env_paths) {
19019
+ renderLines.push(`Saved folder auth in ${projectPath}`);
19020
+ }
19021
+ } else {
19022
+ renderLines.push(`Saved global auth in ${hostEnvFilePath(config.baseUrl)}`);
19023
+ }
19024
+ renderLines.push(
19025
+ `Scope: ${authTarget.requested_scope} -> ${authTarget.effective_scope} (${authTarget.reason})`
19026
+ );
19027
+ if (options.deprecatedSwitch) {
19028
+ renderLines.push("Warning: org switch is deprecated; use org set.");
19029
+ }
19030
+ for (const warning of authTarget.warnings) {
19031
+ renderLines.push(`Warning: ${warning}`);
19032
+ }
19033
+ const warnings = [
19034
+ ...options.deprecatedSwitch ? ["org switch is deprecated; use org set."] : [],
19035
+ ...authTarget.warnings
19036
+ ];
18575
19037
  printCommandEnvelope(
18576
19038
  {
18577
19039
  ok: true,
18578
- host_env_path: hostEnvFilePath(config.baseUrl),
19040
+ host_env_path: authTarget.kind === "global" ? hostEnvFilePath(config.baseUrl) : null,
19041
+ project_env_paths,
18579
19042
  ...publicSwitched,
18580
19043
  api_key_saved: true,
19044
+ requested_auth_scope: authTarget.requested_scope,
19045
+ effective_auth_scope: authTarget.effective_scope,
19046
+ auth_scope_reason: authTarget.reason,
19047
+ auth_scope: authTarget.effective_scope,
19048
+ deprecated_command: options.deprecatedSwitch ? "org switch" : null,
19049
+ replacement_command: options.deprecatedSwitch ? "deepline org set" : null,
19050
+ warnings,
18581
19051
  render: {
18582
19052
  sections: [
18583
19053
  {
18584
- title: "org switch",
18585
- lines: [
18586
- `Switched to ${switched.org_name}.`,
18587
- `Saved host auth in ${hostEnvFilePath(config.baseUrl)}`
18588
- ]
19054
+ title: "org set",
19055
+ lines: renderLines
18589
19056
  }
18590
19057
  ]
18591
19058
  }
@@ -18601,6 +19068,7 @@ async function handleOrgCreate(name, options) {
18601
19068
  name
18602
19069
  });
18603
19070
  saveHostEnvValues(config.baseUrl, {
19071
+ DEEPLINE_HOST_URL: config.baseUrl,
18604
19072
  DEEPLINE_API_KEY: created.api_key,
18605
19073
  DEEPLINE_ACTIVE_ORG_ID: created.org_id,
18606
19074
  DEEPLINE_ACTIVE_ORG_NAME: created.org_name
@@ -18630,18 +19098,20 @@ async function handleOrgCreate(name, options) {
18630
19098
  );
18631
19099
  }
18632
19100
  function registerOrgCommands(program) {
18633
- const org = program.command("org").description("List, create, and switch organizations.").addHelpText(
19101
+ const org = program.command("org").description("List, create, and set organizations.").addHelpText(
18634
19102
  "after",
18635
19103
  `
18636
19104
  Notes:
18637
- Organizations are workspaces. Switching organizations mutates the saved host
18638
- auth file so later CLI commands target the selected workspace.
19105
+ Organizations are workspaces. By default, switching updates the auth scope
19106
+ that will affect later commands from this folder.
18639
19107
 
18640
19108
  Examples:
18641
19109
  deepline org list --json
19110
+ deepline org status --json
18642
19111
  deepline org create Acme --json
18643
- deepline org switch 2
18644
- deepline org switch --org-id org_123 --json
19112
+ deepline org set 2
19113
+ deepline org set 2 --auth-scope folder
19114
+ deepline org set --org-id org_123 --json
18645
19115
  `
18646
19116
  );
18647
19117
  org.command("list").description("List your organizations.").addHelpText(
@@ -18668,21 +19138,65 @@ Examples:
18668
19138
  deepline org create "Acme Sales" --json
18669
19139
  `
18670
19140
  ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleOrgCreate);
18671
- org.command("switch [selection]").description(
18672
- "Switch to another organization and save the new API key in the host auth file."
18673
- ).addHelpText(
19141
+ org.command("status").description("Show the current organization and auth source.").addHelpText(
18674
19142
  "after",
18675
19143
  `
18676
19144
  Notes:
18677
- Mutates the saved host auth file. Selection can be a list number, exact
18678
- organization name, or organization id. Without a selection, prints choices.
19145
+ Read-only. Shows whether commands resolve auth from process env, a folder
19146
+ .env.deepline file, or global host auth.
19147
+
19148
+ Examples:
19149
+ deepline org status
19150
+ deepline org status --json
19151
+ `
19152
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleOrgStatus);
19153
+ const addOrgSetOptions = (command) => command.option("--org-id <id>", "Set using an explicit organization id").option(
19154
+ "--auth-scope <scope>",
19155
+ "Where to save auth: auto, folder, or global",
19156
+ "auto"
19157
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped");
19158
+ addOrgSetOptions(
19159
+ org.command("set [selection]").description("Set the organization for the selected auth scope.").addHelpText(
19160
+ "after",
19161
+ `
19162
+ Notes:
19163
+ Selection can be a list number, exact organization name, or organization id.
19164
+ Without a selection, prints choices. The default --auth-scope auto updates
19165
+ the folder auth file when one controls this command, updates the detected
19166
+ Cowork project folder when present, and otherwise updates global host auth.
19167
+
19168
+ Examples:
19169
+ deepline org set
19170
+ deepline org set 2
19171
+ deepline org set 2 --auth-scope folder
19172
+ deepline org set 2 --auth-scope global
19173
+ deepline org set --org-id org_123 --json
19174
+ `
19175
+ )
19176
+ ).action(handleOrgSwitch);
19177
+ addOrgSetOptions(
19178
+ org.command("switch [selection]").description(
19179
+ "Deprecated alias for org set. Set the organization for the selected auth scope."
19180
+ ).addHelpText(
19181
+ "after",
19182
+ `
19183
+ Notes:
19184
+ Deprecated alias. Use deepline org set instead. The default --auth-scope auto
19185
+ updates the folder auth file when one controls this command, updates the
19186
+ detected Cowork project folder when present, and otherwise updates global host
19187
+ auth.
18679
19188
 
18680
19189
  Examples:
18681
19190
  deepline org switch
18682
19191
  deepline org switch 2
19192
+ deepline org switch 2 --auth-scope folder
19193
+ deepline org switch 2 --auth-scope global
18683
19194
  deepline org switch --org-id org_123 --json
18684
19195
  `
18685
- ).option("--org-id <id>", "Switch using an explicit organization id").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleOrgSwitch);
19196
+ )
19197
+ ).action(
19198
+ (selection, options) => handleOrgSwitch(selection, { ...options, deprecatedSwitch: true })
19199
+ );
18686
19200
  }
18687
19201
 
18688
19202
  // src/cli/commands/quickstart.ts
@@ -21456,7 +21970,7 @@ import { spawn as spawn3 } from "child_process";
21456
21970
  import {
21457
21971
  existsSync as existsSync11,
21458
21972
  mkdirSync as mkdirSync9,
21459
- realpathSync as realpathSync2,
21973
+ realpathSync as realpathSync3,
21460
21974
  readFileSync as readFileSync11,
21461
21975
  renameSync,
21462
21976
  rmSync as rmSync3,
@@ -21955,7 +22469,7 @@ function findRepoBackedSdkRoot(startPath) {
21955
22469
  function inferNpmGlobalPrefixFromEntrypoint(entrypoint) {
21956
22470
  const normalized = (() => {
21957
22471
  try {
21958
- return realpathSync2(entrypoint);
22472
+ return realpathSync3(entrypoint);
21959
22473
  } catch {
21960
22474
  return resolve12(entrypoint);
21961
22475
  }