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.
package/dist/cli/index.js CHANGED
@@ -25,8 +25,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
25
25
 
26
26
  // src/cli/index.ts
27
27
  var import_promises7 = require("fs/promises");
28
- var import_node_path19 = require("path");
29
- var import_node_os11 = require("os");
28
+ var import_node_path20 = require("path");
29
+ var import_node_os12 = require("os");
30
30
  var import_commander3 = require("commander");
31
31
 
32
32
  // src/config.ts
@@ -237,10 +237,12 @@ var SDK_RELEASE = {
237
237
  // failed runs, persisted/succeeded/failed row counts, strict local CSV
238
238
  // preflight (existence, data rows, quotes, duplicate headers), HTML error
239
239
  // scrubbing, and word-boundary watch truncation.
240
- version: "0.1.102",
240
+ // 0.1.103 ships the refined SDK CLI command surface.
241
+ // 0.1.104 ships postgres_fast suspension/billing parity and runtime worker hardening.
242
+ version: "0.1.104",
241
243
  apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
242
244
  supportPolicy: {
243
- latest: "0.1.102",
245
+ latest: "0.1.104",
244
246
  minimumSupported: "0.1.53",
245
247
  deprecatedBelow: "0.1.53"
246
248
  }
@@ -649,7 +651,7 @@ function decodeSseFrame(frame) {
649
651
  return parsed;
650
652
  }
651
653
  function sleep(ms) {
652
- return new Promise((resolve15) => setTimeout(resolve15, ms));
654
+ return new Promise((resolve16) => setTimeout(resolve16, ms));
653
655
  }
654
656
 
655
657
  // src/stream-reconnect.ts
@@ -1360,14 +1362,14 @@ async function* observeRunEvents(options) {
1360
1362
  try {
1361
1363
  for (; ; ) {
1362
1364
  if (queue.length === 0) {
1363
- const waitForItem = new Promise((resolve15) => {
1364
- wake = resolve15;
1365
+ const waitForItem = new Promise((resolve16) => {
1366
+ wake = resolve16;
1365
1367
  });
1366
1368
  if (!sawFirstSnapshot) {
1367
1369
  const timedOut = await Promise.race([
1368
1370
  waitForItem.then(() => false),
1369
1371
  new Promise(
1370
- (resolve15) => setTimeout(() => resolve15(true), OBSERVE_BOOTSTRAP_TIMEOUT_MS)
1372
+ (resolve16) => setTimeout(() => resolve16(true), OBSERVE_BOOTSTRAP_TIMEOUT_MS)
1371
1373
  )
1372
1374
  ]);
1373
1375
  if (timedOut && queue.length === 0) {
@@ -1464,7 +1466,7 @@ var EXECUTE_RESPONSE_CONTRACT_HEADER = "x-deepline-execute-response-contract";
1464
1466
  var V2_EXECUTE_RESPONSE_CONTRACT = "v2-tool-response";
1465
1467
  var COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1e3];
1466
1468
  function sleep2(ms) {
1467
- return new Promise((resolve15) => setTimeout(resolve15, ms));
1469
+ return new Promise((resolve16) => setTimeout(resolve16, ms));
1468
1470
  }
1469
1471
  function isTransientCompileManifestError(error) {
1470
1472
  if (error instanceof DeeplineError && typeof error.statusCode === "number") {
@@ -1906,7 +1908,7 @@ var DeeplineClient = class {
1906
1908
  * or {@link runPlay}.
1907
1909
  *
1908
1910
  * Supported invocation surfaces intentionally share this same run contract:
1909
- * `deepline play run`, repo scripts such as `bun run deepline -- play run`,
1911
+ * `deepline plays run`, repo scripts such as `bun run deepline -- plays run`,
1910
1912
  * SDK context calls like `Deepline.connect().play(name).run()`, and direct
1911
1913
  * `POST /api/v2/plays/run` calls all return a workflow/run id. The completed
1912
1914
  * output is always retrievable from `getPlayStatus(runId).result` (or from
@@ -2075,7 +2077,7 @@ var DeeplineClient = class {
2075
2077
  *
2076
2078
  * Unlike {@link registerPlayArtifact}, this does not store the artifact,
2077
2079
  * publish a revision, or start a run. It is the authoritative cloud validation
2078
- * path used by `deepline play check`.
2080
+ * path used by `deepline plays check`.
2079
2081
  */
2080
2082
  async checkPlayArtifact(input2) {
2081
2083
  return this.http.post("/api/v2/plays/check", input2);
@@ -2268,7 +2270,7 @@ var DeeplineClient = class {
2268
2270
  * Get the current status of a play execution.
2269
2271
  *
2270
2272
  * Internal/advanced primitive. Public callers should usually prefer
2271
- * {@link runPlay}, {@link PlayJob.get}, or `deepline play run --watch`.
2273
+ * {@link runPlay}, {@link PlayJob.get}, or `deepline plays run --watch`.
2272
2274
  *
2273
2275
  * @param workflowId - Play-run id from {@link startPlayRun}
2274
2276
  * @returns Current status with progress logs and partial results
@@ -3111,9 +3113,9 @@ async function writeOutputFile(filename, content) {
3111
3113
  return fullPath;
3112
3114
  }
3113
3115
  function browserOpenStateFile() {
3114
- const homeDir = process.env.HOME || (0, import_node_os3.homedir)();
3116
+ const homeDir2 = process.env.HOME || (0, import_node_os3.homedir)();
3115
3117
  return (0, import_node_path3.join)(
3116
- homeDir,
3118
+ homeDir2,
3117
3119
  ".local",
3118
3120
  "deepline",
3119
3121
  "runtime",
@@ -3587,8 +3589,8 @@ function printCommandEnvelope(envelope, options = {}) {
3587
3589
 
3588
3590
  // src/cli/commands/auth.ts
3589
3591
  var EXIT_OK = 0;
3590
- var EXIT_AUTH = 1;
3591
- var EXIT_SERVER = 2;
3592
+ var EXIT_AUTH = 3;
3593
+ var EXIT_SERVER = 5;
3592
3594
  function envFilePath(baseUrl) {
3593
3595
  return hostEnvFilePath(baseUrl);
3594
3596
  }
@@ -3680,7 +3682,7 @@ function buildCandidateUrls2(url) {
3680
3682
  }
3681
3683
  }
3682
3684
  function sleep4(ms) {
3683
- return new Promise((resolve15) => setTimeout(resolve15, ms));
3685
+ return new Promise((resolve16) => setTimeout(resolve16, ms));
3684
3686
  }
3685
3687
  function printDeeplineLogo() {
3686
3688
  if (process.stdout.isTTY && (process.stdout.columns ?? 80) >= 70) {
@@ -3943,7 +3945,7 @@ async function handleStatus(args) {
3943
3945
  ...hostStatusPayload ?? { host: baseUrl },
3944
3946
  status: "not connected",
3945
3947
  connected: false,
3946
- next: "deepline auth register",
3948
+ next: "deepline auth register --no-wait && deepline auth wait",
3947
3949
  render: {
3948
3950
  sections: [
3949
3951
  {
@@ -3951,7 +3953,10 @@ async function handleStatus(args) {
3951
3953
  lines: [...hostLines, "Status: not connected"]
3952
3954
  }
3953
3955
  ],
3954
- actions: [{ label: "Run", command: "deepline auth register" }]
3956
+ actions: [
3957
+ { label: "Register", command: "deepline auth register --no-wait" },
3958
+ { label: "Wait", command: "deepline auth wait" }
3959
+ ]
3955
3960
  }
3956
3961
  },
3957
3962
  { json: jsonOutput }
@@ -3973,7 +3978,7 @@ async function handleStatus(args) {
3973
3978
  ...hostStatusPayload ?? { host: baseUrl },
3974
3979
  status: "unauthorized",
3975
3980
  connected: false,
3976
- next: "deepline auth register",
3981
+ next: "deepline auth register --no-wait && deepline auth wait",
3977
3982
  render: {
3978
3983
  sections: [
3979
3984
  {
@@ -3981,7 +3986,10 @@ async function handleStatus(args) {
3981
3986
  lines: [...hostLines, "Status: unauthorized"]
3982
3987
  }
3983
3988
  ],
3984
- actions: [{ label: "Run", command: "deepline auth register" }]
3989
+ actions: [
3990
+ { label: "Register", command: "deepline auth register --no-wait" },
3991
+ { label: "Wait", command: "deepline auth wait" }
3992
+ ]
3985
3993
  }
3986
3994
  },
3987
3995
  { json: jsonOutput }
@@ -5627,7 +5635,7 @@ async function handleDbQuery(args) {
5627
5635
  return 0;
5628
5636
  }
5629
5637
  function registerDbCommands(program) {
5630
- const db = program.command("db").alias("customer-db").description("Query the tenant customer database.").addHelpText(
5638
+ const db = program.command("db").description("Query the tenant customer database.").addHelpText(
5631
5639
  "after",
5632
5640
  `
5633
5641
  Notes:
@@ -5648,7 +5656,7 @@ Examples:
5648
5656
  deepline db query --sql "select domain, name from companies limit 20" --format markdown
5649
5657
  `
5650
5658
  );
5651
- db.command("query").alias("psql").description("Run SQL against the tenant customer database.").addHelpText(
5659
+ db.command("query").description("Run SQL against the tenant customer database.").addHelpText(
5652
5660
  "after",
5653
5661
  `
5654
5662
  Notes:
@@ -5664,7 +5672,7 @@ Examples:
5664
5672
  deepline db query --sql "select * from companies limit 20"
5665
5673
  deepline db query --sql "select domain, name from companies limit 20" --json
5666
5674
  deepline db query --sql "create table if not exists storage.agent_notes (id text primary key, note text not null)"
5667
- deepline db psql --sql "select count(*) from contacts" --json
5675
+ deepline db query --sql "select count(*) from contacts" --json
5668
5676
  deepline db query --sql "select * from contacts limit 20" --format csv --out contacts.csv
5669
5677
  deepline db query --sql "select domain, name from companies limit 20" --format markdown
5670
5678
  `
@@ -6915,7 +6923,7 @@ var PLAY_RUNTIME_PROVIDERS = {
6915
6923
  runner: PLAY_RUNTIME_BACKENDS.daytona,
6916
6924
  dedup: PLAY_DEDUP_BACKENDS.durableObject,
6917
6925
  artifactKind: PLAY_ARTIFACT_KINDS.cjsNode20,
6918
- label: "Experimental Postgres Scheduler + warm sandbox runner + DO dedup"
6926
+ label: "BETA: Postgres Scheduler + warm sandbox runner + DO dedup"
6919
6927
  },
6920
6928
  postgres_fast_sandbox: {
6921
6929
  id: PLAY_RUNTIME_PROVIDER_IDS.postgresFastSandbox,
@@ -6923,7 +6931,7 @@ var PLAY_RUNTIME_PROVIDERS = {
6923
6931
  runner: PLAY_RUNTIME_BACKENDS.daytona,
6924
6932
  dedup: PLAY_DEDUP_BACKENDS.durableObject,
6925
6933
  artifactKind: PLAY_ARTIFACT_KINDS.cjsNode20,
6926
- label: "Experimental Postgres Scheduler + warm sandbox runner + DO dedup"
6934
+ label: "BETA: Postgres Scheduler + warm sandbox runner + DO dedup"
6927
6935
  },
6928
6936
  postgres_fast_workers: {
6929
6937
  id: PLAY_RUNTIME_PROVIDER_IDS.postgresFastWorkers,
@@ -9221,7 +9229,7 @@ function traceCliSync(phase, fields, run) {
9221
9229
  }
9222
9230
  }
9223
9231
  function sleep5(ms) {
9224
- return new Promise((resolve15) => setTimeout(resolve15, ms));
9232
+ return new Promise((resolve16) => setTimeout(resolve16, ms));
9225
9233
  }
9226
9234
  function parseReferencedPlayTarget2(target) {
9227
9235
  const trimmed = target.trim();
@@ -12153,7 +12161,7 @@ function writeStartedPlayRun(input2) {
12153
12161
  );
12154
12162
  }
12155
12163
  function parsePlayRunOptions(args) {
12156
- 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.";
12164
+ 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.";
12157
12165
  let filePath = null;
12158
12166
  let playName = null;
12159
12167
  let input2 = null;
@@ -12289,7 +12297,7 @@ function parsePlayRunOptions(args) {
12289
12297
  function parsePlayCheckOptions(args) {
12290
12298
  const target = args[0];
12291
12299
  if (!target) {
12292
- throw new Error("Usage: deepline play check <play-file.ts> [--json]");
12300
+ throw new Error("Usage: deepline plays check <play-file.ts> [--json]");
12293
12301
  }
12294
12302
  const jsonOutput = argsWantJson(args);
12295
12303
  return { target, jsonOutput };
@@ -13219,7 +13227,9 @@ async function handleRunExport(args) {
13219
13227
  async function handlePlayGet(args) {
13220
13228
  const target = args[0];
13221
13229
  if (!target) {
13222
- console.error("Usage: deepline play get <play-file.ts|play-name> [--json]");
13230
+ console.error(
13231
+ "Usage: deepline plays get <play-file.ts|play-name> [--json]"
13232
+ );
13223
13233
  return 1;
13224
13234
  }
13225
13235
  if (looksLikeRunId(target)) {
@@ -13317,7 +13327,7 @@ async function handlePlayVersions(args) {
13317
13327
  const nameIndex = args.indexOf("--name");
13318
13328
  const playName = nameIndex >= 0 ? args[nameIndex + 1] : void 0;
13319
13329
  if (!playName) {
13320
- console.error("Usage: deepline play versions --name <name> [--json]");
13330
+ console.error("Usage: deepline plays versions --name <name> [--json]");
13321
13331
  return 1;
13322
13332
  }
13323
13333
  const client2 = new DeeplineClient();
@@ -13697,7 +13707,7 @@ async function handlePlayPublish(args) {
13697
13707
  const playName = args[0];
13698
13708
  if (!playName) {
13699
13709
  console.error(
13700
- "Usage: deepline play publish <play-file.ts|play-name> [--latest|--revision-id <id>] [--json]"
13710
+ "Usage: deepline plays publish <play-file.ts|play-name> [--latest|--revision-id <id>] [--json]"
13701
13711
  );
13702
13712
  return 1;
13703
13713
  }
@@ -13841,7 +13851,7 @@ async function handlePlayDelete(args) {
13841
13851
  return result.deleted ? 0 : 1;
13842
13852
  }
13843
13853
  function registerPlayCommands(program) {
13844
- const play = program.command("plays").alias("play").description("Search, validate, run, and manage cloud plays.").addHelpText(
13854
+ const play = program.command("plays").description("Search, validate, run, and manage cloud plays.").addHelpText(
13845
13855
  "after",
13846
13856
  `
13847
13857
  Concepts:
@@ -16348,7 +16358,7 @@ async function runGeneratedEnrichPlay(runArgs, options = {}) {
16348
16358
  });
16349
16359
  } catch (error) {
16350
16360
  if (attempt === 0 && isPlayStartStreamEndedError(error)) {
16351
- await new Promise((resolve15) => setTimeout(resolve15, 250));
16361
+ await new Promise((resolve16) => setTimeout(resolve16, 250));
16352
16362
  continue;
16353
16363
  }
16354
16364
  throw error;
@@ -17148,19 +17158,16 @@ Notes:
17148
17158
  Use --command and --payload to attach a reproducible command shape.
17149
17159
 
17150
17160
  Examples:
17151
- deepline feedback "plays run failed after upload" --command "deepline plays run my.play.ts --watch"
17152
- deepline feedback "unexpected billing output" --payload '{"command":"billing usage"}' --json
17161
+ deepline feedback send "plays run failed after upload" --command "deepline plays run my.play.ts --watch"
17162
+ deepline feedback send "unexpected billing output" --payload '{"command":"billing usage"}' --json
17153
17163
  `
17154
17164
  );
17155
- 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);
17156
- program.command("provide-feedback").description("Legacy alias for `deepline feedback`.").addHelpText(
17165
+ feedback.command("send").description("Send CLI feedback to Deepline.").addHelpText(
17157
17166
  "after",
17158
17167
  `
17159
- Notes:
17160
- Compatibility alias. Prefer deepline feedback in new scripts and docs.
17161
-
17162
17168
  Examples:
17163
- deepline feedback "tools search returned stale results" --json
17169
+ deepline feedback send "tools search returned stale results" --json
17170
+ deepline feedback send "plays run failed after upload" --command "deepline plays run my.play.ts --watch"
17164
17171
  `
17165
17172
  ).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);
17166
17173
  }
@@ -17281,8 +17288,44 @@ async function handleOrgSwitch(selection, options) {
17281
17288
  { json: options.json }
17282
17289
  );
17283
17290
  }
17291
+ async function handleOrgCreate(name, options) {
17292
+ const config = resolveConfig();
17293
+ const http = new HttpClient(config);
17294
+ const created = await http.post("/api/v2/auth/cli/org-create", {
17295
+ api_key: config.apiKey,
17296
+ name
17297
+ });
17298
+ saveHostEnvValues(config.baseUrl, {
17299
+ DEEPLINE_API_KEY: created.api_key,
17300
+ DEEPLINE_ACTIVE_ORG_ID: created.org_id,
17301
+ DEEPLINE_ACTIVE_ORG_NAME: created.org_name
17302
+ });
17303
+ const { api_key: _apiKey, ...publicCreated } = created;
17304
+ printCommandEnvelope(
17305
+ {
17306
+ ok: true,
17307
+ ...publicCreated,
17308
+ api_key_saved: true,
17309
+ switched: true,
17310
+ host_env_path: hostEnvFilePath(config.baseUrl),
17311
+ render: {
17312
+ sections: [
17313
+ {
17314
+ title: "org create",
17315
+ lines: [
17316
+ `Created organization: ${created.org_name}.`,
17317
+ `Switched to ${created.org_name}.`,
17318
+ `Saved host auth in ${hostEnvFilePath(config.baseUrl)}`
17319
+ ]
17320
+ }
17321
+ ]
17322
+ }
17323
+ },
17324
+ { json: options.json }
17325
+ );
17326
+ }
17284
17327
  function registerOrgCommands(program) {
17285
- const org = program.command("org").description("List and switch organizations.").addHelpText(
17328
+ const org = program.command("org").description("List, create, and switch organizations.").addHelpText(
17286
17329
  "after",
17287
17330
  `
17288
17331
  Notes:
@@ -17291,6 +17334,7 @@ Notes:
17291
17334
 
17292
17335
  Examples:
17293
17336
  deepline org list --json
17337
+ deepline org create Acme --json
17294
17338
  deepline org switch 2
17295
17339
  deepline org switch --org-id org_123 --json
17296
17340
  `
@@ -17306,6 +17350,19 @@ Examples:
17306
17350
  deepline org list --json
17307
17351
  `
17308
17352
  ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleOrgList);
17353
+ org.command("create <name>").description("Create a new organization and switch this CLI to it.").addHelpText(
17354
+ "after",
17355
+ `
17356
+ Notes:
17357
+ Mutates workspace state. The new organization is created for the current
17358
+ authenticated user, then the returned API key is saved for this host so later
17359
+ CLI commands target the new organization.
17360
+
17361
+ Examples:
17362
+ deepline org create Acme
17363
+ deepline org create "Acme Sales" --json
17364
+ `
17365
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleOrgCreate);
17309
17366
  org.command("switch [selection]").description(
17310
17367
  "Switch to another organization and save the new API key in the host auth file."
17311
17368
  ).addHelpText(
@@ -17350,7 +17407,7 @@ async function readHiddenLine(prompt) {
17350
17407
  if (typeof import_node_process.stdin.setRawMode === "function") import_node_process.stdin.setRawMode(true);
17351
17408
  let value = "";
17352
17409
  import_node_process.stdin.resume();
17353
- return await new Promise((resolve15, reject) => {
17410
+ return await new Promise((resolve16, reject) => {
17354
17411
  let settled = false;
17355
17412
  const cleanup = () => {
17356
17413
  import_node_process.stdin.off("data", onData);
@@ -17365,7 +17422,7 @@ async function readHiddenLine(prompt) {
17365
17422
  settled = true;
17366
17423
  import_node_process.stdout.write("\n");
17367
17424
  cleanup();
17368
- resolve15(line);
17425
+ resolve16(line);
17369
17426
  };
17370
17427
  const fail = (error) => {
17371
17428
  if (settled) return;
@@ -17535,16 +17592,553 @@ Examples:
17535
17592
  );
17536
17593
  }
17537
17594
 
17595
+ // src/cli/commands/sessions.ts
17596
+ var import_node_fs11 = require("fs");
17597
+ var import_node_os8 = require("os");
17598
+ var import_node_path14 = require("path");
17599
+ var import_node_zlib = require("zlib");
17600
+ var import_node_crypto4 = require("crypto");
17601
+ var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
17602
+ var MAX_SESSION_UPLOAD_BYTES = 35e5;
17603
+ var MAX_DIRECT_SESSION_DECODED_BYTES = 50 * 1024 * 1024;
17604
+ var CHUNK_SIZE_BYTES = 25e5;
17605
+ var MAX_EVENT_STRING_CHARS = 8e3;
17606
+ var MAX_EVENT_LIST_ITEMS = 40;
17607
+ var MAX_EVENT_OBJECT_KEYS = 80;
17608
+ var TRUNCATION_MARKER = "...[truncated]";
17609
+ var NOISE_EVENT_TYPES = /* @__PURE__ */ new Set(["progress", "file-history-snapshot"]);
17610
+ function homeDir() {
17611
+ return process.env.HOME?.trim() || (0, import_node_os8.homedir)();
17612
+ }
17613
+ function detectShellContext() {
17614
+ const shellPath = process.env.SHELL?.trim() || process.env.ComSpec?.trim() || process.env.COMSPEC?.trim() || "";
17615
+ return {
17616
+ shell: shellPath ? (0, import_node_path14.basename)(shellPath).replace(/\.exe$/i, "") : "unknown",
17617
+ shell_path: shellPath || null,
17618
+ os: (0, import_node_os8.platform)(),
17619
+ cwd: process.cwd()
17620
+ };
17621
+ }
17622
+ function claudeProjectsRoot() {
17623
+ return (0, import_node_path14.join)(homeDir(), ".claude", "projects");
17624
+ }
17625
+ function listClaudeSessionFiles() {
17626
+ const root = claudeProjectsRoot();
17627
+ if (!(0, import_node_fs11.existsSync)(root)) return [];
17628
+ const projectDirs = readDirectoryNames(root);
17629
+ const files = [];
17630
+ for (const projectDir of projectDirs) {
17631
+ const fullProjectDir = (0, import_node_path14.join)(root, projectDir);
17632
+ for (const fileName of readDirectoryNames(fullProjectDir)) {
17633
+ if (fileName.endsWith(".jsonl")) {
17634
+ files.push((0, import_node_path14.join)(fullProjectDir, fileName));
17635
+ }
17636
+ }
17637
+ }
17638
+ return files;
17639
+ }
17640
+ function readDirectoryNames(dir) {
17641
+ try {
17642
+ return (0, import_node_fs11.readdirSync)(dir);
17643
+ } catch {
17644
+ return [];
17645
+ }
17646
+ }
17647
+ function newestClaudeSessionFile() {
17648
+ let newest = null;
17649
+ for (const filePath of listClaudeSessionFiles()) {
17650
+ try {
17651
+ const stat4 = (0, import_node_fs11.statSync)(filePath);
17652
+ if (!newest || stat4.mtimeMs > newest.mtimeMs) {
17653
+ newest = { filePath, mtimeMs: stat4.mtimeMs };
17654
+ }
17655
+ } catch {
17656
+ continue;
17657
+ }
17658
+ }
17659
+ return newest?.filePath ?? null;
17660
+ }
17661
+ function sessionIdFromFilePath(filePath) {
17662
+ return (0, import_node_path14.basename)(filePath, ".jsonl");
17663
+ }
17664
+ function findSessionFile(sessionId) {
17665
+ if (!UUID_RE.test(sessionId)) {
17666
+ throw new Error(
17667
+ "Invalid session ID format. Expected a UUID such as 5a3bfb97-a2d9-49d9-82c6-52ccc03dadca."
17668
+ );
17669
+ }
17670
+ for (const filePath of listClaudeSessionFiles()) {
17671
+ if (sessionIdFromFilePath(filePath) === sessionId) {
17672
+ return filePath;
17673
+ }
17674
+ }
17675
+ return null;
17676
+ }
17677
+ function resolveSessionTargets(input2) {
17678
+ const targets = [];
17679
+ if (input2.currentSession) {
17680
+ const currentFile = newestClaudeSessionFile();
17681
+ if (!currentFile) {
17682
+ throw new Error("No session files found in ~/.claude/projects/*/.");
17683
+ }
17684
+ const sessionId = sessionIdFromFilePath(currentFile);
17685
+ targets.push({
17686
+ sessionId,
17687
+ label: `session-${sessionId}`,
17688
+ filePath: currentFile
17689
+ });
17690
+ }
17691
+ for (const [index, sessionId] of (input2.sessionIds ?? []).entries()) {
17692
+ const filePath = findSessionFile(sessionId);
17693
+ if (!filePath) {
17694
+ throw new Error(
17695
+ `Session file not found: ~/.claude/projects/*/${sessionId}.jsonl`
17696
+ );
17697
+ }
17698
+ targets.push({
17699
+ sessionId,
17700
+ label: input2.labels?.[index] ?? `session-${sessionId}`,
17701
+ filePath
17702
+ });
17703
+ }
17704
+ if (targets.length === 0) {
17705
+ throw new Error("One of --session-id or --current-session is required.");
17706
+ }
17707
+ return targets;
17708
+ }
17709
+ function parseJsonLine(line) {
17710
+ try {
17711
+ return JSON.parse(line);
17712
+ } catch {
17713
+ return null;
17714
+ }
17715
+ }
17716
+ function normalizedJsonLines(raw) {
17717
+ return raw.toString("utf8").split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
17718
+ }
17719
+ function stripNoiseEvents(raw) {
17720
+ const lines = [];
17721
+ for (const line of normalizedJsonLines(raw)) {
17722
+ const parsed = parseJsonLine(line);
17723
+ if (parsed && typeof parsed === "object" && NOISE_EVENT_TYPES.has(String(parsed.type ?? ""))) {
17724
+ continue;
17725
+ }
17726
+ lines.push(line);
17727
+ }
17728
+ return Buffer.from(lines.length > 0 ? `${lines.join("\n")}
17729
+ ` : "", "utf8");
17730
+ }
17731
+ function messageContentKey(value) {
17732
+ const message = value.message;
17733
+ if (!message || typeof message !== "object") return null;
17734
+ const content = message.content;
17735
+ if (typeof content === "string") return content;
17736
+ if (!Array.isArray(content)) return null;
17737
+ return content.map((block) => {
17738
+ if (!block || typeof block !== "object") return String(block);
17739
+ const record = block;
17740
+ const type = String(record.type ?? "");
17741
+ if (type === "tool_use") {
17742
+ return `tool_use:${String(record.name ?? "")}:${String(record.id ?? "")}`;
17743
+ }
17744
+ if (type === "tool_result") {
17745
+ return `tool_result:${String(record.tool_use_id ?? "")}`;
17746
+ }
17747
+ return String(record.text ?? type);
17748
+ }).join("\n");
17749
+ }
17750
+ function dedupConsecutiveEvents(raw) {
17751
+ const rawLines = normalizedJsonLines(raw);
17752
+ const parsedEvents = rawLines.map(parseJsonLine);
17753
+ const output2 = [];
17754
+ let index = 0;
17755
+ while (index < parsedEvents.length) {
17756
+ const event = parsedEvents[index];
17757
+ if (!event || typeof event !== "object") {
17758
+ output2.push(rawLines[index] ?? "");
17759
+ index += 1;
17760
+ continue;
17761
+ }
17762
+ const record = event;
17763
+ const eventType = String(record.type ?? "");
17764
+ const eventKey = messageContentKey(record);
17765
+ if (!["user", "assistant"].includes(eventType) || !eventKey) {
17766
+ output2.push(rawLines[index] ?? "");
17767
+ index += 1;
17768
+ continue;
17769
+ }
17770
+ let runCount = 1;
17771
+ let cursor = index + 1;
17772
+ while (cursor < parsedEvents.length) {
17773
+ const next = parsedEvents[cursor];
17774
+ if (!next || typeof next !== "object") break;
17775
+ const nextRecord = next;
17776
+ if (String(nextRecord.type ?? "") !== eventType || messageContentKey(nextRecord) !== eventKey) {
17777
+ break;
17778
+ }
17779
+ runCount += 1;
17780
+ cursor += 1;
17781
+ }
17782
+ if (runCount > 1) {
17783
+ record._repeat_count = runCount;
17784
+ record._repeat_summary = `${runCount} consecutive identical ${eventType} messages collapsed`;
17785
+ output2.push(JSON.stringify(record));
17786
+ index = cursor;
17787
+ continue;
17788
+ }
17789
+ output2.push(rawLines[index] ?? "");
17790
+ index += 1;
17791
+ }
17792
+ return Buffer.from(output2.length > 0 ? `${output2.join("\n")}
17793
+ ` : "", "utf8");
17794
+ }
17795
+ function compactEventValue(value) {
17796
+ if (typeof value === "string") {
17797
+ if (value.length <= MAX_EVENT_STRING_CHARS) return value;
17798
+ return `${value.slice(0, MAX_EVENT_STRING_CHARS - TRUNCATION_MARKER.length)}${TRUNCATION_MARKER}`;
17799
+ }
17800
+ if (Array.isArray(value)) {
17801
+ const compacted = value.slice(0, MAX_EVENT_LIST_ITEMS).map(compactEventValue);
17802
+ if (value.length > MAX_EVENT_LIST_ITEMS) {
17803
+ compacted.push(
17804
+ `${TRUNCATION_MARKER} ${value.length - MAX_EVENT_LIST_ITEMS} more item(s)`
17805
+ );
17806
+ }
17807
+ return compacted;
17808
+ }
17809
+ if (value && typeof value === "object") {
17810
+ const entries = Object.entries(value);
17811
+ const compacted = {};
17812
+ for (const [key, item] of entries.slice(0, MAX_EVENT_OBJECT_KEYS)) {
17813
+ compacted[key] = compactEventValue(item);
17814
+ }
17815
+ if (entries.length > MAX_EVENT_OBJECT_KEYS) {
17816
+ compacted._truncated_keys = entries.length - MAX_EVENT_OBJECT_KEYS;
17817
+ }
17818
+ return compacted;
17819
+ }
17820
+ return value;
17821
+ }
17822
+ function selectiveCompactToolResults(raw) {
17823
+ const lines = [];
17824
+ for (const line of normalizedJsonLines(raw)) {
17825
+ const parsed = parseJsonLine(line);
17826
+ if (!parsed || typeof parsed !== "object") {
17827
+ lines.push(line);
17828
+ continue;
17829
+ }
17830
+ const record = parsed;
17831
+ if (record.type === "user") {
17832
+ const message = record.message;
17833
+ const content = message && typeof message === "object" ? message.content : null;
17834
+ if (Array.isArray(content)) {
17835
+ message.content = content.map(
17836
+ (block) => block && typeof block === "object" && block.type === "tool_result" ? compactEventValue(block) : block
17837
+ );
17838
+ }
17839
+ }
17840
+ lines.push(JSON.stringify(record));
17841
+ }
17842
+ return Buffer.from(lines.length > 0 ? `${lines.join("\n")}
17843
+ ` : "", "utf8");
17844
+ }
17845
+ function prepareSessionBuffer(raw) {
17846
+ return selectiveCompactToolResults(
17847
+ dedupConsecutiveEvents(stripNoiseEvents(raw))
17848
+ );
17849
+ }
17850
+ function buildSessionUploadContent(raw) {
17851
+ const prepared = prepareSessionBuffer(raw);
17852
+ const encoded = (0, import_node_zlib.gzipSync)(prepared).toString("base64");
17853
+ if (encoded.length <= MAX_SESSION_UPLOAD_BYTES && prepared.length <= MAX_DIRECT_SESSION_DECODED_BYTES) {
17854
+ return { encodedContent: encoded, needsChunking: false };
17855
+ }
17856
+ return { encodedContent: encoded, needsChunking: true };
17857
+ }
17858
+ async function uploadPayload(path, payload) {
17859
+ const { http } = getAuthedHttpClient();
17860
+ return await http.post(path, payload);
17861
+ }
17862
+ async function uploadChunkedSessions(sessions, options) {
17863
+ const uploadId = (0, import_node_crypto4.randomUUID)();
17864
+ for (const session of sessions) {
17865
+ const bytes = Buffer.from(session.encodedContent, "base64");
17866
+ const chunks = [];
17867
+ for (let offset = 0; offset < bytes.length; offset += CHUNK_SIZE_BYTES) {
17868
+ chunks.push(bytes.subarray(offset, offset + CHUNK_SIZE_BYTES));
17869
+ }
17870
+ process.stderr.write(
17871
+ `Uploading ${session.label} in ${chunks.length} chunk(s)...
17872
+ `
17873
+ );
17874
+ for (const [index, chunk] of chunks.entries()) {
17875
+ await uploadPayload("/api/v2/cli/send-session/chunk", {
17876
+ upload_id: uploadId,
17877
+ session_id: session.sessionId,
17878
+ index,
17879
+ total_chunks: chunks.length,
17880
+ data: chunk.toString("base64")
17881
+ });
17882
+ }
17883
+ }
17884
+ const response = await uploadPayload("/api/v2/cli/send-session/finalize", {
17885
+ upload_id: uploadId,
17886
+ session_ids: sessions.map((session) => session.sessionId),
17887
+ labels: sessions.map((session) => session.label),
17888
+ environments: sessions.map(() => detectShellContext())
17889
+ });
17890
+ printCommandEnvelope(
17891
+ {
17892
+ ...response,
17893
+ ok: true,
17894
+ uploaded: sessions.length,
17895
+ render: {
17896
+ sections: [
17897
+ {
17898
+ title: "sessions send",
17899
+ lines: ["Session uploaded to #internal-reports (chunked)."]
17900
+ }
17901
+ ]
17902
+ }
17903
+ },
17904
+ { json: options.json }
17905
+ );
17906
+ }
17907
+ async function handleSessionsSend(options) {
17908
+ if (options.file) {
17909
+ const filePath = (0, import_node_path14.resolve)(options.file);
17910
+ if (!(0, import_node_fs11.existsSync)(filePath)) {
17911
+ throw new Error(`File not found: ${options.file}`);
17912
+ }
17913
+ const response2 = await uploadPayload("/api/v2/cli/send-session", {
17914
+ file: (0, import_node_fs11.readFileSync)(filePath).toString("base64"),
17915
+ filename: (0, import_node_path14.basename)(filePath)
17916
+ });
17917
+ printCommandEnvelope(
17918
+ {
17919
+ ...response2,
17920
+ ok: true,
17921
+ filename: (0, import_node_path14.basename)(filePath),
17922
+ render: {
17923
+ sections: [
17924
+ {
17925
+ title: "sessions send",
17926
+ lines: [
17927
+ `File '${(0, import_node_path14.basename)(filePath)}' uploaded to #internal-reports.`
17928
+ ]
17929
+ }
17930
+ ]
17931
+ }
17932
+ },
17933
+ { json: options.json }
17934
+ );
17935
+ return;
17936
+ }
17937
+ const targets = resolveSessionTargets({
17938
+ sessionIds: options.sessionId,
17939
+ labels: options.label,
17940
+ currentSession: options.currentSession
17941
+ });
17942
+ const built = targets.map((target) => {
17943
+ const upload = buildSessionUploadContent((0, import_node_fs11.readFileSync)(target.filePath));
17944
+ return { ...target, ...upload };
17945
+ });
17946
+ if (built.some((session) => session.needsChunking)) {
17947
+ await uploadChunkedSessions(built, options);
17948
+ return;
17949
+ }
17950
+ const response = built.length === 1 && !options.label?.length ? await uploadPayload("/api/v2/cli/send-session", {
17951
+ session_id: built[0]?.sessionId,
17952
+ content: built[0]?.encodedContent,
17953
+ environment: detectShellContext()
17954
+ }) : await uploadPayload("/api/v2/cli/send-session", {
17955
+ sessions: built.map((session) => ({
17956
+ session_id: session.sessionId,
17957
+ content: session.encodedContent,
17958
+ label: session.label,
17959
+ environment: detectShellContext()
17960
+ })),
17961
+ environment: detectShellContext()
17962
+ });
17963
+ printCommandEnvelope(
17964
+ {
17965
+ ...response,
17966
+ ok: true,
17967
+ uploaded: built.length,
17968
+ render: {
17969
+ sections: [
17970
+ {
17971
+ title: "sessions send",
17972
+ lines: ["Session uploaded to #internal-reports."]
17973
+ }
17974
+ ]
17975
+ }
17976
+ },
17977
+ { json: options.json }
17978
+ );
17979
+ }
17980
+ function fallbackViewerAssets() {
17981
+ return {
17982
+ css: [
17983
+ "body{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;margin:0;padding:16px;background:#fafafa;color:#111}",
17984
+ ".section{background:#fff;border:1px solid #ddd;border-radius:8px;padding:12px;margin-bottom:12px}",
17985
+ ".section h2{margin:0 0 8px 0;font-size:14px}",
17986
+ "pre{margin:0;white-space:pre-wrap;word-break:break-word;background:#f6f8fa;border:1px solid #e3e5e8;border-radius:6px;padding:10px}"
17987
+ ].join(""),
17988
+ js: [
17989
+ "(() => {",
17990
+ 'const root=document.getElementById("main-content");',
17991
+ 'const raw=document.getElementById("raw-sessions");',
17992
+ "if(!root||!raw)return;",
17993
+ 'let sessions=[];try{sessions=JSON.parse(raw.textContent||"[]")}catch{}',
17994
+ 'root.innerHTML="";',
17995
+ "for(const session of sessions){",
17996
+ 'const section=document.createElement("section");section.className="section";',
17997
+ 'const title=document.createElement("h2");title.textContent=String(session.label||"session");',
17998
+ 'const pre=document.createElement("pre");',
17999
+ 'pre.textContent=(Array.isArray(session.events)?session.events:[]).map((event)=>JSON.stringify(event)).join("\\n");',
18000
+ "section.append(title,pre);root.appendChild(section);",
18001
+ "}",
18002
+ "})();"
18003
+ ].join("")
18004
+ };
18005
+ }
18006
+ function parsePreparedEvents(buffer) {
18007
+ return normalizedJsonLines(buffer).map((line) => {
18008
+ const parsed = parseJsonLine(line);
18009
+ return parsed ?? line;
18010
+ });
18011
+ }
18012
+ async function handleSessionsRender(options) {
18013
+ const targets = resolveSessionTargets({
18014
+ sessionIds: options.sessionId,
18015
+ labels: options.label,
18016
+ currentSession: options.currentSession
18017
+ });
18018
+ let outputPath = options.output ? (0, import_node_path14.resolve)(options.output) : "";
18019
+ if (!outputPath) {
18020
+ const outputDir = (0, import_node_path14.join)(process.cwd(), "deepline", "data");
18021
+ (0, import_node_fs11.mkdirSync)(outputDir, { recursive: true });
18022
+ outputPath = (0, import_node_path14.join)(
18023
+ outputDir,
18024
+ targets.length > 1 ? "session-viewer.html" : `session-${targets[0]?.sessionId}.html`
18025
+ );
18026
+ } else {
18027
+ (0, import_node_fs11.mkdirSync)((0, import_node_path14.dirname)(outputPath), { recursive: true });
18028
+ }
18029
+ const sessions = targets.map((target) => ({
18030
+ label: target.label,
18031
+ events: parsePreparedEvents(
18032
+ prepareSessionBuffer((0, import_node_fs11.readFileSync)(target.filePath))
18033
+ )
18034
+ }));
18035
+ const { css, js } = fallbackViewerAssets();
18036
+ const refreshMeta = options.autoRefresh ? `<meta http-equiv="refresh" content="${Number.parseInt(options.autoRefresh, 10)}">` : "";
18037
+ const rawJson = JSON.stringify(sessions).replace(/<\//g, "<\\/");
18038
+ const html = `<!DOCTYPE html>
18039
+ <html lang="en">
18040
+ <head>
18041
+ <meta charset="UTF-8">
18042
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
18043
+ ${refreshMeta}
18044
+ <title>Session Viewer</title>
18045
+ <style>${css}</style>
18046
+ </head>
18047
+ <body>
18048
+ <div class="layout">
18049
+ <div class="main" id="main-content"></div>
18050
+ </div>
18051
+ <script type="application/json" id="raw-sessions">${rawJson}</script>
18052
+ <script>${js}</script>
18053
+ </body>
18054
+ </html>`;
18055
+ (0, import_node_fs11.writeFileSync)(outputPath, html, "utf8");
18056
+ printCommandEnvelope(
18057
+ {
18058
+ ok: true,
18059
+ file: outputPath,
18060
+ session_count: targets.length,
18061
+ render: {
18062
+ sections: [
18063
+ {
18064
+ title: "sessions render",
18065
+ lines: [`Rendered session viewer: ${outputPath}`]
18066
+ }
18067
+ ]
18068
+ }
18069
+ },
18070
+ { json: options.json }
18071
+ );
18072
+ }
18073
+ function collectOption(value, previous) {
18074
+ previous.push(value);
18075
+ return previous;
18076
+ }
18077
+ function registerSessionsCommands(program) {
18078
+ const sessions = program.command("sessions").description("Upload and render local agent session transcripts.").addHelpText(
18079
+ "after",
18080
+ `
18081
+ Notes:
18082
+ Session commands operate on local Claude session JSONL files under
18083
+ ~/.claude/projects. send uploads a compacted transcript or file to Deepline.
18084
+ render writes a local HTML viewer.
18085
+
18086
+ Examples:
18087
+ deepline sessions send --current-session --json
18088
+ deepline sessions send --session-id 5a3bfb97-a2d9-49d9-82c6-52ccc03dadca
18089
+ deepline sessions render --current-session --output session.html
18090
+ `
18091
+ );
18092
+ sessions.command("send").description("Upload session transcript(s) or a local file to Deepline.").addHelpText(
18093
+ "after",
18094
+ `
18095
+ Examples:
18096
+ deepline sessions send --current-session --json
18097
+ deepline sessions send --session-id 5a3bfb97-a2d9-49d9-82c6-52ccc03dadca --label "pilot run"
18098
+ deepline sessions send --file ./debug.log --json
18099
+ `
18100
+ ).option(
18101
+ "--session-id <uuid>",
18102
+ "Claude session UUID. Repeat for multiple sessions.",
18103
+ collectOption,
18104
+ []
18105
+ ).option(
18106
+ "--label <label>",
18107
+ "Label for the preceding session id",
18108
+ collectOption,
18109
+ []
18110
+ ).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);
18111
+ sessions.command("render").description("Render local session transcript(s) to an HTML viewer.").addHelpText(
18112
+ "after",
18113
+ `
18114
+ Examples:
18115
+ deepline sessions render --current-session
18116
+ deepline sessions render --session-id 5a3bfb97-a2d9-49d9-82c6-52ccc03dadca --output session.html
18117
+ deepline sessions render --current-session --auto-refresh 5 --json
18118
+ `
18119
+ ).option(
18120
+ "--session-id <uuid>",
18121
+ "Claude session UUID. Repeat for multiple sessions.",
18122
+ collectOption,
18123
+ []
18124
+ ).option(
18125
+ "--label <label>",
18126
+ "Label for the preceding session id",
18127
+ collectOption,
18128
+ []
18129
+ ).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);
18130
+ }
18131
+
17538
18132
  // src/cli/commands/tools.ts
17539
18133
  var import_commander2 = require("commander");
18134
+ var import_node_fs13 = require("fs");
18135
+ var import_node_os10 = require("os");
18136
+ var import_node_path16 = require("path");
18137
+
18138
+ // src/tool-output.ts
17540
18139
  var import_node_fs12 = require("fs");
17541
18140
  var import_node_os9 = require("os");
17542
18141
  var import_node_path15 = require("path");
17543
-
17544
- // src/tool-output.ts
17545
- var import_node_fs11 = require("fs");
17546
- var import_node_os8 = require("os");
17547
- var import_node_path14 = require("path");
17548
18142
  function isPlainObject(value) {
17549
18143
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
17550
18144
  }
@@ -17640,19 +18234,19 @@ function tryConvertToList(payload, options) {
17640
18234
  return null;
17641
18235
  }
17642
18236
  function ensureOutputDir() {
17643
- const outputDir = (0, import_node_path14.join)((0, import_node_os8.homedir)(), ".local", "share", "deepline", "data");
17644
- (0, import_node_fs11.mkdirSync)(outputDir, { recursive: true });
18237
+ const outputDir = (0, import_node_path15.join)((0, import_node_os9.homedir)(), ".local", "share", "deepline", "data");
18238
+ (0, import_node_fs12.mkdirSync)(outputDir, { recursive: true });
17645
18239
  return outputDir;
17646
18240
  }
17647
18241
  function writeJsonOutputFile(payload, stem) {
17648
18242
  const outputDir = ensureOutputDir();
17649
- const outputPath = (0, import_node_path14.join)(outputDir, `${stem}_${Date.now()}.json`);
17650
- (0, import_node_fs11.writeFileSync)(outputPath, JSON.stringify(payload, null, 2), "utf-8");
18243
+ const outputPath = (0, import_node_path15.join)(outputDir, `${stem}_${Date.now()}.json`);
18244
+ (0, import_node_fs12.writeFileSync)(outputPath, JSON.stringify(payload, null, 2), "utf-8");
17651
18245
  return outputPath;
17652
18246
  }
17653
18247
  function writeCsvOutputFile(rows, stem) {
17654
18248
  const outputDir = ensureOutputDir();
17655
- const outputPath = (0, import_node_path14.join)(outputDir, `${stem}_${Date.now()}.csv`);
18249
+ const outputPath = (0, import_node_path15.join)(outputDir, `${stem}_${Date.now()}.csv`);
17656
18250
  const seen = /* @__PURE__ */ new Set();
17657
18251
  const columns = [];
17658
18252
  for (const row of rows) {
@@ -17675,7 +18269,7 @@ function writeCsvOutputFile(rows, stem) {
17675
18269
  for (const row of rows) {
17676
18270
  lines.push(columns.map((column) => escapeCell(row[column])).join(","));
17677
18271
  }
17678
- (0, import_node_fs11.writeFileSync)(outputPath, `${lines.join("\n")}
18272
+ (0, import_node_fs12.writeFileSync)(outputPath, `${lines.join("\n")}
17679
18273
  `, "utf-8");
17680
18274
  const previewRows = rows.slice(0, 5);
17681
18275
  const previewColumns = columns.slice(0, 5);
@@ -17961,7 +18555,7 @@ Common commands:
17961
18555
 
17962
18556
  Output:
17963
18557
  Use describe for tool contracts.
17964
- Use execute to run a tool. run is accepted as a compatibility alias.
18558
+ Use execute to run a tool.
17965
18559
  `
17966
18560
  );
17967
18561
  tools.command("list").description("List available tools.").addHelpText(
@@ -18054,7 +18648,7 @@ Examples:
18054
18648
  Notes:
18055
18649
  Shows the compact agent contract by default: what the tool does, cost,
18056
18650
  required inputs, play getters, and a runnable ctx.tools.execute snippet.
18057
- Use --json for the full metadata/debug payload.
18651
+ get is accepted as a compatibility alias for describe.
18058
18652
 
18059
18653
  Examples:
18060
18654
  deepline tools describe hunter_email_verifier
@@ -18088,29 +18682,13 @@ Examples:
18088
18682
  gettersOnly: Boolean(options.gettersOnly)
18089
18683
  });
18090
18684
  });
18091
- addToolMetadataCommand(tools.command("describe <toolId>"));
18092
- tools.command("get <toolId>").description("Deprecated. Use tools describe.").addHelpText(
18093
- "after",
18094
- `
18095
- Examples:
18096
- deepline tools describe hunter_email_verifier --json
18097
- `
18098
- ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (toolId, options) => {
18099
- const message = `tools get has been removed from the V2 SDK CLI. Use: deepline tools describe ${toolId} --json`;
18100
- if (options.json || shouldEmitJson()) {
18101
- printJsonError({ message, code: "TOOLS_GET_REMOVED" });
18102
- } else {
18103
- console.error(message);
18104
- }
18105
- process.exitCode = 2;
18106
- });
18107
- tools.command("execute <toolId>").alias("run").description("Execute a tool by id.").addHelpText(
18685
+ addToolMetadataCommand(tools.command("describe <toolId>").alias("get"));
18686
+ tools.command("execute <toolId>").description("Execute a tool by id.").addHelpText(
18108
18687
  "after",
18109
18688
  `
18110
18689
  Notes:
18111
18690
  Use tools for one atomic provider/API operation. Use plays for composed workflows,
18112
18691
  waterfalls, row maps, checkpoints, and retries.
18113
- execute is the canonical execution verb. run is a compatibility alias.
18114
18692
  Calling a provider-backed tool can spend Deepline credits. Use --json for the
18115
18693
  stable result payload plus output preview and debugging helpers.
18116
18694
 
@@ -18158,7 +18736,7 @@ Examples:
18158
18736
  }
18159
18737
  async function getTool(toolId, options = {}) {
18160
18738
  if (!toolId) {
18161
- console.error("Usage: deepline tools get <toolId> [--json]");
18739
+ console.error("Usage: deepline tools describe <toolId> [--json]");
18162
18740
  return 1;
18163
18741
  }
18164
18742
  const client2 = new DeeplineClient();
@@ -18709,11 +19287,11 @@ function normalizeOutputFormat(raw) {
18709
19287
  }
18710
19288
  function resolveAtFilePath(rawPath) {
18711
19289
  const trimmed = rawPath.trim();
18712
- const resolved = (0, import_node_path15.resolve)(trimmed);
18713
- if ((0, import_node_fs12.existsSync)(resolved)) return resolved;
19290
+ const resolved = (0, import_node_path16.resolve)(trimmed);
19291
+ if ((0, import_node_fs13.existsSync)(resolved)) return resolved;
18714
19292
  if (process.platform !== "win32" && trimmed.includes("\\")) {
18715
- const normalized = (0, import_node_path15.resolve)(trimmed.replace(/\\/g, "/"));
18716
- if ((0, import_node_fs12.existsSync)(normalized)) return normalized;
19293
+ const normalized = (0, import_node_path16.resolve)(trimmed.replace(/\\/g, "/"));
19294
+ if ((0, import_node_fs13.existsSync)(normalized)) return normalized;
18717
19295
  }
18718
19296
  return resolved;
18719
19297
  }
@@ -18724,7 +19302,7 @@ function readJsonArgument(raw, flagName) {
18724
19302
  throw new Error(`Invalid ${flagName} value: empty @file path.`);
18725
19303
  }
18726
19304
  try {
18727
- return (0, import_node_fs12.readFileSync)(resolveAtFilePath(filePath), "utf8").replace(
19305
+ return (0, import_node_fs13.readFileSync)(resolveAtFilePath(filePath), "utf8").replace(
18728
19306
  /^\uFEFF/,
18729
19307
  ""
18730
19308
  );
@@ -18815,9 +19393,9 @@ function powerShellQuote(value) {
18815
19393
  function seedToolListScript(input2) {
18816
19394
  const stem = safeFileStem(input2.toolId);
18817
19395
  const fileName = `${stem}-workflow-seed-${Date.now()}.play.ts`;
18818
- const scriptDir = (0, import_node_fs12.mkdtempSync)((0, import_node_path15.join)((0, import_node_os9.tmpdir)(), "deepline-workflow-seed-"));
18819
- (0, import_node_fs12.chmodSync)(scriptDir, 448);
18820
- const scriptPath = (0, import_node_path15.join)(scriptDir, fileName);
19396
+ const scriptDir = (0, import_node_fs13.mkdtempSync)((0, import_node_path16.join)((0, import_node_os10.tmpdir)(), "deepline-workflow-seed-"));
19397
+ (0, import_node_fs13.chmodSync)(scriptDir, 448);
19398
+ const scriptPath = (0, import_node_path16.join)(scriptDir, fileName);
18821
19399
  const projectDir = `deepline/projects/${stem}-workflow`;
18822
19400
  const playName = `${stem}-workflow`;
18823
19401
  const sampleRows = input2.rows.length > 0 ? `${JSON.stringify(input2.rows.slice(0, 2)).replace(/\]$/, "")}, ...]` : "[]";
@@ -18853,7 +19431,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
18853
19431
  };
18854
19432
  });
18855
19433
  `;
18856
- (0, import_node_fs12.writeFileSync)(scriptPath, script, { encoding: "utf-8", mode: 384 });
19434
+ (0, import_node_fs13.writeFileSync)(scriptPath, script, { encoding: "utf-8", mode: 384 });
18857
19435
  return {
18858
19436
  path: scriptPath,
18859
19437
  sourceCode: script,
@@ -19108,10 +19686,10 @@ async function executeTool(args) {
19108
19686
 
19109
19687
  // src/cli/commands/workflow.ts
19110
19688
  var import_promises6 = require("fs/promises");
19111
- var import_node_path16 = require("path");
19689
+ var import_node_path17 = require("path");
19112
19690
 
19113
19691
  // src/cli/workflow-to-play.ts
19114
- var import_node_crypto4 = require("crypto");
19692
+ var import_node_crypto5 = require("crypto");
19115
19693
  var HITL_WAIT_FOR_SIGNAL_TOOL = "deepline_workflow_wait_for_signal";
19116
19694
  var HITL_SLACK_TOOL = "slack_message_with_hitl";
19117
19695
  var SUB_WORKFLOW_TOOL_PREFIX = "deepline_workflow_";
@@ -19217,7 +19795,7 @@ function sanitizePlayNameSegment(value) {
19217
19795
  }
19218
19796
  function deriveWorkflowPlayName(workflowName) {
19219
19797
  const base = sanitizePlayNameSegment(workflowName) || "workflow";
19220
- const suffix = (0, import_node_crypto4.createHash)("sha256").update(workflowName).digest("hex").slice(0, 8);
19798
+ const suffix = (0, import_node_crypto5.createHash)("sha256").update(workflowName).digest("hex").slice(0, 8);
19221
19799
  const reserved = suffix.length + 1;
19222
19800
  const allowedBase = Math.max(1, MAX_PLAY_NAME_LENGTH - reserved);
19223
19801
  let name = `${base.slice(0, allowedBase)}_${suffix}`;
@@ -19315,7 +19893,7 @@ function readStatus(payload) {
19315
19893
  }
19316
19894
  async function readJsonOption(payload, file) {
19317
19895
  if (file) {
19318
- const raw = await (0, import_promises6.readFile)((0, import_node_path16.resolve)(file), "utf8");
19896
+ const raw = await (0, import_promises6.readFile)((0, import_node_path17.resolve)(file), "utf8");
19319
19897
  return JSON.parse(raw);
19320
19898
  }
19321
19899
  if (payload) {
@@ -19349,8 +19927,8 @@ async function transformOne(api, workflowId, outDir, publish) {
19349
19927
  revision.config,
19350
19928
  { workflowName: workflow.name, version: revision.version }
19351
19929
  );
19352
- const file = (0, import_node_path16.join)((0, import_node_path16.resolve)(outDir), `${compiled.playName}.play.ts`);
19353
- await (0, import_promises6.mkdir)((0, import_node_path16.dirname)(file), { recursive: true });
19930
+ const file = (0, import_node_path17.join)((0, import_node_path17.resolve)(outDir), `${compiled.playName}.play.ts`);
19931
+ await (0, import_promises6.mkdir)((0, import_node_path17.dirname)(file), { recursive: true });
19354
19932
  await (0, import_promises6.writeFile)(file, compiled.sourceCode, "utf8");
19355
19933
  let published = false;
19356
19934
  if (publish) {
@@ -19597,8 +20175,8 @@ Notes:
19597
20175
 
19598
20176
  // src/cli/commands/update.ts
19599
20177
  var import_node_child_process = require("child_process");
19600
- var import_node_fs13 = require("fs");
19601
- var import_node_path17 = require("path");
20178
+ var import_node_fs14 = require("fs");
20179
+ var import_node_path18 = require("path");
19602
20180
  function posixShellQuote(value) {
19603
20181
  return `'${value.replace(/'/g, `'\\''`)}'`;
19604
20182
  }
@@ -19617,19 +20195,19 @@ function buildSourceUpdateCommand(sourceRoot) {
19617
20195
  return `${cdCommand} && git fetch origin main --tags && git merge --ff-only origin/main`;
19618
20196
  }
19619
20197
  function findRepoBackedSdkRoot(startPath) {
19620
- let current = (0, import_node_path17.resolve)(startPath);
20198
+ let current = (0, import_node_path18.resolve)(startPath);
19621
20199
  while (true) {
19622
- if ((0, import_node_fs13.existsSync)((0, import_node_path17.join)(current, "sdk", "package.json")) && (0, import_node_fs13.existsSync)((0, import_node_path17.join)(current, "sdk", "bin", "deepline-dev.ts"))) {
20200
+ if ((0, import_node_fs14.existsSync)((0, import_node_path18.join)(current, "sdk", "package.json")) && (0, import_node_fs14.existsSync)((0, import_node_path18.join)(current, "sdk", "bin", "deepline-dev.ts"))) {
19623
20201
  return current;
19624
20202
  }
19625
- const parent = (0, import_node_path17.dirname)(current);
20203
+ const parent = (0, import_node_path18.dirname)(current);
19626
20204
  if (parent === current) return null;
19627
20205
  current = parent;
19628
20206
  }
19629
20207
  }
19630
20208
  function resolveUpdatePlan() {
19631
- const entrypoint = process.argv[1] ? (0, import_node_path17.resolve)(process.argv[1]) : "";
19632
- const sourceRoot = entrypoint ? findRepoBackedSdkRoot((0, import_node_path17.dirname)(entrypoint)) : null;
20209
+ const entrypoint = process.argv[1] ? (0, import_node_path18.resolve)(process.argv[1]) : "";
20210
+ const sourceRoot = entrypoint ? findRepoBackedSdkRoot((0, import_node_path18.dirname)(entrypoint)) : null;
19633
20211
  if (sourceRoot) {
19634
20212
  return {
19635
20213
  kind: "source",
@@ -19704,7 +20282,7 @@ async function handleUpdate(options) {
19704
20282
  return runCommand(plan.command, plan.args);
19705
20283
  }
19706
20284
  function registerUpdateCommand(program) {
19707
- program.command("update").alias("upgrade").description("Update the Deepline SDK/CLI.").addHelpText(
20285
+ program.command("update").description("Update the Deepline SDK/CLI.").addHelpText(
19708
20286
  "after",
19709
20287
  `
19710
20288
  Notes:
@@ -19732,7 +20310,7 @@ var command_compatibility_default = {
19732
20310
  session: {
19733
20311
  family: "python",
19734
20312
  label: "a legacy Python CLI session/playground command",
19735
- sdk_alternative: "Use SDK play run output and run commands such as `deepline plays run ...`."
20313
+ sdk_alternative: "Use `deepline sessions send ...` or `deepline sessions render ...` for transcript workflows."
19736
20314
  },
19737
20315
  workflows: {
19738
20316
  family: "python",
@@ -19752,15 +20330,14 @@ var command_compatibility_default = {
19752
20330
  label: "an SDK CLI play command",
19753
20331
  python_alternative: "Use `deepline workflows ...` only for legacy workflows."
19754
20332
  },
19755
- play: {
19756
- family: "sdk",
19757
- label: "an SDK CLI play command",
19758
- python_alternative: "Use `deepline workflows ...` only for legacy workflows."
19759
- },
19760
20333
  runs: {
19761
20334
  family: "sdk",
19762
20335
  label: "an SDK CLI run inspection command"
19763
20336
  },
20337
+ sessions: {
20338
+ family: "sdk",
20339
+ label: "an SDK CLI session transcript command"
20340
+ },
19764
20341
  health: {
19765
20342
  family: "sdk",
19766
20343
  label: "an SDK CLI health command"
@@ -19892,9 +20469,9 @@ function unknownCommandNameFromMessage(message) {
19892
20469
 
19893
20470
  // src/cli/skills-sync.ts
19894
20471
  var import_node_child_process2 = require("child_process");
19895
- var import_node_fs14 = require("fs");
19896
- var import_node_os10 = require("os");
19897
- var import_node_path18 = require("path");
20472
+ var import_node_fs15 = require("fs");
20473
+ var import_node_os11 = require("os");
20474
+ var import_node_path19 = require("path");
19898
20475
  var CHECK_TIMEOUT_MS2 = 3e3;
19899
20476
  var SDK_SKILL_NAME = "deepline-plays";
19900
20477
  var attemptedSync = false;
@@ -19908,20 +20485,20 @@ function activePluginSkillsDir() {
19908
20485
  return "";
19909
20486
  }
19910
20487
  const dir = process.env.DEEPLINE_PLUGIN_SKILLS_DIR?.trim() ?? "";
19911
- return dir && (0, import_node_fs14.existsSync)(dir) ? dir : "";
20488
+ return dir && (0, import_node_fs15.existsSync)(dir) ? dir : "";
19912
20489
  }
19913
20490
  function readPluginSkillsVersion() {
19914
20491
  const dir = activePluginSkillsDir();
19915
20492
  if (!dir) return "";
19916
20493
  try {
19917
- return (0, import_node_fs14.readFileSync)((0, import_node_path18.join)(dir, ".version"), "utf-8").trim();
20494
+ return (0, import_node_fs15.readFileSync)((0, import_node_path19.join)(dir, ".version"), "utf-8").trim();
19918
20495
  } catch {
19919
20496
  return "";
19920
20497
  }
19921
20498
  }
19922
20499
  function sdkSkillsVersionPath(baseUrl) {
19923
- const home = process.env.HOME?.trim() || (0, import_node_os10.homedir)();
19924
- return (0, import_node_path18.join)(
20500
+ const home = process.env.HOME?.trim() || (0, import_node_os11.homedir)();
20501
+ return (0, import_node_path19.join)(
19925
20502
  home,
19926
20503
  ".local",
19927
20504
  "deepline",
@@ -19934,25 +20511,25 @@ function readLocalSkillsVersion(baseUrl) {
19934
20511
  const pluginVersion = readPluginSkillsVersion();
19935
20512
  if (pluginVersion) return pluginVersion;
19936
20513
  const path = sdkSkillsVersionPath(baseUrl);
19937
- if (!(0, import_node_fs14.existsSync)(path)) return "";
20514
+ if (!(0, import_node_fs15.existsSync)(path)) return "";
19938
20515
  try {
19939
- return (0, import_node_fs14.readFileSync)(path, "utf-8").trim();
20516
+ return (0, import_node_fs15.readFileSync)(path, "utf-8").trim();
19940
20517
  } catch {
19941
20518
  return "";
19942
20519
  }
19943
20520
  }
19944
20521
  function writeLocalSkillsVersion(baseUrl, version) {
19945
20522
  const path = sdkSkillsVersionPath(baseUrl);
19946
- (0, import_node_fs14.mkdirSync)((0, import_node_path18.dirname)(path), { recursive: true });
19947
- (0, import_node_fs14.writeFileSync)(path, `${version}
20523
+ (0, import_node_fs15.mkdirSync)((0, import_node_path19.dirname)(path), { recursive: true });
20524
+ (0, import_node_fs15.writeFileSync)(path, `${version}
19948
20525
  `, "utf-8");
19949
20526
  }
19950
20527
  function installedSdkSkillHasStalePositionalExecuteExamples() {
19951
- const home = process.env.HOME?.trim() || (0, import_node_os10.homedir)();
20528
+ const home = process.env.HOME?.trim() || (0, import_node_os11.homedir)();
19952
20529
  const pluginSkillsDir = activePluginSkillsDir();
19953
- const roots = pluginSkillsDir ? [(0, import_node_path18.join)(pluginSkillsDir, SDK_SKILL_NAME)] : [
19954
- (0, import_node_path18.join)(home, ".claude", "skills", SDK_SKILL_NAME),
19955
- (0, import_node_path18.join)(home, ".agents", "skills", SDK_SKILL_NAME)
20530
+ const roots = pluginSkillsDir ? [(0, import_node_path19.join)(pluginSkillsDir, SDK_SKILL_NAME)] : [
20531
+ (0, import_node_path19.join)(home, ".claude", "skills", SDK_SKILL_NAME),
20532
+ (0, import_node_path19.join)(home, ".agents", "skills", SDK_SKILL_NAME)
19956
20533
  ];
19957
20534
  const staleMarkers = [
19958
20535
  "ctx.tools.execute(key",
@@ -19962,22 +20539,22 @@ function installedSdkSkillHasStalePositionalExecuteExamples() {
19962
20539
  'rowCtx.tools.execute("'
19963
20540
  ];
19964
20541
  const scan = (dir) => {
19965
- for (const entry of (0, import_node_fs14.readdirSync)(dir)) {
19966
- const path = (0, import_node_path18.join)(dir, entry);
19967
- const stat4 = (0, import_node_fs14.statSync)(path);
20542
+ for (const entry of (0, import_node_fs15.readdirSync)(dir)) {
20543
+ const path = (0, import_node_path19.join)(dir, entry);
20544
+ const stat4 = (0, import_node_fs15.statSync)(path);
19968
20545
  if (stat4.isDirectory()) {
19969
20546
  if (scan(path)) return true;
19970
20547
  continue;
19971
20548
  }
19972
20549
  if (!entry.endsWith(".md")) continue;
19973
- const text = (0, import_node_fs14.readFileSync)(path, "utf-8");
20550
+ const text = (0, import_node_fs15.readFileSync)(path, "utf-8");
19974
20551
  if (staleMarkers.some((marker) => text.includes(marker))) return true;
19975
20552
  }
19976
20553
  return false;
19977
20554
  };
19978
20555
  for (const root of roots) {
19979
20556
  try {
19980
- if ((0, import_node_fs14.existsSync)(root) && scan(root)) return true;
20557
+ if ((0, import_node_fs15.existsSync)(root) && scan(root)) return true;
19981
20558
  } catch {
19982
20559
  continue;
19983
20560
  }
@@ -20049,7 +20626,7 @@ function resolveSkillsInstallCommands(baseUrl) {
20049
20626
  return [npxInstall];
20050
20627
  }
20051
20628
  function runOneSkillsInstall(install) {
20052
- return new Promise((resolve15) => {
20629
+ return new Promise((resolve16) => {
20053
20630
  const child = (0, import_node_child_process2.spawn)(install.command, install.args, {
20054
20631
  stdio: ["ignore", "ignore", "pipe"],
20055
20632
  env: process.env
@@ -20059,7 +20636,7 @@ function runOneSkillsInstall(install) {
20059
20636
  stderr += chunk.toString("utf-8");
20060
20637
  });
20061
20638
  child.on("error", (error) => {
20062
- resolve15({
20639
+ resolve16({
20063
20640
  ok: false,
20064
20641
  detail: `failed to start ${install.command}: ${error.message}`,
20065
20642
  manualCommand: install.manualCommand
@@ -20067,11 +20644,11 @@ function runOneSkillsInstall(install) {
20067
20644
  });
20068
20645
  child.on("close", (code) => {
20069
20646
  if (code === 0) {
20070
- resolve15({ ok: true, detail: "", manualCommand: install.manualCommand });
20647
+ resolve16({ ok: true, detail: "", manualCommand: install.manualCommand });
20071
20648
  return;
20072
20649
  }
20073
20650
  const detail = stderr.trim();
20074
- resolve15({
20651
+ resolve16({
20075
20652
  ok: false,
20076
20653
  detail: detail ? `${install.command}: ${detail}` : `${install.command} exited ${code}`,
20077
20654
  manualCommand: install.manualCommand
@@ -20159,8 +20736,8 @@ function shouldDeferSkillsSyncForCommand() {
20159
20736
  return (command === "play" || command === "plays") && subcommand === "run" && args.includes("--json");
20160
20737
  }
20161
20738
  async function runPlayRunnerHealthCheck() {
20162
- const dir = await (0, import_promises7.mkdtemp)((0, import_node_path19.join)((0, import_node_os11.tmpdir)(), "deepline-health-play-"));
20163
- const file = (0, import_node_path19.join)(dir, "health-check.play.ts");
20739
+ const dir = await (0, import_promises7.mkdtemp)((0, import_node_path20.join)((0, import_node_os12.tmpdir)(), "deepline-health-play-"));
20740
+ const file = (0, import_node_path20.join)(dir, "health-check.play.ts");
20164
20741
  try {
20165
20742
  await (0, import_promises7.writeFile)(
20166
20743
  file,
@@ -20348,6 +20925,7 @@ Common commands:
20348
20925
  deepline preflight
20349
20926
  deepline health
20350
20927
  deepline auth status --json
20928
+ deepline sessions send --current-session --json
20351
20929
  deepline plays search email --json
20352
20930
  deepline plays describe person-linkedin-to-email --json
20353
20931
  deepline plays run my.play.ts --input '{"domain":"stripe.com"}'
@@ -20400,6 +20978,7 @@ Exit codes:
20400
20978
  registerAuthCommands(program);
20401
20979
  registerToolsCommands(program);
20402
20980
  registerPlayCommands(program);
20981
+ registerSessionsCommands(program);
20403
20982
  registerWorkflowCommands(program);
20404
20983
  registerSecretsCommands(program);
20405
20984
  registerBillingCommands(program);