deepline 0.1.102 → 0.1.104

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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  // src/cli/index.ts
4
4
  import { mkdtemp as mkdtemp2, rm as rm2, writeFile as writeFile6 } from "fs/promises";
5
- import { join as join14 } from "path";
5
+ import { join as join15 } from "path";
6
6
  import { tmpdir as tmpdir5 } from "os";
7
7
  import { Command as Command3 } from "commander";
8
8
 
@@ -214,10 +214,12 @@ var SDK_RELEASE = {
214
214
  // failed runs, persisted/succeeded/failed row counts, strict local CSV
215
215
  // preflight (existence, data rows, quotes, duplicate headers), HTML error
216
216
  // scrubbing, and word-boundary watch truncation.
217
- version: "0.1.102",
217
+ // 0.1.103 ships the refined SDK CLI command surface.
218
+ // 0.1.104 ships postgres_fast suspension/billing parity and runtime worker hardening.
219
+ version: "0.1.104",
218
220
  apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
219
221
  supportPolicy: {
220
- latest: "0.1.102",
222
+ latest: "0.1.104",
221
223
  minimumSupported: "0.1.53",
222
224
  deprecatedBelow: "0.1.53"
223
225
  }
@@ -626,7 +628,7 @@ function decodeSseFrame(frame) {
626
628
  return parsed;
627
629
  }
628
630
  function sleep(ms) {
629
- return new Promise((resolve15) => setTimeout(resolve15, ms));
631
+ return new Promise((resolve16) => setTimeout(resolve16, ms));
630
632
  }
631
633
 
632
634
  // src/stream-reconnect.ts
@@ -1337,14 +1339,14 @@ async function* observeRunEvents(options) {
1337
1339
  try {
1338
1340
  for (; ; ) {
1339
1341
  if (queue.length === 0) {
1340
- const waitForItem = new Promise((resolve15) => {
1341
- wake = resolve15;
1342
+ const waitForItem = new Promise((resolve16) => {
1343
+ wake = resolve16;
1342
1344
  });
1343
1345
  if (!sawFirstSnapshot) {
1344
1346
  const timedOut = await Promise.race([
1345
1347
  waitForItem.then(() => false),
1346
1348
  new Promise(
1347
- (resolve15) => setTimeout(() => resolve15(true), OBSERVE_BOOTSTRAP_TIMEOUT_MS)
1349
+ (resolve16) => setTimeout(() => resolve16(true), OBSERVE_BOOTSTRAP_TIMEOUT_MS)
1348
1350
  )
1349
1351
  ]);
1350
1352
  if (timedOut && queue.length === 0) {
@@ -1441,7 +1443,7 @@ var EXECUTE_RESPONSE_CONTRACT_HEADER = "x-deepline-execute-response-contract";
1441
1443
  var V2_EXECUTE_RESPONSE_CONTRACT = "v2-tool-response";
1442
1444
  var COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1e3];
1443
1445
  function sleep2(ms) {
1444
- return new Promise((resolve15) => setTimeout(resolve15, ms));
1446
+ return new Promise((resolve16) => setTimeout(resolve16, ms));
1445
1447
  }
1446
1448
  function isTransientCompileManifestError(error) {
1447
1449
  if (error instanceof DeeplineError && typeof error.statusCode === "number") {
@@ -1883,7 +1885,7 @@ var DeeplineClient = class {
1883
1885
  * or {@link runPlay}.
1884
1886
  *
1885
1887
  * Supported invocation surfaces intentionally share this same run contract:
1886
- * `deepline play run`, repo scripts such as `bun run deepline -- play run`,
1888
+ * `deepline plays run`, repo scripts such as `bun run deepline -- plays run`,
1887
1889
  * SDK context calls like `Deepline.connect().play(name).run()`, and direct
1888
1890
  * `POST /api/v2/plays/run` calls all return a workflow/run id. The completed
1889
1891
  * output is always retrievable from `getPlayStatus(runId).result` (or from
@@ -2052,7 +2054,7 @@ var DeeplineClient = class {
2052
2054
  *
2053
2055
  * Unlike {@link registerPlayArtifact}, this does not store the artifact,
2054
2056
  * publish a revision, or start a run. It is the authoritative cloud validation
2055
- * path used by `deepline play check`.
2057
+ * path used by `deepline plays check`.
2056
2058
  */
2057
2059
  async checkPlayArtifact(input2) {
2058
2060
  return this.http.post("/api/v2/plays/check", input2);
@@ -2245,7 +2247,7 @@ var DeeplineClient = class {
2245
2247
  * Get the current status of a play execution.
2246
2248
  *
2247
2249
  * Internal/advanced primitive. Public callers should usually prefer
2248
- * {@link runPlay}, {@link PlayJob.get}, or `deepline play run --watch`.
2250
+ * {@link runPlay}, {@link PlayJob.get}, or `deepline plays run --watch`.
2249
2251
  *
2250
2252
  * @param workflowId - Play-run id from {@link startPlayRun}
2251
2253
  * @returns Current status with progress logs and partial results
@@ -3100,9 +3102,9 @@ async function writeOutputFile(filename, content) {
3100
3102
  return fullPath;
3101
3103
  }
3102
3104
  function browserOpenStateFile() {
3103
- const homeDir = process.env.HOME || homedir3();
3105
+ const homeDir2 = process.env.HOME || homedir3();
3104
3106
  return join3(
3105
- homeDir,
3107
+ homeDir2,
3106
3108
  ".local",
3107
3109
  "deepline",
3108
3110
  "runtime",
@@ -3576,8 +3578,8 @@ function printCommandEnvelope(envelope, options = {}) {
3576
3578
 
3577
3579
  // src/cli/commands/auth.ts
3578
3580
  var EXIT_OK = 0;
3579
- var EXIT_AUTH = 1;
3580
- var EXIT_SERVER = 2;
3581
+ var EXIT_AUTH = 3;
3582
+ var EXIT_SERVER = 5;
3581
3583
  function envFilePath(baseUrl) {
3582
3584
  return hostEnvFilePath(baseUrl);
3583
3585
  }
@@ -3669,7 +3671,7 @@ function buildCandidateUrls2(url) {
3669
3671
  }
3670
3672
  }
3671
3673
  function sleep4(ms) {
3672
- return new Promise((resolve15) => setTimeout(resolve15, ms));
3674
+ return new Promise((resolve16) => setTimeout(resolve16, ms));
3673
3675
  }
3674
3676
  function printDeeplineLogo() {
3675
3677
  if (process.stdout.isTTY && (process.stdout.columns ?? 80) >= 70) {
@@ -3932,7 +3934,7 @@ async function handleStatus(args) {
3932
3934
  ...hostStatusPayload ?? { host: baseUrl },
3933
3935
  status: "not connected",
3934
3936
  connected: false,
3935
- next: "deepline auth register",
3937
+ next: "deepline auth register --no-wait && deepline auth wait",
3936
3938
  render: {
3937
3939
  sections: [
3938
3940
  {
@@ -3940,7 +3942,10 @@ async function handleStatus(args) {
3940
3942
  lines: [...hostLines, "Status: not connected"]
3941
3943
  }
3942
3944
  ],
3943
- actions: [{ label: "Run", command: "deepline auth register" }]
3945
+ actions: [
3946
+ { label: "Register", command: "deepline auth register --no-wait" },
3947
+ { label: "Wait", command: "deepline auth wait" }
3948
+ ]
3944
3949
  }
3945
3950
  },
3946
3951
  { json: jsonOutput }
@@ -3962,7 +3967,7 @@ async function handleStatus(args) {
3962
3967
  ...hostStatusPayload ?? { host: baseUrl },
3963
3968
  status: "unauthorized",
3964
3969
  connected: false,
3965
- next: "deepline auth register",
3970
+ next: "deepline auth register --no-wait && deepline auth wait",
3966
3971
  render: {
3967
3972
  sections: [
3968
3973
  {
@@ -3970,7 +3975,10 @@ async function handleStatus(args) {
3970
3975
  lines: [...hostLines, "Status: unauthorized"]
3971
3976
  }
3972
3977
  ],
3973
- actions: [{ label: "Run", command: "deepline auth register" }]
3978
+ actions: [
3979
+ { label: "Register", command: "deepline auth register --no-wait" },
3980
+ { label: "Wait", command: "deepline auth wait" }
3981
+ ]
3974
3982
  }
3975
3983
  },
3976
3984
  { json: jsonOutput }
@@ -5616,7 +5624,7 @@ async function handleDbQuery(args) {
5616
5624
  return 0;
5617
5625
  }
5618
5626
  function registerDbCommands(program) {
5619
- const db = program.command("db").alias("customer-db").description("Query the tenant customer database.").addHelpText(
5627
+ const db = program.command("db").description("Query the tenant customer database.").addHelpText(
5620
5628
  "after",
5621
5629
  `
5622
5630
  Notes:
@@ -5637,7 +5645,7 @@ Examples:
5637
5645
  deepline db query --sql "select domain, name from companies limit 20" --format markdown
5638
5646
  `
5639
5647
  );
5640
- db.command("query").alias("psql").description("Run SQL against the tenant customer database.").addHelpText(
5648
+ db.command("query").description("Run SQL against the tenant customer database.").addHelpText(
5641
5649
  "after",
5642
5650
  `
5643
5651
  Notes:
@@ -5653,7 +5661,7 @@ Examples:
5653
5661
  deepline db query --sql "select * from companies limit 20"
5654
5662
  deepline db query --sql "select domain, name from companies limit 20" --json
5655
5663
  deepline db query --sql "create table if not exists storage.agent_notes (id text primary key, note text not null)"
5656
- deepline db psql --sql "select count(*) from contacts" --json
5664
+ deepline db query --sql "select count(*) from contacts" --json
5657
5665
  deepline db query --sql "select * from contacts limit 20" --format csv --out contacts.csv
5658
5666
  deepline db query --sql "select domain, name from companies limit 20" --format markdown
5659
5667
  `
@@ -6925,7 +6933,7 @@ var PLAY_RUNTIME_PROVIDERS = {
6925
6933
  runner: PLAY_RUNTIME_BACKENDS.daytona,
6926
6934
  dedup: PLAY_DEDUP_BACKENDS.durableObject,
6927
6935
  artifactKind: PLAY_ARTIFACT_KINDS.cjsNode20,
6928
- label: "Experimental Postgres Scheduler + warm sandbox runner + DO dedup"
6936
+ label: "BETA: Postgres Scheduler + warm sandbox runner + DO dedup"
6929
6937
  },
6930
6938
  postgres_fast_sandbox: {
6931
6939
  id: PLAY_RUNTIME_PROVIDER_IDS.postgresFastSandbox,
@@ -6933,7 +6941,7 @@ var PLAY_RUNTIME_PROVIDERS = {
6933
6941
  runner: PLAY_RUNTIME_BACKENDS.daytona,
6934
6942
  dedup: PLAY_DEDUP_BACKENDS.durableObject,
6935
6943
  artifactKind: PLAY_ARTIFACT_KINDS.cjsNode20,
6936
- label: "Experimental Postgres Scheduler + warm sandbox runner + DO dedup"
6944
+ label: "BETA: Postgres Scheduler + warm sandbox runner + DO dedup"
6937
6945
  },
6938
6946
  postgres_fast_workers: {
6939
6947
  id: PLAY_RUNTIME_PROVIDER_IDS.postgresFastWorkers,
@@ -9238,7 +9246,7 @@ function traceCliSync(phase, fields, run) {
9238
9246
  }
9239
9247
  }
9240
9248
  function sleep5(ms) {
9241
- return new Promise((resolve15) => setTimeout(resolve15, ms));
9249
+ return new Promise((resolve16) => setTimeout(resolve16, ms));
9242
9250
  }
9243
9251
  function parseReferencedPlayTarget2(target) {
9244
9252
  const trimmed = target.trim();
@@ -12170,7 +12178,7 @@ function writeStartedPlayRun(input2) {
12170
12178
  );
12171
12179
  }
12172
12180
  function parsePlayRunOptions(args) {
12173
- const usage = "Usage: deepline plays run <play-name> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run <play-file.ts> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run --file <play-file.ts> [--input '{...}'] [--profile <id>] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run --name <name> [--input '{...}'] [--profile <id>] [--live|--latest|--revision-id <id>] [--no-wait] [--tail-timeout-ms 30000] [--force] [--no-open] [--json] [--full] [--<input> value]\n Unknown --<input> value flags, such as --limit 5, are passed into play input.\nRun `deepline plays run --help` for idempotency, tool call id, and ctx.dataset guidance.";
12181
+ const usage = "Usage: deepline plays run <play-name> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run <play-file.ts> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run --file <play-file.ts> [--input '{...}'] [--profile <id>] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run --name <name> [--input '{...}'] [--profile <id>] [--live|--latest|--revision-id <id>] [--no-wait] [--tail-timeout-ms 30000] [--force] [--no-open] [--json] [--full] [--<input> value]\n --profile defaults to workers_edge; postgres_fast is BETA (opt-in per run, never the default).\n Unknown --<input> value flags, such as --limit 5, are passed into play input.\nRun `deepline plays run --help` for idempotency, tool call id, and ctx.dataset guidance.";
12174
12182
  let filePath = null;
12175
12183
  let playName = null;
12176
12184
  let input2 = null;
@@ -12306,7 +12314,7 @@ function parsePlayRunOptions(args) {
12306
12314
  function parsePlayCheckOptions(args) {
12307
12315
  const target = args[0];
12308
12316
  if (!target) {
12309
- throw new Error("Usage: deepline play check <play-file.ts> [--json]");
12317
+ throw new Error("Usage: deepline plays check <play-file.ts> [--json]");
12310
12318
  }
12311
12319
  const jsonOutput = argsWantJson(args);
12312
12320
  return { target, jsonOutput };
@@ -13236,7 +13244,9 @@ async function handleRunExport(args) {
13236
13244
  async function handlePlayGet(args) {
13237
13245
  const target = args[0];
13238
13246
  if (!target) {
13239
- console.error("Usage: deepline play get <play-file.ts|play-name> [--json]");
13247
+ console.error(
13248
+ "Usage: deepline plays get <play-file.ts|play-name> [--json]"
13249
+ );
13240
13250
  return 1;
13241
13251
  }
13242
13252
  if (looksLikeRunId(target)) {
@@ -13334,7 +13344,7 @@ async function handlePlayVersions(args) {
13334
13344
  const nameIndex = args.indexOf("--name");
13335
13345
  const playName = nameIndex >= 0 ? args[nameIndex + 1] : void 0;
13336
13346
  if (!playName) {
13337
- console.error("Usage: deepline play versions --name <name> [--json]");
13347
+ console.error("Usage: deepline plays versions --name <name> [--json]");
13338
13348
  return 1;
13339
13349
  }
13340
13350
  const client2 = new DeeplineClient();
@@ -13714,7 +13724,7 @@ async function handlePlayPublish(args) {
13714
13724
  const playName = args[0];
13715
13725
  if (!playName) {
13716
13726
  console.error(
13717
- "Usage: deepline play publish <play-file.ts|play-name> [--latest|--revision-id <id>] [--json]"
13727
+ "Usage: deepline plays publish <play-file.ts|play-name> [--latest|--revision-id <id>] [--json]"
13718
13728
  );
13719
13729
  return 1;
13720
13730
  }
@@ -13858,7 +13868,7 @@ async function handlePlayDelete(args) {
13858
13868
  return result.deleted ? 0 : 1;
13859
13869
  }
13860
13870
  function registerPlayCommands(program) {
13861
- const play = program.command("plays").alias("play").description("Search, validate, run, and manage cloud plays.").addHelpText(
13871
+ const play = program.command("plays").description("Search, validate, run, and manage cloud plays.").addHelpText(
13862
13872
  "after",
13863
13873
  `
13864
13874
  Concepts:
@@ -16365,7 +16375,7 @@ async function runGeneratedEnrichPlay(runArgs, options = {}) {
16365
16375
  });
16366
16376
  } catch (error) {
16367
16377
  if (attempt === 0 && isPlayStartStreamEndedError(error)) {
16368
- await new Promise((resolve15) => setTimeout(resolve15, 250));
16378
+ await new Promise((resolve16) => setTimeout(resolve16, 250));
16369
16379
  continue;
16370
16380
  }
16371
16381
  throw error;
@@ -17165,19 +17175,16 @@ Notes:
17165
17175
  Use --command and --payload to attach a reproducible command shape.
17166
17176
 
17167
17177
  Examples:
17168
- deepline feedback "plays run failed after upload" --command "deepline plays run my.play.ts --watch"
17169
- deepline feedback "unexpected billing output" --payload '{"command":"billing usage"}' --json
17178
+ deepline feedback send "plays run failed after upload" --command "deepline plays run my.play.ts --watch"
17179
+ deepline feedback send "unexpected billing output" --payload '{"command":"billing usage"}' --json
17170
17180
  `
17171
17181
  );
17172
- feedback.argument("<text>", "Feedback text").option("--command <command>", "Command that reproduced the issue").option("--payload <payload>", "JSON or plain-text payload for the repro").option("--json", "Emit JSON output").action(handleFeedback);
17173
- program.command("provide-feedback").description("Legacy alias for `deepline feedback`.").addHelpText(
17182
+ feedback.command("send").description("Send CLI feedback to Deepline.").addHelpText(
17174
17183
  "after",
17175
17184
  `
17176
- Notes:
17177
- Compatibility alias. Prefer deepline feedback in new scripts and docs.
17178
-
17179
17185
  Examples:
17180
- deepline feedback "tools search returned stale results" --json
17186
+ deepline feedback send "tools search returned stale results" --json
17187
+ deepline feedback send "plays run failed after upload" --command "deepline plays run my.play.ts --watch"
17181
17188
  `
17182
17189
  ).argument("<text>", "Feedback text").option("--command <command>", "Command that reproduced the issue").option("--payload <payload>", "JSON or plain-text payload for the repro").option("--json", "Emit JSON output").action(handleFeedback);
17183
17190
  }
@@ -17298,8 +17305,44 @@ async function handleOrgSwitch(selection, options) {
17298
17305
  { json: options.json }
17299
17306
  );
17300
17307
  }
17308
+ async function handleOrgCreate(name, options) {
17309
+ const config = resolveConfig();
17310
+ const http = new HttpClient(config);
17311
+ const created = await http.post("/api/v2/auth/cli/org-create", {
17312
+ api_key: config.apiKey,
17313
+ name
17314
+ });
17315
+ saveHostEnvValues(config.baseUrl, {
17316
+ DEEPLINE_API_KEY: created.api_key,
17317
+ DEEPLINE_ACTIVE_ORG_ID: created.org_id,
17318
+ DEEPLINE_ACTIVE_ORG_NAME: created.org_name
17319
+ });
17320
+ const { api_key: _apiKey, ...publicCreated } = created;
17321
+ printCommandEnvelope(
17322
+ {
17323
+ ok: true,
17324
+ ...publicCreated,
17325
+ api_key_saved: true,
17326
+ switched: true,
17327
+ host_env_path: hostEnvFilePath(config.baseUrl),
17328
+ render: {
17329
+ sections: [
17330
+ {
17331
+ title: "org create",
17332
+ lines: [
17333
+ `Created organization: ${created.org_name}.`,
17334
+ `Switched to ${created.org_name}.`,
17335
+ `Saved host auth in ${hostEnvFilePath(config.baseUrl)}`
17336
+ ]
17337
+ }
17338
+ ]
17339
+ }
17340
+ },
17341
+ { json: options.json }
17342
+ );
17343
+ }
17301
17344
  function registerOrgCommands(program) {
17302
- const org = program.command("org").description("List and switch organizations.").addHelpText(
17345
+ const org = program.command("org").description("List, create, and switch organizations.").addHelpText(
17303
17346
  "after",
17304
17347
  `
17305
17348
  Notes:
@@ -17308,6 +17351,7 @@ Notes:
17308
17351
 
17309
17352
  Examples:
17310
17353
  deepline org list --json
17354
+ deepline org create Acme --json
17311
17355
  deepline org switch 2
17312
17356
  deepline org switch --org-id org_123 --json
17313
17357
  `
@@ -17323,6 +17367,19 @@ Examples:
17323
17367
  deepline org list --json
17324
17368
  `
17325
17369
  ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleOrgList);
17370
+ org.command("create <name>").description("Create a new organization and switch this CLI to it.").addHelpText(
17371
+ "after",
17372
+ `
17373
+ Notes:
17374
+ Mutates workspace state. The new organization is created for the current
17375
+ authenticated user, then the returned API key is saved for this host so later
17376
+ CLI commands target the new organization.
17377
+
17378
+ Examples:
17379
+ deepline org create Acme
17380
+ deepline org create "Acme Sales" --json
17381
+ `
17382
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleOrgCreate);
17326
17383
  org.command("switch [selection]").description(
17327
17384
  "Switch to another organization and save the new API key in the host auth file."
17328
17385
  ).addHelpText(
@@ -17367,7 +17424,7 @@ async function readHiddenLine(prompt) {
17367
17424
  if (typeof input.setRawMode === "function") input.setRawMode(true);
17368
17425
  let value = "";
17369
17426
  input.resume();
17370
- return await new Promise((resolve15, reject) => {
17427
+ return await new Promise((resolve16, reject) => {
17371
17428
  let settled = false;
17372
17429
  const cleanup = () => {
17373
17430
  input.off("data", onData);
@@ -17382,7 +17439,7 @@ async function readHiddenLine(prompt) {
17382
17439
  settled = true;
17383
17440
  output.write("\n");
17384
17441
  cleanup();
17385
- resolve15(line);
17442
+ resolve16(line);
17386
17443
  };
17387
17444
  const fail = (error) => {
17388
17445
  if (settled) return;
@@ -17552,22 +17609,566 @@ Examples:
17552
17609
  );
17553
17610
  }
17554
17611
 
17612
+ // src/cli/commands/sessions.ts
17613
+ import {
17614
+ existsSync as existsSync8,
17615
+ mkdirSync as mkdirSync4,
17616
+ readdirSync as readdirSync2,
17617
+ readFileSync as readFileSync7,
17618
+ statSync as statSync3,
17619
+ writeFileSync as writeFileSync8
17620
+ } from "fs";
17621
+ import { homedir as homedir5, platform } from "os";
17622
+ import { basename as basename4, dirname as dirname9, join as join9, resolve as resolve12 } from "path";
17623
+ import { gzipSync } from "zlib";
17624
+ import { randomUUID } from "crypto";
17625
+ var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
17626
+ var MAX_SESSION_UPLOAD_BYTES = 35e5;
17627
+ var MAX_DIRECT_SESSION_DECODED_BYTES = 50 * 1024 * 1024;
17628
+ var CHUNK_SIZE_BYTES = 25e5;
17629
+ var MAX_EVENT_STRING_CHARS = 8e3;
17630
+ var MAX_EVENT_LIST_ITEMS = 40;
17631
+ var MAX_EVENT_OBJECT_KEYS = 80;
17632
+ var TRUNCATION_MARKER = "...[truncated]";
17633
+ var NOISE_EVENT_TYPES = /* @__PURE__ */ new Set(["progress", "file-history-snapshot"]);
17634
+ function homeDir() {
17635
+ return process.env.HOME?.trim() || homedir5();
17636
+ }
17637
+ function detectShellContext() {
17638
+ const shellPath = process.env.SHELL?.trim() || process.env.ComSpec?.trim() || process.env.COMSPEC?.trim() || "";
17639
+ return {
17640
+ shell: shellPath ? basename4(shellPath).replace(/\.exe$/i, "") : "unknown",
17641
+ shell_path: shellPath || null,
17642
+ os: platform(),
17643
+ cwd: process.cwd()
17644
+ };
17645
+ }
17646
+ function claudeProjectsRoot() {
17647
+ return join9(homeDir(), ".claude", "projects");
17648
+ }
17649
+ function listClaudeSessionFiles() {
17650
+ const root = claudeProjectsRoot();
17651
+ if (!existsSync8(root)) return [];
17652
+ const projectDirs = readDirectoryNames(root);
17653
+ const files = [];
17654
+ for (const projectDir of projectDirs) {
17655
+ const fullProjectDir = join9(root, projectDir);
17656
+ for (const fileName of readDirectoryNames(fullProjectDir)) {
17657
+ if (fileName.endsWith(".jsonl")) {
17658
+ files.push(join9(fullProjectDir, fileName));
17659
+ }
17660
+ }
17661
+ }
17662
+ return files;
17663
+ }
17664
+ function readDirectoryNames(dir) {
17665
+ try {
17666
+ return readdirSync2(dir);
17667
+ } catch {
17668
+ return [];
17669
+ }
17670
+ }
17671
+ function newestClaudeSessionFile() {
17672
+ let newest = null;
17673
+ for (const filePath of listClaudeSessionFiles()) {
17674
+ try {
17675
+ const stat4 = statSync3(filePath);
17676
+ if (!newest || stat4.mtimeMs > newest.mtimeMs) {
17677
+ newest = { filePath, mtimeMs: stat4.mtimeMs };
17678
+ }
17679
+ } catch {
17680
+ continue;
17681
+ }
17682
+ }
17683
+ return newest?.filePath ?? null;
17684
+ }
17685
+ function sessionIdFromFilePath(filePath) {
17686
+ return basename4(filePath, ".jsonl");
17687
+ }
17688
+ function findSessionFile(sessionId) {
17689
+ if (!UUID_RE.test(sessionId)) {
17690
+ throw new Error(
17691
+ "Invalid session ID format. Expected a UUID such as 5a3bfb97-a2d9-49d9-82c6-52ccc03dadca."
17692
+ );
17693
+ }
17694
+ for (const filePath of listClaudeSessionFiles()) {
17695
+ if (sessionIdFromFilePath(filePath) === sessionId) {
17696
+ return filePath;
17697
+ }
17698
+ }
17699
+ return null;
17700
+ }
17701
+ function resolveSessionTargets(input2) {
17702
+ const targets = [];
17703
+ if (input2.currentSession) {
17704
+ const currentFile = newestClaudeSessionFile();
17705
+ if (!currentFile) {
17706
+ throw new Error("No session files found in ~/.claude/projects/*/.");
17707
+ }
17708
+ const sessionId = sessionIdFromFilePath(currentFile);
17709
+ targets.push({
17710
+ sessionId,
17711
+ label: `session-${sessionId}`,
17712
+ filePath: currentFile
17713
+ });
17714
+ }
17715
+ for (const [index, sessionId] of (input2.sessionIds ?? []).entries()) {
17716
+ const filePath = findSessionFile(sessionId);
17717
+ if (!filePath) {
17718
+ throw new Error(
17719
+ `Session file not found: ~/.claude/projects/*/${sessionId}.jsonl`
17720
+ );
17721
+ }
17722
+ targets.push({
17723
+ sessionId,
17724
+ label: input2.labels?.[index] ?? `session-${sessionId}`,
17725
+ filePath
17726
+ });
17727
+ }
17728
+ if (targets.length === 0) {
17729
+ throw new Error("One of --session-id or --current-session is required.");
17730
+ }
17731
+ return targets;
17732
+ }
17733
+ function parseJsonLine(line) {
17734
+ try {
17735
+ return JSON.parse(line);
17736
+ } catch {
17737
+ return null;
17738
+ }
17739
+ }
17740
+ function normalizedJsonLines(raw) {
17741
+ return raw.toString("utf8").split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
17742
+ }
17743
+ function stripNoiseEvents(raw) {
17744
+ const lines = [];
17745
+ for (const line of normalizedJsonLines(raw)) {
17746
+ const parsed = parseJsonLine(line);
17747
+ if (parsed && typeof parsed === "object" && NOISE_EVENT_TYPES.has(String(parsed.type ?? ""))) {
17748
+ continue;
17749
+ }
17750
+ lines.push(line);
17751
+ }
17752
+ return Buffer.from(lines.length > 0 ? `${lines.join("\n")}
17753
+ ` : "", "utf8");
17754
+ }
17755
+ function messageContentKey(value) {
17756
+ const message = value.message;
17757
+ if (!message || typeof message !== "object") return null;
17758
+ const content = message.content;
17759
+ if (typeof content === "string") return content;
17760
+ if (!Array.isArray(content)) return null;
17761
+ return content.map((block) => {
17762
+ if (!block || typeof block !== "object") return String(block);
17763
+ const record = block;
17764
+ const type = String(record.type ?? "");
17765
+ if (type === "tool_use") {
17766
+ return `tool_use:${String(record.name ?? "")}:${String(record.id ?? "")}`;
17767
+ }
17768
+ if (type === "tool_result") {
17769
+ return `tool_result:${String(record.tool_use_id ?? "")}`;
17770
+ }
17771
+ return String(record.text ?? type);
17772
+ }).join("\n");
17773
+ }
17774
+ function dedupConsecutiveEvents(raw) {
17775
+ const rawLines = normalizedJsonLines(raw);
17776
+ const parsedEvents = rawLines.map(parseJsonLine);
17777
+ const output2 = [];
17778
+ let index = 0;
17779
+ while (index < parsedEvents.length) {
17780
+ const event = parsedEvents[index];
17781
+ if (!event || typeof event !== "object") {
17782
+ output2.push(rawLines[index] ?? "");
17783
+ index += 1;
17784
+ continue;
17785
+ }
17786
+ const record = event;
17787
+ const eventType = String(record.type ?? "");
17788
+ const eventKey = messageContentKey(record);
17789
+ if (!["user", "assistant"].includes(eventType) || !eventKey) {
17790
+ output2.push(rawLines[index] ?? "");
17791
+ index += 1;
17792
+ continue;
17793
+ }
17794
+ let runCount = 1;
17795
+ let cursor = index + 1;
17796
+ while (cursor < parsedEvents.length) {
17797
+ const next = parsedEvents[cursor];
17798
+ if (!next || typeof next !== "object") break;
17799
+ const nextRecord = next;
17800
+ if (String(nextRecord.type ?? "") !== eventType || messageContentKey(nextRecord) !== eventKey) {
17801
+ break;
17802
+ }
17803
+ runCount += 1;
17804
+ cursor += 1;
17805
+ }
17806
+ if (runCount > 1) {
17807
+ record._repeat_count = runCount;
17808
+ record._repeat_summary = `${runCount} consecutive identical ${eventType} messages collapsed`;
17809
+ output2.push(JSON.stringify(record));
17810
+ index = cursor;
17811
+ continue;
17812
+ }
17813
+ output2.push(rawLines[index] ?? "");
17814
+ index += 1;
17815
+ }
17816
+ return Buffer.from(output2.length > 0 ? `${output2.join("\n")}
17817
+ ` : "", "utf8");
17818
+ }
17819
+ function compactEventValue(value) {
17820
+ if (typeof value === "string") {
17821
+ if (value.length <= MAX_EVENT_STRING_CHARS) return value;
17822
+ return `${value.slice(0, MAX_EVENT_STRING_CHARS - TRUNCATION_MARKER.length)}${TRUNCATION_MARKER}`;
17823
+ }
17824
+ if (Array.isArray(value)) {
17825
+ const compacted = value.slice(0, MAX_EVENT_LIST_ITEMS).map(compactEventValue);
17826
+ if (value.length > MAX_EVENT_LIST_ITEMS) {
17827
+ compacted.push(
17828
+ `${TRUNCATION_MARKER} ${value.length - MAX_EVENT_LIST_ITEMS} more item(s)`
17829
+ );
17830
+ }
17831
+ return compacted;
17832
+ }
17833
+ if (value && typeof value === "object") {
17834
+ const entries = Object.entries(value);
17835
+ const compacted = {};
17836
+ for (const [key, item] of entries.slice(0, MAX_EVENT_OBJECT_KEYS)) {
17837
+ compacted[key] = compactEventValue(item);
17838
+ }
17839
+ if (entries.length > MAX_EVENT_OBJECT_KEYS) {
17840
+ compacted._truncated_keys = entries.length - MAX_EVENT_OBJECT_KEYS;
17841
+ }
17842
+ return compacted;
17843
+ }
17844
+ return value;
17845
+ }
17846
+ function selectiveCompactToolResults(raw) {
17847
+ const lines = [];
17848
+ for (const line of normalizedJsonLines(raw)) {
17849
+ const parsed = parseJsonLine(line);
17850
+ if (!parsed || typeof parsed !== "object") {
17851
+ lines.push(line);
17852
+ continue;
17853
+ }
17854
+ const record = parsed;
17855
+ if (record.type === "user") {
17856
+ const message = record.message;
17857
+ const content = message && typeof message === "object" ? message.content : null;
17858
+ if (Array.isArray(content)) {
17859
+ message.content = content.map(
17860
+ (block) => block && typeof block === "object" && block.type === "tool_result" ? compactEventValue(block) : block
17861
+ );
17862
+ }
17863
+ }
17864
+ lines.push(JSON.stringify(record));
17865
+ }
17866
+ return Buffer.from(lines.length > 0 ? `${lines.join("\n")}
17867
+ ` : "", "utf8");
17868
+ }
17869
+ function prepareSessionBuffer(raw) {
17870
+ return selectiveCompactToolResults(
17871
+ dedupConsecutiveEvents(stripNoiseEvents(raw))
17872
+ );
17873
+ }
17874
+ function buildSessionUploadContent(raw) {
17875
+ const prepared = prepareSessionBuffer(raw);
17876
+ const encoded = gzipSync(prepared).toString("base64");
17877
+ if (encoded.length <= MAX_SESSION_UPLOAD_BYTES && prepared.length <= MAX_DIRECT_SESSION_DECODED_BYTES) {
17878
+ return { encodedContent: encoded, needsChunking: false };
17879
+ }
17880
+ return { encodedContent: encoded, needsChunking: true };
17881
+ }
17882
+ async function uploadPayload(path, payload) {
17883
+ const { http } = getAuthedHttpClient();
17884
+ return await http.post(path, payload);
17885
+ }
17886
+ async function uploadChunkedSessions(sessions, options) {
17887
+ const uploadId = randomUUID();
17888
+ for (const session of sessions) {
17889
+ const bytes = Buffer.from(session.encodedContent, "base64");
17890
+ const chunks = [];
17891
+ for (let offset = 0; offset < bytes.length; offset += CHUNK_SIZE_BYTES) {
17892
+ chunks.push(bytes.subarray(offset, offset + CHUNK_SIZE_BYTES));
17893
+ }
17894
+ process.stderr.write(
17895
+ `Uploading ${session.label} in ${chunks.length} chunk(s)...
17896
+ `
17897
+ );
17898
+ for (const [index, chunk] of chunks.entries()) {
17899
+ await uploadPayload("/api/v2/cli/send-session/chunk", {
17900
+ upload_id: uploadId,
17901
+ session_id: session.sessionId,
17902
+ index,
17903
+ total_chunks: chunks.length,
17904
+ data: chunk.toString("base64")
17905
+ });
17906
+ }
17907
+ }
17908
+ const response = await uploadPayload("/api/v2/cli/send-session/finalize", {
17909
+ upload_id: uploadId,
17910
+ session_ids: sessions.map((session) => session.sessionId),
17911
+ labels: sessions.map((session) => session.label),
17912
+ environments: sessions.map(() => detectShellContext())
17913
+ });
17914
+ printCommandEnvelope(
17915
+ {
17916
+ ...response,
17917
+ ok: true,
17918
+ uploaded: sessions.length,
17919
+ render: {
17920
+ sections: [
17921
+ {
17922
+ title: "sessions send",
17923
+ lines: ["Session uploaded to #internal-reports (chunked)."]
17924
+ }
17925
+ ]
17926
+ }
17927
+ },
17928
+ { json: options.json }
17929
+ );
17930
+ }
17931
+ async function handleSessionsSend(options) {
17932
+ if (options.file) {
17933
+ const filePath = resolve12(options.file);
17934
+ if (!existsSync8(filePath)) {
17935
+ throw new Error(`File not found: ${options.file}`);
17936
+ }
17937
+ const response2 = await uploadPayload("/api/v2/cli/send-session", {
17938
+ file: readFileSync7(filePath).toString("base64"),
17939
+ filename: basename4(filePath)
17940
+ });
17941
+ printCommandEnvelope(
17942
+ {
17943
+ ...response2,
17944
+ ok: true,
17945
+ filename: basename4(filePath),
17946
+ render: {
17947
+ sections: [
17948
+ {
17949
+ title: "sessions send",
17950
+ lines: [
17951
+ `File '${basename4(filePath)}' uploaded to #internal-reports.`
17952
+ ]
17953
+ }
17954
+ ]
17955
+ }
17956
+ },
17957
+ { json: options.json }
17958
+ );
17959
+ return;
17960
+ }
17961
+ const targets = resolveSessionTargets({
17962
+ sessionIds: options.sessionId,
17963
+ labels: options.label,
17964
+ currentSession: options.currentSession
17965
+ });
17966
+ const built = targets.map((target) => {
17967
+ const upload = buildSessionUploadContent(readFileSync7(target.filePath));
17968
+ return { ...target, ...upload };
17969
+ });
17970
+ if (built.some((session) => session.needsChunking)) {
17971
+ await uploadChunkedSessions(built, options);
17972
+ return;
17973
+ }
17974
+ const response = built.length === 1 && !options.label?.length ? await uploadPayload("/api/v2/cli/send-session", {
17975
+ session_id: built[0]?.sessionId,
17976
+ content: built[0]?.encodedContent,
17977
+ environment: detectShellContext()
17978
+ }) : await uploadPayload("/api/v2/cli/send-session", {
17979
+ sessions: built.map((session) => ({
17980
+ session_id: session.sessionId,
17981
+ content: session.encodedContent,
17982
+ label: session.label,
17983
+ environment: detectShellContext()
17984
+ })),
17985
+ environment: detectShellContext()
17986
+ });
17987
+ printCommandEnvelope(
17988
+ {
17989
+ ...response,
17990
+ ok: true,
17991
+ uploaded: built.length,
17992
+ render: {
17993
+ sections: [
17994
+ {
17995
+ title: "sessions send",
17996
+ lines: ["Session uploaded to #internal-reports."]
17997
+ }
17998
+ ]
17999
+ }
18000
+ },
18001
+ { json: options.json }
18002
+ );
18003
+ }
18004
+ function fallbackViewerAssets() {
18005
+ return {
18006
+ css: [
18007
+ "body{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;margin:0;padding:16px;background:#fafafa;color:#111}",
18008
+ ".section{background:#fff;border:1px solid #ddd;border-radius:8px;padding:12px;margin-bottom:12px}",
18009
+ ".section h2{margin:0 0 8px 0;font-size:14px}",
18010
+ "pre{margin:0;white-space:pre-wrap;word-break:break-word;background:#f6f8fa;border:1px solid #e3e5e8;border-radius:6px;padding:10px}"
18011
+ ].join(""),
18012
+ js: [
18013
+ "(() => {",
18014
+ 'const root=document.getElementById("main-content");',
18015
+ 'const raw=document.getElementById("raw-sessions");',
18016
+ "if(!root||!raw)return;",
18017
+ 'let sessions=[];try{sessions=JSON.parse(raw.textContent||"[]")}catch{}',
18018
+ 'root.innerHTML="";',
18019
+ "for(const session of sessions){",
18020
+ 'const section=document.createElement("section");section.className="section";',
18021
+ 'const title=document.createElement("h2");title.textContent=String(session.label||"session");',
18022
+ 'const pre=document.createElement("pre");',
18023
+ 'pre.textContent=(Array.isArray(session.events)?session.events:[]).map((event)=>JSON.stringify(event)).join("\\n");',
18024
+ "section.append(title,pre);root.appendChild(section);",
18025
+ "}",
18026
+ "})();"
18027
+ ].join("")
18028
+ };
18029
+ }
18030
+ function parsePreparedEvents(buffer) {
18031
+ return normalizedJsonLines(buffer).map((line) => {
18032
+ const parsed = parseJsonLine(line);
18033
+ return parsed ?? line;
18034
+ });
18035
+ }
18036
+ async function handleSessionsRender(options) {
18037
+ const targets = resolveSessionTargets({
18038
+ sessionIds: options.sessionId,
18039
+ labels: options.label,
18040
+ currentSession: options.currentSession
18041
+ });
18042
+ let outputPath = options.output ? resolve12(options.output) : "";
18043
+ if (!outputPath) {
18044
+ const outputDir = join9(process.cwd(), "deepline", "data");
18045
+ mkdirSync4(outputDir, { recursive: true });
18046
+ outputPath = join9(
18047
+ outputDir,
18048
+ targets.length > 1 ? "session-viewer.html" : `session-${targets[0]?.sessionId}.html`
18049
+ );
18050
+ } else {
18051
+ mkdirSync4(dirname9(outputPath), { recursive: true });
18052
+ }
18053
+ const sessions = targets.map((target) => ({
18054
+ label: target.label,
18055
+ events: parsePreparedEvents(
18056
+ prepareSessionBuffer(readFileSync7(target.filePath))
18057
+ )
18058
+ }));
18059
+ const { css, js } = fallbackViewerAssets();
18060
+ const refreshMeta = options.autoRefresh ? `<meta http-equiv="refresh" content="${Number.parseInt(options.autoRefresh, 10)}">` : "";
18061
+ const rawJson = JSON.stringify(sessions).replace(/<\//g, "<\\/");
18062
+ const html = `<!DOCTYPE html>
18063
+ <html lang="en">
18064
+ <head>
18065
+ <meta charset="UTF-8">
18066
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
18067
+ ${refreshMeta}
18068
+ <title>Session Viewer</title>
18069
+ <style>${css}</style>
18070
+ </head>
18071
+ <body>
18072
+ <div class="layout">
18073
+ <div class="main" id="main-content"></div>
18074
+ </div>
18075
+ <script type="application/json" id="raw-sessions">${rawJson}</script>
18076
+ <script>${js}</script>
18077
+ </body>
18078
+ </html>`;
18079
+ writeFileSync8(outputPath, html, "utf8");
18080
+ printCommandEnvelope(
18081
+ {
18082
+ ok: true,
18083
+ file: outputPath,
18084
+ session_count: targets.length,
18085
+ render: {
18086
+ sections: [
18087
+ {
18088
+ title: "sessions render",
18089
+ lines: [`Rendered session viewer: ${outputPath}`]
18090
+ }
18091
+ ]
18092
+ }
18093
+ },
18094
+ { json: options.json }
18095
+ );
18096
+ }
18097
+ function collectOption(value, previous) {
18098
+ previous.push(value);
18099
+ return previous;
18100
+ }
18101
+ function registerSessionsCommands(program) {
18102
+ const sessions = program.command("sessions").description("Upload and render local agent session transcripts.").addHelpText(
18103
+ "after",
18104
+ `
18105
+ Notes:
18106
+ Session commands operate on local Claude session JSONL files under
18107
+ ~/.claude/projects. send uploads a compacted transcript or file to Deepline.
18108
+ render writes a local HTML viewer.
18109
+
18110
+ Examples:
18111
+ deepline sessions send --current-session --json
18112
+ deepline sessions send --session-id 5a3bfb97-a2d9-49d9-82c6-52ccc03dadca
18113
+ deepline sessions render --current-session --output session.html
18114
+ `
18115
+ );
18116
+ sessions.command("send").description("Upload session transcript(s) or a local file to Deepline.").addHelpText(
18117
+ "after",
18118
+ `
18119
+ Examples:
18120
+ deepline sessions send --current-session --json
18121
+ deepline sessions send --session-id 5a3bfb97-a2d9-49d9-82c6-52ccc03dadca --label "pilot run"
18122
+ deepline sessions send --file ./debug.log --json
18123
+ `
18124
+ ).option(
18125
+ "--session-id <uuid>",
18126
+ "Claude session UUID. Repeat for multiple sessions.",
18127
+ collectOption,
18128
+ []
18129
+ ).option(
18130
+ "--label <label>",
18131
+ "Label for the preceding session id",
18132
+ collectOption,
18133
+ []
18134
+ ).option("--current-session", "Use the newest local Claude session JSONL").option("--file <path>", "Upload a raw local file instead of a session").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleSessionsSend);
18135
+ sessions.command("render").description("Render local session transcript(s) to an HTML viewer.").addHelpText(
18136
+ "after",
18137
+ `
18138
+ Examples:
18139
+ deepline sessions render --current-session
18140
+ deepline sessions render --session-id 5a3bfb97-a2d9-49d9-82c6-52ccc03dadca --output session.html
18141
+ deepline sessions render --current-session --auto-refresh 5 --json
18142
+ `
18143
+ ).option(
18144
+ "--session-id <uuid>",
18145
+ "Claude session UUID. Repeat for multiple sessions.",
18146
+ collectOption,
18147
+ []
18148
+ ).option(
18149
+ "--label <label>",
18150
+ "Label for the preceding session id",
18151
+ collectOption,
18152
+ []
18153
+ ).option("--current-session", "Use the newest local Claude session JSONL").option("--auto-refresh <seconds>", "Add a browser auto-refresh interval").option("-o, --output <path>", "Output HTML path").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleSessionsRender);
18154
+ }
18155
+
17555
18156
  // src/cli/commands/tools.ts
17556
18157
  import { Option } from "commander";
17557
18158
  import {
17558
18159
  chmodSync,
17559
- existsSync as existsSync8,
18160
+ existsSync as existsSync9,
17560
18161
  mkdtempSync,
17561
- readFileSync as readFileSync7,
17562
- writeFileSync as writeFileSync9
18162
+ readFileSync as readFileSync8,
18163
+ writeFileSync as writeFileSync10
17563
18164
  } from "fs";
17564
18165
  import { tmpdir as tmpdir4 } from "os";
17565
- import { join as join10, resolve as resolve12 } from "path";
18166
+ import { join as join11, resolve as resolve13 } from "path";
17566
18167
 
17567
18168
  // src/tool-output.ts
17568
- import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync8 } from "fs";
17569
- import { homedir as homedir5 } from "os";
17570
- import { join as join9 } from "path";
18169
+ import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync9 } from "fs";
18170
+ import { homedir as homedir6 } from "os";
18171
+ import { join as join10 } from "path";
17571
18172
  function isPlainObject(value) {
17572
18173
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
17573
18174
  }
@@ -17663,19 +18264,19 @@ function tryConvertToList(payload, options) {
17663
18264
  return null;
17664
18265
  }
17665
18266
  function ensureOutputDir() {
17666
- const outputDir = join9(homedir5(), ".local", "share", "deepline", "data");
17667
- mkdirSync4(outputDir, { recursive: true });
18267
+ const outputDir = join10(homedir6(), ".local", "share", "deepline", "data");
18268
+ mkdirSync5(outputDir, { recursive: true });
17668
18269
  return outputDir;
17669
18270
  }
17670
18271
  function writeJsonOutputFile(payload, stem) {
17671
18272
  const outputDir = ensureOutputDir();
17672
- const outputPath = join9(outputDir, `${stem}_${Date.now()}.json`);
17673
- writeFileSync8(outputPath, JSON.stringify(payload, null, 2), "utf-8");
18273
+ const outputPath = join10(outputDir, `${stem}_${Date.now()}.json`);
18274
+ writeFileSync9(outputPath, JSON.stringify(payload, null, 2), "utf-8");
17674
18275
  return outputPath;
17675
18276
  }
17676
18277
  function writeCsvOutputFile(rows, stem) {
17677
18278
  const outputDir = ensureOutputDir();
17678
- const outputPath = join9(outputDir, `${stem}_${Date.now()}.csv`);
18279
+ const outputPath = join10(outputDir, `${stem}_${Date.now()}.csv`);
17679
18280
  const seen = /* @__PURE__ */ new Set();
17680
18281
  const columns = [];
17681
18282
  for (const row of rows) {
@@ -17698,7 +18299,7 @@ function writeCsvOutputFile(rows, stem) {
17698
18299
  for (const row of rows) {
17699
18300
  lines.push(columns.map((column) => escapeCell(row[column])).join(","));
17700
18301
  }
17701
- writeFileSync8(outputPath, `${lines.join("\n")}
18302
+ writeFileSync9(outputPath, `${lines.join("\n")}
17702
18303
  `, "utf-8");
17703
18304
  const previewRows = rows.slice(0, 5);
17704
18305
  const previewColumns = columns.slice(0, 5);
@@ -17984,7 +18585,7 @@ Common commands:
17984
18585
 
17985
18586
  Output:
17986
18587
  Use describe for tool contracts.
17987
- Use execute to run a tool. run is accepted as a compatibility alias.
18588
+ Use execute to run a tool.
17988
18589
  `
17989
18590
  );
17990
18591
  tools.command("list").description("List available tools.").addHelpText(
@@ -18077,7 +18678,7 @@ Examples:
18077
18678
  Notes:
18078
18679
  Shows the compact agent contract by default: what the tool does, cost,
18079
18680
  required inputs, play getters, and a runnable ctx.tools.execute snippet.
18080
- Use --json for the full metadata/debug payload.
18681
+ get is accepted as a compatibility alias for describe.
18081
18682
 
18082
18683
  Examples:
18083
18684
  deepline tools describe hunter_email_verifier
@@ -18111,29 +18712,13 @@ Examples:
18111
18712
  gettersOnly: Boolean(options.gettersOnly)
18112
18713
  });
18113
18714
  });
18114
- addToolMetadataCommand(tools.command("describe <toolId>"));
18115
- tools.command("get <toolId>").description("Deprecated. Use tools describe.").addHelpText(
18116
- "after",
18117
- `
18118
- Examples:
18119
- deepline tools describe hunter_email_verifier --json
18120
- `
18121
- ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (toolId, options) => {
18122
- const message = `tools get has been removed from the V2 SDK CLI. Use: deepline tools describe ${toolId} --json`;
18123
- if (options.json || shouldEmitJson()) {
18124
- printJsonError({ message, code: "TOOLS_GET_REMOVED" });
18125
- } else {
18126
- console.error(message);
18127
- }
18128
- process.exitCode = 2;
18129
- });
18130
- tools.command("execute <toolId>").alias("run").description("Execute a tool by id.").addHelpText(
18715
+ addToolMetadataCommand(tools.command("describe <toolId>").alias("get"));
18716
+ tools.command("execute <toolId>").description("Execute a tool by id.").addHelpText(
18131
18717
  "after",
18132
18718
  `
18133
18719
  Notes:
18134
18720
  Use tools for one atomic provider/API operation. Use plays for composed workflows,
18135
18721
  waterfalls, row maps, checkpoints, and retries.
18136
- execute is the canonical execution verb. run is a compatibility alias.
18137
18722
  Calling a provider-backed tool can spend Deepline credits. Use --json for the
18138
18723
  stable result payload plus output preview and debugging helpers.
18139
18724
 
@@ -18181,7 +18766,7 @@ Examples:
18181
18766
  }
18182
18767
  async function getTool(toolId, options = {}) {
18183
18768
  if (!toolId) {
18184
- console.error("Usage: deepline tools get <toolId> [--json]");
18769
+ console.error("Usage: deepline tools describe <toolId> [--json]");
18185
18770
  return 1;
18186
18771
  }
18187
18772
  const client2 = new DeeplineClient();
@@ -18732,11 +19317,11 @@ function normalizeOutputFormat(raw) {
18732
19317
  }
18733
19318
  function resolveAtFilePath(rawPath) {
18734
19319
  const trimmed = rawPath.trim();
18735
- const resolved = resolve12(trimmed);
18736
- if (existsSync8(resolved)) return resolved;
19320
+ const resolved = resolve13(trimmed);
19321
+ if (existsSync9(resolved)) return resolved;
18737
19322
  if (process.platform !== "win32" && trimmed.includes("\\")) {
18738
- const normalized = resolve12(trimmed.replace(/\\/g, "/"));
18739
- if (existsSync8(normalized)) return normalized;
19323
+ const normalized = resolve13(trimmed.replace(/\\/g, "/"));
19324
+ if (existsSync9(normalized)) return normalized;
18740
19325
  }
18741
19326
  return resolved;
18742
19327
  }
@@ -18747,7 +19332,7 @@ function readJsonArgument(raw, flagName) {
18747
19332
  throw new Error(`Invalid ${flagName} value: empty @file path.`);
18748
19333
  }
18749
19334
  try {
18750
- return readFileSync7(resolveAtFilePath(filePath), "utf8").replace(
19335
+ return readFileSync8(resolveAtFilePath(filePath), "utf8").replace(
18751
19336
  /^\uFEFF/,
18752
19337
  ""
18753
19338
  );
@@ -18838,9 +19423,9 @@ function powerShellQuote(value) {
18838
19423
  function seedToolListScript(input2) {
18839
19424
  const stem = safeFileStem(input2.toolId);
18840
19425
  const fileName = `${stem}-workflow-seed-${Date.now()}.play.ts`;
18841
- const scriptDir = mkdtempSync(join10(tmpdir4(), "deepline-workflow-seed-"));
19426
+ const scriptDir = mkdtempSync(join11(tmpdir4(), "deepline-workflow-seed-"));
18842
19427
  chmodSync(scriptDir, 448);
18843
- const scriptPath = join10(scriptDir, fileName);
19428
+ const scriptPath = join11(scriptDir, fileName);
18844
19429
  const projectDir = `deepline/projects/${stem}-workflow`;
18845
19430
  const playName = `${stem}-workflow`;
18846
19431
  const sampleRows = input2.rows.length > 0 ? `${JSON.stringify(input2.rows.slice(0, 2)).replace(/\]$/, "")}, ...]` : "[]";
@@ -18876,7 +19461,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
18876
19461
  };
18877
19462
  });
18878
19463
  `;
18879
- writeFileSync9(scriptPath, script, { encoding: "utf-8", mode: 384 });
19464
+ writeFileSync10(scriptPath, script, { encoding: "utf-8", mode: 384 });
18880
19465
  return {
18881
19466
  path: scriptPath,
18882
19467
  sourceCode: script,
@@ -19131,7 +19716,7 @@ async function executeTool(args) {
19131
19716
 
19132
19717
  // src/cli/commands/workflow.ts
19133
19718
  import { mkdir as mkdir5, readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
19134
- import { dirname as dirname9, join as join11, resolve as resolve13 } from "path";
19719
+ import { dirname as dirname10, join as join12, resolve as resolve14 } from "path";
19135
19720
 
19136
19721
  // src/cli/workflow-to-play.ts
19137
19722
  import { createHash as createHash4 } from "crypto";
@@ -19338,7 +19923,7 @@ function readStatus(payload) {
19338
19923
  }
19339
19924
  async function readJsonOption(payload, file) {
19340
19925
  if (file) {
19341
- const raw = await readFile4(resolve13(file), "utf8");
19926
+ const raw = await readFile4(resolve14(file), "utf8");
19342
19927
  return JSON.parse(raw);
19343
19928
  }
19344
19929
  if (payload) {
@@ -19372,8 +19957,8 @@ async function transformOne(api, workflowId, outDir, publish) {
19372
19957
  revision.config,
19373
19958
  { workflowName: workflow.name, version: revision.version }
19374
19959
  );
19375
- const file = join11(resolve13(outDir), `${compiled.playName}.play.ts`);
19376
- await mkdir5(dirname9(file), { recursive: true });
19960
+ const file = join12(resolve14(outDir), `${compiled.playName}.play.ts`);
19961
+ await mkdir5(dirname10(file), { recursive: true });
19377
19962
  await writeFile5(file, compiled.sourceCode, "utf8");
19378
19963
  let published = false;
19379
19964
  if (publish) {
@@ -19620,8 +20205,8 @@ Notes:
19620
20205
 
19621
20206
  // src/cli/commands/update.ts
19622
20207
  import { spawn } from "child_process";
19623
- import { existsSync as existsSync9 } from "fs";
19624
- import { dirname as dirname10, join as join12, resolve as resolve14 } from "path";
20208
+ import { existsSync as existsSync10 } from "fs";
20209
+ import { dirname as dirname11, join as join13, resolve as resolve15 } from "path";
19625
20210
  function posixShellQuote(value) {
19626
20211
  return `'${value.replace(/'/g, `'\\''`)}'`;
19627
20212
  }
@@ -19640,19 +20225,19 @@ function buildSourceUpdateCommand(sourceRoot) {
19640
20225
  return `${cdCommand} && git fetch origin main --tags && git merge --ff-only origin/main`;
19641
20226
  }
19642
20227
  function findRepoBackedSdkRoot(startPath) {
19643
- let current = resolve14(startPath);
20228
+ let current = resolve15(startPath);
19644
20229
  while (true) {
19645
- if (existsSync9(join12(current, "sdk", "package.json")) && existsSync9(join12(current, "sdk", "bin", "deepline-dev.ts"))) {
20230
+ if (existsSync10(join13(current, "sdk", "package.json")) && existsSync10(join13(current, "sdk", "bin", "deepline-dev.ts"))) {
19646
20231
  return current;
19647
20232
  }
19648
- const parent = dirname10(current);
20233
+ const parent = dirname11(current);
19649
20234
  if (parent === current) return null;
19650
20235
  current = parent;
19651
20236
  }
19652
20237
  }
19653
20238
  function resolveUpdatePlan() {
19654
- const entrypoint = process.argv[1] ? resolve14(process.argv[1]) : "";
19655
- const sourceRoot = entrypoint ? findRepoBackedSdkRoot(dirname10(entrypoint)) : null;
20239
+ const entrypoint = process.argv[1] ? resolve15(process.argv[1]) : "";
20240
+ const sourceRoot = entrypoint ? findRepoBackedSdkRoot(dirname11(entrypoint)) : null;
19656
20241
  if (sourceRoot) {
19657
20242
  return {
19658
20243
  kind: "source",
@@ -19727,7 +20312,7 @@ async function handleUpdate(options) {
19727
20312
  return runCommand(plan.command, plan.args);
19728
20313
  }
19729
20314
  function registerUpdateCommand(program) {
19730
- program.command("update").alias("upgrade").description("Update the Deepline SDK/CLI.").addHelpText(
20315
+ program.command("update").description("Update the Deepline SDK/CLI.").addHelpText(
19731
20316
  "after",
19732
20317
  `
19733
20318
  Notes:
@@ -19755,7 +20340,7 @@ var command_compatibility_default = {
19755
20340
  session: {
19756
20341
  family: "python",
19757
20342
  label: "a legacy Python CLI session/playground command",
19758
- sdk_alternative: "Use SDK play run output and run commands such as `deepline plays run ...`."
20343
+ sdk_alternative: "Use `deepline sessions send ...` or `deepline sessions render ...` for transcript workflows."
19759
20344
  },
19760
20345
  workflows: {
19761
20346
  family: "python",
@@ -19775,15 +20360,14 @@ var command_compatibility_default = {
19775
20360
  label: "an SDK CLI play command",
19776
20361
  python_alternative: "Use `deepline workflows ...` only for legacy workflows."
19777
20362
  },
19778
- play: {
19779
- family: "sdk",
19780
- label: "an SDK CLI play command",
19781
- python_alternative: "Use `deepline workflows ...` only for legacy workflows."
19782
- },
19783
20363
  runs: {
19784
20364
  family: "sdk",
19785
20365
  label: "an SDK CLI run inspection command"
19786
20366
  },
20367
+ sessions: {
20368
+ family: "sdk",
20369
+ label: "an SDK CLI session transcript command"
20370
+ },
19787
20371
  health: {
19788
20372
  family: "sdk",
19789
20373
  label: "an SDK CLI health command"
@@ -19916,15 +20500,15 @@ function unknownCommandNameFromMessage(message) {
19916
20500
  // src/cli/skills-sync.ts
19917
20501
  import { spawn as spawn2, spawnSync } from "child_process";
19918
20502
  import {
19919
- existsSync as existsSync10,
19920
- mkdirSync as mkdirSync5,
19921
- readdirSync as readdirSync2,
19922
- readFileSync as readFileSync8,
19923
- statSync as statSync3,
19924
- writeFileSync as writeFileSync10
20503
+ existsSync as existsSync11,
20504
+ mkdirSync as mkdirSync6,
20505
+ readdirSync as readdirSync3,
20506
+ readFileSync as readFileSync9,
20507
+ statSync as statSync4,
20508
+ writeFileSync as writeFileSync11
19925
20509
  } from "fs";
19926
- import { homedir as homedir6 } from "os";
19927
- import { dirname as dirname11, join as join13 } from "path";
20510
+ import { homedir as homedir7 } from "os";
20511
+ import { dirname as dirname12, join as join14 } from "path";
19928
20512
  var CHECK_TIMEOUT_MS2 = 3e3;
19929
20513
  var SDK_SKILL_NAME = "deepline-plays";
19930
20514
  var attemptedSync = false;
@@ -19938,20 +20522,20 @@ function activePluginSkillsDir() {
19938
20522
  return "";
19939
20523
  }
19940
20524
  const dir = process.env.DEEPLINE_PLUGIN_SKILLS_DIR?.trim() ?? "";
19941
- return dir && existsSync10(dir) ? dir : "";
20525
+ return dir && existsSync11(dir) ? dir : "";
19942
20526
  }
19943
20527
  function readPluginSkillsVersion() {
19944
20528
  const dir = activePluginSkillsDir();
19945
20529
  if (!dir) return "";
19946
20530
  try {
19947
- return readFileSync8(join13(dir, ".version"), "utf-8").trim();
20531
+ return readFileSync9(join14(dir, ".version"), "utf-8").trim();
19948
20532
  } catch {
19949
20533
  return "";
19950
20534
  }
19951
20535
  }
19952
20536
  function sdkSkillsVersionPath(baseUrl) {
19953
- const home = process.env.HOME?.trim() || homedir6();
19954
- return join13(
20537
+ const home = process.env.HOME?.trim() || homedir7();
20538
+ return join14(
19955
20539
  home,
19956
20540
  ".local",
19957
20541
  "deepline",
@@ -19964,25 +20548,25 @@ function readLocalSkillsVersion(baseUrl) {
19964
20548
  const pluginVersion = readPluginSkillsVersion();
19965
20549
  if (pluginVersion) return pluginVersion;
19966
20550
  const path = sdkSkillsVersionPath(baseUrl);
19967
- if (!existsSync10(path)) return "";
20551
+ if (!existsSync11(path)) return "";
19968
20552
  try {
19969
- return readFileSync8(path, "utf-8").trim();
20553
+ return readFileSync9(path, "utf-8").trim();
19970
20554
  } catch {
19971
20555
  return "";
19972
20556
  }
19973
20557
  }
19974
20558
  function writeLocalSkillsVersion(baseUrl, version) {
19975
20559
  const path = sdkSkillsVersionPath(baseUrl);
19976
- mkdirSync5(dirname11(path), { recursive: true });
19977
- writeFileSync10(path, `${version}
20560
+ mkdirSync6(dirname12(path), { recursive: true });
20561
+ writeFileSync11(path, `${version}
19978
20562
  `, "utf-8");
19979
20563
  }
19980
20564
  function installedSdkSkillHasStalePositionalExecuteExamples() {
19981
- const home = process.env.HOME?.trim() || homedir6();
20565
+ const home = process.env.HOME?.trim() || homedir7();
19982
20566
  const pluginSkillsDir = activePluginSkillsDir();
19983
- const roots = pluginSkillsDir ? [join13(pluginSkillsDir, SDK_SKILL_NAME)] : [
19984
- join13(home, ".claude", "skills", SDK_SKILL_NAME),
19985
- join13(home, ".agents", "skills", SDK_SKILL_NAME)
20567
+ const roots = pluginSkillsDir ? [join14(pluginSkillsDir, SDK_SKILL_NAME)] : [
20568
+ join14(home, ".claude", "skills", SDK_SKILL_NAME),
20569
+ join14(home, ".agents", "skills", SDK_SKILL_NAME)
19986
20570
  ];
19987
20571
  const staleMarkers = [
19988
20572
  "ctx.tools.execute(key",
@@ -19992,22 +20576,22 @@ function installedSdkSkillHasStalePositionalExecuteExamples() {
19992
20576
  'rowCtx.tools.execute("'
19993
20577
  ];
19994
20578
  const scan = (dir) => {
19995
- for (const entry of readdirSync2(dir)) {
19996
- const path = join13(dir, entry);
19997
- const stat4 = statSync3(path);
20579
+ for (const entry of readdirSync3(dir)) {
20580
+ const path = join14(dir, entry);
20581
+ const stat4 = statSync4(path);
19998
20582
  if (stat4.isDirectory()) {
19999
20583
  if (scan(path)) return true;
20000
20584
  continue;
20001
20585
  }
20002
20586
  if (!entry.endsWith(".md")) continue;
20003
- const text = readFileSync8(path, "utf-8");
20587
+ const text = readFileSync9(path, "utf-8");
20004
20588
  if (staleMarkers.some((marker) => text.includes(marker))) return true;
20005
20589
  }
20006
20590
  return false;
20007
20591
  };
20008
20592
  for (const root of roots) {
20009
20593
  try {
20010
- if (existsSync10(root) && scan(root)) return true;
20594
+ if (existsSync11(root) && scan(root)) return true;
20011
20595
  } catch {
20012
20596
  continue;
20013
20597
  }
@@ -20079,7 +20663,7 @@ function resolveSkillsInstallCommands(baseUrl) {
20079
20663
  return [npxInstall];
20080
20664
  }
20081
20665
  function runOneSkillsInstall(install) {
20082
- return new Promise((resolve15) => {
20666
+ return new Promise((resolve16) => {
20083
20667
  const child = spawn2(install.command, install.args, {
20084
20668
  stdio: ["ignore", "ignore", "pipe"],
20085
20669
  env: process.env
@@ -20089,7 +20673,7 @@ function runOneSkillsInstall(install) {
20089
20673
  stderr += chunk.toString("utf-8");
20090
20674
  });
20091
20675
  child.on("error", (error) => {
20092
- resolve15({
20676
+ resolve16({
20093
20677
  ok: false,
20094
20678
  detail: `failed to start ${install.command}: ${error.message}`,
20095
20679
  manualCommand: install.manualCommand
@@ -20097,11 +20681,11 @@ function runOneSkillsInstall(install) {
20097
20681
  });
20098
20682
  child.on("close", (code) => {
20099
20683
  if (code === 0) {
20100
- resolve15({ ok: true, detail: "", manualCommand: install.manualCommand });
20684
+ resolve16({ ok: true, detail: "", manualCommand: install.manualCommand });
20101
20685
  return;
20102
20686
  }
20103
20687
  const detail = stderr.trim();
20104
- resolve15({
20688
+ resolve16({
20105
20689
  ok: false,
20106
20690
  detail: detail ? `${install.command}: ${detail}` : `${install.command} exited ${code}`,
20107
20691
  manualCommand: install.manualCommand
@@ -20189,8 +20773,8 @@ function shouldDeferSkillsSyncForCommand() {
20189
20773
  return (command === "play" || command === "plays") && subcommand === "run" && args.includes("--json");
20190
20774
  }
20191
20775
  async function runPlayRunnerHealthCheck() {
20192
- const dir = await mkdtemp2(join14(tmpdir5(), "deepline-health-play-"));
20193
- const file = join14(dir, "health-check.play.ts");
20776
+ const dir = await mkdtemp2(join15(tmpdir5(), "deepline-health-play-"));
20777
+ const file = join15(dir, "health-check.play.ts");
20194
20778
  try {
20195
20779
  await writeFile6(
20196
20780
  file,
@@ -20378,6 +20962,7 @@ Common commands:
20378
20962
  deepline preflight
20379
20963
  deepline health
20380
20964
  deepline auth status --json
20965
+ deepline sessions send --current-session --json
20381
20966
  deepline plays search email --json
20382
20967
  deepline plays describe person-linkedin-to-email --json
20383
20968
  deepline plays run my.play.ts --input '{"domain":"stripe.com"}'
@@ -20430,6 +21015,7 @@ Exit codes:
20430
21015
  registerAuthCommands(program);
20431
21016
  registerToolsCommands(program);
20432
21017
  registerPlayCommands(program);
21018
+ registerSessionsCommands(program);
20433
21019
  registerWorkflowCommands(program);
20434
21020
  registerSecretsCommands(program);
20435
21021
  registerBillingCommands(program);