@zeroxyz/cli 1.5.0 → 1.7.0

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.
Files changed (2) hide show
  1. package/dist/index.js +390 -57
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import * as nc from 'crypto';
6
6
  import nc__default, { randomUUID, randomBytes as randomBytes$1, createHash } from 'crypto';
7
7
  import os, { homedir } from 'os';
8
8
  import y2, { stdin, stdout } from 'process';
9
- import childProcess, { execFile as execFile$1 } from 'child_process';
9
+ import childProcess, { execFile as execFile$1, spawnSync } from 'child_process';
10
10
  import fs5, { constants } from 'fs/promises';
11
11
  import util2, { promisify } from 'util';
12
12
  import fs3, { createReadStream, existsSync, readFileSync, mkdirSync, writeFileSync, chmodSync, lstatSync, readlinkSync, rmSync, readdirSync } from 'fs';
@@ -76582,7 +76582,7 @@ init_esm_shims();
76582
76582
 
76583
76583
  // package.json
76584
76584
  var package_default = {
76585
- version: "1.5.0"};
76585
+ version: "1.7.0"};
76586
76586
 
76587
76587
  // src/app.ts
76588
76588
  init_esm_shims();
@@ -77563,6 +77563,18 @@ var authExchangeCommand = (appContext) => new Command("exchange").description(
77563
77563
  process.exitCode = 1;
77564
77564
  }
77565
77565
  });
77566
+ var ensureAuthenticated = async (client, shouldOpen = true) => {
77567
+ const session4 = readConfig(getConfigPath()).session;
77568
+ if (session4) return;
77569
+ process.stdout.write(
77570
+ "\nZero requires authentication before handing off to Claude.\n\n"
77571
+ );
77572
+ await runInteractive(client, shouldOpen);
77573
+ if (!readConfig(getConfigPath()).session) {
77574
+ process.exitCode = 1;
77575
+ process.exit(1);
77576
+ }
77577
+ };
77566
77578
  var authCommand = (appContext) => {
77567
77579
  const cmd = new Command("auth").description("Authentication commands");
77568
77580
  cmd.addCommand(authLoginCommand(appContext));
@@ -77578,7 +77590,7 @@ init_esm_shims();
77578
77590
  // ../sdk/dist/index.js
77579
77591
  init_esm_shims();
77580
77592
 
77581
- // ../sdk/dist/chunk-RPL7VC32.js
77593
+ // ../sdk/dist/chunk-3YKWO4B2.js
77582
77594
  init_esm_shims();
77583
77595
 
77584
77596
  // ../../node_modules/.pnpm/viem@2.52.2_bufferutil@4.1.0_typescript@5.9.3_utf-8-validate@6.0.6_zod@4.3.6/node_modules/viem/_esm/index.js
@@ -143069,6 +143081,76 @@ var ZeroConfigurationError = class extends ZeroError {
143069
143081
  this.name = "ZeroConfigurationError";
143070
143082
  }
143071
143083
  };
143084
+ var asSchemaNode = (v) => v && typeof v === "object" && !Array.isArray(v) ? v : null;
143085
+ var extractInputEnvelope = (bodySchema, method) => {
143086
+ const root = asSchemaNode(bodySchema);
143087
+ if (!root) return {};
143088
+ const props = asSchemaNode(root.properties);
143089
+ if (!props) return {};
143090
+ const inputProps = asSchemaNode(asSchemaNode(props.input)?.properties);
143091
+ if (inputProps) {
143092
+ return {
143093
+ queryParams: asSchemaNode(inputProps.queryParams) ?? void 0,
143094
+ body: asSchemaNode(inputProps.body) ?? void 0
143095
+ };
143096
+ }
143097
+ const upperMethod = method.toUpperCase();
143098
+ const isGetLike = upperMethod === "GET" || upperMethod === "DELETE";
143099
+ return isGetLike ? { queryParams: root } : { body: root };
143100
+ };
143101
+ var unwrapTransportEnvelope = (request22) => {
143102
+ const input = asSchemaNode(asSchemaNode(request22)?.input);
143103
+ if (!input || input.type !== "http") return request22;
143104
+ const body = input.body;
143105
+ const hasBody = body !== void 0 && body !== null && !(typeof body === "object" && Object.keys(body).length === 0);
143106
+ if (hasBody) return body;
143107
+ const qp = asSchemaNode(input.queryParams);
143108
+ if (qp && Object.keys(qp).length > 0) return qp;
143109
+ return null;
143110
+ };
143111
+ var GET_LIKE = /* @__PURE__ */ new Set(["GET", "HEAD", "DELETE"]);
143112
+ var appendQueryParams = (url4, params) => {
143113
+ const entries = Object.entries(params).filter(([, v]) => v != null);
143114
+ if (entries.length === 0) return url4;
143115
+ try {
143116
+ const u2 = new URL(url4);
143117
+ for (const [k3, v] of entries) u2.searchParams.set(k3, String(v));
143118
+ return u2.toString();
143119
+ } catch {
143120
+ const qs = entries.map(
143121
+ ([k3, v]) => `${encodeURIComponent(k3)}=${encodeURIComponent(String(v))}`
143122
+ ).join("&");
143123
+ return url4.includes("?") ? `${url4}&${qs}` : `${url4}?${qs}`;
143124
+ }
143125
+ };
143126
+ var normalizeTransportEnvelopeRequest = (url4, opts) => {
143127
+ const { method, body } = opts;
143128
+ if (typeof body !== "string") return { url: url4, method, body };
143129
+ let parsed;
143130
+ try {
143131
+ parsed = JSON.parse(body);
143132
+ } catch {
143133
+ return { url: url4, method, body };
143134
+ }
143135
+ const input = asSchemaNode(asSchemaNode(parsed)?.input);
143136
+ if (!input || input.type !== "http") return { url: url4, method, body };
143137
+ const innerBody = input.body;
143138
+ const hasInnerBody = innerBody !== void 0 && innerBody !== null && !(typeof innerBody === "object" && Object.keys(innerBody).length === 0);
143139
+ const verb = (method ?? (typeof input.method === "string" ? input.method : void 0) ?? (hasInnerBody ? "POST" : "GET")).toUpperCase();
143140
+ if (GET_LIKE.has(verb)) {
143141
+ const qp = asSchemaNode(input.queryParams);
143142
+ return {
143143
+ url: qp ? appendQueryParams(url4, qp) : url4,
143144
+ method: verb,
143145
+ body: void 0
143146
+ };
143147
+ }
143148
+ return {
143149
+ url: url4,
143150
+ method: verb,
143151
+ body: hasInnerBody ? JSON.stringify(innerBody) : void 0
143152
+ };
143153
+ };
143072
143154
  var KNOWN_EIP712_DOMAINS = {
143073
143155
  // Base mainnet USDC. On-chain `name()` is "USD Coin" (NOT "USDC")
143074
143156
  // — verified via the contract's name() / version().
@@ -144080,7 +144162,7 @@ var Payments = class {
144080
144162
  };
144081
144163
  };
