deepline 0.1.106 → 0.1.107

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
@@ -242,12 +242,22 @@ var SDK_RELEASE = {
242
242
  // 0.1.105 ships the billing catalog surface: billing plans, subscribe,
243
243
  // subscription status/cancel, invoices, and the client.billing namespace.
244
244
  // 0.1.106 ships play cell provenance metadata and v2 preview retry hardening.
245
- version: "0.1.106",
245
+ // 0.1.107 ships the v2 quickstart command, the deepline-plays-quickstart
246
+ // skill on the sdk sync surface, and the people-search-to-email prebuilt.
247
+ version: "0.1.107",
246
248
  apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
247
249
  supportPolicy: {
248
- latest: "0.1.106",
250
+ latest: "0.1.107",
249
251
  minimumSupported: "0.1.53",
250
- deprecatedBelow: "0.1.53"
252
+ deprecatedBelow: "0.1.53",
253
+ commandMinimumSupported: [
254
+ {
255
+ command: "enrich",
256
+ minimumSupported: "0.1.106",
257
+ reason: "Older SDK CLI enrich generated stale play source for the current dataset API."
258
+ }
259
+ ],
260
+ autoUpdatePatchLag: 2
251
261
  }
252
262
  };
253
263
 
@@ -3169,7 +3179,7 @@ function shouldSkipCompatibilityCheck() {
3169
3179
  const value = process.env.DEEPLINE_SKIP_SDK_COMPAT_CHECK?.trim().toLowerCase();
3170
3180
  return value === "1" || value === "true" || value === "yes";
3171
3181
  }
