deepline 0.1.138 → 0.1.139

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -237,22 +237,6 @@ 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
- ];
256
240
  function baseUrlSlug(baseUrl) {
257
241
  let url;
258
242
  try {
@@ -298,124 +282,9 @@ function findNearestEnvFile(name, startDir = process.cwd()) {
298
282
  current = parent;
299
283
  }
300
284
  }
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
- }));
285
+ function loadProjectDeeplineEnv(startDir = process.cwd()) {
286
+ const filePath = findNearestEnvFile(PROJECT_DEEPLINE_ENV_FILE, startDir);
287
+ return filePath ? parseEnvFile(filePath) : {};
419
288
  }
420
289
  function normalizeBaseUrl(baseUrl) {
421
290
  const trimmed = baseUrl.trim().replace(/\/+$/, "");
@@ -479,35 +348,23 @@ function loadGlobalCliEnv() {
479
348
  return loadCliEnv(PROD_URL);
480
349
  }
481
350
  function autoDetectBaseUrl() {
482
- const projectEnvs = loadProjectEnvCandidates();
351
+ const projectEnv = loadProjectDeeplineEnv();
483
352
  const globalEnv = loadGlobalCliEnv();
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;
353
+ return normalizeBaseUrl(process.env[HOST_URL_ENV] ?? "") || normalizeBaseUrl(projectEnv[HOST_URL_ENV] ?? "") || normalizeBaseUrl(globalEnv[HOST_URL_ENV] ?? "") || PROD_URL;
487
354
  }
488
355
  function resolveApiKeyForBaseUrl(baseUrl, explicitApiKey) {
489
356
  const normalizedBaseUrl = normalizeBaseUrl(baseUrl);
490
- const projectEnvs = loadProjectEnvCandidates();
357
+ const projectEnv = loadProjectDeeplineEnv();
491
358
  const cliEnv = loadCliEnv(normalizedBaseUrl || baseUrl);
359
+ const projectBaseUrl = normalizeBaseUrl(projectEnv[HOST_URL_ENV] ?? "");
360
+ const projectKeyApplies = projectBaseUrl === normalizedBaseUrl;
492
361
  return firstNonEmpty(
493
362
  explicitApiKey,
494
363
  process.env[API_KEY_ENV],
495
- ...projectEnvs.map(({ env }) => {
496
- const projectBaseUrl = normalizeBaseUrl(env[HOST_URL_ENV] ?? "");
497
- return projectBaseUrl === normalizedBaseUrl ? env[API_KEY_ENV] : "";
498
- }),
364
+ projectKeyApplies ? projectEnv[API_KEY_ENV] : "",
499
365
  cliEnv[API_KEY_ENV]
500
366
  );
501
367
  }
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
- }
511
368
  function resolveConfig(options) {
512
369
  const baseUrl = normalizeBaseUrl(
513
370
  options?.baseUrl?.trim() || autoDetectBaseUrl()
@@ -530,69 +387,6 @@ function resolveConfig(options) {
530
387
  maxRetries: options?.maxRetries ?? DEFAULT_MAX_RETRIES
531
388
  };
532
389
  }
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
- }
596
390
 
597
391
  // src/http.ts
598
392
  var import_node_fs2 = require("fs");
