deepline 0.1.102 → 0.1.103

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