144082
144164
  var package_default2 = {
144083
- version: "0.4.0"
144165
+ version: "0.6.0"
144084
144166
  };
144085
144167
  var SDK_VERSION2 = package_default2.version;
144086
144168
  var userWalletDtoSchema = external_exports3.object({
@@ -144726,6 +144808,11 @@ var capabilityResponseSchema = external_exports3.object({
144726
144808
  lastUsedAt: external_exports3.string().nullable().optional(),
144727
144809
  lastSuccessfullyRanAt: external_exports3.string().nullable().optional()
144728
144810
  });
144811
+ var resolveCapabilityResponseSchema = external_exports3.object({
144812
+ capabilityId: external_exports3.string(),
144813
+ capabilitySlug: external_exports3.string(),
144814
+ matchedVia: external_exports3.enum(["exact", "template"])
144815
+ });
144729
144816
  var Capabilities = class {
144730
144817
  constructor(client) {
144731
144818
  this.client = client;
@@ -144740,6 +144827,31 @@ var Capabilities = class {
144740
144827
  },
144741
144828
  capabilityResponseSchema
144742
144829
  );
144830
+ // Resolve a raw endpoint URL + method back to the capability that owns it,
144831
+ // for the `zero fetch <url>` case where the client has no local search
144832
+ // context to match against (a memoized/cross-session URL). Returns null on
144833
+ // 404 — i.e. no match or an ambiguous multi-match, both of which the server
144834
+ // reports as 404 (resolveByUrl fails closed rather than mis-attribute).
144835
+ // The URL travels in the POST body so it stays out of access logs and is
144836
+ // never stored; the caller uses the returned capabilityId to record an
144837
+ // attributed run without the URL ever touching the run row (ZERO-335).
144838
+ resolveByUrl = async (url4, method, opts = {}) => {
144839
+ try {
144840
+ return await request2(
144841
+ this.client,
144842
+ {
144843
+ method: "POST",
144844
+ path: "/v1/capabilities/resolve",
144845
+ body: { url: url4, method },
144846
+ signal: opts.signal
144847
+ },
144848
+ resolveCapabilityResponseSchema
144849
+ );
144850
+ } catch (err) {
144851
+ if (err instanceof ZeroApiError && err.status === 404) return null;
144852
+ throw err;
144853
+ }
144854
+ };
144743
144855
  };
144744
144856
  var createRunResponseSchema = external_exports3.object({
144745
144857
  runId: external_exports3.string()
@@ -144765,6 +144877,30 @@ var listRunsResponseSchema = external_exports3.object({
144765
144877
  runs: external_exports3.array(runListItemSchema),
144766
144878
  nextCursor: external_exports3.string().nullable()
144767
144879
  });
144880
+ var runDetailSchema = external_exports3.object({
144881
+ runId: external_exports3.string(),
144882
+ status: external_exports3.number().nullable(),
144883
+ latencyMs: external_exports3.number().nullable(),
144884
+ errorClass: external_exports3.string().nullable(),
144885
+ createdAt: external_exports3.coerce.date(),
144886
+ cost: external_exports3.object({ amount: external_exports3.string(), asset: external_exports3.string().nullable() }).nullable(),
144887
+ payment: external_exports3.object({
144888
+ protocol: external_exports3.string(),
144889
+ chain: external_exports3.string().nullable(),
144890
+ txHash: external_exports3.string().nullable(),
144891
+ mode: external_exports3.string().nullable()
144892
+ }).nullable(),
144893
+ capability: external_exports3.object({
144894
+ uid: external_exports3.string(),
144895
+ slug: external_exports3.string(),
144896
+ name: external_exports3.string(),
144897
+ url: external_exports3.string(),
144898
+ method: external_exports3.string(),
144899
+ whatItDoes: external_exports3.string().nullable(),
144900
+ tags: external_exports3.array(external_exports3.string())
144901
+ }),
144902
+ reviewed: external_exports3.boolean()
144903
+ });
144768
144904
  var createReviewResponseSchema = external_exports3.object({
144769
144905
  reviewId: external_exports3.string(),
144770
144906
  recorded: external_exports3.boolean(),
@@ -144844,6 +144980,15 @@ var Runs = class {
144844
144980
  listRunsResponseSchema
144845
144981
  );
144846
144982
  };
144983
+ get = (runId, opts = {}) => request2(
144984
+ this.client,
144985
+ {
144986
+ method: "GET",
144987
+ path: `/v1/runs/${runId}`,
144988
+ signal: opts.signal
144989
+ },
144990
+ runDetailSchema
144991
+ );
144847
144992
  review = (input, opts = {}) => request2(
144848
144993
  this.client,
144849
144994
  {
@@ -145312,14 +145457,17 @@ var resolveRecordingClient = (client, opts) => {
145312
145457
  const canRecord = opts.account !== void 0 || credentials.kind === "account" || credentials.kind === "session";
145313
145458
  return { recordingClient, canRecord };
145314
145459
  };
145315
- var recordErrorFetchRun = async (client, opts, result) => {
145316
- if (opts.capabilityId === void 0) return;
145460
+ var recordErrorFetchRun = async (client, opts, result, capabilityIdOverride) => {
145461
+ const effectiveCapId = opts.capabilityId;
145462
+ if (effectiveCapId === void 0) return;
145317
145463
  const { recordingClient, canRecord } = resolveRecordingClient(client, opts);
145318
145464
  if (!canRecord) return;
145465
+ const fetchOriginForRecord = opts.capabilityId === void 0 ? "direct_url" : opts.fetchOrigin;
145319
145466
  try {
145320
145467
  const created = await recordingClient.runs.create({
145321
- capabilityId: opts.capabilityId,
145468
+ capabilityId: effectiveCapId,
145322
145469
  ...opts.searchId && { searchId: opts.searchId },
145470
+ ...fetchOriginForRecord && { fetchOrigin: fetchOriginForRecord },
145323
145471
  ...result.status !== null && { status: result.status },
145324
145472
  latencyMs: result.latencyMs,
145325
145473
  ...opts.requestSchema && { requestSchema: opts.requestSchema }
@@ -145329,7 +145477,7 @@ var recordErrorFetchRun = async (client, opts, result) => {
145329
145477
  } catch {
145330
145478
  }
145331
145479
  };
145332
- var recordTimeoutRun = async (client, opts, err, startedAt, capabilityIdRequested) => {
145480
+ var recordTimeoutRun = async (client, opts, err, startedAt, capabilityIdRequested, capabilityIdOverride) => {
145333
145481
  const result = errorFetchResult(
145334
145482
  startedAt,
145335
145483
  err.message,
@@ -145365,12 +145513,23 @@ var withDefaultContentType = (headers, body) => {
145365
145513
  var clientFetch = async (client, url4, opts = {}) => {
145366
145514
  const startedAt = Date.now();
145367
145515
  const capabilityIdRequested = opts.capabilityId !== void 0;
145368
- const method = opts.method ?? (opts.body !== void 0 ? "POST" : "GET");
145369
- const probeHeaders = withDefaultContentType(opts.headers, opts.body);
145516
+ const normalized = normalizeTransportEnvelopeRequest(url4, {
145517
+ method: opts.method,
145518
+ body: opts.body
145519
+ });
145520
+ const requestUrl = normalized.url;
145521
+ const requestBody = normalized.body;
145522
+ const method = normalized.method ?? (requestBody !== void 0 ? "POST" : "GET");
145523
+ const { canRecord: canRecordForResolve } = resolveRecordingClient(
145524
+ client,
145525
+ opts
145526
+ );
145527
+ const resolvePromise = !capabilityIdRequested && canRecordForResolve ? client.capabilities.resolveByUrl(redactUrl2(requestUrl), method).catch(() => null) : Promise.resolve(null);
145528
+ const probeHeaders = withDefaultContentType(opts.headers, requestBody);
145370
145529
  const requestInit = {
145371
145530
  method,
145372
145531
  headers: probeHeaders,
145373
- body: opts.body,
145532
+ body: requestBody,
145374
145533
  signal: opts.signal
145375
145534
  };
145376
145535
  const configuredFetch = buildConfiguredFetch(client, {
@@ -145381,7 +145540,7 @@ var clientFetch = async (client, url4, opts = {}) => {
145381
145540
  const skipReasons = [];
145382
145541
  const warnings = [];
145383
145542
  try {
145384
- response = await configuredFetch(url4, requestInit);
145543
+ response = await configuredFetch(requestUrl, requestInit);
145385
145544
  } catch (err) {
145386
145545
  if (err instanceof ZeroTimeoutError) {
145387
145546
  await recordTimeoutRun(
@@ -145411,13 +145570,13 @@ var clientFetch = async (client, url4, opts = {}) => {
145411
145570
  const payCall = requirement.protocol === "x402" ? client.payments.pay : client.payments.payMpp;
145412
145571
  try {
145413
145572
  const paid = await payCall({
145414
- url: url4,
145573
+ url: requestUrl,
145415
145574
  method,
145416
145575
  // Fresh clone for the paid retry — same rationale as
145417
145576
  // the probe-side clone above. Re-derives the default
145418
145577
  // Content-Type so the paid leg matches the probe.
145419
- headers: withDefaultContentType(opts.headers, opts.body),
145420
- body: opts.body,
145578
+ headers: withDefaultContentType(opts.headers, requestBody),
145579
+ body: requestBody,
145421
145580
  maxPay: opts.maxPay,
145422
145581
  account: opts.account,
145423
145582
  signal: opts.signal,
@@ -145557,7 +145716,15 @@ var clientFetch = async (client, url4, opts = {}) => {
145557
145716
  else if (closeFailed)
145558
145717
  skipReasons.push(FETCH_SKIP_REASONS.mppSessionCloseFailedNotRecorded);
145559
145718
  }
145560
- if (opts.capabilityId !== void 0 && !paidButStill402 && !closeFailed) {
145719
+ const resolvedCap = await resolvePromise;
145720
+ const effectiveCapabilityId = opts.capabilityId ?? resolvedCap?.capabilityId;
145721
+ const capabilityResolution = !capabilityIdRequested && canRecordForResolve ? resolvedCap !== null ? {
145722
+ resolved: true,
145723
+ capabilityId: resolvedCap.capabilityId,
145724
+ capabilitySlug: resolvedCap.capabilitySlug,
145725
+ matchedVia: resolvedCap.matchedVia
145726
+ } : { resolved: false } : void 0;
145727
+ if (effectiveCapabilityId !== void 0 && !paidButStill402 && !closeFailed) {
145561
145728
  const { recordingClient, canRecord } = resolveRecordingClient(client, opts);
145562
145729
  if (!canRecord) {
145563
145730
  skipReasons.push("no_credentials");
@@ -145577,8 +145744,11 @@ var clientFetch = async (client, url4, opts = {}) => {
145577
145744
  }
145578
145745
  }
145579
145746
  const result2 = await recordingClient.runs.create({
145580
- capabilityId: opts.capabilityId,
145747
+ capabilityId: effectiveCapabilityId,
145581
145748
  searchId: opts.searchId,
145749
+ // Auto-resolved runs are always direct_url — they only fire when
145750
+ // no capabilityId was supplied (the direct_url path by definition).
145751
+ ...opts.capabilityId === void 0 ? { fetchOrigin: "direct_url" } : opts.fetchOrigin && { fetchOrigin: opts.fetchOrigin },
145582
145752
  status: response.status,
145583
145753
  latencyMs,
145584
145754
  ...opts.requestSchema && { requestSchema: opts.requestSchema },
@@ -145611,7 +145781,7 @@ var clientFetch = async (client, url4, opts = {}) => {
145611
145781
  message: "Failed to record run for fetch",
145612
145782
  meta: {
145613
145783
  url: redactUrl2(url4),
145614
- capabilityId: opts.capabilityId,
145784
+ capabilityId: effectiveCapabilityId,
145615
145785
  error: errorMessage22,
145616
145786
  errorCode: code
145617
145787
  }
@@ -145639,6 +145809,8 @@ var clientFetch = async (client, url4, opts = {}) => {
145639
145809
  result.runTrackingSkipped = skipReasons;
145640
145810
  }
145641
145811
  if (warnings.length > 0) result.warnings = warnings;
145812
+ if (capabilityResolution !== void 0)
145813
+ result.capabilityResolution = capabilityResolution;
145642
145814
  return result;
145643
145815
  };
145644
145816
  var searchResultSchema = external_exports3.object({
@@ -146582,7 +146754,7 @@ var fetchCommand = (appContext) => new Command("fetch").description(
146582
146754
  headers["content-type"] = Buffer.isBuffer(resolvedBody) ? sniffJsonShape(resolvedBody) ? "application/json" : "application/octet-stream" : "application/json";
146583
146755
  }
146584
146756
  const log2 = (msg) => console.error(` ${msg}`);
146585
- const method = options.method ? options.method.toUpperCase() : resolvedMethodFromCapability && !resolvedBody ? resolvedMethodFromCapability.toUpperCase() : resolvedBody ? "POST" : "GET";
146757
+ const method = options.method ? options.method.toUpperCase() : resolvedMethodFromCapability ? resolvedMethodFromCapability.toUpperCase() : resolvedBody ? "POST" : "GET";
146586
146758
  const explicitCapabilityCtx = options.capability ? stateService.findSearchContextByCapability(options.capability) : null;
146587
146759
  const urlCtx = stateService.findSearchContextByUrl(resolvedUrl, {
146588
146760
  matchTemplate: (template) => {
@@ -146595,8 +146767,8 @@ var fetchCommand = (appContext) => new Command("fetch").description(
146595
146767
  });
146596
146768
  const matchCtx = explicitCapabilityCtx ?? urlCtx;
146597
146769
  const capabilityId = options.capability ?? matchCtx?.capabilityId ?? null;
146598
- const capabilityUid = matchCtx?.capabilityUid ?? null;
146599
- const capabilitySlug = matchCtx?.capabilitySlug ?? null;
146770
+ let capabilityUid = matchCtx?.capabilityUid ?? null;
146771
+ let capabilitySlug = matchCtx?.capabilitySlug ?? null;
146600
146772
  const searchId = matchCtx?.searchId;
146601
146773
  const resultRank = matchCtx?.resultRank;
146602
146774
  const fetchOrigin = matchCtx ? "from_search" : options.capability ? "direct_slug" : "direct_url";
@@ -146607,23 +146779,10 @@ var fetchCommand = (appContext) => new Command("fetch").description(
146607
146779
  "no wallet configured (run `zero auth login`, or `zero wallet set <key>` / set ZERO_PRIVATE_KEY)"
146608
146780
  );
146609
146781
  }
146610
- if (!capabilityId) {
146782
+ if (!capabilityId && !walletAddress) {
146611
146783
  cliSkipReasons.push(
146612
146784
  "no capability resolved \u2014 pass --capability <uid|slug> or run `zero search` first so the URL can be matched"
146613
146785
  );
146614
- if (!options.capability) {
146615
- const lastSearch = stateService.loadLastSearch();
146616
- const cached2 = lastSearch?.capabilities ?? [];
146617
- analyticsService.capture("capability_resolution_missed", {
146618
- url: redactUrl(resolvedUrl),
146619
- method,
146620
- hasLastSearch: lastSearch !== null,
146621
- lastSearchSize: cached2.length,
146622
- lastSearchHasTemplates: cached2.some(
146623
- (c) => Boolean(c.urlTemplate)
146624
- )
146625
- });
146626
- }
146627
146786
  }
146628
146787
  let requestSchema;
146629
146788
  if (typeof resolvedBody === "string") {
@@ -146659,6 +146818,11 @@ var fetchCommand = (appContext) => new Command("fetch").description(
146659
146818
  // and omitting here keeps result.runTrackingSkipped clean.
146660
146819
  ...capabilityId && walletAddress && { capabilityId },
146661
146820
  ...searchId && { searchId },
146821
+ // Stamp how the agent arrived (from_search | direct_slug |
146822
+ // direct_url) onto the run's metadata so direct execution is
146823
+ // distinguishable from search-driven runs server-side. Only
146824
+ // when a run is actually recorded (capabilityId + wallet).
146825
+ ...capabilityId && walletAddress && { fetchOrigin },
146662
146826
  ...requestSchema && { requestSchema },
146663
146827
  deriveRunMetadata: ({ bodyRaw: bodyRaw2, bodyEncoding: bodyEncoding2 }) => {
146664
146828
  if (bodyRaw2 && bodyEncoding2 !== "base64") {
@@ -146693,7 +146857,8 @@ var fetchCommand = (appContext) => new Command("fetch").description(
146693
146857
  upstreamError,
146694
146858
  warnings: sdkWarnings,
146695
146859
  runTrackingSkipped: sdkSkipReasons,
146696
- error: resultError
146860
+ error: resultError,
146861
+ capabilityResolution
146697
146862
  } = result;
146698
146863
  const isBinary = bodyEncoding === "base64";
146699
146864
  const bodyBytes = isBinary && bodyRaw ? Buffer.from(bodyRaw, "base64") : void 0;
@@ -146765,6 +146930,36 @@ var fetchCommand = (appContext) => new Command("fetch").description(
146765
146930
  log2(`Warning: ${w2}`);
146766
146931
  }
146767
146932
  }
146933
+ if (fetchOrigin === "direct_url") {
146934
+ if (capabilityResolution?.resolved) {
146935
+ capabilityUid = capabilityResolution.capabilityId ?? capabilityUid;
146936
+ capabilitySlug = capabilityResolution.capabilitySlug ?? capabilitySlug;
146937
+ analyticsService.capture("capability_resolution_recovered", {
146938
+ url: redactUrl(resolvedUrl),
146939
+ method,
146940
+ capabilityUid: capabilityResolution.capabilityId,
146941
+ capabilitySlug: capabilityResolution.capabilitySlug,
146942
+ matchedVia: capabilityResolution.matchedVia
146943
+ });
146944
+ } else {
146945
+ if (walletAddress && !runId) {
146946
+ cliSkipReasons.push(
146947
+ "no capability resolved \u2014 pass --capability <uid|slug> or run `zero search` first so the URL can be matched"
146948
+ );
146949
+ }
146950
+ const lastSearch = stateService.loadLastSearch();
146951
+ const cached2 = lastSearch?.capabilities ?? [];
146952
+ analyticsService.capture("capability_resolution_missed", {
146953
+ url: redactUrl(resolvedUrl),
146954
+ method,
146955
+ hasLastSearch: lastSearch !== null,
146956
+ lastSearchSize: cached2.length,
146957
+ lastSearchHasTemplates: cached2.some(
146958
+ (c) => Boolean(c.urlTemplate)
146959
+ )
146960
+ });
146961
+ }
146962
+ }
146768
146963
  analyticsService.capture("fetch_executed", {
146769
146964
  url: redactUrl(resolvedUrl),
146770
146965
  status: status ?? void 0,
@@ -146897,6 +147092,8 @@ var fetchCommand = (appContext) => new Command("fetch").description(
146897
147092
  ` --value 1-5 Was it worth the price? (1 = overpriced, 5 = great deal)`,
146898
147093
  ` --reliability 1-5 Did it respond quickly and without errors? (1 = flaky, 5 = rock solid)`,
146899
147094
  ` --content Free-text is optional but helps other agents pick the best capability.`,
147095
+ ` Published publicly \u2014 do not include personal or identifying`,
147096
+ ` information (names, emails, phone numbers, addresses, keys, SSNs).`,
146900
147097
  ``
146901
147098
  ].join("\n")
146902
147099
  );
@@ -147049,22 +147246,6 @@ var sampleValueFor = (fieldName, propSchema, depth = 0) => {
147049
147246
  }
147050
147247
  };
147051
147248
  var placeholderFor = (fieldName, propSchema) => String(sampleValueFor(fieldName, propSchema));
147052
- var extractInputEnvelope = (bodySchema, method) => {
147053
- const root = asNode(bodySchema);
147054
- if (!root) return {};
147055
- const props = asNode(root.properties);
147056
- if (!props) return {};
147057
- const inputProps = asNode(asNode(props.input)?.properties);
147058
- if (inputProps) {
147059
- return {
147060
- queryParams: asNode(inputProps.queryParams) ?? void 0,
147061
- body: asNode(inputProps.body) ?? void 0
147062
- };
147063
- }
147064
- const upperMethod = method.toUpperCase();
147065
- const isGetLike = upperMethod === "GET" || upperMethod === "DELETE";
147066
- return isGetLike ? { queryParams: root } : { body: root };
147067
- };
147068
147249
  var schemaTypeLabel = (node) => {
147069
147250
  const t = node.type;
147070
147251
  if (typeof t === "string") return t;
@@ -147206,7 +147387,9 @@ var buildResponseSection = (capability) => {
147206
147387
  var buildVerifiedExampleSection = (capability) => {
147207
147388
  const req = capability.example?.request;
147208
147389
  if (req === void 0 || req === null) return [];
147209
- const json3 = typeof req === "string" ? req : JSON.stringify(req);
147390
+ const shown = unwrapTransportEnvelope(req);
147391
+ if (shown === void 0 || shown === null) return [];
147392
+ const json3 = typeof shown === "string" ? shown : JSON.stringify(shown);
147210
147393
  const truncated = json3.length > 600 ? `${json3.slice(0, 600)}\u2026` : json3;
147211
147394
  return ["", "Verified example (request):", ` ${truncated}`];
147212
147395
  };
@@ -147293,7 +147476,7 @@ var getCommand = (appContext) => new Command("get").description(
147293
147476
  ).argument(
147294
147477
  "<identifier>",
147295
147478
  "Position number from search results, or a capability slug"
147296
- ).option("--formatted", "Output formatted capability details").option(
147479
+ ).option("--formatted", "Output formatted capability details").option("--json", "Output raw JSON to stdout (default)").option(
147297
147480
  "--agent <name>",
147298
147481
  "Identify your agent host for this invocation. Overrides auto-detect for this call only."
147299
147482
  ).action(async (identifier, options) => {
@@ -147330,7 +147513,7 @@ var getCommand = (appContext) => new Command("get").description(
147330
147513
  const capability = await client.capabilities.get(capabilityId, {
147331
147514
  searchId
147332
147515
  });
147333
- if (options.formatted) {
147516
+ if (options.formatted && !options.json) {
147334
147517
  console.log(formatCapability(capability));
147335
147518
  } else {
147336
147519
  console.log(JSON.stringify(capability, null, 2));
@@ -147665,6 +147848,8 @@ Tips for a great review:
147665
147848
  --value 1-5 Was it worth the price? (1 = overpriced, 5 = great deal)
147666
147849
  --reliability 1-5 Did it respond quickly and without errors? (1 = flaky, 5 = rock solid)
147667
147850
  --content Free-text is optional but helps other agents pick the best capability.
147851
+ Published publicly \u2014 do not include personal or identifying information
147852
+ (names, emails, phone numbers, addresses, keys, SSNs).
147668
147853
 
147669
147854
  Examples:
147670
147855
  zero review run_abc123 --success --accuracy 5 --value 4 --reliability 5 --content "Fast, accurate translation"
@@ -147834,6 +148019,109 @@ Bulk review complete: ${ok} ok, ${failed} failed`);
147834
148019
  }
147835
148020
  );
147836
148021
 
148022
+ // src/commands/run-command.ts
148023
+ init_esm_shims();
148024
+ var readSkillMd = async (webBase) => {
148025
+ const home = homedir();
148026
+ for (const dir of SKILL_DIRS) {
148027
+ const path3 = join(home, dir, "zero", "SKILL.md");
148028
+ if (existsSync(path3)) return readFileSync(path3, "utf8");
148029
+ }
148030
+ const res = await fetch(`${webBase}/SKILL.md`);
148031
+ if (!res.ok) throw new Error(`Failed to fetch SKILL.md: ${res.status}`);
148032
+ return res.text();
148033
+ };
148034
+ var installCodexSkill = (skill) => {
148035
+ const dir = join(homedir(), ".codex", "skills", "zero");
148036
+ mkdirSync(dir, { recursive: true });
148037
+ writeFileSync(join(dir, "SKILL.md"), skill, "utf8");
148038
+ };
148039
+ var resolveZeroBinary = () => {
148040
+ const runner = process.env.ZERO_RUNNER;
148041
+ if (runner && existsSync(runner)) return runner;
148042
+ const fallback2 = join(homedir(), ".zero", "runtime", "bin", "zero");
148043
+ if (existsSync(fallback2)) return fallback2;
148044
+ return "zero";
148045
+ };
148046
+ var prepareHandoff = async (appContext, opts) => {
148047
+ const { client } = appContext.services;
148048
+ const webBase = appContext.env.ZERO_WEB_URL;
148049
+ const apiUrl = appContext.env.ZERO_API_URL;
148050
+ await ensureAuthenticated(client, opts.open);
148051
+ const skill = await readSkillMd(webBase);
148052
+ const zeroBin = resolveZeroBinary();
148053
+ const { ZERO_ENV: _drop, ...parentEnv } = process.env;
148054
+ const childEnv = { ...parentEnv };
148055
+ childEnv.ZERO_RUNNER = zeroBin !== "zero" ? zeroBin : childEnv.ZERO_RUNNER ?? "zero";
148056
+ if (zeroBin !== "zero") {
148057
+ childEnv.PATH = `${dirname(zeroBin)}:${process.env.PATH ?? ""}`;
148058
+ }
148059
+ for (let i = 0; i < 20; i++) {
148060
+ try {
148061
+ const res = await fetch(`${apiUrl}/health`, {
148062
+ signal: AbortSignal.timeout(2e3)
148063
+ });
148064
+ if (res.ok) break;
148065
+ } catch {
148066
+ await new Promise((r2) => setTimeout(r2, 500));
148067
+ }
148068
+ }
148069
+ return { skill, childEnv };
148070
+ };
148071
+ var claudeCommand = (appContext) => new Command("claude").description(
148072
+ "Open Claude Code with Zero capabilities pre-loaded \u2014 authenticate if needed, then hand off"
148073
+ ).argument(
148074
+ "[task...]",
148075
+ "Initial task for Claude Code (starts an interactive session with this as the first message)"
148076
+ ).option("--no-open", "Do not open the browser if sign-in is required").action(async (taskParts, opts) => {
148077
+ const { skill, childEnv } = await prepareHandoff(appContext, opts);
148078
+ const claudeArgs = ["--append-system-prompt", skill];
148079
+ const task = taskParts.join(" ").trim();
148080
+ if (task) claudeArgs.push(task);
148081
+ const result = spawnSync("claude", claudeArgs, {
148082
+ stdio: "inherit",
148083
+ env: childEnv
148084
+ });
148085
+ if (result.error) {
148086
+ process.stderr.write(
148087
+ `
148088
+ Failed to launch Claude Code: ${result.error.message}
148089
+ Make sure it is installed: https://claude.ai/download
148090
+ `
148091
+ );
148092
+ process.exitCode = 1;
148093
+ return;
148094
+ }
148095
+ if (result.status !== null) process.exitCode = result.status;
148096
+ });
148097
+ var codexCommand = (appContext) => new Command("codex").description(
148098
+ "Open Codex CLI with Zero capabilities pre-loaded \u2014 authenticate if needed, then hand off"
148099
+ ).argument(
148100
+ "[task...]",
148101
+ "Initial task for Codex (starts an interactive session with this as the first message)"
148102
+ ).option("--no-open", "Do not open the browser if sign-in is required").action(async (taskParts, opts) => {
148103
+ const { skill, childEnv } = await prepareHandoff(appContext, opts);
148104
+ installCodexSkill(skill);
148105
+ const codexArgs = [];
148106
+ const task = taskParts.join(" ").trim();
148107
+ if (task) codexArgs.push(task);
148108
+ const result = spawnSync("codex", codexArgs, {
148109
+ stdio: "inherit",
148110
+ env: childEnv
148111
+ });
148112
+ if (result.error) {
148113
+ process.stderr.write(
148114
+ `
148115
+ Failed to launch Codex: ${result.error.message}
148116
+ Make sure it is installed: https://openai.com/codex
148117
+ `
148118
+ );
148119
+ process.exitCode = 1;
148120
+ return;
148121
+ }
148122
+ if (result.status !== null) process.exitCode = result.status;
148123
+ });
148124
+
147837
148125
  // src/commands/runs-command.ts
147838
148126
  init_esm_shims();
147839
148127
  var USD_ASSETS = /* @__PURE__ */ new Set(["USD", "USDC"]);
@@ -147850,6 +148138,48 @@ var formatPayment = (payment) => {
147850
148138
  const mode = payment.mode ? ` (${payment.mode})` : "";
147851
148139
  return `${payment.protocol}${chain2}${mode}`;
147852
148140
  };
148141
+ var formatDetail = (r2) => {
148142
+ const lines = [];
148143
+ const when = r2.createdAt.toISOString().replace("T", " ").slice(0, 19);
148144
+ lines.push(`Run: ${r2.runId}`);
148145
+ lines.push(`When: ${when}`);
148146
+ lines.push(`Status: ${r2.status ?? "\u2014"}`);
148147
+ lines.push(`Latency: ${r2.latencyMs != null ? `${r2.latencyMs}ms` : "\u2014"}`);
148148
+ lines.push(`Result: ${r2.errorClass ?? "\u2014"}`);
148149
+ lines.push(`Reviewed: ${r2.reviewed ? "yes" : "no"}`);
148150
+ lines.push("");
148151
+ lines.push(`Capability: ${r2.capability.name} (${r2.capability.slug})`);
148152
+ lines.push(`URL: ${r2.capability.method} ${r2.capability.url}`);
148153
+ if (r2.capability.whatItDoes)
148154
+ lines.push(`What: ${r2.capability.whatItDoes}`);
148155
+ if (r2.capability.tags.length > 0)
148156
+ lines.push(`Tags: ${r2.capability.tags.join(", ")}`);
148157
+ if (r2.cost) {
148158
+ const { amount: amount2, asset } = r2.cost;
148159
+ lines.push(`Cost: ${asset ? `${amount2} ${asset}` : amount2}`);
148160
+ }
148161
+ if (r2.payment) {
148162
+ const chain2 = r2.payment.chain ? `:${r2.payment.chain}` : "";
148163
+ const mode = r2.payment.mode ? ` (${r2.payment.mode})` : "";
148164
+ const tx = r2.payment.txHash ? ` tx=${r2.payment.txHash}` : "";
148165
+ lines.push(`Payment: ${r2.payment.protocol}${chain2}${mode}${tx}`);
148166
+ }
148167
+ return lines.join("\n");
148168
+ };
148169
+ var runsDetailCommand = (appContext) => new Command("detail").description("Show full metadata for a single run").argument("<runId>", "Run ID (run_\u2026)").option("--json", "Output raw JSON to stdout").action(async (runId, options) => {
148170
+ try {
148171
+ const { client } = appContext.services;
148172
+ const run = await client.runs.get(runId);
148173
+ if (options.json) {
148174
+ console.log(JSON.stringify(run, null, 2));
148175
+ return;
148176
+ }
148177
+ console.log(formatDetail(run));
148178
+ } catch (err) {
148179
+ console.error(err instanceof Error ? err.message : "Failed");
148180
+ process.exitCode = 1;
148181
+ }
148182
+ });
147853
148183
  var runsCommand = (appContext) => new Command("runs").description("List your recent capability runs").addHelpText(
147854
148184
  "after",
147855
148185
  `
@@ -147860,8 +148190,9 @@ Examples:
147860
148190
  zero runs # most recent runs
147861
148191
  zero runs --unreviewed # filter to runs without a review
147862
148192
  zero runs --capability translate-en # filter to one capability (uid or slug)
147863
- zero runs --json # full structured output for scripts`
147864
- ).option("--capability <id>", "Filter by capability uid or slug").option("--unreviewed", "Only show runs without a review").option(
148193
+ zero runs --json # full structured output for scripts
148194
+ zero runs detail <runId> # full metadata for a single run`
148195
+ ).addCommand(runsDetailCommand(appContext)).option("--capability <id>", "Filter by capability uid or slug").option("--unreviewed", "Only show runs without a review").option(
147865
148196
  "--limit <n>",
147866
148197
  "Max rows (1-100, default 25)",
147867
148198
  (v) => Number.parseInt(v, 10)
@@ -149234,6 +149565,8 @@ var createApp = (appContext) => {
149234
149565
  program2.addCommand(configCommand());
149235
149566
  program2.addCommand(termsCommand());
149236
149567
  program2.addCommand(authCommand(appContext));
149568
+ program2.addCommand(claudeCommand(appContext));
149569
+ program2.addCommand(codexCommand(appContext));
149237
149570
  return program2;
149238
149571
  };
149239
149572
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeroxyz/cli",
3
- "version": "1.5.0",
3
+ "version": "1.7.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "zero": "dist/index.js",