@@ -619,10 +413,10 @@ var SDK_RELEASE = {
619
413
  // 0.1.108 ships explicit dataset column/tool recompute policy and removes
620
414
  // the SDK enrich generator's one-second stale policy.
621
415
  // 0.1.110 ships authored V2 prebuilts and required top-level play descriptions.
622
- version: "0.1.138",
416
+ version: "0.1.139",
623
417
  apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
624
418
  supportPolicy: {
625
- latest: "0.1.138",
419
+ latest: "0.1.139",
626
420
  minimumSupported: "0.1.53",
627
421
  deprecatedBelow: "0.1.53",
628
422
  commandMinimumSupported: [
@@ -713,7 +507,7 @@ function normalizeAgentRuntime(value) {
713
507
  if (explicit === "gemini_cli") return "gemini";
714
508
  return EXPLICIT_AGENT_RUNTIMES.has(explicit) ? explicit : null;
715
509
  }
716
- function isCoworkLikeSandbox2() {
510
+ function isCoworkLikeSandbox() {
717
511
  const pluginMode = truthyEnv("DEEPLINE_PLUGIN_MODE");
718
512
  const claudeRemote = truthyEnv("CLAUDE_CODE_REMOTE");
719
513
  const projectDir = Boolean(process.env.CLAUDE_PROJECT_DIR?.trim());
@@ -726,7 +520,7 @@ function detectAgentRuntime(options = {}) {
726
520
  const explicit = normalizeAgentRuntime(process.env.DEEPLINE_AGENT_RUNTIME);
727
521
  if (explicit) return explicit;
728
522
  if (process.env.CODEX_THREAD_ID?.trim()) return "codex";
729
- if (options.detectCowork !== false && isCoworkLikeSandbox2()) {
523
+ if (options.detectCowork !== false && isCoworkLikeSandbox()) {
730
524
  return "claude_cowork";
731
525
  }
732
526
  if (process.env.CLAUDECODE?.trim() === "1") return "claude_code";
@@ -1192,7 +986,7 @@ function sleep(ms) {
1192
986
  return new Promise((resolve13) => setTimeout(resolve13, ms));
1193
987
  }
1194
988
  function withCoworkNetworkHint(message) {
1195
- if (!isCoworkLikeSandbox2() || message.includes(COWORK_NETWORK_HINT)) {
989
+ if (!isCoworkLikeSandbox() || message.includes(COWORK_NETWORK_HINT)) {
1196
990
  return message;
1197
991
  }
1198
992
  return `${message}
@@ -15260,6 +15054,7 @@ function renderPlayStep(command, options) {
15260
15054
  ` const templateRow = __dlPrepareEnrichRow(row, [${alias}]);`,
15261
15055
  ...runIfLines,
15262
15056
  ` const payload = __dlTemplate(${payload}, templateRow) as Record<string, unknown>;`,
15057
+ ` if (__dlShouldSkipBlankPlayPayload(payload)) return null;`,
15263
15058
  ` let result: unknown;`,
15264
15059
  ` try {`,
15265
15060
  ` result = await stepCtx.runPlay(${callId}, ${playRef}, payload, {`,
@@ -16193,6 +15988,17 @@ function helperSource() {
16193
15988
  ` return false;`,
16194
15989
  `}`,
16195
15990
  ``,
15991
+ `function __dlPayloadHasMeaningfulValue(value: unknown): boolean {`,
15992
+ ` if (__dlBlankPayloadValue(value)) return false;`,
15993
+ ` if (Array.isArray(value)) return value.some(__dlPayloadHasMeaningfulValue);`,
15994
+ ` if (value && typeof value === 'object') return Object.values(value as Record<string, unknown>).some(__dlPayloadHasMeaningfulValue);`,
15995
+ ` return true;`,
15996
+ `}`,
15997
+ ``,
15998
+ `function __dlShouldSkipBlankPlayPayload(payload: Record<string, unknown>): boolean {`,
15999
+ ` return Object.keys(payload).length > 0 && !__dlPayloadHasMeaningfulValue(payload);`,
16000
+ `}`,
16001
+ ``,
16196
16002
  `function __dlAliasCandidates(alias: string): string[] {`,
16197
16003
  ` const aliases: string[] = [];`,
16198
16004
  ` for (const candidate of [alias, alias.replace(/-/g, '_'), alias.replace(/_/g, '-')]) {`,
@@ -18671,15 +18477,6 @@ Examples:
18671
18477
  async function fetchOrganizations(http, apiKey) {
18672
18478
  return http.post("/api/v2/auth/cli/organizations", { api_key: apiKey });
18673
18479
  }
18674
- function normalizeAuthScope(value) {
18675
- if (!value) return "auto";
18676
- if (value === "auto" || value === "folder" || value === "global") {
18677
- return value;
18678
- }
18679
- throw new Error(
18680
- `Invalid --auth-scope "${value}". Expected one of: auto, folder, global.`
18681
- );
18682
- }
18683
18480
  function orgListLines(orgs) {
18684
18481
  return orgs.map((org, index) => {
18685
18482
  const current = org.is_current ? " (current)" : "";
@@ -18687,90 +18484,6 @@ function orgListLines(orgs) {
18687
18484
  return `${index + 1}. ${org.name}${role}${current}`;
18688
18485
  });
18689
18486
  }
18690
- function redactApiKey(value) {
18691
- if (!value) return null;
18692
- if (value.length <= 10) return `${value.slice(0, 3)}...`;
18693
- return `${value.slice(0, 8)}...${value.slice(-4)}`;
18694
- }
18695
- function processEnvValue(name) {
18696
- return process.env[name]?.trim() ?? "";
18697
- }
18698
- function resolveOrgSwitchAuthTarget(scope, config) {
18699
- const activeProject = getResolvedProjectAuthSource(
18700
- config.baseUrl,
18701
- config.apiKey
18702
- );
18703
- const folderTarget = resolveProjectPinTarget();
18704
- const globalOverrideWarning = activeProject && scope === "global" ? [
18705
- `Folder auth in ${activeProject.filePath} overrides global auth for commands run here.`
18706
- ] : [];
18707
- if (scope === "folder") {
18708
- if (!folderTarget.ok) {
18709
- throw new Error(
18710
- `Cowork project folder is ambiguous. Candidate folders: ${folderTarget.candidates.join(
18711
- ", "
18712
- )}. Set CLAUDE_PROJECT_DIR or cd into the intended project folder before running this command.`
18713
- );
18714
- }
18715
- return {
18716
- kind: "folder",
18717
- requested_scope: scope,
18718
- effective_scope: "folder",
18719
- reason: "explicit_folder",
18720
- source: folderTarget.source,
18721
- warnings: []
18722
- };
18723
- }
18724
- if (scope === "global") {
18725
- return {
18726
- kind: "global",
18727
- requested_scope: scope,
18728
- effective_scope: "global",
18729
- reason: "explicit_global",
18730
- warnings: globalOverrideWarning
18731
- };
18732
- }
18733
- if (activeProject) {
18734
- return {
18735
- kind: "folder",
18736
- requested_scope: scope,
18737
- effective_scope: "folder",
18738
- reason: "existing_folder_auth",
18739
- source: activeProject.source,
18740
- warnings: []
18741
- };
18742
- }
18743
- if (folderTarget.ok && folderTarget.source === "cowork") {
18744
- return {
18745
- kind: "folder",
18746
- requested_scope: scope,
18747
- effective_scope: "folder",
18748
- reason: "detected_cowork_project",
18749
- source: "cowork",
18750
- warnings: []
18751
- };
18752
- }
18753
- if (!folderTarget.ok) {
18754
- return {
18755
- kind: "global",
18756
- requested_scope: scope,
18757
- effective_scope: "global",
18758
- reason: "ambiguous_cowork_fell_back_global",
18759
- warnings: [
18760
- `Cowork project folder is ambiguous, so global auth was updated. Candidate folders: ${folderTarget.candidates.join(
18761
- ", "
18762
- )}. Set CLAUDE_PROJECT_DIR or cd into the intended project folder to update folder auth.`
18763
- ]
18764
- };
18765
- }
18766
- return {
18767
- kind: "global",
18768
- requested_scope: scope,
18769
- effective_scope: "global",
18770
- reason: "default_global",
18771
- warnings: []
18772
- };
18773
- }
18774
18487
  async function handleOrgList(options) {
18775
18488
  const config = resolveConfig();
18776
18489
  const http = new HttpClient(config);
@@ -18790,89 +18503,7 @@ async function handleOrgList(options) {
18790
18503
  { json: options.json }
18791
18504
  );
18792
18505
  }
18793
- async function handleOrgStatus(options) {
18794
- const config = resolveConfig();
18795
- const http = new HttpClient(config);
18796
- const payload = await fetchOrganizations(http, config.apiKey);
18797
- const current = payload.organizations.find((org) => org.is_current) ?? payload.organizations.find((org) => org.org_id === payload.current_org_id) ?? null;
18798
- const projectCandidate = getActiveProjectAuthSource();
18799
- const activeProject = getResolvedProjectAuthSource(
18800
- config.baseUrl,
18801
- config.apiKey
18802
- );
18803
- const folderTarget = resolveProjectPinTarget();
18804
- const hostPath = hostEnvFilePath(config.baseUrl);
18805
- const envApiKey = processEnvValue(API_KEY_ENV);
18806
- const envHostUrl = processEnvValue(HOST_URL_ENV);
18807
- const authSource = envApiKey ? {
18808
- scope: "env",
18809
- source: "process",
18810
- path: null,
18811
- api_key: redactApiKey(envApiKey),
18812
- host: envHostUrl || null,
18813
- overrides_global: true,
18814
- overrides_folder: Boolean(projectCandidate)
18815
- } : activeProject ? {
18816
- scope: "folder",
18817
- source: activeProject.source,
18818
- path: activeProject.filePath,
18819
- api_key: redactApiKey(activeProject.env.DEEPLINE_API_KEY),
18820
- overrides_global: true
18821
- } : {
18822
- scope: "global",
18823
- source: "host",
18824
- path: hostPath,
18825
- api_key: redactApiKey(config.apiKey),
18826
- overrides_global: false
18827
- };
18828
- const folderTargetPayload = folderTarget.ok ? {
18829
- ok: true,
18830
- source: folderTarget.source,
18831
- dir: folderTarget.dir,
18832
- env_path: `${folderTarget.dir}/.env.deepline`
18833
- } : {
18834
- ok: false,
18835
- reason: folderTarget.reason,
18836
- candidates: folderTarget.candidates
18837
- };
18838
- const lines = [
18839
- `Organization: ${current?.name ?? "(unknown)"}`,
18840
- `Host: ${config.baseUrl}`,
18841
- `Auth scope: ${authSource.scope}`
18842
- ];
18843
- if (authSource.path) {
18844
- lines.push(`Auth file: ${authSource.path}`);
18845
- } else {
18846
- lines.push(`Auth source: ${API_KEY_ENV} process environment`);
18847
- }
18848
- if (envApiKey) {
18849
- lines.push(`${API_KEY_ENV} overrides saved auth for this process.`);
18850
- } else if (activeProject) {
18851
- lines.push("Global auth is overridden in this folder.");
18852
- }
18853
- printCommandEnvelope(
18854
- {
18855
- ok: true,
18856
- host: config.baseUrl,
18857
- organization: current,
18858
- current_org_id: payload.current_org_id,
18859
- auth_source: authSource,
18860
- host_env_path: hostPath,
18861
- folder_target: folderTargetPayload,
18862
- next: {
18863
- set_auto: "deepline org set <org>",
18864
- set_folder: "deepline org set <org> --auth-scope folder",
18865
- set_global: "deepline org set <org> --auth-scope global"
18866
- },
18867
- render: {
18868
- sections: [{ title: "org status", lines }]
18869
- }
18870
- },
18871
- { json: options.json }
18872
- );
18873
- }
18874
18506
  async function handleOrgSwitch(selection, options) {
18875
- const authScope = normalizeAuthScope(options.authScope);
18876
18507
  const config = resolveConfig();
18877
18508
  const http = new HttpClient(config);
18878
18509
  const payload = await fetchOrganizations(http, config.apiKey);
@@ -18880,10 +18511,7 @@ async function handleOrgSwitch(selection, options) {
18880
18511
  printCommandEnvelope(
18881
18512
  {
18882
18513
  ...payload,
18883
- next: { set: "deepline org set <number>" },
18884
- deprecated_command: options.deprecatedSwitch ? "org switch" : null,
18885
- replacement_command: options.deprecatedSwitch ? "deepline org set" : null,
18886
- warnings: options.deprecatedSwitch ? ["org switch is deprecated; use org set."] : [],
18514
+ next: { switch: "deepline org switch <number>" },
18887
18515
  render: {
18888
18516
  sections: [
18889
18517
  {
@@ -18891,7 +18519,7 @@ async function handleOrgSwitch(selection, options) {
18891
18519
  lines: orgListLines(payload.organizations)
18892
18520
  }
18893
18521
  ],
18894
- actions: [{ label: "Run", command: "deepline org set <number>" }]
18522
+ actions: [{ label: "Run", command: "deepline org switch <number>" }]
18895
18523
  }
18896
18524
  },
18897
18525
  { json: options.json }
@@ -18914,56 +18542,16 @@ async function handleOrgSwitch(selection, options) {
18914
18542
  if (!target) {
18915
18543
  throw new Error("Could not resolve the selected organization.");
18916
18544
  }
18917
- const authTarget = resolveOrgSwitchAuthTarget(authScope, config);
18918
18545
  if (target.is_current) {
18919
- let project_env_paths2 = [];
18920
- if (authTarget.kind === "folder") {
18921
- project_env_paths2 = saveProjectDeeplineEnvValues({
18922
- DEEPLINE_HOST_URL: config.baseUrl,
18923
- DEEPLINE_API_KEY: config.apiKey
18924
- });
18925
- } else {
18926
- saveHostEnvValues(config.baseUrl, {
18927
- DEEPLINE_HOST_URL: config.baseUrl,
18928
- DEEPLINE_API_KEY: config.apiKey
18929
- });
18930
- }
18931
- const renderLines2 = [`Already on ${target.name}.`];
18932
- for (const projectPath of project_env_paths2) {
18933
- renderLines2.push(`Saved folder auth in ${projectPath}`);
18934
- }
18935
- if (authTarget.kind === "global") {
18936
- renderLines2.push(`Saved global auth in ${hostEnvFilePath(config.baseUrl)}`);
18937
- }
18938
- renderLines2.push(
18939
- `Scope: ${authTarget.requested_scope} -> ${authTarget.effective_scope} (${authTarget.reason})`
18940
- );
18941
- if (options.deprecatedSwitch) {
18942
- renderLines2.push("Warning: org switch is deprecated; use org set.");
18943
- }
18944
- for (const warning of authTarget.warnings) {
18945
- renderLines2.push(`Warning: ${warning}`);
18946
- }
18947
- const warnings2 = [
18948
- ...options.deprecatedSwitch ? ["org switch is deprecated; use org set."] : [],
18949
- ...authTarget.warnings
18950
- ];
18951
18546
  printCommandEnvelope(
18952
18547
  {
18953
18548
  ok: true,
18954
18549
  unchanged: true,
18955
18550
  organization: target,
18956
- requested_auth_scope: authTarget.requested_scope,
18957
- effective_auth_scope: authTarget.effective_scope,
18958
- auth_scope_reason: authTarget.reason,
18959
- auth_scope: authTarget.effective_scope,
18960
- host_env_path: authTarget.kind === "global" ? hostEnvFilePath(config.baseUrl) : null,
18961
- project_env_paths: project_env_paths2,
18962
- deprecated_command: options.deprecatedSwitch ? "org switch" : null,
18963
- replacement_command: options.deprecatedSwitch ? "deepline org set" : null,
18964
- warnings: warnings2,
18965
18551
  render: {
18966
- sections: [{ title: "org set", lines: renderLines2 }]
18552
+ sections: [
18553
+ { title: "org switch", lines: [`Already on ${target.name}.`] }
18554
+ ]
18967
18555
  }
18968
18556
  },
18969
18557
  { json: options.json }
@@ -18974,61 +18562,26 @@ async function handleOrgSwitch(selection, options) {
18974
18562
  api_key: config.apiKey,
18975
18563
  org_id: target.org_id
18976
18564
  });
18977
- let project_env_paths = [];
18978
- if (authTarget.kind === "folder") {
18979
- project_env_paths = saveProjectDeeplineEnvValues({
18980
- DEEPLINE_HOST_URL: config.baseUrl,
18981
- DEEPLINE_API_KEY: switched.api_key
18982
- });
18983
- } else {
18984
- saveHostEnvValues(config.baseUrl, {
18985
- DEEPLINE_HOST_URL: config.baseUrl,
18986
- DEEPLINE_API_KEY: switched.api_key,
18987
- DEEPLINE_ACTIVE_ORG_ID: switched.org_id,
18988
- DEEPLINE_ACTIVE_ORG_NAME: switched.org_name
18989
- });
18990
- }
18565
+ saveHostEnvValues(config.baseUrl, {
18566
+ DEEPLINE_API_KEY: switched.api_key,
18567
+ DEEPLINE_ACTIVE_ORG_ID: switched.org_id,
18568
+ DEEPLINE_ACTIVE_ORG_NAME: switched.org_name
18569
+ });
18991
18570
  const { api_key: _apiKey, ...publicSwitched } = switched;
18992
- const renderLines = [`Switched to ${switched.org_name}.`];
18993
- if (authTarget.kind === "folder") {
18994
- for (const projectPath of project_env_paths) {
18995
- renderLines.push(`Saved folder auth in ${projectPath}`);
18996
- }
18997
- } else {
18998
- renderLines.push(`Saved global auth in ${hostEnvFilePath(config.baseUrl)}`);
18999
- }
19000
- renderLines.push(
19001
- `Scope: ${authTarget.requested_scope} -> ${authTarget.effective_scope} (${authTarget.reason})`
19002
- );
19003
- if (options.deprecatedSwitch) {
19004
- renderLines.push("Warning: org switch is deprecated; use org set.");
19005
- }
19006
- for (const warning of authTarget.warnings) {
19007
- renderLines.push(`Warning: ${warning}`);
19008
- }
19009
- const warnings = [
19010
- ...options.deprecatedSwitch ? ["org switch is deprecated; use org set."] : [],
19011
- ...authTarget.warnings
19012
- ];
19013
18571
  printCommandEnvelope(
19014
18572
  {
19015
18573
  ok: true,
19016
- host_env_path: authTarget.kind === "global" ? hostEnvFilePath(config.baseUrl) : null,
19017
- project_env_paths,
18574
+ host_env_path: hostEnvFilePath(config.baseUrl),
19018
18575
  ...publicSwitched,
19019
18576
  api_key_saved: true,
19020
- requested_auth_scope: authTarget.requested_scope,
19021
- effective_auth_scope: authTarget.effective_scope,
19022
- auth_scope_reason: authTarget.reason,
19023
- auth_scope: authTarget.effective_scope,
19024
- deprecated_command: options.deprecatedSwitch ? "org switch" : null,
19025
- replacement_command: options.deprecatedSwitch ? "deepline org set" : null,
19026
- warnings,
19027
18577
  render: {
19028
18578
  sections: [
19029
18579
  {
19030
- title: "org set",
19031
- lines: renderLines
18580
+ title: "org switch",
18581
+ lines: [
18582
+ `Switched to ${switched.org_name}.`,
18583
+ `Saved host auth in ${hostEnvFilePath(config.baseUrl)}`
18584
+ ]
19032
18585
  }
19033
18586
  ]
19034
18587
  }
@@ -19044,7 +18597,6 @@ async function handleOrgCreate(name, options) {
19044
18597
  name
19045
18598
  });
19046
18599
  saveHostEnvValues(config.baseUrl, {
19047
- DEEPLINE_HOST_URL: config.baseUrl,
19048
18600
  DEEPLINE_API_KEY: created.api_key,
19049
18601
  DEEPLINE_ACTIVE_ORG_ID: created.org_id,
19050
18602
  DEEPLINE_ACTIVE_ORG_NAME: created.org_name
@@ -19074,20 +18626,18 @@ async function handleOrgCreate(name, options) {
19074
18626
  );
19075
18627
  }
19076
18628
  function registerOrgCommands(program) {
19077
- const org = program.command("org").description("List, create, and set organizations.").addHelpText(
18629
+ const org = program.command("org").description("List, create, and switch organizations.").addHelpText(
19078
18630
  "after",
19079
18631
  `
19080
18632
  Notes:
19081
- Organizations are workspaces. By default, switching updates the auth scope
19082
- that will affect later commands from this folder.
18633
+ Organizations are workspaces. Switching organizations mutates the saved host
18634
+ auth file so later CLI commands target the selected workspace.
19083
18635
 
19084
18636
  Examples:
19085
18637
  deepline org list --json
19086
- deepline org status --json
19087
18638
  deepline org create Acme --json
19088
- deepline org set 2
19089
- deepline org set 2 --auth-scope folder
19090
- deepline org set --org-id org_123 --json
18639
+ deepline org switch 2
18640
+ deepline org switch --org-id org_123 --json
19091
18641
  `
19092
18642
  );
19093
18643
  org.command("list").description("List your organizations.").addHelpText(
@@ -19114,65 +18664,21 @@ Examples:
19114
18664
  deepline org create "Acme Sales" --json
19115
18665
  `
19116
18666
  ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleOrgCreate);
19117
- org.command("status").description("Show the current organization and auth source.").addHelpText(
18667
+ org.command("switch [selection]").description(
18668
+ "Switch to another organization and save the new API key in the host auth file."
18669
+ ).addHelpText(
19118
18670
  "after",
19119
18671
  `
19120
18672
  Notes:
19121
- Read-only. Shows whether commands resolve auth from process env, a folder
19122
- .env.deepline file, or global host auth.
19123
-
19124
- Examples:
19125
- deepline org status
19126
- deepline org status --json
19127
- `
19128
- ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleOrgStatus);
19129
- const addOrgSetOptions = (command) => command.option("--org-id <id>", "Set using an explicit organization id").option(
19130
- "--auth-scope <scope>",
19131
- "Where to save auth: auto, folder, or global",
19132
- "auto"
19133
- ).option("--json", "Emit JSON output. Also automatic when stdout is piped");
19134
- addOrgSetOptions(
19135
- org.command("set [selection]").description("Set the organization for the selected auth scope.").addHelpText(
19136
- "after",
19137
- `
19138
- Notes:
19139
- Selection can be a list number, exact organization name, or organization id.
19140
- Without a selection, prints choices. The default --auth-scope auto updates
19141
- the folder auth file when one controls this command, updates the detected
19142
- Cowork project folder when present, and otherwise updates global host auth.
19143
-
19144
- Examples:
19145
- deepline org set
19146
- deepline org set 2
19147
- deepline org set 2 --auth-scope folder
19148
- deepline org set 2 --auth-scope global
19149
- deepline org set --org-id org_123 --json
19150
- `
19151
- )
19152
- ).action(handleOrgSwitch);
19153
- addOrgSetOptions(
19154
- org.command("switch [selection]").description(
19155
- "Deprecated alias for org set. Set the organization for the selected auth scope."
19156
- ).addHelpText(
19157
- "after",
19158
- `
19159
- Notes:
19160
- Deprecated alias. Use deepline org set instead. The default --auth-scope auto
19161
- updates the folder auth file when one controls this command, updates the
19162
- detected Cowork project folder when present, and otherwise updates global host
19163
- auth.
18673
+ Mutates the saved host auth file. Selection can be a list number, exact
18674
+ organization name, or organization id. Without a selection, prints choices.
19164
18675
 
19165
18676
  Examples:
19166
18677
  deepline org switch
19167
18678
  deepline org switch 2
19168
- deepline org switch 2 --auth-scope folder
19169
- deepline org switch 2 --auth-scope global
19170
18679
  deepline org switch --org-id org_123 --json
19171
18680
  `
19172
- )
19173
- ).action(
19174
- (selection, options) => handleOrgSwitch(selection, { ...options, deprecatedSwitch: true })
19175
- );
18681
+ ).option("--org-id <id>", "Switch using an explicit organization id").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleOrgSwitch);
19176
18682
  }
19177
18683
 
19178
18684
  // src/cli/commands/quickstart.ts
@@ -22125,6 +21631,34 @@ async function fetchV1SkillNames(baseUrl) {
22125
21631
  function buildSdkSkillNames(v1SkillNames) {
22126
21632
  return sortedUniqueSkillNames(v1SkillNames);
22127
21633
  }
21634
+ async function fetchSkillsUpdate(baseUrl, localVersion) {
21635
+ const controller = new AbortController();
21636
+ const timeout = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS2);
21637
+ try {
21638
+ const response = await fetch(new URL("/api/v2/cli/update-check", baseUrl), {
21639
+ method: "POST",
21640
+ headers: { "Content-Type": "application/json" },
21641
+ body: JSON.stringify({
21642
+ skills: {
21643
+ version: localVersion
21644
+ }
21645
+ }),
21646
+ signal: controller.signal
21647
+ });
21648
+ if (!response.ok) return null;
21649
+ const data = await response.json().catch(() => null);
21650
+ const skills = data?.skills;
21651
+ if (!skills) return null;
21652
+ return {
21653
+ needsUpdate: skills.needs_update === true,
21654
+ remoteVersion: typeof skills.remote?.version === "string" ? skills.remote.version.trim() : ""
21655
+ };
21656
+ } catch {
21657
+ return null;
21658
+ } finally {
21659
+ clearTimeout(timeout);
21660
+ }
21661
+ }
22128
21662
  function buildSkillsInstallArgs(baseUrl, skillNames = DEFAULT_SDK_SKILL_NAMES) {
22129
21663
  return buildSkillsAddArgs(baseUrl, sortedUniqueSkillNames(skillNames));
22130
21664
  }
@@ -22265,12 +21799,6 @@ function writeSdkSkillsStatusLine(line) {
22265
21799
  process.stderr.write(`${line}
22266
21800
  `);
22267
21801
  }
22268
- function skillsStaleHintLine(update) {
22269
- if (!update?.needs_update || !update.remote.version) {
22270
- return null;
22271
- }
22272
- return "Deepline agent skills are out of date. Run `deepline update` to sync.";
22273
- }
22274
21802
  async function syncSdkSkillsIfNeeded(baseUrl, options = {}) {
22275
21803
  if (attemptedSync || shouldSkipSkillsSync()) return;
22276
21804
  attemptedSync = true;
@@ -22278,11 +21806,14 @@ async function syncSdkSkillsIfNeeded(baseUrl, options = {}) {
22278
21806
  if (usingPluginSkills) {
22279
21807
  return;
22280
21808
  }
22281
- const update = options.update ?? null;
22282
- if (!update?.needs_update || !update.remote.version) {
21809
+ const localVersion = readSdkSkillsLocalVersion(baseUrl);
21810
+ const update = options.update === void 0 ? await fetchSkillsUpdate(baseUrl, localVersion) : options.update ? {
21811
+ needsUpdate: options.update.needs_update,
21812
+ remoteVersion: options.update.remote.version
21813
+ } : null;
21814
+ if (!update?.needsUpdate || !update.remoteVersion) {
22283
21815
  return;
22284
21816
  }
22285
- const remoteVersion = update.remote.version;
22286
21817
  const remoteSkillNames = await fetchV1SkillNames(baseUrl);
22287
21818
  const skillNames = buildSdkSkillNames(
22288
21819
  remoteSkillNames.length > 0 ? remoteSkillNames : DEFAULT_SDK_SKILL_NAMES
@@ -22292,17 +21823,11 @@ async function syncSdkSkillsIfNeeded(baseUrl, options = {}) {
22292
21823
  const installed = await runSkillsInstall(baseUrl, skillNames);
22293
21824
  if (!installed) return;
22294
21825
  runLegacySkillsCleanup();
22295
- writeLocalSkillsVersion(baseUrl, remoteVersion);
21826
+ writeLocalSkillsVersion(baseUrl, update.remoteVersion);
22296
21827
  writeSdkSkillsStatusLine("Deepline agent skills are up to date.");
22297
21828
  }
22298
21829
 
22299
21830
  // src/cli/commands/update.ts
22300
- async function resolveSkillsVerdictFromCompat(baseUrl) {
22301
- const { response } = await checkSdkCompatibility(baseUrl, {
22302
- skillsVersion: readSdkSkillsLocalVersion(baseUrl)
22303
- });
22304
- return response?.skills ?? null;
22305
- }
22306
21831
  var NPM_SDK_INSTALL_COMMON_FLAGS = ["--no-audit", "--no-fund"];
22307
21832
  var NPM_SDK_GLOBAL_INSTALL_FLAGS = [
22308
21833
  "--no-audit",
@@ -22741,7 +22266,6 @@ async function runUpdateCommand(options, dependencies = {}) {
22741
22266
  const detectBaseUrl = dependencies.detectBaseUrl ?? autoDetectBaseUrl;
22742
22267
  const resolvePlan = dependencies.resolvePlan ?? resolveUpdatePlan;
22743
22268
  const runPlan = dependencies.runPlan ?? runUpdatePlan;
22744
- const resolveSkillsVerdict = dependencies.resolveSkillsVerdict ?? resolveSkillsVerdictFromCompat;
22745
22269
  const syncSkills = dependencies.syncSkillsIfNeeded ?? syncSdkSkillsIfNeeded;
22746
22270
  const stderr = dependencies.stderr ?? process.stderr;
22747
22271
  const plan = resolvePlan();
@@ -22786,9 +22310,7 @@ async function runUpdateCommand(options, dependencies = {}) {
22786
22310
  if (updateExitCode !== 0) {
22787
22311
  return updateExitCode;
22788
22312
  }
22789
- const updatedBaseUrl = normalizeBaseUrl3(detectBaseUrl());
22790
- const skillsUpdate = await resolveSkillsVerdict(updatedBaseUrl);
22791
- await syncSkills(updatedBaseUrl, { update: skillsUpdate });
22313
+ await syncSkills(normalizeBaseUrl3(detectBaseUrl()));
22792
22314
  return 0;
22793
22315
  }
22794
22316
  function registerUpdateCommand(program) {
@@ -23505,7 +23027,7 @@ Exit codes:
23505
23027
  const baseUrl = autoDetectBaseUrl().replace(/\/$/, "");
23506
23028
  const compatibilityCommand = compatibilityCommandPath(actionCommand) || actionCommand.name();
23507
23029
  const shouldDeferSkillsSync = shouldDeferSkillsSyncForCommand();
23508
- const skillsVersion = readSdkSkillsLocalVersion(baseUrl);
23030
+ const skillsVersion = shouldDeferSkillsSync ? void 0 : readSdkSkillsLocalVersion(baseUrl);
23509
23031
  const compatibility = await traceCliSpan(
23510
23032
  "cli.sdk_compatibility",
23511
23033
  {
@@ -23541,14 +23063,8 @@ Exit codes:
23541
23063
  if (printStartupPhase) {
23542
23064
  progress?.phase("checking sdk skills");
23543
23065
  }
23544
- const skillsUpdate = compatibility.response?.skills ?? null;
23545
- if (shouldDeferSkillsSync) {
23546
- const hint = skillsStaleHintLine(skillsUpdate);
23547
- if (hint && !process.argv.includes("--json")) {
23548
- process.stderr.write(`${hint}
23549
- `);
23550
- }
23551
- } else {
23066
+ if (!shouldDeferSkillsSync) {
23067
+ const skillsUpdate = compatibility.response && Object.prototype.hasOwnProperty.call(compatibility.response, "skills") ? compatibility.response.skills ?? null : void 0;
23552
23068
  await traceCliSpan(
23553
23069
  "cli.sdk_skills_sync",
23554
23070
  { baseUrl },