3172
- async function checkSdkCompatibility(baseUrl) {
3182
+ async function checkSdkCompatibility(baseUrl, options = {}) {
3173
3183
  if (shouldSkipCompatibilityCheck()) {
3174
3184
  return { response: null, error: null };
3175
3185
  }
@@ -3178,6 +3188,9 @@ async function checkSdkCompatibility(baseUrl) {
3178
3188
  try {
3179
3189
  const url = new URL("/api/v2/sdk/compat", baseUrl);
3180
3190
  url.searchParams.set("version", SDK_VERSION);
3191
+ if (options.command?.trim()) {
3192
+ url.searchParams.set("command", options.command.trim());
3193
+ }
3181
3194
  const response = await fetch(url, {
3182
3195
  method: "GET",
3183
3196
  headers: {
@@ -3198,9 +3211,8 @@ async function checkSdkCompatibility(baseUrl) {
3198
3211
  clearTimeout(timeout);
3199
3212
  }
3200
3213
  }
3201
- async function enforceSdkCompatibility(baseUrl) {
3202
- const { response, error } = await checkSdkCompatibility(baseUrl);
3203
- if (error || !response) {
3214
+ function enforceSdkCompatibilityResponse(response) {
3215
+ if (!response) {
3204
3216
  return;
3205
3217
  }
3206
3218
  if (response.update_required) {
@@ -17951,6 +17963,244 @@ Examples:
17951
17963
  ).option("--org-id <id>", "Switch using an explicit organization id").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleOrgSwitch);
17952
17964
  }
17953
17965
 
17966
+ // src/cli/commands/quickstart.ts
17967
+ var import_node_child_process = require("child_process");
17968
+ var import_node_crypto4 = require("crypto");
17969
+ var import_node_http = require("http");
17970
+ var EXIT_OK2 = 0;
17971
+ var EXIT_AUTH2 = 1;
17972
+ var EXIT_SERVER3 = 2;
17973
+ var MAX_PROMPT_LENGTH = 8e3;
17974
+ var MAX_BODY_BYTES = 64 * 1024;
17975
+ function shellQuote(arg) {
17976
+ return `'${arg.replace(/'/g, `'\\''`)}'`;
17977
+ }
17978
+ function hasClaudeBinary() {
17979
+ try {
17980
+ const result = (0, import_node_child_process.spawnSync)("claude", ["--version"], {
17981
+ stdio: "ignore",
17982
+ shell: process.platform === "win32"
17983
+ });
17984
+ return result.status === 0;
17985
+ } catch {
17986
+ return false;
17987
+ }
17988
+ }
17989
+ function launchClaude(prompt) {
17990
+ return new Promise((resolve16) => {
17991
+ const child = (0, import_node_child_process.spawn)("claude", [prompt], {
17992
+ stdio: "inherit",
17993
+ shell: process.platform === "win32"
17994
+ });
17995
+ child.on("error", () => resolve16(EXIT_SERVER3));
17996
+ child.on("close", (status) => resolve16(status ?? EXIT_OK2));
17997
+ });
17998
+ }
17999
+ function readBody(req) {
18000
+ return new Promise((resolve16, reject) => {
18001
+ let raw = "";
18002
+ req.setEncoding("utf8");
18003
+ req.on("data", (chunk) => {
18004
+ raw += chunk;
18005
+ if (raw.length > MAX_BODY_BYTES) {
18006
+ reject(new Error("Request body too large."));
18007
+ req.destroy();
18008
+ }
18009
+ });
18010
+ req.on("end", () => resolve16(raw));
18011
+ req.on("error", reject);
18012
+ });
18013
+ }
18014
+ function writeJson(res, status, payload) {
18015
+ res.writeHead(status, { "content-type": "application/json" });
18016
+ res.end(JSON.stringify(payload));
18017
+ }
18018
+ function startCallbackServer(input2) {
18019
+ const server = (0, import_node_http.createServer)((req, res) => {
18020
+ res.setHeader("Access-Control-Allow-Origin", req.headers.origin ?? "*");
18021
+ res.setHeader("Vary", "Origin");
18022
+ res.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS");
18023
+ res.setHeader("Access-Control-Allow-Headers", "content-type");
18024
+ res.setHeader("Access-Control-Allow-Private-Network", "true");
18025
+ res.setHeader("Access-Control-Max-Age", "600");
18026
+ if (req.method === "OPTIONS") {
18027
+ res.writeHead(204);
18028
+ res.end();
18029
+ return;
18030
+ }
18031
+ if (req.method !== "POST" || req.url !== "/submit") {
18032
+ writeJson(res, 404, { error: "Not found." });
18033
+ return;
18034
+ }
18035
+ void readBody(req).then((raw) => {
18036
+ let body = null;
18037
+ try {
18038
+ body = JSON.parse(raw);
18039
+ } catch {
18040
+ body = null;
18041
+ }
18042
+ const state = typeof body?.state === "string" ? body.state : "";
18043
+ const prompt = typeof body?.prompt === "string" ? body.prompt.trim() : "";
18044
+ const workflowId = typeof body?.workflow_id === "string" && body.workflow_id.trim() ? body.workflow_id.trim() : null;
18045
+ if (!state || state !== input2.state) {
18046
+ writeJson(res, 403, { error: "Invalid quickstart state token." });
18047
+ return;
18048
+ }
18049
+ if (!prompt) {
18050
+ writeJson(res, 400, { error: "prompt is required." });
18051
+ return;
18052
+ }
18053
+ if (prompt.length > MAX_PROMPT_LENGTH) {
18054
+ writeJson(res, 400, {
18055
+ error: `prompt exceeds ${MAX_PROMPT_LENGTH} characters.`
18056
+ });
18057
+ return;
18058
+ }
18059
+ writeJson(res, 200, { ok: true });
18060
+ setImmediate(() => input2.onSelection({ prompt, workflowId }));
18061
+ }).catch(() => {
18062
+ writeJson(res, 400, { error: "Invalid request body." });
18063
+ });
18064
+ });
18065
+ return new Promise((resolve16, reject) => {
18066
+ server.once("error", reject);
18067
+ server.listen(0, "127.0.0.1", () => {
18068
+ const address = server.address();
18069
+ if (!address || typeof address === "string") {
18070
+ reject(new Error("Failed to bind quickstart callback server."));
18071
+ return;
18072
+ }
18073
+ resolve16({ server, port: address.port });
18074
+ });
18075
+ });
18076
+ }
18077
+ async function handleQuickstart(options) {
18078
+ const jsonOutput = shouldEmitJson(options.json === true);
18079
+ const baseUrl = autoDetectBaseUrl().replace(/\/$/, "");
18080
+ const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
18081
+ let apiKey = resolveApiKeyForBaseUrl(baseUrl);
18082
+ if (!apiKey) {
18083
+ if (interactive) {
18084
+ console.error("Not connected yet \u2014 registering this device first.");
18085
+ const registerExit = await handleRegister([]);
18086
+ if (registerExit !== EXIT_OK2) return registerExit;
18087
+ apiKey = resolveApiKeyForBaseUrl(baseUrl);
18088
+ }
18089
+ if (!apiKey) {
18090
+ console.error("Not connected. Run: deepline auth register");
18091
+ return EXIT_AUTH2;
18092
+ }
18093
+ }
18094
+ const state = (0, import_node_crypto4.randomBytes)(32).toString("hex");
18095
+ let resolveSelection;
18096
+ const selectionPromise = new Promise((resolve16) => {
18097
+ resolveSelection = resolve16;
18098
+ });
18099
+ let callback;
18100
+ try {
18101
+ callback = await startCallbackServer({
18102
+ state,
18103
+ onSelection: (selection) => resolveSelection(selection)
18104
+ });
18105
+ } catch (error) {
18106
+ console.error(
18107
+ `Could not start the local quickstart listener: ${error instanceof Error ? error.message : String(error)}`
18108
+ );
18109
+ return EXIT_SERVER3;
18110
+ }
18111
+ const quickstartUrl = `${baseUrl}/cli/quickstart?cb=${callback.port}&state=${state}`;
18112
+ console.error(" Opening the recipe picker in your browser.");
18113
+ console.error(` If it didn't open, cmd+click: ${quickstartUrl}`);
18114
+ if (options.open !== false) {
18115
+ openInBrowser(quickstartUrl);
18116
+ }
18117
+ const timeoutSeconds = Number.parseInt(options.timeout ?? "300", 10);
18118
+ const timeoutMs = (Number.isFinite(timeoutSeconds) && timeoutSeconds > 0 ? timeoutSeconds : 300) * 1e3;
18119
+ const timeoutHandle = setTimeout(
18120
+ () => resolveSelection("timeout"),
18121
+ timeoutMs
18122
+ );
18123
+ const progress = createCliProgress(!jsonOutput);
18124
+ progress.phase("waiting for your pick in the browser (Ctrl+C to skip)");
18125
+ const onSigint = () => resolveSelection("sigint");
18126
+ process.once("SIGINT", onSigint);
18127
+ const outcome = await selectionPromise;
18128
+ clearTimeout(timeoutHandle);
18129
+ process.removeListener("SIGINT", onSigint);
18130
+ callback.server.close();
18131
+ if (outcome === "sigint") {
18132
+ progress.fail();
18133
+ console.error("\nSkipped \u2014 run `deepline quickstart` anytime.");
18134
+ return EXIT_OK2;
18135
+ }
18136
+ if (outcome === "timeout") {
18137
+ progress.fail();
18138
+ console.error(
18139
+ "Timed out waiting for a selection. Run: deepline quickstart"
18140
+ );
18141
+ return EXIT_AUTH2;
18142
+ }
18143
+ progress.complete();
18144
+ const { prompt, workflowId } = outcome;
18145
+ const claudeCommand = `claude ${shellQuote(prompt)}`;
18146
+ const claudeAvailable = hasClaudeBinary();
18147
+ const willLaunch = options.launch !== false && !jsonOutput && interactive && claudeAvailable;
18148
+ printCommandEnvelope(
18149
+ {
18150
+ status: "submitted",
18151
+ workflowId,
18152
+ prompt,
18153
+ claudeCommand,
18154
+ url: quickstartUrl,
18155
+ launched: willLaunch,
18156
+ render: {
18157
+ sections: [
18158
+ {
18159
+ title: "quickstart",
18160
+ lines: [
18161
+ ...workflowId ? [`Recipe: ${workflowId}`] : [],
18162
+ willLaunch ? "Launching Claude Code with your recipe..." : claudeAvailable ? "Run the command below to start your recipe." : "Claude Code not found. Install it (https://code.claude.com/docs/en/overview), then run the command below."
18163
+ ]
18164
+ }
18165
+ ],
18166
+ actions: [{ label: "Run", command: claudeCommand }]
18167
+ }
18168
+ },
18169
+ { json: jsonOutput }
18170
+ );
18171
+ if (willLaunch) {
18172
+ return launchClaude(prompt);
18173
+ }
18174
+ return EXIT_OK2;
18175
+ }
18176
+ function registerQuickstartCommands(program) {
18177
+ program.command("quickstart").description(
18178
+ "Pick a starter recipe in the browser and launch it with Claude Code."
18179
+ ).addHelpText(
18180
+ "after",
18181
+ `
18182
+ Notes:
18183
+ Opens the hosted recipe picker in your browser. The picker sends your
18184
+ selection back to a temporary listener on 127.0.0.1, so the browser must run
18185
+ on the same machine as the CLI. Once a recipe arrives, the CLI prints the
18186
+ matching claude command and, when Claude Code is installed and the shell is
18187
+ interactive, launches it directly. Press Ctrl+C while waiting to skip.
18188
+
18189
+ Examples:
18190
+ deepline quickstart
18191
+ deepline quickstart --no-open
18192
+ deepline quickstart --no-launch --json
18193
+ deepline quickstart --timeout 120
18194
+ `
18195
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").option("--no-open", "Do not open the browser; print the URL only").option("--no-launch", "Print the claude command instead of launching it").option(
18196
+ "--timeout <seconds>",
18197
+ "Maximum seconds to wait for a selection",
18198
+ "300"
18199
+ ).action(async (options) => {
18200
+ process.exitCode = await handleQuickstart(options);
18201
+ });
18202
+ }
18203
+
17954
18204
  // src/cli/commands/secrets.ts
17955
18205
  var import_node_process = require("process");
17956
18206
  var hiddenInputBuffer = "";
@@ -18168,7 +18418,7 @@ var import_node_fs11 = require("fs");
18168
18418
  var import_node_os8 = require("os");
18169
18419
  var import_node_path14 = require("path");
18170
18420
  var import_node_zlib = require("zlib");
18171
- var import_node_crypto4 = require("crypto");
18421
+ var import_node_crypto5 = require("crypto");
18172
18422
  var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
18173
18423
  var MAX_SESSION_UPLOAD_BYTES = 35e5;
18174
18424
  var MAX_DIRECT_SESSION_DECODED_BYTES = 50 * 1024 * 1024;
@@ -18431,7 +18681,7 @@ async function uploadPayload(path, payload) {
18431
18681
  return await http.post(path, payload);
18432
18682
  }
18433
18683
  async function uploadChunkedSessions(sessions, options) {
18434
- const uploadId = (0, import_node_crypto4.randomUUID)();
18684
+ const uploadId = (0, import_node_crypto5.randomUUID)();
18435
18685
  for (const session of sessions) {
18436
18686
  const bytes = Buffer.from(session.encodedContent, "base64");
18437
18687
  const chunks = [];
@@ -19955,7 +20205,7 @@ function parseExecuteOptions(args) {
19955
20205
  function safeFileStem(value) {
19956
20206
  return value.trim().replace(/[^a-zA-Z0-9_-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64) || "tool";
19957
20207
  }
19958
- function shellQuote(value) {
20208
+ function shellQuote2(value) {
19959
20209
  return `'${value.replace(/'/g, `'\\''`)}'`;
19960
20210
  }
19961
20211
  function powerShellQuote(value) {
@@ -20007,7 +20257,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
20007
20257
  path: scriptPath,
20008
20258
  sourceCode: script,
20009
20259
  projectDir,
20010
- macCopyCommand: `mkdir -p ${shellQuote(projectDir)} && cp ${shellQuote(scriptPath)} ${shellQuote(`${projectDir}/${fileName}`)}`,
20260
+ macCopyCommand: `mkdir -p ${shellQuote2(projectDir)} && cp ${shellQuote2(scriptPath)} ${shellQuote2(`${projectDir}/${fileName}`)}`,
20011
20261
  windowsCopyCommand: `New-Item -ItemType Directory -Force -Path ${powerShellQuote(projectDir.replace(/\//g, "\\"))} | Out-Null; Copy-Item -LiteralPath ${powerShellQuote(scriptPath)} -Destination ${powerShellQuote(`${projectDir.replace(/\//g, "\\")}\\${fileName}`)}`
20012
20262
  };
20013
20263
  }
@@ -20026,7 +20276,7 @@ function buildToolExecuteBaseEnvelope(input2) {
20026
20276
  summary: input2.summary
20027
20277
  };
20028
20278
  const envelopeHasCanonicalOutput = isRecord7(envelope.toolResponse) && Object.prototype.hasOwnProperty.call(envelope.toolResponse, "raw");
20029
- const inspectCommand = `deepline tools execute ${input2.toolId} --input ${shellQuote(JSON.stringify(input2.params))} --json`;
20279
+ const inspectCommand = `deepline tools execute ${input2.toolId} --input ${shellQuote2(JSON.stringify(input2.params))} --json`;
20030
20280
  const actions = input2.listConversion ? [
20031
20281
  {
20032
20282
  label: "next",
@@ -20260,7 +20510,7 @@ var import_promises6 = require("fs/promises");
20260
20510
  var import_node_path17 = require("path");
20261
20511
 
20262
20512
  // src/cli/workflow-to-play.ts
20263
- var import_node_crypto5 = require("crypto");
20513
+ var import_node_crypto6 = require("crypto");
20264
20514
  var HITL_WAIT_FOR_SIGNAL_TOOL = "deepline_workflow_wait_for_signal";
20265
20515
  var HITL_SLACK_TOOL = "slack_message_with_hitl";
20266
20516
  var SUB_WORKFLOW_TOOL_PREFIX = "deepline_workflow_";
@@ -20366,7 +20616,7 @@ function sanitizePlayNameSegment(value) {
20366
20616
  }
20367
20617
  function deriveWorkflowPlayName(workflowName) {
20368
20618
  const base = sanitizePlayNameSegment(workflowName) || "workflow";
20369
- const suffix = (0, import_node_crypto5.createHash)("sha256").update(workflowName).digest("hex").slice(0, 8);
20619
+ const suffix = (0, import_node_crypto6.createHash)("sha256").update(workflowName).digest("hex").slice(0, 8);
20370
20620
  const reserved = suffix.length + 1;
20371
20621
  const allowedBase = Math.max(1, MAX_PLAY_NAME_LENGTH - reserved);
20372
20622
  let name = `${base.slice(0, allowedBase)}_${suffix}`;
@@ -20745,7 +20995,7 @@ Notes:
20745
20995
  }
20746
20996
 
20747
20997
  // src/cli/commands/update.ts
20748
- var import_node_child_process = require("child_process");
20998
+ var import_node_child_process2 = require("child_process");
20749
20999
  var import_node_fs14 = require("fs");
20750
21000
  var import_node_path18 = require("path");
20751
21001
  function posixShellQuote(value) {
@@ -20754,14 +21004,14 @@ function posixShellQuote(value) {
20754
21004
  function windowsCmdQuote(value) {
20755
21005
  return `"${value.replace(/"/g, '""')}"`;
20756
21006
  }
20757
- function shellQuote2(value) {
21007
+ function shellQuote3(value) {
20758
21008
  if (process.platform === "win32") {
20759
21009
  return /^[A-Za-z0-9_./:@%+=,-]+$/.test(value) ? value : windowsCmdQuote(value);
20760
21010
  }
20761
21011
  return posixShellQuote(value);
20762
21012
  }
20763
21013
  function buildSourceUpdateCommand(sourceRoot) {
20764
- const quotedRoot = shellQuote2(sourceRoot);
21014
+ const quotedRoot = shellQuote3(sourceRoot);
20765
21015
  const cdCommand = process.platform === "win32" ? `cd /d ${quotedRoot}` : `cd ${quotedRoot}`;
20766
21016
  return `${cdCommand} && git fetch origin main --tags && git merge --ff-only origin/main`;
20767
21017
  }
@@ -20792,12 +21042,12 @@ function resolveUpdatePlan() {
20792
21042
  kind: "npm-global",
20793
21043
  command,
20794
21044
  args,
20795
- manualCommand: `${command} ${args.map(shellQuote2).join(" ")}`
21045
+ manualCommand: `${command} ${args.map(shellQuote3).join(" ")}`
20796
21046
  };
20797
21047
  }
20798
21048
  function runCommand(command, args) {
20799
21049
  return new Promise((resolveExitCode) => {
20800
- const child = (0, import_node_child_process.spawn)(command, args, {
21050
+ const child = (0, import_node_child_process2.spawn)(command, args, {
20801
21051
  stdio: "inherit",
20802
21052
  shell: process.platform === "win32",
20803
21053
  env: process.env
@@ -20812,6 +21062,12 @@ function runCommand(command, args) {
20812
21062
  });
20813
21063
  });
20814
21064
  }
21065
+ async function runNpmGlobalUpdatePlan(plan) {
21066
+ if (plan.kind !== "npm-global") {
21067
+ return 1;
21068
+ }
21069
+ return runCommand(plan.command, plan.args);
21070
+ }
20815
21071
  async function handleUpdate(options) {
20816
21072
  const plan = resolveUpdatePlan();
20817
21073
  const render = {
@@ -20958,16 +21214,27 @@ function skillsIndexUrl(baseUrl) {
20958
21214
  return `${normalizeBaseUrl2(baseUrl)}${INSTALL_COMMANDS.skills.index_path}`;
20959
21215
  }
20960
21216
  function buildSkillsAddArgs(baseUrl, skillName, options = {}) {
21217
+ const skillNames = Array.isArray(skillName) ? skillName : [skillName];
21218
+ const [firstSkillName, ...extraSkillNames] = skillNames;
20961
21219
  const values = {
20962
21220
  skills_index_url: skillsIndexUrl(baseUrl),
20963
21221
  agents: INSTALL_COMMANDS.skills.default_agents.join(" "),
20964
- skill_name: skillName
21222
+ skill_name: firstSkillName ?? ""
20965
21223
  };
20966
21224
  const rendered = INSTALL_COMMANDS.skills.npx_add_args_template.flatMap(
20967
21225
  (arg, index) => {
20968
21226
  const next = index === 0 && options.firstArg ? options.firstArg : arg;
20969
21227
  const value = renderTemplate(next, values);
20970
- return arg === "{agents}" ? INSTALL_COMMANDS.skills.default_agents : value;
21228
+ if (arg === "{agents}") {
21229
+ return INSTALL_COMMANDS.skills.default_agents;
21230
+ }
21231
+ if (arg === "{skill_name}") {
21232
+ return [
21233
+ value,
21234
+ ...extraSkillNames.flatMap((name) => ["--skill", name])
21235
+ ];
21236
+ }
21237
+ return value;
20971
21238
  }
20972
21239
  );
20973
21240
  return rendered;
@@ -21038,13 +21305,78 @@ function unknownCommandNameFromMessage(message) {
21038
21305
  return command ? command : null;
21039
21306
  }
21040
21307
 
21308
+ // src/cli/self-update.ts
21309
+ var import_node_child_process3 = require("child_process");
21310
+ function envTruthy(name) {
21311
+ const value = process.env[name]?.trim().toLowerCase();
21312
+ return value === "1" || value === "true" || value === "yes";
21313
+ }
21314
+ function isCi() {
21315
+ return envTruthy("CI") || envTruthy("GITHUB_ACTIONS");
21316
+ }
21317
+ function shouldSkipSelfUpdate() {
21318
+ return envTruthy("DEEPLINE_SKIP_SELF_UPDATE") || envTruthy("DEEPLINE_NO_AUTO_UPDATE") || envTruthy("DEEPLINE_SKIP_SDK_AUTO_UPDATE") || envTruthy("DEEPLINE_DISABLE_AUTO_UPDATE") || isCi();
21319
+ }
21320
+ function relaunchCurrentCommand() {
21321
+ return new Promise((resolve16) => {
21322
+ const child = (0, import_node_child_process3.spawn)(process.execPath, process.argv.slice(1), {
21323
+ stdio: "inherit",
21324
+ env: {
21325
+ ...process.env,
21326
+ DEEPLINE_NO_AUTO_UPDATE: "1"
21327
+ }
21328
+ });
21329
+ child.on("error", (error) => {
21330
+ process.stderr.write(
21331
+ `Deepline SDK/CLI updated, but relaunch failed: ${error.message}
21332
+ `
21333
+ );
21334
+ resolve16(1);
21335
+ });
21336
+ child.on("close", (code) => resolve16(code ?? 1));
21337
+ });
21338
+ }
21339
+ async function maybeAutoUpdateAndRelaunch(response) {
21340
+ const autoUpdate = response?.auto_update;
21341
+ if (!response || !autoUpdate?.should_auto_update || shouldSkipSelfUpdate()) {
21342
+ return false;
21343
+ }
21344
+ const plan = resolveUpdatePlan();
21345
+ if (plan.kind !== "npm-global") {
21346
+ return false;
21347
+ }
21348
+ const label = autoUpdate.required ? "requires an update" : "is more than the supported auto-update lag behind";
21349
+ process.stderr.write(
21350
+ `Deepline SDK/CLI ${label}; running ${plan.manualCommand}
21351
+ `
21352
+ );
21353
+ const updateExitCode = await runNpmGlobalUpdatePlan(plan);
21354
+ if (updateExitCode !== 0) {
21355
+ if (autoUpdate.required) {
21356
+ throw new Error(
21357
+ `Automatic Deepline SDK/CLI update failed with exit code ${updateExitCode}. ${response.message}`
21358
+ );
21359
+ }
21360
+ process.stderr.write(
21361
+ `Deepline SDK/CLI auto-update failed with exit code ${updateExitCode}; continuing with ${response.current ?? "current version"}.
21362
+ `
21363
+ );
21364
+ return false;
21365
+ }
21366
+ process.stderr.write("Deepline SDK/CLI updated; rerunning command.\n");
21367
+ const exitCode = await relaunchCurrentCommand();
21368
+ process.exit(exitCode);
21369
+ return true;
21370
+ }
21371
+
21041
21372
  // src/cli/skills-sync.ts
21042
- var import_node_child_process2 = require("child_process");
21373
+ var import_node_child_process4 = require("child_process");
21043
21374
  var import_node_fs15 = require("fs");
21044
21375
  var import_node_os11 = require("os");
21045
21376
  var import_node_path19 = require("path");
21046
21377
  var CHECK_TIMEOUT_MS2 = 3e3;
21047
21378
  var SDK_SKILL_NAME = "deepline-plays";
21379
+ var SDK_SKILL_NAMES = [SDK_SKILL_NAME, "deepline-plays-quickstart"];
21048
21380
  var attemptedSync = false;
21049
21381
  function shouldSkipSkillsSync() {
21050
21382
  const value = process.env.DEEPLINE_SKIP_SKILLS_SYNC?.trim().toLowerCase();
@@ -21161,19 +21493,19 @@ async function fetchSkillsUpdate(baseUrl, localVersion) {
21161
21493
  }
21162
21494
  }
21163
21495
  function buildSkillsInstallArgs(baseUrl) {
21164
- return buildSkillsAddArgs(baseUrl, SDK_SKILL_NAME);
21496
+ return buildSkillsAddArgs(baseUrl, SDK_SKILL_NAMES);
21165
21497
  }
21166
21498
  function buildBunxSkillsInstallArgs(baseUrl) {
21167
- return buildSkillsAddArgs(baseUrl, SDK_SKILL_NAME, { firstArg: "--bun" });
21499
+ return buildSkillsAddArgs(baseUrl, SDK_SKILL_NAMES, { firstArg: "--bun" });
21168
21500
  }
21169
21501
  function hasCommand(command) {
21170
- const result = (0, import_node_child_process2.spawnSync)(command, ["--version"], {
21502
+ const result = (0, import_node_child_process4.spawnSync)(command, ["--version"], {
21171
21503
  stdio: "ignore",
21172
21504
  shell: process.platform === "win32"
21173
21505
  });
21174
21506
  return result.status === 0;
21175
21507
  }
21176
- function shellQuote3(arg) {
21508
+ function shellQuote4(arg) {
21177
21509
  return `'${arg.replace(/'/g, `'\\''`)}'`;
21178
21510
  }
21179
21511
  function resolveSkillsInstallCommands(baseUrl) {
@@ -21181,7 +21513,7 @@ function resolveSkillsInstallCommands(baseUrl) {
21181
21513
  const npxInstall = {
21182
21514
  command: "npx",
21183
21515
  args: npxArgs,
21184
- manualCommand: `npx ${npxArgs.map(shellQuote3).join(" ")}`
21516
+ manualCommand: `npx ${npxArgs.map(shellQuote4).join(" ")}`
21185
21517
  };
21186
21518
  if (hasCommand("bunx")) {
21187
21519
  const bunxArgs = buildBunxSkillsInstallArgs(baseUrl);
@@ -21189,7 +21521,7 @@ function resolveSkillsInstallCommands(baseUrl) {
21189
21521
  {
21190
21522
  command: "bunx",
21191
21523
  args: bunxArgs,
21192
- manualCommand: `bunx ${bunxArgs.map(shellQuote3).join(" ")}`
21524
+ manualCommand: `bunx ${bunxArgs.map(shellQuote4).join(" ")}`
21193
21525
  },
21194
21526
  npxInstall
21195
21527
  ];
@@ -21198,7 +21530,7 @@ function resolveSkillsInstallCommands(baseUrl) {
21198
21530
  }
21199
21531
  function runOneSkillsInstall(install) {
21200
21532
  return new Promise((resolve16) => {
21201
- const child = (0, import_node_child_process2.spawn)(install.command, install.args, {
21533
+ const child = (0, import_node_child_process4.spawn)(install.command, install.args, {
21202
21534
  stdio: ["ignore", "ignore", "pipe"],
21203
21535
  env: process.env
21204
21536
  });
@@ -21266,7 +21598,7 @@ async function syncSdkSkillsIfNeeded(baseUrl) {
21266
21598
  if (!update?.needsUpdate && !hasStaleInstalledSkill || !update?.remoteVersion) {
21267
21599
  return;
21268
21600
  }
21269
- writeSdkSkillsStatusLine("SDK skills changed; syncing deepline-plays skill...");
21601
+ writeSdkSkillsStatusLine("SDK skills changed; syncing Deepline SDK skills...");
21270
21602
  const installed = await runSkillsInstall(baseUrl);
21271
21603
  if (!installed) return;
21272
21604
  if (installedSdkSkillHasStalePositionalExecuteExamples()) {
@@ -21489,7 +21821,9 @@ async function main() {
21489
21821
  progress?.phase("loading deepline cli");
21490
21822
  }
21491
21823
  const program = new import_commander3.Command();
21492
- program.name("deepline").description("Deepline CLI (TypeScript SDK)").version(SDK_VERSION, "-v, --version", "Show version").exitOverride().showHelpAfterError().showSuggestionAfterError(true).addHelpText(
21824
+ program.name("deepline").description(
21825
+ "Deepline CLI \u2014 GTM enrichment tools, plays, and runs from your terminal."
21826
+ ).version(SDK_VERSION, "-v, --version", "Show version").exitOverride().showHelpAfterError().showSuggestionAfterError(true).addHelpText(
21493
21827
  "after",
21494
21828
  `
21495
21829
  Common commands:
@@ -21530,11 +21864,23 @@ Exit codes:
21530
21864
  progress?.phase("checking sdk compatibility");
21531
21865
  }
21532
21866
  const baseUrl = autoDetectBaseUrl().replace(/\/$/, "");
21533
- await traceCliSpan(
21867
+ const compatibility = await traceCliSpan(
21534
21868
  "cli.sdk_compatibility",
21535
- { baseUrl },
21536
- () => enforceSdkCompatibility(baseUrl)
21869
+ { baseUrl, command: actionCommand.name() },
21870
+ () => checkSdkCompatibility(baseUrl, {
21871
+ command: actionCommand.name()
21872
+ })
21873
+ );
21874
+ if (compatibility.error) {
21875
+ return;
21876
+ }
21877
+ const relaunched = await maybeAutoUpdateAndRelaunch(
21878
+ compatibility.response
21537
21879
  );
21880
+ if (relaunched) {
21881
+ return;
21882
+ }
21883
+ enforceSdkCompatibilityResponse(compatibility.response);
21538
21884
  if (printStartupPhase) {
21539
21885
  progress?.phase("checking sdk skills");
21540
21886
  }
@@ -21559,6 +21905,7 @@ Exit codes:
21559
21905
  registerDbCommands(program);
21560
21906
  registerFeedbackCommands(program);
21561
21907
  registerUpdateCommand(program);
21908
+ registerQuickstartCommands(program);
21562
21909
  program.command("preflight").description("Run compact health, auth, and Deepline billing checks.").option("--json", "Force JSON output.").addHelpText(
21563
21910
  "after",
21564
21911
  `
@@ -21634,6 +21981,29 @@ Examples:
21634
21981
  process.stdout.write(`deepline ${SDK_VERSION}
21635
21982
  `);
21636
21983
  });
21984
+ if (process.argv.slice(2).length === 0) {
21985
+ if (!process.stdout.isTTY) {
21986
+ printJson({
21987
+ ok: false,
21988
+ exitCode: 2,
21989
+ code: "MISSING_COMMAND",
21990
+ message: "No command provided.",
21991
+ next: "deepline --help"
21992
+ });
21993
+ console.error("error: missing command (see: deepline --help)");
21994
+ } else {
21995
+ program.outputHelp({ error: true });
21996
+ console.error("\nerror: missing command (see usage above)");
21997
+ }
21998
+ recordCliTrace({
21999
+ phase: "cli.main_total",
22000
+ ms: Date.now() - mainStartedAt,
22001
+ ok: false,
22002
+ error: "missing command"
22003
+ });
22004
+ process.exitCode = 2;
22005
+ return;
22006
+ }
21637
22007
  try {
21638
22008
  await program.parseAsync(process.argv);
21639
22009
  recordCliTrace({