deepline 0.1.266 → 0.1.267

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.
@@ -1,4 +1,4 @@
1
- import { SDK_API_CONTRACT, SDK_VERSION } from './version.js';
1
+ import { SDK_API_CONTRACT, SDK_API_MAJOR, SDK_VERSION } from './version.js';
2
2
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
3
3
  import { homedir } from 'node:os';
4
4
  import { dirname, join } from 'node:path';
@@ -87,6 +87,7 @@ function compatibilityCacheKey(
87
87
  baseUrl: baseUrl.replace(/\/$/, ''),
88
88
  version: SDK_VERSION,
89
89
  apiContract: SDK_API_CONTRACT,
90
+ apiMajor: SDK_API_MAJOR,
90
91
  command: command?.trim() || null,
91
92
  skillsVersion: skillsVersion ?? null,
92
93
  });
@@ -186,6 +187,7 @@ export async function checkSdkCompatibility(
186
187
  headers: {
187
188
  'User-Agent': `deepline-ts-sdk/${SDK_VERSION}`,
188
189
  'X-Deepline-SDK-Version': SDK_VERSION,
190
+ 'X-Deepline-API-Major': String(SDK_API_MAJOR),
189
191
  'X-Deepline-API-Contract': SDK_API_CONTRACT,
190
192
  },
191
193
  signal: controller.signal,
@@ -12,9 +12,10 @@
12
12
  *
13
13
  * Edit THIS file by hand only for deliberate release decisions:
14
14
  * - minor/major version bumps (set `version`),
15
- * - `apiContract` cutovers (see `docs/sdk-runtime-compatibility.md`),
15
+ * - API-major cutovers (set `contracts.api.currentMajor`; leave `version` to the
16
+ * publish-time patch selector),
16
17
  * - support-window moves (`minimumSupported` / `deprecatedBelow`).
17
- * The automation never touches `apiContract`, `minimumSupported`, or
18
+ * The automation never touches API compatibility policy, `minimumSupported`, or
18
19
  * `deprecatedBelow`.
19
20
  *
20
21
  * Everything else derives from these values:
@@ -35,6 +36,37 @@
35
36
 
36
37
  export type SdkReleaseChannel = 'latest' | 'next' | 'beta';
37
38
 
39
+ /**
40
+ * The named public protocols. These are intentionally independent:
41
+ *
42
+ * - `api` is the HTTP SDK/CLI protocol. It is additive within a major.
43
+ * - `playArtifact` is the immutable client-bundled Play payload ABI.
44
+ * - `release` controls promotion/publishing; it is not a client protocol.
45
+ *
46
+ * Do not use an SDK package version or a date string as an artifact ABI.
47
+ */
48
+ export type DeeplineContractPolicy = {
49
+ api: {
50
+ name: 'sdk-http-api';
51
+ currentMajor: number;
52
+ supportedMajors: readonly number[];
53
+ /** Transitional value for installed SDKs that only send the old header. */
54
+ legacyWireIds: readonly string[];
55
+ };
56
+ playArtifact: {
57
+ name: 'play-artifact-runtime';
58
+ currentVersion: number;
59
+ supportedVersions: readonly number[];
60
+ };
61
+ release: {
62
+ name: 'production-sdk-release';
63
+ /** npm may publish only from the active, healthy Production SHA. */
64
+ publishFrom: 'latest-successful-production-deployment';
65
+ /** A newer merge cancels an in-flight decision; reconciliation picks the last healthy SHA. */
66
+ coalesce: 'latest-healthy';
67
+ };
68
+ };
69
+
38
70
  export type SdkSupportPolicy = {
39
71
  /**
40
72
  * Anything strictly below this returns `status: "unsupported"` from
@@ -57,6 +89,8 @@ export type SdkSupportPolicy = {
57
89
  minimumSupported: string;
58
90
  reason: string;
59
91
  }>;
92
+ /** Previously published wire contracts that remain supported. */
93
+ compatibleApiContracts?: readonly string[];
60
94
  /**
61
95
  * Published package versions that must keep working for direct SDK tool
62
96
  * callers. CI installs each package from npm and exercises `tools.get` and
@@ -77,12 +111,8 @@ export type SdkRelease = {
77
111
  * publish time (auto-bump); edit by hand only for minor/major releases.
78
112
  */
79
113
  version: string;
80
- /**
81
- * SDK/API contract identifier. Bump on incompatible protocol or schema
82
- * changes between the installed SDK/CLI and the Deepline backend.
83
- * See `docs/sdk-runtime-compatibility.md`.
84
- */
85
- apiContract: string;
114
+ /** Named compatibility policies. This is the only authored contract policy. */
115
+ contracts: DeeplineContractPolicy;
86
116
  /** Public support policy reported by `/api/v2/sdk/compat`. */
87
117
  supportPolicy: SdkSupportPolicy;
88
118
  };
@@ -125,8 +155,31 @@ export const SDK_RELEASE = {
125
155
  // 0.1.253 makes play-page browser opening opt-in and retires --no-open.
126
156
  // 0.1.254 removes the internal operations tree from the published SDK CLI.
127
157
  // Operators use the checkout-local deepline-admin binary instead.
128
- version: '0.1.266',
129
- apiContract: '2026-07-admin-cli-local-cutover',
158
+ version: '0.1.267',
159
+ contracts: {
160
+ api: {
161
+ name: 'sdk-http-api',
162
+ // API v2 is append-only. A breaking public request/response change needs
163
+ // v3 and an explicit v2 support-window decision, never a patch release.
164
+ currentMajor: 2,
165
+ supportedMajors: [2],
166
+ // Accepted only to bridge SDKs released before X-Deepline-API-Major.
167
+ legacyWireIds: [
168
+ '2026-07-admin-cli-local-cutover',
169
+ '2026-07-native-monitor-launch-hard-cutover',
170
+ ],
171
+ },
172
+ playArtifact: {
173
+ name: 'play-artifact-runtime',
174
+ currentVersion: 2,
175
+ supportedVersions: [1, 2],
176
+ },
177
+ release: {
178
+ name: 'production-sdk-release',
179
+ publishFrom: 'latest-successful-production-deployment',
180
+ coalesce: 'latest-healthy',
181
+ },
182
+ },
130
183
  supportPolicy: {
131
184
  minimumSupported: '0.1.53',
132
185
  deprecatedBelow: '0.1.219',
@@ -3,4 +3,8 @@
3
3
  import { SDK_RELEASE } from './release.js';
4
4
 
5
5
  export const SDK_VERSION: string = SDK_RELEASE.version;
6
- export const SDK_API_CONTRACT: string = SDK_RELEASE.apiContract;
6
+ /** Numbered SDK HTTP API major sent by current SDK/CLI clients. */
7
+ export const SDK_API_MAJOR: number = SDK_RELEASE.contracts.api.currentMajor;
8
+ /** @deprecated Transitional wire id for pre-major-header SDKs only. */
9
+ export const SDK_API_CONTRACT: string =
10
+ SDK_RELEASE.contracts.api.legacyWireIds[0] ?? `api-v${SDK_API_MAJOR}`;
@@ -5432,13 +5432,13 @@ export class PlayContextImpl {
5432
5432
  this.rowStates.get(idx)?.results.set(fieldName, cellValue);
5433
5433
  const currentCellMeta =
5434
5434
  this.activeMapCellMeta?.get(rowKey)?.[fieldName];
5435
- const currentCellStatus =
5435
+ const currentCellRecord =
5436
5436
  currentCellMeta &&
5437
5437
  typeof currentCellMeta === 'object' &&
5438
- !Array.isArray(currentCellMeta) &&
5439
- 'status' in currentCellMeta
5440
- ? (currentCellMeta as { status?: unknown }).status
5438
+ !Array.isArray(currentCellMeta)
5439
+ ? (currentCellMeta as { status?: unknown; reused?: unknown })
5441
5440
  : null;
5441
+ const currentCellStatus = currentCellRecord?.status ?? null;
5442
5442
  if (currentCellStatus === 'skipped') {
5443
5443
  if (
5444
5444
  shouldPersistMapCellField(fieldName) &&
@@ -5455,13 +5455,25 @@ export class PlayContextImpl {
5455
5455
  }
5456
5456
  continue;
5457
5457
  }
5458
+ // A cell whose underlying durable work was fully satisfied from
5459
+ // content-addressed receipts recorded a `cached`/`reused` cell-meta
5460
+ // marker while the body ran (see resolveRequestsFromReceipt). Emitting
5461
+ // an unconditional `completed` here would clobber that marker to a
5462
+ // non-reused `completed`, so the run's per-column `cached` counter
5463
+ // reads 0 on a full-reuse rerun even though provider spend was 0.
5464
+ // Preserve the reuse signal so `columnStats.cached` reflects real
5465
+ // receipt reuse consistent with the near-zero provider spend.
5466
+ const cellWasReused =
5467
+ currentCellStatus === 'cached' &&
5468
+ currentCellRecord?.reused === true;
5458
5469
  this.emitScopedFieldMetaUpdate({
5459
5470
  rowId: idx,
5460
5471
  key: rowKey,
5461
5472
  tableNamespace: normalizedTableNamespace,
5462
5473
  fieldName,
5463
- status: 'completed',
5464
- stage: 'completed',
5474
+ status: cellWasReused ? 'cached' : 'completed',
5475
+ stage: cellWasReused ? 'cached' : 'completed',
5476
+ ...(cellWasReused ? { reused: true } : {}),
5465
5477
  completedAt: Date.now(),
5466
5478
  dataPatch: shouldPersistMapCellField(fieldName)
5467
5479
  ? { [fieldName]: cellValue }
@@ -0,0 +1,30 @@
1
+ type DatasetLogIdentity = {
2
+ path: string;
3
+ tableNamespace: string;
4
+ };
5
+
6
+ /**
7
+ * Dataset paths identify runtime state. They are not CLI export selectors: a
8
+ * returned result field (for example `result.rows`) is the supported export
9
+ * handle. Keep this distinction explicit in operator logs.
10
+ */
11
+ export function formatDatasetRegistrationLog(input: {
12
+ dataset: DatasetLogIdentity;
13
+ rows: number;
14
+ }): string {
15
+ if (input.rows === 0) {
16
+ return `Dataset ${input.dataset.path} registered (0 rows); export unavailable: empty dataset`;
17
+ }
18
+ return `Dataset ${input.dataset.path} registered (${input.rows} rows); awaiting terminal persistence`;
19
+ }
20
+
21
+ export function formatDatasetAvailabilityLog(input: {
22
+ runId: string;
23
+ dataset: DatasetLogIdentity;
24
+ persistedRows: number;
25
+ }): string {
26
+ if (input.persistedRows === 0) {
27
+ return `Dataset ${input.dataset.path} available: 0 persisted rows; export unavailable: empty dataset`;
28
+ }
29
+ return `Dataset ${input.dataset.path} available: ${input.persistedRows} persisted rows; inspect deepline runs get ${input.runId} --full --json for the verified export action`;
30
+ }
package/dist/cli/index.js CHANGED
@@ -718,8 +718,31 @@ var SDK_RELEASE = {
718
718
  // 0.1.253 makes play-page browser opening opt-in and retires --no-open.
719
719
  // 0.1.254 removes the internal operations tree from the published SDK CLI.
720
720
  // Operators use the checkout-local deepline-admin binary instead.
721
- version: "0.1.266",
722
- apiContract: "2026-07-admin-cli-local-cutover",
721
+ version: "0.1.267",
722
+ contracts: {
723
+ api: {
724
+ name: "sdk-http-api",
725
+ // API v2 is append-only. A breaking public request/response change needs
726
+ // v3 and an explicit v2 support-window decision, never a patch release.
727
+ currentMajor: 2,
728
+ supportedMajors: [2],
729
+ // Accepted only to bridge SDKs released before X-Deepline-API-Major.
730
+ legacyWireIds: [
731
+ "2026-07-admin-cli-local-cutover",
732
+ "2026-07-native-monitor-launch-hard-cutover"
733
+ ]
734
+ },
735
+ playArtifact: {
736
+ name: "play-artifact-runtime",
737
+ currentVersion: 2,
738
+ supportedVersions: [1, 2]
739
+ },
740
+ release: {
741
+ name: "production-sdk-release",
742
+ publishFrom: "latest-successful-production-deployment",
743
+ coalesce: "latest-healthy"
744
+ }
745
+ },
723
746
  supportPolicy: {
724
747
  minimumSupported: "0.1.53",
725
748
  deprecatedBelow: "0.1.219",
@@ -816,7 +839,8 @@ var SDK_RELEASE = {
816
839
 
817
840
  // src/version.ts
818
841
  var SDK_VERSION = SDK_RELEASE.version;
819
- var SDK_API_CONTRACT = SDK_RELEASE.apiContract;
842
+ var SDK_API_MAJOR = SDK_RELEASE.contracts.api.currentMajor;
843
+ var SDK_API_CONTRACT = SDK_RELEASE.contracts.api.legacyWireIds[0] ?? `api-v${SDK_API_MAJOR}`;
820
844
 
821
845
  // src/agent-runtime.ts
822
846
  var import_node_os2 = require("os");
@@ -4838,6 +4862,7 @@ function compatibilityCacheKey(baseUrl, command, skillsVersion) {
4838
4862
  baseUrl: baseUrl.replace(/\/$/, ""),
4839
4863
  version: SDK_VERSION,
4840
4864
  apiContract: SDK_API_CONTRACT,
4865
+ apiMajor: SDK_API_MAJOR,
4841
4866
  command: command?.trim() || null,
4842
4867
  skillsVersion: skillsVersion ?? null
4843
4868
  });
@@ -4906,6 +4931,7 @@ async function checkSdkCompatibility(baseUrl, options = {}) {
4906
4931
  headers: {
4907
4932
  "User-Agent": `deepline-ts-sdk/${SDK_VERSION}`,
4908
4933
  "X-Deepline-SDK-Version": SDK_VERSION,
4934
+ "X-Deepline-API-Major": String(SDK_API_MAJOR),
4909
4935
  "X-Deepline-API-Contract": SDK_API_CONTRACT
4910
4936
  },
4911
4937
  signal: controller.signal
@@ -5284,26 +5310,29 @@ function browserOpeningDisabled() {
5284
5310
  ).trim().toLowerCase();
5285
5311
  return value === "1" || value === "true" || value === "yes" || value === "on";
5286
5312
  }
5287
- function openInBrowser(url) {
5313
+ function openInBrowser(url, options = {}) {
5288
5314
  try {
5289
- if (browserOpeningDisabled()) return;
5315
+ if (browserOpeningDisabled()) return "failed";
5290
5316
  const targetUrl = String(url || "").trim();
5291
- if (!targetUrl) return;
5292
- if (!claimBrowserOpen(Date.now(), void 0, targetUrl)) return;
5317
+ if (!targetUrl) return "failed";
5318
+ if (options.deduplicate !== false && !claimBrowserOpen(Date.now(), void 0, targetUrl)) {
5319
+ return "suppressed";
5320
+ }
5293
5321
  const allowFocus = true;
5294
5322
  if (process.platform === "darwin") {
5295
- openUrlMacos(targetUrl, allowFocus);
5296
- return;
5323
+ return openUrlMacos(targetUrl, allowFocus) ? "opened" : "failed";
5297
5324
  }
5298
- if (!allowFocus) return;
5325
+ if (!allowFocus) return "failed";
5299
5326
  if (process.platform === "win32") {
5300
5327
  childProcess.execFileSync("cmd.exe", ["/c", "start", "", targetUrl], {
5301
5328
  stdio: "ignore"
5302
5329
  });
5303
- return;
5330
+ return "opened";
5304
5331
  }
5305
5332
  childProcess.execFileSync("xdg-open", [targetUrl], { stdio: "ignore" });
5333
+ return "opened";
5306
5334
  } catch {
5335
+ return "failed";
5307
5336
  }
5308
5337
  }
5309
5338
  function sleep3(ms) {
@@ -29514,6 +29543,18 @@ function inferNpmGlobalPrefixFromEntrypoint(entrypoint) {
29514
29543
  const prefix = normalized.startsWith("/") && prefixParts[0] !== "" ? `/${prefixParts.join("/")}` : prefixParts.join("/");
29515
29544
  return prefix || null;
29516
29545
  }
29546
+ function isHomebrewFormulaEntrypoint(entrypoint) {
29547
+ const normalized = (() => {
29548
+ try {
29549
+ return (0, import_node_fs17.realpathSync)(entrypoint);
29550
+ } catch {
29551
+ return (0, import_node_path19.resolve)(entrypoint);
29552
+ }
29553
+ })();
29554
+ const parts = normalized.split(/[\\/]+/);
29555
+ const cellarIndex = parts.lastIndexOf("Cellar");
29556
+ return cellarIndex >= 0 && parts[cellarIndex + 1] === "deepline" && parts.slice(cellarIndex + 3).includes("libexec");
29557
+ }
29517
29558
  function resolveUpdatePlan(options = {}) {
29518
29559
  const env = options.env ?? process.env;
29519
29560
  const homeDir2 = options.homeDir ?? (0, import_node_os14.homedir)();
@@ -29526,6 +29567,12 @@ function resolveUpdatePlan(options = {}) {
29526
29567
  manualCommand: buildSourceUpdateCommand(sourceRoot)
29527
29568
  };
29528
29569
  }
29570
+ if (entrypoint && isHomebrewFormulaEntrypoint(entrypoint)) {
29571
+ return {
29572
+ kind: "homebrew",
29573
+ manualCommand: "brew upgrade deepline"
29574
+ };
29575
+ }
29529
29576
  const sidecarPlan = resolvePythonSidecarUpdatePlan({
29530
29577
  entrypoint,
29531
29578
  env,
@@ -29557,7 +29604,7 @@ function resolveUpdatePlan(options = {}) {
29557
29604
  }
29558
29605
  var AUTO_UPDATE_FAILURE_FILE = ".auto-update-failure.json";
29559
29606
  function autoUpdateFailurePath(plan) {
29560
- if (plan.kind === "source") return null;
29607
+ if (plan.kind === "source" || plan.kind === "homebrew") return null;
29561
29608
  if (plan.kind === "python-sidecar") {
29562
29609
  return (0, import_node_path19.join)(plan.stateDir, AUTO_UPDATE_FAILURE_FILE);
29563
29610
  }
@@ -29570,7 +29617,7 @@ function autoUpdateFailurePath(plan) {
29570
29617
  );
29571
29618
  }
29572
29619
  function autoUpdatePackageSpec(plan) {
29573
- if (plan.kind === "source") return "";
29620
+ if (plan.kind === "source" || plan.kind === "homebrew") return "";
29574
29621
  if (plan.kind === "python-sidecar") return plan.packageSpec;
29575
29622
  return plan.args[plan.args.length - 1] ?? plan.manualCommand;
29576
29623
  }
@@ -29591,7 +29638,7 @@ function readAutoUpdateFailure(plan) {
29591
29638
  }
29592
29639
  function writeAutoUpdateFailure(plan, exitCode) {
29593
29640
  const path = autoUpdateFailurePath(plan);
29594
- if (!path || plan.kind === "source") return;
29641
+ if (!path || plan.kind === "source" || plan.kind === "homebrew") return;
29595
29642
  const marker = {
29596
29643
  kind: plan.kind,
29597
29644
  packageSpec: autoUpdatePackageSpec(plan),
@@ -29616,7 +29663,9 @@ function clearAutoUpdateFailure(plan) {
29616
29663
  }
29617
29664
  function matchingAutoUpdateFailure(plan) {
29618
29665
  const marker = readAutoUpdateFailure(plan);
29619
- if (!marker || plan.kind === "source") return null;
29666
+ if (!marker || plan.kind === "source" || plan.kind === "homebrew") {
29667
+ return null;
29668
+ }
29620
29669
  if (marker.kind !== plan.kind) return null;
29621
29670
  if (marker.packageSpec !== autoUpdatePackageSpec(plan)) return null;
29622
29671
  return marker;
@@ -29874,6 +29923,8 @@ async function runUpdatePlan(plan) {
29874
29923
  });
29875
29924
  } else if (plan.kind === "python-sidecar") {
29876
29925
  exitCode = await runPythonSidecarUpdatePlan(plan);
29926
+ } else if (plan.kind === "homebrew") {
29927
+ exitCode = 0;
29877
29928
  }
29878
29929
  if (exitCode === 0) {
29879
29930
  clearAutoUpdateFailure(plan);
@@ -29912,6 +29963,9 @@ async function runUpdateCommand(options, dependencies = {}) {
29912
29963
  lines: plan.kind === "source" ? [
29913
29964
  "This Deepline CLI is running from SDK source, so it cannot safely update itself like an npm global.",
29914
29965
  `Update the backing checkout with: ${plan.manualCommand}`
29966
+ ] : plan.kind === "homebrew" ? [
29967
+ "This Deepline CLI was installed by Homebrew, which owns its upgrades.",
29968
+ `Update it with: ${plan.manualCommand}`
29915
29969
  ] : plan.kind === "python-sidecar" ? [
29916
29970
  "This Deepline CLI is running from the Python-managed SDK sidecar.",
29917
29971
  "Updating will refresh that sidecar, not a global npm binary."
@@ -29936,7 +29990,7 @@ async function runUpdateCommand(options, dependencies = {}) {
29936
29990
  );
29937
29991
  return 0;
29938
29992
  }
29939
- if (plan.kind === "source") {
29993
+ if (plan.kind === "source" || plan.kind === "homebrew") {
29940
29994
  printCommandEnvelope({ ...plan, render }, { json: false });
29941
29995
  return 0;
29942
29996
  }
@@ -29955,6 +30009,8 @@ function registerUpdateCommand(program) {
29955
30009
  `
29956
30010
  Notes:
29957
30011
  For the published npm CLI, this runs npm install -g deepline@latest.
30012
+ For a Homebrew installation, this prints brew upgrade deepline; Homebrew
30013
+ owns formula upgrades and Deepline never runs npm inside its Cellar.
29958
30014
  For Python-managed SDK sidecars, this refreshes the sidecar that launched
29959
30015
  the current SDK CLI instead of changing a global npm binary.
29960
30016
  For repo-backed SDK wrappers such as cli-env sdk-prod or sdk-worktree, this
@@ -30074,14 +30130,37 @@ function resolveScopeRoot(scope) {
30074
30130
  function authScopeForSetup(scope) {
30075
30131
  return scope === "local" ? "folder" : "global";
30076
30132
  }
30077
- function shouldOpenSetupAuthorization(runtime = detectAgentRuntime()) {
30078
- return runtime !== "claude_cowork";
30079
- }
30080
30133
  function openSetupAuthorization(authorizationUrl, options = {}) {
30081
30134
  const url = authorizationUrl.trim();
30082
- if (!url || !shouldOpenSetupAuthorization(options.runtime)) return false;
30083
- (options.open ?? openInBrowser)(url);
30084
- return true;
30135
+ if (!url) return "failed";
30136
+ if (options.open) return options.open(url);
30137
+ const result = openInBrowser(url, { deduplicate: false });
30138
+ return result === "opened" ? "opened" : "failed";
30139
+ }
30140
+ function buildPendingAuthorizationOutput(input2) {
30141
+ const authorizationUrl = input2.authorizationUrl.trim();
30142
+ if (input2.browserOpenStatus === "opened") {
30143
+ return {
30144
+ authorizationUrl: null,
30145
+ next: `Complete browser approval, then run: ${input2.resumeCommand}`,
30146
+ lines: ["Complete authorization in the browser window Deepline opened."]
30147
+ };
30148
+ }
30149
+ if (authorizationUrl) {
30150
+ return {
30151
+ authorizationUrl,
30152
+ next: `Open the authorization URL, approve it, then run: ${input2.resumeCommand}`,
30153
+ lines: [
30154
+ "Browser launch failed. Open the authorization URL to continue.",
30155
+ authorizationUrl
30156
+ ]
30157
+ };
30158
+ }
30159
+ return {
30160
+ authorizationUrl: null,
30161
+ next: `Authorization is pending without a browser URL. Retry: ${input2.resumeCommand}`,
30162
+ lines: ["Authorization is pending, but no browser URL was returned."]
30163
+ };
30085
30164
  }
30086
30165
  function setupStatePath(baseUrl, scope, root) {
30087
30166
  return scope === "local" && root ? (0, import_node_path20.join)(root, ".deepline", "setup", "state.json") : (0, import_node_path20.join)(sdkCliStateDirPath(baseUrl), "setup.json");
@@ -30111,15 +30190,6 @@ function parseCapturedJson(stdout) {
30111
30190
  function asRecord2(value) {
30112
30191
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
30113
30192
  }
30114
- function printCapturedAuthorizationUrl(stdout) {
30115
- const urls = stdout.match(/https:\/\/[^\s]+/g) ?? [];
30116
- for (const url of new Set(
30117
- urls.map((value) => value.replace(/[).,]+$/, ""))
30118
- )) {
30119
- process.stderr.write(`Authorize Deepline: ${url}
30120
- `);
30121
- }
30122
- }
30123
30193
  function safeRead(path) {
30124
30194
  try {
30125
30195
  return (0, import_node_fs18.readFileSync)(path, "utf8");
@@ -30458,18 +30528,32 @@ function pendingResult(input2) {
30458
30528
  status: "authorization_pending",
30459
30529
  phases: input2.phases
30460
30530
  });
30531
+ let browserOpenStatus = "failed";
30461
30532
  if (input2.authorizationUrl) {
30462
- openSetupAuthorization(input2.authorizationUrl);
30463
- process.stderr.write(`Authorize Deepline: ${input2.authorizationUrl}
30533
+ browserOpenStatus = openSetupAuthorization(input2.authorizationUrl);
30534
+ if (browserOpenStatus === "opened") {
30535
+ process.stderr.write(
30536
+ "Opened Deepline authorization in your browser. Complete approval there.\n"
30537
+ );
30538
+ } else if (browserOpenStatus === "failed") {
30539
+ process.stderr.write(`Authorize Deepline: ${input2.authorizationUrl}
30464
30540
  `);
30541
+ }
30465
30542
  }
30543
+ const pendingOutput = buildPendingAuthorizationOutput({
30544
+ authorizationUrl: input2.authorizationUrl,
30545
+ browserOpenStatus,
30546
+ resumeCommand: setupResumeCommand(input2.baseUrl, input2.scope)
30547
+ });
30466
30548
  printCommandEnvelope(
30467
30549
  {
30468
30550
  ok: true,
30469
30551
  status: "authorization_pending",
30470
30552
  complete: false,
30471
30553
  scope: input2.scope,
30472
- authorizationUrl: input2.authorizationUrl || null,
30554
+ authorizationUrl: pendingOutput.authorizationUrl,
30555
+ browserOpened: browserOpenStatus === "opened",
30556
+ browserOpenStatus,
30473
30557
  statePath,
30474
30558
  phases: input2.phases,
30475
30559
  currentPhase: "auth",
@@ -30479,15 +30563,12 @@ function pendingResult(input2) {
30479
30563
  scope: input2.scope,
30480
30564
  phase: "auth"
30481
30565
  }),
30482
- next: `Approve the link, then run: ${setupResumeCommand(input2.baseUrl, input2.scope)}`,
30566
+ next: pendingOutput.next,
30483
30567
  render: {
30484
30568
  sections: [
30485
30569
  {
30486
30570
  title: "setup",
30487
- lines: [
30488
- "Authorization is waiting for browser approval.",
30489
- ...input2.authorizationUrl ? [input2.authorizationUrl] : []
30490
- ]
30571
+ lines: pendingOutput.lines
30491
30572
  }
30492
30573
  ]
30493
30574
  }
@@ -30656,10 +30737,9 @@ async function runSetupCommand(options) {
30656
30737
  const pending = readPendingAuthClaim(baseUrl, authScope);
30657
30738
  if (pending) {
30658
30739
  process.stderr.write("Checking pending Deepline authorization...\n");
30659
- const waited = await captureStdout2(
30740
+ await captureStdout2(
30660
30741
  () => handleWait(["--timeout", "1", "--auth-scope", authScope])
30661
30742
  );
30662
- printCapturedAuthorizationUrl(waited.stdout);
30663
30743
  auth = await readAuthStatus(authScope);
30664
30744
  const resumedAuthFailure = reportSetupAuthStatusFailure({
30665
30745
  auth,
@@ -30695,7 +30775,6 @@ async function runSetupCommand(options) {
30695
30775
  const registered = await captureStdout2(
30696
30776
  () => handleRegister(["--wait", waitMode, "--auth-scope", authScope])
30697
30777
  );
30698
- printCapturedAuthorizationUrl(registered.stdout);
30699
30778
  if (registered.exitCode !== 0) {
30700
30779
  return reportSetupPhaseFailure({
30701
30780
  baseUrl,
@@ -703,8 +703,31 @@ var SDK_RELEASE = {
703
703
  // 0.1.253 makes play-page browser opening opt-in and retires --no-open.
704
704
  // 0.1.254 removes the internal operations tree from the published SDK CLI.
705
705
  // Operators use the checkout-local deepline-admin binary instead.
706
- version: "0.1.266",
707
- apiContract: "2026-07-admin-cli-local-cutover",
706
+ version: "0.1.267",
707
+ contracts: {
708
+ api: {
709
+ name: "sdk-http-api",
710
+ // API v2 is append-only. A breaking public request/response change needs
711
+ // v3 and an explicit v2 support-window decision, never a patch release.
712
+ currentMajor: 2,
713
+ supportedMajors: [2],
714
+ // Accepted only to bridge SDKs released before X-Deepline-API-Major.
715
+ legacyWireIds: [
716
+ "2026-07-admin-cli-local-cutover",
717
+ "2026-07-native-monitor-launch-hard-cutover"
718
+ ]
719
+ },
720
+ playArtifact: {
721
+ name: "play-artifact-runtime",
722
+ currentVersion: 2,
723
+ supportedVersions: [1, 2]
724
+ },
725
+ release: {
726
+ name: "production-sdk-release",
727
+ publishFrom: "latest-successful-production-deployment",
728
+ coalesce: "latest-healthy"
729
+ }
730
+ },
708
731
  supportPolicy: {
709
732
  minimumSupported: "0.1.53",
710
733
  deprecatedBelow: "0.1.219",
@@ -801,7 +824,8 @@ var SDK_RELEASE = {
801
824
 
802
825
  // src/version.ts
803
826
  var SDK_VERSION = SDK_RELEASE.version;
804
- var SDK_API_CONTRACT = SDK_RELEASE.apiContract;
827
+ var SDK_API_MAJOR = SDK_RELEASE.contracts.api.currentMajor;
828
+ var SDK_API_CONTRACT = SDK_RELEASE.contracts.api.legacyWireIds[0] ?? `api-v${SDK_API_MAJOR}`;
805
829
 
806
830
  // src/agent-runtime.ts
807
831
  import { homedir as homedir2 } from "os";
@@ -4823,6 +4847,7 @@ function compatibilityCacheKey(baseUrl, command, skillsVersion) {
4823
4847
  baseUrl: baseUrl.replace(/\/$/, ""),
4824
4848
  version: SDK_VERSION,
4825
4849
  apiContract: SDK_API_CONTRACT,
4850
+ apiMajor: SDK_API_MAJOR,
4826
4851
  command: command?.trim() || null,
4827
4852
  skillsVersion: skillsVersion ?? null
4828
4853
  });
@@ -4891,6 +4916,7 @@ async function checkSdkCompatibility(baseUrl, options = {}) {
4891
4916
  headers: {
4892
4917
  "User-Agent": `deepline-ts-sdk/${SDK_VERSION}`,
4893
4918
  "X-Deepline-SDK-Version": SDK_VERSION,
4919
+ "X-Deepline-API-Major": String(SDK_API_MAJOR),
4894
4920
  "X-Deepline-API-Contract": SDK_API_CONTRACT
4895
4921
  },
4896
4922
  signal: controller.signal
@@ -5281,26 +5307,29 @@ function browserOpeningDisabled() {
5281
5307
  ).trim().toLowerCase();
5282
5308
  return value === "1" || value === "true" || value === "yes" || value === "on";
5283
5309
  }
5284
- function openInBrowser(url) {
5310
+ function openInBrowser(url, options = {}) {
5285
5311
  try {
5286
- if (browserOpeningDisabled()) return;
5312
+ if (browserOpeningDisabled()) return "failed";
5287
5313
  const targetUrl = String(url || "").trim();
5288
- if (!targetUrl) return;
5289
- if (!claimBrowserOpen(Date.now(), void 0, targetUrl)) return;
5314
+ if (!targetUrl) return "failed";
5315
+ if (options.deduplicate !== false && !claimBrowserOpen(Date.now(), void 0, targetUrl)) {
5316
+ return "suppressed";
5317
+ }
5290
5318
  const allowFocus = true;
5291
5319
  if (process.platform === "darwin") {
5292
- openUrlMacos(targetUrl, allowFocus);
5293
- return;
5320
+ return openUrlMacos(targetUrl, allowFocus) ? "opened" : "failed";
5294
5321
  }
5295
- if (!allowFocus) return;
5322
+ if (!allowFocus) return "failed";
5296
5323
  if (process.platform === "win32") {
5297
5324
  childProcess.execFileSync("cmd.exe", ["/c", "start", "", targetUrl], {
5298
5325
  stdio: "ignore"
5299
5326
  });
5300
- return;
5327
+ return "opened";
5301
5328
  }
5302
5329
  childProcess.execFileSync("xdg-open", [targetUrl], { stdio: "ignore" });
5330
+ return "opened";
5303
5331
  } catch {
5332
+ return "failed";
5304
5333
  }
5305
5334
  }
5306
5335
  function sleep3(ms) {
@@ -29571,6 +29600,18 @@ function inferNpmGlobalPrefixFromEntrypoint(entrypoint) {
29571
29600
  const prefix = normalized.startsWith("/") && prefixParts[0] !== "" ? `/${prefixParts.join("/")}` : prefixParts.join("/");
29572
29601
  return prefix || null;
29573
29602
  }
29603
+ function isHomebrewFormulaEntrypoint(entrypoint) {
29604
+ const normalized = (() => {
29605
+ try {
29606
+ return realpathSync3(entrypoint);
29607
+ } catch {
29608
+ return resolve13(entrypoint);
29609
+ }
29610
+ })();
29611
+ const parts = normalized.split(/[\\/]+/);
29612
+ const cellarIndex = parts.lastIndexOf("Cellar");
29613
+ return cellarIndex >= 0 && parts[cellarIndex + 1] === "deepline" && parts.slice(cellarIndex + 3).includes("libexec");
29614
+ }
29574
29615
  function resolveUpdatePlan(options = {}) {
29575
29616
  const env = options.env ?? process.env;
29576
29617
  const homeDir2 = options.homeDir ?? homedir12();
@@ -29583,6 +29624,12 @@ function resolveUpdatePlan(options = {}) {
29583
29624
  manualCommand: buildSourceUpdateCommand(sourceRoot)
29584
29625
  };
29585
29626
  }
29627
+ if (entrypoint && isHomebrewFormulaEntrypoint(entrypoint)) {
29628
+ return {
29629
+ kind: "homebrew",
29630
+ manualCommand: "brew upgrade deepline"
29631
+ };
29632
+ }
29586
29633
  const sidecarPlan = resolvePythonSidecarUpdatePlan({
29587
29634
  entrypoint,
29588
29635
  env,
@@ -29614,7 +29661,7 @@ function resolveUpdatePlan(options = {}) {
29614
29661
  }
29615
29662
  var AUTO_UPDATE_FAILURE_FILE = ".auto-update-failure.json";
29616
29663
  function autoUpdateFailurePath(plan) {
29617
- if (plan.kind === "source") return null;
29664
+ if (plan.kind === "source" || plan.kind === "homebrew") return null;
29618
29665
  if (plan.kind === "python-sidecar") {
29619
29666
  return join15(plan.stateDir, AUTO_UPDATE_FAILURE_FILE);
29620
29667
  }
@@ -29627,7 +29674,7 @@ function autoUpdateFailurePath(plan) {
29627
29674
  );
29628
29675
  }
29629
29676
  function autoUpdatePackageSpec(plan) {
29630
- if (plan.kind === "source") return "";
29677
+ if (plan.kind === "source" || plan.kind === "homebrew") return "";
29631
29678
  if (plan.kind === "python-sidecar") return plan.packageSpec;
29632
29679
  return plan.args[plan.args.length - 1] ?? plan.manualCommand;
29633
29680
  }
@@ -29648,7 +29695,7 @@ function readAutoUpdateFailure(plan) {
29648
29695
  }
29649
29696
  function writeAutoUpdateFailure(plan, exitCode) {
29650
29697
  const path = autoUpdateFailurePath(plan);
29651
- if (!path || plan.kind === "source") return;
29698
+ if (!path || plan.kind === "source" || plan.kind === "homebrew") return;
29652
29699
  const marker = {
29653
29700
  kind: plan.kind,
29654
29701
  packageSpec: autoUpdatePackageSpec(plan),
@@ -29673,7 +29720,9 @@ function clearAutoUpdateFailure(plan) {
29673
29720
  }
29674
29721
  function matchingAutoUpdateFailure(plan) {
29675
29722
  const marker = readAutoUpdateFailure(plan);
29676
- if (!marker || plan.kind === "source") return null;
29723
+ if (!marker || plan.kind === "source" || plan.kind === "homebrew") {
29724
+ return null;
29725
+ }
29677
29726
  if (marker.kind !== plan.kind) return null;
29678
29727
  if (marker.packageSpec !== autoUpdatePackageSpec(plan)) return null;
29679
29728
  return marker;
@@ -29931,6 +29980,8 @@ async function runUpdatePlan(plan) {
29931
29980
  });
29932
29981
  } else if (plan.kind === "python-sidecar") {
29933
29982
  exitCode = await runPythonSidecarUpdatePlan(plan);
29983
+ } else if (plan.kind === "homebrew") {
29984
+ exitCode = 0;
29934
29985
  }
29935
29986
  if (exitCode === 0) {
29936
29987
  clearAutoUpdateFailure(plan);
@@ -29969,6 +30020,9 @@ async function runUpdateCommand(options, dependencies = {}) {
29969
30020
  lines: plan.kind === "source" ? [
29970
30021
  "This Deepline CLI is running from SDK source, so it cannot safely update itself like an npm global.",
29971
30022
  `Update the backing checkout with: ${plan.manualCommand}`
30023
+ ] : plan.kind === "homebrew" ? [
30024
+ "This Deepline CLI was installed by Homebrew, which owns its upgrades.",
30025
+ `Update it with: ${plan.manualCommand}`
29972
30026
  ] : plan.kind === "python-sidecar" ? [
29973
30027
  "This Deepline CLI is running from the Python-managed SDK sidecar.",
29974
30028
  "Updating will refresh that sidecar, not a global npm binary."
@@ -29993,7 +30047,7 @@ async function runUpdateCommand(options, dependencies = {}) {
29993
30047
  );
29994
30048
  return 0;
29995
30049
  }
29996
- if (plan.kind === "source") {
30050
+ if (plan.kind === "source" || plan.kind === "homebrew") {
29997
30051
  printCommandEnvelope({ ...plan, render }, { json: false });
29998
30052
  return 0;
29999
30053
  }
@@ -30012,6 +30066,8 @@ function registerUpdateCommand(program) {
30012
30066
  `
30013
30067
  Notes:
30014
30068
  For the published npm CLI, this runs npm install -g deepline@latest.
30069
+ For a Homebrew installation, this prints brew upgrade deepline; Homebrew
30070
+ owns formula upgrades and Deepline never runs npm inside its Cellar.
30015
30071
  For Python-managed SDK sidecars, this refreshes the sidecar that launched
30016
30072
  the current SDK CLI instead of changing a global npm binary.
30017
30073
  For repo-backed SDK wrappers such as cli-env sdk-prod or sdk-worktree, this
@@ -30139,14 +30195,37 @@ function resolveScopeRoot(scope) {
30139
30195
  function authScopeForSetup(scope) {
30140
30196
  return scope === "local" ? "folder" : "global";
30141
30197
  }
30142
- function shouldOpenSetupAuthorization(runtime = detectAgentRuntime()) {
30143
- return runtime !== "claude_cowork";
30144
- }
30145
30198
  function openSetupAuthorization(authorizationUrl, options = {}) {
30146
30199
  const url = authorizationUrl.trim();
30147
- if (!url || !shouldOpenSetupAuthorization(options.runtime)) return false;
30148
- (options.open ?? openInBrowser)(url);
30149
- return true;
30200
+ if (!url) return "failed";
30201
+ if (options.open) return options.open(url);
30202
+ const result = openInBrowser(url, { deduplicate: false });
30203
+ return result === "opened" ? "opened" : "failed";
30204
+ }
30205
+ function buildPendingAuthorizationOutput(input2) {
30206
+ const authorizationUrl = input2.authorizationUrl.trim();
30207
+ if (input2.browserOpenStatus === "opened") {
30208
+ return {
30209
+ authorizationUrl: null,
30210
+ next: `Complete browser approval, then run: ${input2.resumeCommand}`,
30211
+ lines: ["Complete authorization in the browser window Deepline opened."]
30212
+ };
30213
+ }
30214
+ if (authorizationUrl) {
30215
+ return {
30216
+ authorizationUrl,
30217
+ next: `Open the authorization URL, approve it, then run: ${input2.resumeCommand}`,
30218
+ lines: [
30219
+ "Browser launch failed. Open the authorization URL to continue.",
30220
+ authorizationUrl
30221
+ ]
30222
+ };
30223
+ }
30224
+ return {
30225
+ authorizationUrl: null,
30226
+ next: `Authorization is pending without a browser URL. Retry: ${input2.resumeCommand}`,
30227
+ lines: ["Authorization is pending, but no browser URL was returned."]
30228
+ };
30150
30229
  }
30151
30230
  function setupStatePath(baseUrl, scope, root) {
30152
30231
  return scope === "local" && root ? join16(root, ".deepline", "setup", "state.json") : join16(sdkCliStateDirPath(baseUrl), "setup.json");
@@ -30176,15 +30255,6 @@ function parseCapturedJson(stdout) {
30176
30255
  function asRecord2(value) {
30177
30256
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
30178
30257
  }
30179
- function printCapturedAuthorizationUrl(stdout) {
30180
- const urls = stdout.match(/https:\/\/[^\s]+/g) ?? [];
30181
- for (const url of new Set(
30182
- urls.map((value) => value.replace(/[).,]+$/, ""))
30183
- )) {
30184
- process.stderr.write(`Authorize Deepline: ${url}
30185
- `);
30186
- }
30187
- }
30188
30258
  function safeRead(path) {
30189
30259
  try {
30190
30260
  return readFileSync14(path, "utf8");
@@ -30523,18 +30593,32 @@ function pendingResult(input2) {
30523
30593
  status: "authorization_pending",
30524
30594
  phases: input2.phases
30525
30595
  });
30596
+ let browserOpenStatus = "failed";
30526
30597
  if (input2.authorizationUrl) {
30527
- openSetupAuthorization(input2.authorizationUrl);
30528
- process.stderr.write(`Authorize Deepline: ${input2.authorizationUrl}
30598
+ browserOpenStatus = openSetupAuthorization(input2.authorizationUrl);
30599
+ if (browserOpenStatus === "opened") {
30600
+ process.stderr.write(
30601
+ "Opened Deepline authorization in your browser. Complete approval there.\n"
30602
+ );
30603
+ } else if (browserOpenStatus === "failed") {
30604
+ process.stderr.write(`Authorize Deepline: ${input2.authorizationUrl}
30529
30605
  `);
30606
+ }
30530
30607
  }
30608
+ const pendingOutput = buildPendingAuthorizationOutput({
30609
+ authorizationUrl: input2.authorizationUrl,
30610
+ browserOpenStatus,
30611
+ resumeCommand: setupResumeCommand(input2.baseUrl, input2.scope)
30612
+ });
30531
30613
  printCommandEnvelope(
30532
30614
  {
30533
30615
  ok: true,
30534
30616
  status: "authorization_pending",
30535
30617
  complete: false,
30536
30618
  scope: input2.scope,
30537
- authorizationUrl: input2.authorizationUrl || null,
30619
+ authorizationUrl: pendingOutput.authorizationUrl,
30620
+ browserOpened: browserOpenStatus === "opened",
30621
+ browserOpenStatus,
30538
30622
  statePath,
30539
30623
  phases: input2.phases,
30540
30624
  currentPhase: "auth",
@@ -30544,15 +30628,12 @@ function pendingResult(input2) {
30544
30628
  scope: input2.scope,
30545
30629
  phase: "auth"
30546
30630
  }),
30547
- next: `Approve the link, then run: ${setupResumeCommand(input2.baseUrl, input2.scope)}`,
30631
+ next: pendingOutput.next,
30548
30632
  render: {
30549
30633
  sections: [
30550
30634
  {
30551
30635
  title: "setup",
30552
- lines: [
30553
- "Authorization is waiting for browser approval.",
30554
- ...input2.authorizationUrl ? [input2.authorizationUrl] : []
30555
- ]
30636
+ lines: pendingOutput.lines
30556
30637
  }
30557
30638
  ]
30558
30639
  }
@@ -30721,10 +30802,9 @@ async function runSetupCommand(options) {
30721
30802
  const pending = readPendingAuthClaim(baseUrl, authScope);
30722
30803
  if (pending) {
30723
30804
  process.stderr.write("Checking pending Deepline authorization...\n");
30724
- const waited = await captureStdout2(
30805
+ await captureStdout2(
30725
30806
  () => handleWait(["--timeout", "1", "--auth-scope", authScope])
30726
30807
  );
30727
- printCapturedAuthorizationUrl(waited.stdout);
30728
30808
  auth = await readAuthStatus(authScope);
30729
30809
  const resumedAuthFailure = reportSetupAuthStatusFailure({
30730
30810
  auth,
@@ -30760,7 +30840,6 @@ async function runSetupCommand(options) {
30760
30840
  const registered = await captureStdout2(
30761
30841
  () => handleRegister(["--wait", waitMode, "--auth-scope", authScope])
30762
30842
  );
30763
- printCapturedAuthorizationUrl(registered.stdout);
30764
30843
  if (registered.exitCode !== 0) {
30765
30844
  return reportSetupPhaseFailure({
30766
30845
  baseUrl,
package/dist/index.d.mts CHANGED
@@ -2703,6 +2703,7 @@ declare class RunObserveTransportUnavailableError extends Error {
2703
2703
  }
2704
2704
 
2705
2705
  declare const SDK_VERSION: string;
2706
+ /** @deprecated Transitional wire id for pre-major-header SDKs only. */
2706
2707
  declare const SDK_API_CONTRACT: string;
2707
2708
 
2708
2709
  /**
package/dist/index.d.ts CHANGED
@@ -2703,6 +2703,7 @@ declare class RunObserveTransportUnavailableError extends Error {
2703
2703
  }
2704
2704
 
2705
2705
  declare const SDK_VERSION: string;
2706
+ /** @deprecated Transitional wire id for pre-major-header SDKs only. */
2706
2707
  declare const SDK_API_CONTRACT: string;
2707
2708
 
2708
2709
  /**
package/dist/index.js CHANGED
@@ -437,8 +437,31 @@ var SDK_RELEASE = {
437
437
  // 0.1.253 makes play-page browser opening opt-in and retires --no-open.
438
438
  // 0.1.254 removes the internal operations tree from the published SDK CLI.
439
439
  // Operators use the checkout-local deepline-admin binary instead.
440
- version: "0.1.266",
441
- apiContract: "2026-07-admin-cli-local-cutover",
440
+ version: "0.1.267",
441
+ contracts: {
442
+ api: {
443
+ name: "sdk-http-api",
444
+ // API v2 is append-only. A breaking public request/response change needs
445
+ // v3 and an explicit v2 support-window decision, never a patch release.
446
+ currentMajor: 2,
447
+ supportedMajors: [2],
448
+ // Accepted only to bridge SDKs released before X-Deepline-API-Major.
449
+ legacyWireIds: [
450
+ "2026-07-admin-cli-local-cutover",
451
+ "2026-07-native-monitor-launch-hard-cutover"
452
+ ]
453
+ },
454
+ playArtifact: {
455
+ name: "play-artifact-runtime",
456
+ currentVersion: 2,
457
+ supportedVersions: [1, 2]
458
+ },
459
+ release: {
460
+ name: "production-sdk-release",
461
+ publishFrom: "latest-successful-production-deployment",
462
+ coalesce: "latest-healthy"
463
+ }
464
+ },
442
465
  supportPolicy: {
443
466
  minimumSupported: "0.1.53",
444
467
  deprecatedBelow: "0.1.219",
@@ -535,7 +558,8 @@ var SDK_RELEASE = {
535
558
 
536
559
  // src/version.ts
537
560
  var SDK_VERSION = SDK_RELEASE.version;
538
- var SDK_API_CONTRACT = SDK_RELEASE.apiContract;
561
+ var SDK_API_MAJOR = SDK_RELEASE.contracts.api.currentMajor;
562
+ var SDK_API_CONTRACT = SDK_RELEASE.contracts.api.legacyWireIds[0] ?? `api-v${SDK_API_MAJOR}`;
539
563
 
540
564
  // src/agent-runtime.ts
541
565
  var import_node_os2 = require("os");
package/dist/index.mjs CHANGED
@@ -367,8 +367,31 @@ var SDK_RELEASE = {
367
367
  // 0.1.253 makes play-page browser opening opt-in and retires --no-open.
368
368
  // 0.1.254 removes the internal operations tree from the published SDK CLI.
369
369
  // Operators use the checkout-local deepline-admin binary instead.
370
- version: "0.1.266",
371
- apiContract: "2026-07-admin-cli-local-cutover",
370
+ version: "0.1.267",
371
+ contracts: {
372
+ api: {
373
+ name: "sdk-http-api",
374
+ // API v2 is append-only. A breaking public request/response change needs
375
+ // v3 and an explicit v2 support-window decision, never a patch release.
376
+ currentMajor: 2,
377
+ supportedMajors: [2],
378
+ // Accepted only to bridge SDKs released before X-Deepline-API-Major.
379
+ legacyWireIds: [
380
+ "2026-07-admin-cli-local-cutover",
381
+ "2026-07-native-monitor-launch-hard-cutover"
382
+ ]
383
+ },
384
+ playArtifact: {
385
+ name: "play-artifact-runtime",
386
+ currentVersion: 2,
387
+ supportedVersions: [1, 2]
388
+ },
389
+ release: {
390
+ name: "production-sdk-release",
391
+ publishFrom: "latest-successful-production-deployment",
392
+ coalesce: "latest-healthy"
393
+ }
394
+ },
372
395
  supportPolicy: {
373
396
  minimumSupported: "0.1.53",
374
397
  deprecatedBelow: "0.1.219",
@@ -465,7 +488,8 @@ var SDK_RELEASE = {
465
488
 
466
489
  // src/version.ts
467
490
  var SDK_VERSION = SDK_RELEASE.version;
468
- var SDK_API_CONTRACT = SDK_RELEASE.apiContract;
491
+ var SDK_API_MAJOR = SDK_RELEASE.contracts.api.currentMajor;
492
+ var SDK_API_CONTRACT = SDK_RELEASE.contracts.api.legacyWireIds[0] ?? `api-v${SDK_API_MAJOR}`;
469
493
 
470
494
  // src/agent-runtime.ts
471
495
  import { homedir as homedir2 } from "os";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepline",
3
- "version": "0.1.266",
3
+ "version": "0.1.267",
4
4
  "description": "Deepline SDK + CLI — B2B data enrichment powered by durable cloud execution",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -62,6 +62,7 @@
62
62
  "typescript": "^6.0.2"
63
63
  },
64
64
  "deepline": {
65
- "apiContract": "2026-07-admin-cli-local-cutover"
65
+ "apiContract": "2026-07-admin-cli-local-cutover",
66
+ "apiMajor": 2
66
67
  }
67
68
  }