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