deepline 0.1.220 → 0.1.222

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
@@ -625,10 +625,10 @@ var SDK_RELEASE = {
625
625
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
626
626
  // 0.1.220 deprecates SDK CLI versions below 0.1.219 and updates them
627
627
  // automatically without blocking their current command.
628
- version: "0.1.220",
628
+ version: "0.1.222",
629
629
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
630
630
  supportPolicy: {
631
- latest: "0.1.220",
631
+ latest: "0.1.222",
632
632
  minimumSupported: "0.1.53",
633
633
  deprecatedBelow: "0.1.219",
634
634
  commandMinimumSupported: [
@@ -5350,6 +5350,12 @@ function printCommandEnvelope(envelope, options = {}) {
5350
5350
  }
5351
5351
 
5352
5352
  // src/cli/commands/admin.ts
5353
+ function laneStatusLine(input2) {
5354
+ if (input2.lane) {
5355
+ return `status: ${input2.lane.status}${input2.lane.active ? " (active)" : ""}`;
5356
+ }
5357
+ return input2.registration ? `status: ${input2.registration.status}` : "status: (not in registry)";
5358
+ }
5353
5359
  function normalizeEnvironment(value) {
5354
5360
  const trimmed = value?.trim().toLowerCase();
5355
5361
  if (!trimmed || trimmed === "production" || trimmed === "prod") {
@@ -5402,7 +5408,7 @@ async function handleLanesShow(releaseId, options) {
5402
5408
  title: `Lane ${releaseId} (${environment}):`,
5403
5409
  lines: [
5404
5410
  `registered: ${payload.registered}`,
5405
- payload.lane ? `status: ${payload.lane.status}${payload.lane.active ? " (active)" : ""}` : "status: (not in registry)",
5411
+ laneStatusLine(payload),
5406
5412
  `queue: ${payload.retireCheck.queue}`,
5407
5413
  `queued tasks: ${payload.retireCheck.queuedTasks}`,
5408
5414
  `non-terminal runs: ${payload.retireCheck.nonTerminalRuns}`,
@@ -5444,7 +5450,7 @@ async function handleReleasesActivate(releaseId, options) {
5444
5450
  {
5445
5451
  releaseId,
5446
5452
  environment,
5447
- ...options.schedulerBackend ? { schedulerBackend: options.schedulerBackend } : {}
5453
+ schedulerBackend: options.schedulerBackend ?? "absurd"
5448
5454
  }
5449
5455
  );
5450
5456
  printCommandEnvelope(
@@ -5469,7 +5475,10 @@ function registerAdminCommands(program) {
5469
5475
  lanes.command("show <releaseId>").description("Show one lane and its retire-gate depth.").option("--environment <env>", "production (default) or preview").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleLanesShow);
5470
5476
  lanes.command("retire-check <releaseId>").description("Check whether a lane is safe to retire (queue empty).").option("--environment <env>", "production (default) or preview").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleLanesRetireCheck);
5471
5477
  const releases = admin.command("releases").description("Manage the active runtime release pointer.");
5472
- releases.command("activate <releaseId>").description("Flip the active runtime release to a prior registered lane.").option("--environment <env>", "production (default) or preview").option("--scheduler-backend <backend>", "absurd or workers_edge").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleReleasesActivate);
5478
+ releases.command("activate <releaseId>").description("Activate a prior registered Absurd release lane.").option("--environment <env>", "production (default) or preview").option(
5479
+ "--scheduler-backend <backend>",
5480
+ "compatibility flag: absurd only; workers_edge is disabled"
5481
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleReleasesActivate);
5473
5482
  }
5474
5483
 
5475
5484
  // src/cli/commands/auth.ts
@@ -14648,6 +14657,73 @@ function parsePlayCheckOptions(args) {
14648
14657
  const jsonOutput = argsWantJson(args);
14649
14658
  return { target, jsonOutput };
14650
14659
  }
14660
+ function parsePlayPublishOptions(args) {
14661
+ const target = args[0];
14662
+ if (!target) {
14663
+ throw new Error(
14664
+ "Usage: deepline plays publish <play-file.ts|play-name> [--expected-artifact <hash>] [--dry-run] [--latest|--revision-id <id>] [--json]"
14665
+ );
14666
+ }
14667
+ let revisionId;
14668
+ let useLatest = false;
14669
+ let expectedArtifactHash;
14670
+ let dryRun = false;
14671
+ for (let index = 1; index < args.length; index += 1) {
14672
+ const arg = args[index];
14673
+ if (arg === "--revision-id") {
14674
+ revisionId = args[++index];
14675
+ if (!revisionId) throw new Error("--revision-id requires a revision id.");
14676
+ continue;
14677
+ }
14678
+ if (arg === "--latest") {
14679
+ useLatest = true;
14680
+ continue;
14681
+ }
14682
+ if (arg === "--expected-artifact") {
14683
+ expectedArtifactHash = args[++index];
14684
+ if (!expectedArtifactHash) {
14685
+ throw new Error("--expected-artifact requires an artifact hash.");
14686
+ }
14687
+ continue;
14688
+ }
14689
+ if (arg.startsWith("--expected-artifact=")) {
14690
+ expectedArtifactHash = arg.slice("--expected-artifact=".length);
14691
+ if (!expectedArtifactHash) {
14692
+ throw new Error("--expected-artifact requires an artifact hash.");
14693
+ }
14694
+ continue;
14695
+ }
14696
+ if (arg === "--dry-run") {
14697
+ dryRun = true;
14698
+ continue;
14699
+ }
14700
+ if (arg === "--json") continue;
14701
+ throw new Error(`Unknown plays publish option: ${arg}`);
14702
+ }
14703
+ if (revisionId && useLatest) {
14704
+ throw new Error("Choose only one live target: --latest or --revision-id.");
14705
+ }
14706
+ return {
14707
+ target,
14708
+ revisionId,
14709
+ useLatest,
14710
+ expectedArtifactHash,
14711
+ dryRun,
14712
+ jsonOutput: argsWantJson(args)
14713
+ };
14714
+ }
14715
+ function formatByteBudget(usedBytes, limitBytes) {
14716
+ return `${usedBytes.toLocaleString()} B / ${limitBytes.toLocaleString()} B`;
14717
+ }
14718
+ function printPlayCheckLimits(limits) {
14719
+ if (!limits) return;
14720
+ console.log(
14721
+ ` revision storage: ${formatByteBudget(limits.revisionStorage.usedBytes, limits.revisionStorage.limitBytes)}`
14722
+ );
14723
+ console.log(
14724
+ ` bundle: ${formatByteBudget(limits.bundle.usedBytes, limits.bundle.limitBytes)}`
14725
+ );
14726
+ }
14651
14727
  function shouldUseLocalOnlyPlayCheck() {
14652
14728
  const value = process.env.DEEPLINE_PLAY_CHECK_LOCAL_ONLY?.trim().toLowerCase();
14653
14729
  return value === "1" || value === "true" || value === "yes" || value === "on";
@@ -14960,7 +15036,11 @@ async function handlePlayCheck(args) {
14960
15036
  );
14961
15037
  } else {
14962
15038
  console.log(`\u2713 ${playName} passed local play check`);
15039
+ console.log(` source: ${graph.root.artifact.sourceHash.slice(0, 12)}`);
14963
15040
  console.log(` artifact: ${result2.artifactHash.slice(0, 12)}`);
15041
+ console.log(
15042
+ ` publish: deepline plays publish ${shellQuote2(options.target)} --expected-artifact ${result2.artifactHash}`
15043
+ );
14964
15044
  printToolGetterHints(result2.toolGetterHints);
14965
15045
  }
14966
15046
  return 0;
@@ -15002,6 +15082,15 @@ async function handlePlayCheck(args) {
15002
15082
  if (enrichedResult.artifactHash) {
15003
15083
  console.log(` artifact: ${enrichedResult.artifactHash.slice(0, 12)}`);
15004
15084
  }
15085
+ if (enrichedResult.sourceHash) {
15086
+ console.log(` source: ${enrichedResult.sourceHash.slice(0, 12)}`);
15087
+ }
15088
+ printPlayCheckLimits(enrichedResult.limits);
15089
+ if (enrichedResult.artifactHash) {
15090
+ console.log(
15091
+ ` publish: deepline plays publish ${shellQuote2(options.target)} --expected-artifact ${enrichedResult.artifactHash}`
15092
+ );
15093
+ }
15005
15094
  printPlayTriggers(enrichedResult.triggers);
15006
15095
  printRecognizedSummary(enrichedResult.recognized);
15007
15096
  printPlayCheckIssues(enrichedResult.issues, (line) => console.log(line));
@@ -16358,28 +16447,15 @@ async function handlePlayDescribe(args) {
16358
16447
  return 0;
16359
16448
  }
16360
16449
  async function handlePlayPublish(args) {
16361
- const playName = args[0];
16362
- if (!playName) {
16363
- console.error(
16364
- "Usage: deepline plays publish <play-file.ts|play-name> [--latest|--revision-id <id>] [--json]"
16365
- );
16366
- return 1;
16367
- }
16368
- let revisionId;
16369
- let useLatest = false;
16370
- for (let index = 1; index < args.length; index += 1) {
16371
- const arg = args[index];
16372
- if (arg === "--revision-id" && args[index + 1]) {
16373
- revisionId = args[++index];
16374
- }
16375
- if (arg === "--latest") {
16376
- useLatest = true;
16377
- }
16378
- }
16379
- if (revisionId && useLatest) {
16380
- console.error("Choose only one live target: --latest or --revision-id.");
16381
- return 1;
16450
+ let options;
16451
+ try {
16452
+ options = parsePlayPublishOptions(args);
16453
+ } catch (error) {
16454
+ console.error(error instanceof Error ? error.message : String(error));
16455
+ return 2;
16382
16456
  }
16457
+ const { target: playName, useLatest } = options;
16458
+ let revisionId = options.revisionId;
16383
16459
  const client2 = new DeeplineClient();
16384
16460
  if (isFileTarget(playName)) {
16385
16461
  if (revisionId || useLatest) {
@@ -16396,6 +16472,66 @@ async function handlePlayPublish(args) {
16396
16472
  () => collectBundledPlayGraph((0, import_node_path11.resolve)(playName))
16397
16473
  );
16398
16474
  assertBundledPlayGraphDescriptions(graph);
16475
+ } catch (error) {
16476
+ console.error(error instanceof Error ? error.message : String(error));
16477
+ return 1;
16478
+ }
16479
+ const rootPlayName = graph.root.playName ?? extractPlayName(graph.root.sourceCode, graph.root.filePath);
16480
+ const artifactHash = graph.root.artifact.artifactHash;
16481
+ if (options.expectedArtifactHash && options.expectedArtifactHash !== artifactHash) {
16482
+ const result3 = {
16483
+ ok: false,
16484
+ code: "PLAY_ARTIFACT_HASH_MISMATCH",
16485
+ message: "Refusing to publish: the local file no longer produces the artifact checked earlier.",
16486
+ expectedArtifactHash: options.expectedArtifactHash,
16487
+ currentArtifactHash: artifactHash,
16488
+ next: `deepline plays check ${shellQuote2(playName)}`
16489
+ };
16490
+ if (options.jsonOutput) {
16491
+ process.stdout.write(`${JSON.stringify(result3)}
16492
+ `);
16493
+ } else {
16494
+ console.error(result3.message);
16495
+ console.error(` checked artifact: ${result3.expectedArtifactHash}`);
16496
+ console.error(` current artifact: ${result3.currentArtifactHash}`);
16497
+ console.error(` run: ${result3.next}`);
16498
+ }
16499
+ return 7;
16500
+ }
16501
+ const dryRun = {
16502
+ ok: true,
16503
+ dryRun: true,
16504
+ name: rootPlayName,
16505
+ sourcePath: graph.root.filePath,
16506
+ sourceHash: graph.root.artifact.sourceHash,
16507
+ artifactHash,
16508
+ graphHash: graph.root.artifact.graphHash,
16509
+ importedPlayCount: Math.max(0, graph.nodes.size - 1),
16510
+ plannedMutation: "register revision and promote it live",
16511
+ expectedArtifactHash: options.expectedArtifactHash ?? null
16512
+ };
16513
+ if (options.dryRun) {
16514
+ if (options.jsonOutput) {
16515
+ process.stdout.write(`${JSON.stringify(dryRun)}
16516
+ `);
16517
+ } else {
16518
+ console.log(`Dry run: ${rootPlayName}`);
16519
+ console.log(` source: ${dryRun.sourceHash}`);
16520
+ console.log(` artifact: ${dryRun.artifactHash}`);
16521
+ console.log(` would: ${dryRun.plannedMutation}`);
16522
+ }
16523
+ return 0;
16524
+ }
16525
+ let previousLive = null;
16526
+ try {
16527
+ previousLive = (await client2.getPlay(rootPlayName)).play.liveRevision ?? null;
16528
+ } catch (error) {
16529
+ if (!(error instanceof DeeplineError) || error.statusCode !== 404) {
16530
+ console.error(error instanceof Error ? error.message : String(error));
16531
+ return 5;
16532
+ }
16533
+ }
16534
+ try {
16399
16535
  await traceCliSpan(
16400
16536
  "cli.play_publish_compile_manifests",
16401
16537
  { targetKind: "file", nodeCount: graph.nodes.size },
@@ -16410,13 +16546,12 @@ async function handlePlayPublish(args) {
16410
16546
  console.error(error instanceof Error ? error.message : String(error));
16411
16547
  return 1;
16412
16548
  }
16413
- const rootPlayName = graph.root.playName ?? extractPlayName(graph.root.sourceCode, graph.root.filePath);
16414
16549
  const published = await traceCliSpan(
16415
16550
  "cli.play_publish_register_root",
16416
16551
  {
16417
16552
  targetKind: "file",
16418
16553
  playName: rootPlayName,
16419
- artifactHash: graph.root.artifact.artifactHash
16554
+ artifactHash
16420
16555
  },
16421
16556
  () => client2.registerPlayArtifact({
16422
16557
  name: rootPlayName,
@@ -16428,17 +16563,63 @@ async function handlePlayPublish(args) {
16428
16563
  publish: true
16429
16564
  })
16430
16565
  );
16431
- process.stdout.write(
16432
- `${JSON.stringify({
16433
- success: true,
16434
- name: rootPlayName,
16435
- liveVersion: published.version ?? null,
16436
- revisionId: published.revisionId ?? null,
16437
- triggerMetadata: published.triggerMetadata ?? null,
16438
- triggerBindings: published.triggerBindings ?? []
16439
- })}
16440
- `
16441
- );
16566
+ const result2 = {
16567
+ success: true,
16568
+ name: rootPlayName,
16569
+ sourcePath: graph.root.filePath,
16570
+ sourceHash: graph.root.artifact.sourceHash,
16571
+ artifactHash,
16572
+ liveVersion: published.version ?? null,
16573
+ revisionId: published.revisionId ?? null,
16574
+ previousLiveVersion: previousLive?.version ?? null,
16575
+ previousArtifactHash: previousLive?.artifactHash ?? null,
16576
+ sourceBytes: {
16577
+ before: previousLive?.sourceCode ? Buffer.byteLength(previousLive.sourceCode, "utf8") : null,
16578
+ after: Buffer.byteLength(graph.root.sourceCode, "utf8")
16579
+ },
16580
+ triggerMetadata: published.triggerMetadata ?? null,
16581
+ triggerBindings: published.triggerBindings ?? []
16582
+ };
16583
+ if (options.jsonOutput) {
16584
+ process.stdout.write(`${JSON.stringify(result2)}
16585
+ `);
16586
+ } else {
16587
+ console.log(
16588
+ `\u2713 Published ${rootPlayName} as v${result2.liveVersion ?? "?"}`
16589
+ );
16590
+ console.log(` source: ${result2.sourceHash.slice(0, 12)}`);
16591
+ console.log(` artifact: ${result2.artifactHash.slice(0, 12)}`);
16592
+ if (result2.previousLiveVersion !== null) {
16593
+ console.log(
16594
+ ` previous live: v${result2.previousLiveVersion} (${result2.previousArtifactHash?.slice(0, 12) ?? "unknown artifact"})`
16595
+ );
16596
+ }
16597
+ if (result2.sourceBytes.before !== null) {
16598
+ console.log(
16599
+ ` source bytes: ${result2.sourceBytes.before.toLocaleString()} \u2192 ${result2.sourceBytes.after.toLocaleString()}`
16600
+ );
16601
+ }
16602
+ console.log(
16603
+ ` revisions: deepline plays versions --name ${rootPlayName}`
16604
+ );
16605
+ }
16606
+ return 0;
16607
+ }
16608
+ if (options.expectedArtifactHash) {
16609
+ console.error("--expected-artifact only applies to a local play file.");
16610
+ return 2;
16611
+ }
16612
+ if (options.dryRun) {
16613
+ const result2 = {
16614
+ ok: true,
16615
+ dryRun: true,
16616
+ name: playName,
16617
+ plannedMutation: "promote a saved revision live",
16618
+ revisionId: revisionId ?? null,
16619
+ latest: useLatest
16620
+ };
16621
+ process.stdout.write(`${JSON.stringify(result2)}
16622
+ `);
16442
16623
  return 0;
16443
16624
  }
16444
16625
  const resolvedName = parseReferencedPlayTarget2(playName).playName;
@@ -16802,7 +16983,9 @@ Notes:
16802
16983
  Mutates cloud state. For a saved play, --latest or --revision-id promotes an
16803
16984
  existing saved revision live.
16804
16985
  Local .play.ts publishing bundles the file, validates it, saves a revision,
16805
- and promotes that revision live.
16986
+ and promotes that revision live. Use --expected-artifact with the hash from
16987
+ plays check to refuse publishing bytes that changed after validation.
16988
+ --dry-run bundles only and prints the exact artifact that would be published.
16806
16989
  Running a local file with plays run does not publish it.
16807
16990
 
16808
16991
  Examples:
@@ -16810,27 +16993,40 @@ Examples:
16810
16993
  deepline plays set-live my-play --revision-id <revision-id> --json
16811
16994
  deepline plays set-live my.play.ts --json
16812
16995
  deepline plays publish my.play.ts --json
16996
+ deepline plays check my.play.ts
16997
+ deepline plays publish my.play.ts --expected-artifact <artifact-hash>
16998
+ deepline plays publish my.play.ts --dry-run --json
16813
16999
  `
16814
17000
  );
16815
17001
  addPublishHelp(
16816
17002
  play.command("publish <target>").description(
16817
17003
  "Promote a saved play revision or publish a local play file."
16818
17004
  )
16819
- ).option("--latest", "Promote the newest saved revision").option("--revision-id <id>", "Revision to promote").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (target, options) => {
17005
+ ).option("--latest", "Promote the newest saved revision").option("--revision-id <id>", "Revision to promote").option(
17006
+ "--expected-artifact <hash>",
17007
+ "Require the local file to produce this checked artifact hash"
17008
+ ).option("--dry-run", "Bundle and show the planned publish without mutation").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (target, options) => {
16820
17009
  process.exitCode = await handlePlayPublish([
16821
17010
  target,
16822
17011
  ...options.latest ? ["--latest"] : [],
16823
17012
  ...options.revisionId ? ["--revision-id", options.revisionId] : [],
17013
+ ...options.expectedArtifact ? ["--expected-artifact", options.expectedArtifact] : [],
17014
+ ...options.dryRun ? ["--dry-run"] : [],
16824
17015
  ...options.json ? ["--json"] : []
16825
17016
  ]);
16826
17017
  });
16827
17018
  addPublishHelp(
16828
17019
  play.command("set-live <target>").description("Promote a saved revision or publish a local play file.")
16829
- ).option("--latest", "Promote the newest saved revision").option("--revision-id <id>", "Revision to promote").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (target, options) => {
17020
+ ).option("--latest", "Promote the newest saved revision").option("--revision-id <id>", "Revision to promote").option(
17021
+ "--expected-artifact <hash>",
17022
+ "Require the local file to produce this checked artifact hash"
17023
+ ).option("--dry-run", "Bundle and show the planned publish without mutation").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (target, options) => {
16830
17024
  process.exitCode = await handlePlayPublish([
16831
17025
  target,
16832
17026
  ...options.latest ? ["--latest"] : [],
16833
17027
  ...options.revisionId ? ["--revision-id", options.revisionId] : [],
17028
+ ...options.expectedArtifact ? ["--expected-artifact", options.expectedArtifact] : [],
17029
+ ...options.dryRun ? ["--dry-run"] : [],
16834
17030
  ...options.json ? ["--json"] : []
16835
17031
  ]);
16836
17032
  });