deepline 0.1.276 → 0.1.278

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.
@@ -155,7 +155,7 @@ export const SDK_RELEASE = {
155
155
  // 0.1.253 makes play-page browser opening opt-in and retires --no-open.
156
156
  // 0.1.254 removes the internal operations tree from the published SDK CLI.
157
157
  // Operators use the checkout-local deepline-admin binary instead.
158
- version: '0.1.276',
158
+ version: '0.1.278',
159
159
  contracts: {
160
160
  api: {
161
161
  name: 'sdk-http-api',
@@ -1225,6 +1225,16 @@ export class PlayContextImpl {
1225
1225
  private readonly executionScope: RunExecutionScope;
1226
1226
  private logBuffer: string[] = [];
1227
1227
  private checkpoint: PlayCheckpoint;
1228
+ /**
1229
+ * Durable tool receipts are the replay/cache authority for the execution
1230
+ * paths the host supports. Keeping the same completed result in this
1231
+ * checkpoint retained every provider payload for the lifetime of a run and
1232
+ * copied it again while serializing the terminal. Paths without a matching
1233
+ * receipt API keep the legacy checkpoint cache so local/in-process replay
1234
+ * and bulk-only hosts' direct calls still work.
1235
+ */
1236
+ private readonly durableMappedToolResultsBackedByReceipts: boolean;
1237
+ private readonly durableDirectToolResultsBackedByReceipts: boolean;
1228
1238
  private steps: PlayStep[] = [];
1229
1239
  private explicitMapInvocationKeys = new Set<string>();
1230
1240
  /** The map step currently being built — substeps go here instead of top-level. */
@@ -1383,6 +1393,24 @@ export class PlayContextImpl {
1383
1393
  constructor(options: ContextOptions) {
1384
1394
  this.#options = options;
1385
1395
  this.checkpoint = options.checkpoint ?? emptyCheckpoint();
1396
+ this.durableMappedToolResultsBackedByReceipts = Boolean(
1397
+ (options.claimRuntimeStepReceipt || options.claimRuntimeStepReceipts) &&
1398
+ (options.getRuntimeStepReceipt || options.getRuntimeStepReceipts) &&
1399
+ (options.completeRuntimeStepReceipt ||
1400
+ options.completeRuntimeStepReceipts),
1401
+ );
1402
+ this.durableDirectToolResultsBackedByReceipts = Boolean(
1403
+ options.claimRuntimeStepReceipt &&
1404
+ options.getRuntimeStepReceipt &&
1405
+ options.completeRuntimeStepReceipt,
1406
+ );
1407
+ if (this.durableDirectToolResultsBackedByReceipts) {
1408
+ // A resumed durable runner may receive a legacy checkpoint containing
1409
+ // full tool results. Drop that redundant copy immediately and recover
1410
+ // through the receipt store below. Bulk-only receipt contexts retain the
1411
+ // checkpoint because direct tool calls cannot use the bulk claim path.
1412
+ this.checkpoint.completedToolBatches = {};
1413
+ }
1386
1414
  // The governance play id keys durable ctx receipts (durableCtxKey), the
1387
1415
  // cycle guard, and per-parent child-call counters. It must be the STABLE
1388
1416
  // play name — not the per-run workflow id — so receipts written by one
@@ -3077,16 +3105,25 @@ export class PlayContextImpl {
3077
3105
  private getCachedToolResult(
3078
3106
  toolId: string,
3079
3107
  rowCacheKey: string,
3108
+ path: 'mapped' | 'direct' = 'mapped',
3080
3109
  ): ToolBatchResult | undefined {
3110
+ if (
3111
+ path === 'direct'
3112
+ ? this.durableDirectToolResultsBackedByReceipts
3113
+ : this.durableMappedToolResultsBackedByReceipts
3114
+ ) {
3115
+ return undefined;
3116
+ }
3081
3117
  return this.checkpoint.completedToolBatches[toolId]?.[rowCacheKey];
3082
3118
  }
3083
3119
 
3084
3120
  private getCachedToolResultCandidate(
3085
3121
  toolId: string,
3086
3122
  rowCacheKeys: readonly string[],
3123
+ path: 'mapped' | 'direct' = 'mapped',
3087
3124
  ): { cacheKey: string; result: ToolBatchResult } | null {
3088
3125
  for (const rowCacheKey of rowCacheKeys) {
3089
- const cached = this.getCachedToolResult(toolId, rowCacheKey);
3126
+ const cached = this.getCachedToolResult(toolId, rowCacheKey, path);
3090
3127
  if (cached?.done) {
3091
3128
  return { cacheKey: rowCacheKey, result: cached };
3092
3129
  }
@@ -3098,7 +3135,15 @@ export class PlayContextImpl {
3098
3135
  toolId: string,
3099
3136
  rowCacheKey: string,
3100
3137
  result: unknown | null,
3138
+ path: 'mapped' | 'direct' = 'mapped',
3101
3139
  ): void {
3140
+ if (
3141
+ path === 'direct'
3142
+ ? this.durableDirectToolResultsBackedByReceipts
3143
+ : this.durableMappedToolResultsBackedByReceipts
3144
+ ) {
3145
+ return;
3146
+ }
3102
3147
  if (!this.checkpoint.completedToolBatches[toolId]) {
3103
3148
  this.checkpoint.completedToolBatches[toolId] = {};
3104
3149
  }
@@ -6349,7 +6394,11 @@ export class PlayContextImpl {
6349
6394
  ? null
6350
6395
  : toolCachePolicy.force
6351
6396
  ? null
6352
- : this.getCachedToolResultCandidate(toolId, checkpointCacheKeys);
6397
+ : this.getCachedToolResultCandidate(
6398
+ toolId,
6399
+ checkpointCacheKeys,
6400
+ 'direct',
6401
+ );
6353
6402
  if (cached) {
6354
6403
  this.log(`Calling tool: ${toolId} recovered from checkpoint`);
6355
6404
  return await this.wrapToolExecutionResult({
@@ -6429,13 +6478,7 @@ export class PlayContextImpl {
6429
6478
  }),
6430
6479
  });
6431
6480
  if (cacheableToolResult) {
6432
- this.checkpoint.completedToolBatches[toolId] = {
6433
- ...(this.checkpoint.completedToolBatches[toolId] ?? {}),
6434
- [directCacheKey]: {
6435
- done: true,
6436
- result: wrapped,
6437
- },
6438
- };
6481
+ this.cacheToolResult(toolId, directCacheKey, wrapped, 'direct');
6439
6482
  this.#options.onBatchComplete?.(this.checkpoint);
6440
6483
  }
6441
6484
  return wrapped;
@@ -7348,23 +7391,27 @@ export class PlayContextImpl {
7348
7391
  const toolSettlements = await Promise.allSettled(
7349
7392
  [...byTool.entries()].map(async ([toolId, requests]) => {
7350
7393
  this.log(`Executing tool batch ${toolId}: ${requests.length} calls`);
7351
- const liveStepResults = new Map<string, unknown>();
7394
+ const successfulLiveStepCallIds = new Set<string>();
7352
7395
 
7353
7396
  const recordToolStep = (stepRequests: ToolCallRequest[]): void => {
7354
7397
  if (stepRequests.length === 0) return;
7355
7398
  const stepResults: PlayStepRowResult[] = stepRequests.map((req) => {
7356
- const hasLiveResult = liveStepResults.has(req.callId);
7357
- const result = hasLiveResult
7358
- ? liveStepResults.get(req.callId)
7359
- : this.getCachedToolResult(toolId, req.cacheKey)?.result;
7399
+ const success =
7400
+ successfulLiveStepCallIds.has(req.callId) ||
7401
+ this.getCachedToolResult(toolId, req.cacheKey)?.result != null;
7360
7402
  return {
7361
7403
  rowId: req.rowId,
7362
- status: result != null ? 'completed' : 'failed',
7363
- success: result != null,
7364
- value: result,
7365
- error: result != null ? null : 'Tool call failed',
7404
+ status: success ? 'completed' : 'failed',
7405
+ success,
7406
+ error: success ? null : 'Tool call failed',
7366
7407
  };
7367
7408
  });
7409
+ // Step traces are lifecycle observability, not a second row/receipt
7410
+ // store. Keep only call ids long enough to record their bounded
7411
+ // status preview.
7412
+ for (const request of stepRequests) {
7413
+ successfulLiveStepCallIds.delete(request.callId);
7414
+ }
7368
7415
  const toolStep = {
7369
7416
  type: 'tool' as const,
7370
7417
  toolId,
@@ -7643,6 +7690,7 @@ export class PlayContextImpl {
7643
7690
  });
7644
7691
  this.cacheToolResult(toolId, request.cacheKey, wrapped);
7645
7692
  for (const waitingRequest of requestsForKey) {
7693
+ successfulLiveStepCallIds.add(waitingRequest.callId);
7646
7694
  const resolver = this.toolCallResolvers.get(
7647
7695
  waitingRequest.callId,
7648
7696
  );
@@ -7822,7 +7870,9 @@ export class PlayContextImpl {
7822
7870
  execution?.jobId,
7823
7871
  execution?.meta,
7824
7872
  );
7825
- liveStepResults.set(owner.callId, result);
7873
+ if (result != null) {
7874
+ successfulLiveStepCallIds.add(owner.callId);
7875
+ }
7826
7876
  resolveLiveFollowers(owner, result);
7827
7877
  recordToolStep([owner]);
7828
7878
  this.#options.onBatchComplete?.(this.checkpoint);
@@ -8110,7 +8160,9 @@ export class PlayContextImpl {
8110
8160
  index += 1
8111
8161
  ) {
8112
8162
  const request = entry.request.memberRequests[index]!;
8113
- liveStepResults.set(request.callId, resolvedResults[index]);
8163
+ if (resolvedResults[index] != null) {
8164
+ successfulLiveStepCallIds.add(request.callId);
8165
+ }
8114
8166
  resolveLiveFollowers(request, resolvedResults[index]);
8115
8167
  }
8116
8168
  }
@@ -8150,7 +8202,9 @@ export class PlayContextImpl {
8150
8202
  for (let index = 0; index < entries.length; index += 1) {
8151
8203
  const entry = entries[index]!;
8152
8204
  const result = resolvedResults[index];
8153
- liveStepResults.set(entry.request.callId, result);
8205
+ if (result != null) {
8206
+ successfulLiveStepCallIds.add(entry.request.callId);
8207
+ }
8154
8208
  resolveLiveFollowers(entry.request, result);
8155
8209
  entry.resolve(result);
8156
8210
  }
package/dist/cli/index.js CHANGED
@@ -718,7 +718,7 @@ var SDK_RELEASE = {
718
718
  // 0.1.253 makes play-page browser opening opt-in and retires --no-open.
719
719
  // 0.1.254 removes the internal operations tree from the published SDK CLI.
720
720
  // Operators use the checkout-local deepline-admin binary instead.
721
- version: "0.1.276",
721
+ version: "0.1.278",
722
722
  contracts: {
723
723
  api: {
724
724
  name: "sdk-http-api",
@@ -27365,43 +27365,6 @@ async function listTools(category, options = {}) {
27365
27365
  }
27366
27366
  return listToolCategories(emitJson, compact);
27367
27367
  }
27368
- async function listProviders(options = {}) {
27369
- const client2 = new DeeplineClient();
27370
- const changed = options.changed === true;
27371
- const emitJson = options.json === true || shouldEmitJson();
27372
- const providers = await client2.listProviders({ changed });
27373
- const render = {
27374
- sections: [
27375
- {
27376
- title: changed ? `${providers.length} recently added providers:` : `${providers.length} providers:`,
27377
- lines: providers.map((provider) => {
27378
- const release2 = provider.releasedAt ? ` - v${provider.version ?? "unknown"} (${provider.releasedAt})` : "";
27379
- return `${provider.provider} (${provider.displayName}) - ${provider.toolCount} tools${release2}`;
27380
- })
27381
- },
27382
- {
27383
- title: "next",
27384
- lines: [
27385
- "Run `deepline tools list <category>` to browse provider tools by category."
27386
- ]
27387
- }
27388
- ]
27389
- };
27390
- printCommandEnvelope(
27391
- {
27392
- providers,
27393
- count: providers.length,
27394
- filters: { changed },
27395
- commandTemplates: {
27396
- list: "deepline tools providers",
27397
- changed: "deepline tools providers --changed"
27398
- },
27399
- render
27400
- },
27401
- { json: emitJson }
27402
- );
27403
- return 0;
27404
- }
27405
27368
  async function searchTools(queryInput, options = {}) {
27406
27369
  const query = queryInput?.trim() ?? "";
27407
27370
  const hasStructuredSearch = Boolean(
@@ -27594,7 +27557,6 @@ Concepts:
27594
27557
  through the plays namespace.
27595
27558
 
27596
27559
  Common commands:
27597
- deepline tools providers --changed --json
27598
27560
  deepline tools search email --json
27599
27561
  deepline tools describe hunter_email_verifier --json
27600
27562
  deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
@@ -27604,28 +27566,6 @@ Output:
27604
27566
  Use execute to run a tool.
27605
27567
  `
27606
27568
  );
27607
- tools.command("providers").description("List discoverable providers and their available tool counts.").addHelpText(
27608
- "after",
27609
- `
27610
- Notes:
27611
- This directory is served by Deepline's provider catalog; it does not require
27612
- cloning a public plugins repository. Use --changed to show recently added
27613
- providers with their catalog version and release date.
27614
-
27615
- Examples:
27616
- deepline tools providers
27617
- deepline tools providers --changed
27618
- deepline tools providers --changed --json
27619
- `
27620
- ).option(
27621
- "--changed",
27622
- "Only list recently added providers with release metadata"
27623
- ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
27624
- process.exitCode = await listProviders({
27625
- changed: Boolean(options.changed),
27626
- json: Boolean(options.json)
27627
- });
27628
- });
27629
27569
  tools.command("list [category]").description("Browse tool categories, or list every tool in a category.").addHelpText(
27630
27570
  "after",
27631
27571
  `
@@ -28019,7 +27959,9 @@ function printMonitorTypeFilters(tool) {
28019
27959
  }
28020
27960
  }
28021
27961
  function printMonitorTypeStreams(tool) {
28022
- const streams = arrayField2(tool, "streams", "output_streams").filter(isRecord9);
27962
+ const streams = arrayField2(tool, "streams", "output_streams").filter(
27963
+ isRecord9
27964
+ );
28023
27965
  if (!streams.length) return;
28024
27966
  console.log("");
28025
27967
  console.log("Filter columns (a play's sqlListeners.where, per stream):");
@@ -29058,6 +29000,83 @@ async function executeTool(args) {
29058
29000
  return 0;
29059
29001
  }
29060
29002
 
29003
+ // src/cli/commands/providers.ts
29004
+ async function listProviders(options = {}) {
29005
+ const client2 = new DeeplineClient();
29006
+ const changed = options.changed === true;
29007
+ const emitJson = options.json === true || shouldEmitJson();
29008
+ const providers = await client2.listProviders({ changed });
29009
+ const render = {
29010
+ sections: [
29011
+ {
29012
+ title: changed ? `${providers.length} recently added providers:` : `${providers.length} providers:`,
29013
+ lines: providers.map((provider) => {
29014
+ const release2 = provider.releasedAt ? ` - v${provider.version ?? "unknown"} (${provider.releasedAt})` : "";
29015
+ return `${provider.provider} (${provider.displayName}) - ${provider.toolCount} tools${release2}`;
29016
+ })
29017
+ },
29018
+ {
29019
+ title: "next",
29020
+ lines: [
29021
+ "Run `deepline tools list <category>` to browse provider tools by category."
29022
+ ]
29023
+ }
29024
+ ]
29025
+ };
29026
+ printCommandEnvelope(
29027
+ {
29028
+ providers,
29029
+ count: providers.length,
29030
+ filters: { changed },
29031
+ commandTemplates: {
29032
+ list: "deepline providers list",
29033
+ changed: "deepline providers list --changed"
29034
+ },
29035
+ render
29036
+ },
29037
+ { json: emitJson }
29038
+ );
29039
+ return 0;
29040
+ }
29041
+ function registerProviderCommands(program) {
29042
+ const providers = program.command("providers").description("Browse the catalog of provider integrations.").addHelpText(
29043
+ "after",
29044
+ `
29045
+ Notes:
29046
+ This directory is served by Deepline's provider catalog; it does not require
29047
+ cloning a public plugins repository. Use --changed to show recently added
29048
+ providers with their catalog version and release date.
29049
+
29050
+ Examples:
29051
+ deepline providers list
29052
+ deepline providers list --changed
29053
+ deepline providers list --changed --json
29054
+ `
29055
+ );
29056
+ providers.command("list").description("List discoverable providers and their available tool counts.").addHelpText(
29057
+ "after",
29058
+ `
29059
+ Notes:
29060
+ The catalog does not require cloning a public plugins repository. Use
29061
+ --changed to show recently added providers with their catalog version and
29062
+ release date.
29063
+
29064
+ Examples:
29065
+ deepline providers list
29066
+ deepline providers list --changed
29067
+ deepline providers list --changed --json
29068
+ `
29069
+ ).option(
29070
+ "--changed",
29071
+ "Only list recently added providers with release metadata"
29072
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
29073
+ process.exitCode = await listProviders({
29074
+ changed: Boolean(options.changed),
29075
+ json: Boolean(options.json)
29076
+ });
29077
+ });
29078
+ }
29079
+
29061
29080
  // src/cli/commands/workflow.ts
29062
29081
  var import_promises5 = require("fs/promises");
29063
29082
  var import_node_path17 = require("path");
@@ -30960,7 +30979,20 @@ function resolvePathCommands(command) {
30960
30979
  function resolvePathCommand(command) {
30961
30980
  return resolvePathCommands(command)[0] ?? null;
30962
30981
  }
30963
- function resolvePersistentGlobalCommand() {
30982
+ function isHomebrewFormulaCommand(path) {
30983
+ let resolvedPath = path;
30984
+ try {
30985
+ resolvedPath = (0, import_node_fs18.realpathSync)(path);
30986
+ } catch {
30987
+ return false;
30988
+ }
30989
+ const parts = resolvedPath.split(/[\\/]+/);
30990
+ const cellarIndex = parts.lastIndexOf("Cellar");
30991
+ return cellarIndex >= 0 && parts[cellarIndex + 1] === "deepline" && parts.slice(cellarIndex + 3).includes("libexec");
30992
+ }
30993
+ function resolvePersistentGlobalCommand(pathClis) {
30994
+ const homebrewCommand = pathClis.find(isHomebrewFormulaCommand);
30995
+ if (homebrewCommand) return homebrewCommand;
30964
30996
  const prefix = (0, import_node_child_process4.spawnSync)("npm", ["prefix", "-g"], { encoding: "utf8" });
30965
30997
  if (prefix.status !== 0) return null;
30966
30998
  const root = String(prefix.stdout ?? "").trim();
@@ -30969,8 +31001,8 @@ function resolvePersistentGlobalCommand() {
30969
31001
  return candidates.find((candidate) => (0, import_node_fs18.existsSync)(candidate)) ?? null;
30970
31002
  }
30971
31003
  function inspectGlobalCliAvailability(input2) {
30972
- const persistentPath = input2 && "persistentGlobalCli" in input2 ? input2.persistentGlobalCli ?? null : resolvePersistentGlobalCommand();
30973
31004
  const pathClis = input2?.pathClis ?? resolvePathCommands("deepline");
31005
+ const persistentPath = input2 && "persistentGlobalCli" in input2 ? input2.persistentGlobalCli ?? null : resolvePersistentGlobalCommand(pathClis);
30974
31006
  const path = persistentPath ? pathClis.find(
30975
31007
  (candidate) => pathsResolveToSameFile(candidate, persistentPath)
30976
31008
  ) ?? null : null;
@@ -32437,11 +32469,10 @@ function shouldDeferSkillsSyncForCommand() {
32437
32469
  const args = process.argv.slice(2);
32438
32470
  const command = args[0];
32439
32471
  const subcommand = args[1];
32440
- if (command === "tools" && ["list", "providers", "search", "grep", "describe", "get"].includes(
32441
- subcommand ?? ""
32442
- )) {
32472
+ if (command === "tools" && ["list", "search", "grep", "describe", "get"].includes(subcommand ?? "")) {
32443
32473
  return true;
32444
32474
  }
32475
+ if (command === "providers" && subcommand === "list") return true;
32445
32476
  return (command === "play" || command === "plays") && subcommand === "run" && args.includes("--json");
32446
32477
  }
32447
32478
  function isLegacyNoopInvocation() {
@@ -32665,7 +32696,7 @@ Common commands:
32665
32696
  deepline plays describe prebuilt/person-linkedin-to-email --json
32666
32697
  deepline plays run my.play.ts --input '{"domain":"stripe.com"}'
32667
32698
  deepline secrets check HUBSPOT_TOKEN
32668
- deepline tools providers --changed --json
32699
+ deepline providers list --changed --json
32669
32700
  deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
32670
32701
  deepline update
32671
32702
 
@@ -32745,6 +32776,7 @@ Exit codes:
32745
32776
  }
32746
32777
  });
32747
32778
  registerAuthCommands(program);
32779
+ registerProviderCommands(program);
32748
32780
  registerToolsCommands(program);
32749
32781
  registerPlayCommands(program);
32750
32782
  registerSessionsCommands(program);
@@ -703,7 +703,7 @@ var SDK_RELEASE = {
703
703
  // 0.1.253 makes play-page browser opening opt-in and retires --no-open.
704
704
  // 0.1.254 removes the internal operations tree from the published SDK CLI.
705
705
  // Operators use the checkout-local deepline-admin binary instead.
706
- version: "0.1.276",
706
+ version: "0.1.278",
707
707
  contracts: {
708
708
  api: {
709
709
  name: "sdk-http-api",
@@ -27413,43 +27413,6 @@ async function listTools(category, options = {}) {
27413
27413
  }
27414
27414
  return listToolCategories(emitJson, compact);
27415
27415
  }
27416
- async function listProviders(options = {}) {
27417
- const client2 = new DeeplineClient();
27418
- const changed = options.changed === true;
27419
- const emitJson = options.json === true || shouldEmitJson();
27420
- const providers = await client2.listProviders({ changed });
27421
- const render = {
27422
- sections: [
27423
- {
27424
- title: changed ? `${providers.length} recently added providers:` : `${providers.length} providers:`,
27425
- lines: providers.map((provider) => {
27426
- const release2 = provider.releasedAt ? ` - v${provider.version ?? "unknown"} (${provider.releasedAt})` : "";
27427
- return `${provider.provider} (${provider.displayName}) - ${provider.toolCount} tools${release2}`;
27428
- })
27429
- },
27430
- {
27431
- title: "next",
27432
- lines: [
27433
- "Run `deepline tools list <category>` to browse provider tools by category."
27434
- ]
27435
- }
27436
- ]
27437
- };
27438
- printCommandEnvelope(
27439
- {
27440
- providers,
27441
- count: providers.length,
27442
- filters: { changed },
27443
- commandTemplates: {
27444
- list: "deepline tools providers",
27445
- changed: "deepline tools providers --changed"
27446
- },
27447
- render
27448
- },
27449
- { json: emitJson }
27450
- );
27451
- return 0;
27452
- }
27453
27416
  async function searchTools(queryInput, options = {}) {
27454
27417
  const query = queryInput?.trim() ?? "";
27455
27418
  const hasStructuredSearch = Boolean(
@@ -27642,7 +27605,6 @@ Concepts:
27642
27605
  through the plays namespace.
27643
27606
 
27644
27607
  Common commands:
27645
- deepline tools providers --changed --json
27646
27608
  deepline tools search email --json
27647
27609
  deepline tools describe hunter_email_verifier --json
27648
27610
  deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
@@ -27652,28 +27614,6 @@ Output:
27652
27614
  Use execute to run a tool.
27653
27615
  `
27654
27616
  );
27655
- tools.command("providers").description("List discoverable providers and their available tool counts.").addHelpText(
27656
- "after",
27657
- `
27658
- Notes:
27659
- This directory is served by Deepline's provider catalog; it does not require
27660
- cloning a public plugins repository. Use --changed to show recently added
27661
- providers with their catalog version and release date.
27662
-
27663
- Examples:
27664
- deepline tools providers
27665
- deepline tools providers --changed
27666
- deepline tools providers --changed --json
27667
- `
27668
- ).option(
27669
- "--changed",
27670
- "Only list recently added providers with release metadata"
27671
- ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
27672
- process.exitCode = await listProviders({
27673
- changed: Boolean(options.changed),
27674
- json: Boolean(options.json)
27675
- });
27676
- });
27677
27617
  tools.command("list [category]").description("Browse tool categories, or list every tool in a category.").addHelpText(
27678
27618
  "after",
27679
27619
  `
@@ -28067,7 +28007,9 @@ function printMonitorTypeFilters(tool) {
28067
28007
  }
28068
28008
  }
28069
28009
  function printMonitorTypeStreams(tool) {
28070
- const streams = arrayField2(tool, "streams", "output_streams").filter(isRecord9);
28010
+ const streams = arrayField2(tool, "streams", "output_streams").filter(
28011
+ isRecord9
28012
+ );
28071
28013
  if (!streams.length) return;
28072
28014
  console.log("");
28073
28015
  console.log("Filter columns (a play's sqlListeners.where, per stream):");
@@ -29106,6 +29048,83 @@ async function executeTool(args) {
29106
29048
  return 0;
29107
29049
  }
29108
29050
 
29051
+ // src/cli/commands/providers.ts
29052
+ async function listProviders(options = {}) {
29053
+ const client2 = new DeeplineClient();
29054
+ const changed = options.changed === true;
29055
+ const emitJson = options.json === true || shouldEmitJson();
29056
+ const providers = await client2.listProviders({ changed });
29057
+ const render = {
29058
+ sections: [
29059
+ {
29060
+ title: changed ? `${providers.length} recently added providers:` : `${providers.length} providers:`,
29061
+ lines: providers.map((provider) => {
29062
+ const release2 = provider.releasedAt ? ` - v${provider.version ?? "unknown"} (${provider.releasedAt})` : "";
29063
+ return `${provider.provider} (${provider.displayName}) - ${provider.toolCount} tools${release2}`;
29064
+ })
29065
+ },
29066
+ {
29067
+ title: "next",
29068
+ lines: [
29069
+ "Run `deepline tools list <category>` to browse provider tools by category."
29070
+ ]
29071
+ }
29072
+ ]
29073
+ };
29074
+ printCommandEnvelope(
29075
+ {
29076
+ providers,
29077
+ count: providers.length,
29078
+ filters: { changed },
29079
+ commandTemplates: {
29080
+ list: "deepline providers list",
29081
+ changed: "deepline providers list --changed"
29082
+ },
29083
+ render
29084
+ },
29085
+ { json: emitJson }
29086
+ );
29087
+ return 0;
29088
+ }
29089
+ function registerProviderCommands(program) {
29090
+ const providers = program.command("providers").description("Browse the catalog of provider integrations.").addHelpText(
29091
+ "after",
29092
+ `
29093
+ Notes:
29094
+ This directory is served by Deepline's provider catalog; it does not require
29095
+ cloning a public plugins repository. Use --changed to show recently added
29096
+ providers with their catalog version and release date.
29097
+
29098
+ Examples:
29099
+ deepline providers list
29100
+ deepline providers list --changed
29101
+ deepline providers list --changed --json
29102
+ `
29103
+ );
29104
+ providers.command("list").description("List discoverable providers and their available tool counts.").addHelpText(
29105
+ "after",
29106
+ `
29107
+ Notes:
29108
+ The catalog does not require cloning a public plugins repository. Use
29109
+ --changed to show recently added providers with their catalog version and
29110
+ release date.
29111
+
29112
+ Examples:
29113
+ deepline providers list
29114
+ deepline providers list --changed
29115
+ deepline providers list --changed --json
29116
+ `
29117
+ ).option(
29118
+ "--changed",
29119
+ "Only list recently added providers with release metadata"
29120
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
29121
+ process.exitCode = await listProviders({
29122
+ changed: Boolean(options.changed),
29123
+ json: Boolean(options.json)
29124
+ });
29125
+ });
29126
+ }
29127
+
29109
29128
  // src/cli/commands/workflow.ts
29110
29129
  import { mkdir as mkdir4, readFile as readFile2, writeFile as writeFile4 } from "fs/promises";
29111
29130
  import { dirname as dirname11, join as join13, resolve as resolve12 } from "path";
@@ -31025,7 +31044,20 @@ function resolvePathCommands(command) {
31025
31044
  function resolvePathCommand(command) {
31026
31045
  return resolvePathCommands(command)[0] ?? null;
31027
31046
  }
31028
- function resolvePersistentGlobalCommand() {
31047
+ function isHomebrewFormulaCommand(path) {
31048
+ let resolvedPath = path;
31049
+ try {
31050
+ resolvedPath = realpathSync4(path);
31051
+ } catch {
31052
+ return false;
31053
+ }
31054
+ const parts = resolvedPath.split(/[\\/]+/);
31055
+ const cellarIndex = parts.lastIndexOf("Cellar");
31056
+ return cellarIndex >= 0 && parts[cellarIndex + 1] === "deepline" && parts.slice(cellarIndex + 3).includes("libexec");
31057
+ }
31058
+ function resolvePersistentGlobalCommand(pathClis) {
31059
+ const homebrewCommand = pathClis.find(isHomebrewFormulaCommand);
31060
+ if (homebrewCommand) return homebrewCommand;
31029
31061
  const prefix = spawnSync("npm", ["prefix", "-g"], { encoding: "utf8" });
31030
31062
  if (prefix.status !== 0) return null;
31031
31063
  const root = String(prefix.stdout ?? "").trim();
@@ -31034,8 +31066,8 @@ function resolvePersistentGlobalCommand() {
31034
31066
  return candidates.find((candidate) => existsSync13(candidate)) ?? null;
31035
31067
  }
31036
31068
  function inspectGlobalCliAvailability(input2) {
31037
- const persistentPath = input2 && "persistentGlobalCli" in input2 ? input2.persistentGlobalCli ?? null : resolvePersistentGlobalCommand();
31038
31069
  const pathClis = input2?.pathClis ?? resolvePathCommands("deepline");
31070
+ const persistentPath = input2 && "persistentGlobalCli" in input2 ? input2.persistentGlobalCli ?? null : resolvePersistentGlobalCommand(pathClis);
31039
31071
  const path = persistentPath ? pathClis.find(
31040
31072
  (candidate) => pathsResolveToSameFile(candidate, persistentPath)
31041
31073
  ) ?? null : null;
@@ -32508,11 +32540,10 @@ function shouldDeferSkillsSyncForCommand() {
32508
32540
  const args = process.argv.slice(2);
32509
32541
  const command = args[0];
32510
32542
  const subcommand = args[1];
32511
- if (command === "tools" && ["list", "providers", "search", "grep", "describe", "get"].includes(
32512
- subcommand ?? ""
32513
- )) {
32543
+ if (command === "tools" && ["list", "search", "grep", "describe", "get"].includes(subcommand ?? "")) {
32514
32544
  return true;
32515
32545
  }
32546
+ if (command === "providers" && subcommand === "list") return true;
32516
32547
  return (command === "play" || command === "plays") && subcommand === "run" && args.includes("--json");
32517
32548
  }
32518
32549
  function isLegacyNoopInvocation() {
@@ -32736,7 +32767,7 @@ Common commands:
32736
32767
  deepline plays describe prebuilt/person-linkedin-to-email --json
32737
32768
  deepline plays run my.play.ts --input '{"domain":"stripe.com"}'
32738
32769
  deepline secrets check HUBSPOT_TOKEN
32739
- deepline tools providers --changed --json
32770
+ deepline providers list --changed --json
32740
32771
  deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
32741
32772
  deepline update
32742
32773
 
@@ -32816,6 +32847,7 @@ Exit codes:
32816
32847
  }
32817
32848
  });
32818
32849
  registerAuthCommands(program);
32850
+ registerProviderCommands(program);
32819
32851
  registerToolsCommands(program);
32820
32852
  registerPlayCommands(program);
32821
32853
  registerSessionsCommands(program);
package/dist/index.js CHANGED
@@ -438,7 +438,7 @@ var SDK_RELEASE = {
438
438
  // 0.1.253 makes play-page browser opening opt-in and retires --no-open.
439
439
  // 0.1.254 removes the internal operations tree from the published SDK CLI.
440
440
  // Operators use the checkout-local deepline-admin binary instead.
441
- version: "0.1.276",
441
+ version: "0.1.278",
442
442
  contracts: {
443
443
  api: {
444
444
  name: "sdk-http-api",
package/dist/index.mjs CHANGED
@@ -367,7 +367,7 @@ var SDK_RELEASE = {
367
367
  // 0.1.253 makes play-page browser opening opt-in and retires --no-open.
368
368
  // 0.1.254 removes the internal operations tree from the published SDK CLI.
369
369
  // Operators use the checkout-local deepline-admin binary instead.
370
- version: "0.1.276",
370
+ version: "0.1.278",
371
371
  contracts: {
372
372
  api: {
373
373
  name: "sdk-http-api",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepline",
3
- "version": "0.1.276",
3
+ "version": "0.1.278",
4
4
  "description": "Deepline SDK + CLI — B2B data enrichment powered by durable cloud execution",
5
5
  "license": "MIT",
6
6
  "repository": {