agent-inspect 1.8.0 → 1.9.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.
@@ -12,7 +12,7 @@ import process2, { stdin, stdout } from 'process';
12
12
  import tty from 'tty';
13
13
 
14
14
  // package.json
15
- var version = "1.8.0";
15
+ var version = "1.9.0";
16
16
 
17
17
  // packages/core/src/types.ts
18
18
  var STEP_TYPES = [
@@ -4058,6 +4058,151 @@ ${attrsSection}
4058
4058
  };
4059
4059
  }
4060
4060
 
4061
+ // packages/core/src/explain.ts
4062
+ function flatten(nodes, out = []) {
4063
+ for (const node of nodes) {
4064
+ out.push({ node, index: out.length + 1 });
4065
+ flatten(node.children, out);
4066
+ }
4067
+ return out;
4068
+ }
4069
+ function redactValue(redactor, key, value) {
4070
+ return redactor.redactValue(key, value);
4071
+ }
4072
+ function fact(id, label, value, redactor) {
4073
+ return {
4074
+ id,
4075
+ label,
4076
+ value: redactValue(redactor, id.split(".").at(-1) ?? id, value),
4077
+ source: "trace",
4078
+ confidence: "observed"
4079
+ };
4080
+ }
4081
+ function topKinds(run) {
4082
+ return Object.entries(run.metadata.kinds).filter(([, count]) => count > 0).sort((a, b) => {
4083
+ if (b[1] !== a[1]) return b[1] - a[1];
4084
+ return a[0].localeCompare(b[0]);
4085
+ }).slice(0, 5).map(([kind, count]) => `${kind}:${count}`);
4086
+ }
4087
+ function countErrorNodes(nodes) {
4088
+ return nodes.filter((entry) => entry.node.event.status === "error").length;
4089
+ }
4090
+ function slowestNode(nodes) {
4091
+ return nodes.filter((entry) => entry.node.event.durationMs !== void 0).sort((a, b) => {
4092
+ const delta = (b.node.event.durationMs ?? 0) - (a.node.event.durationMs ?? 0);
4093
+ return delta !== 0 ? delta : a.index - b.index;
4094
+ })[0];
4095
+ }
4096
+ function attributeFacts(nodes, redactor) {
4097
+ const facts = [];
4098
+ for (const entry of nodes) {
4099
+ const attrs = entry.node.event.attributes;
4100
+ if (attrs === void 0) continue;
4101
+ for (const key of Object.keys(attrs).sort()) {
4102
+ facts.push({
4103
+ id: `node.${entry.index}.attributes.${key}`,
4104
+ label: `${entry.node.event.name} attribute ${key}`,
4105
+ value: redactValue(redactor, key, attrs[key]),
4106
+ source: "trace",
4107
+ confidence: "observed"
4108
+ });
4109
+ if (facts.length >= 8) return facts;
4110
+ }
4111
+ }
4112
+ return facts;
4113
+ }
4114
+ function buildFacts(run, redactor) {
4115
+ const nodes = flatten(run.children);
4116
+ const facts = [
4117
+ fact("run.id", "Run id", run.runId, redactor),
4118
+ fact("run.name", "Run name", run.name ?? run.runId, redactor),
4119
+ fact("run.status", "Run status", run.status ?? "unknown", redactor),
4120
+ fact("run.totalEvents", "Total events", run.metadata.totalEvents, redactor),
4121
+ fact("run.stepCount", "Top-level step count", run.children.length, redactor),
4122
+ fact("run.nodeCount", "Total node count", nodes.length, redactor),
4123
+ fact("run.errorNodeCount", "Error node count", countErrorNodes(nodes), redactor),
4124
+ fact("run.kinds", "Observed kind mix", topKinds(run), redactor)
4125
+ ];
4126
+ if (run.durationMs !== void 0) {
4127
+ facts.push(fact("run.durationMs", "Run duration milliseconds", run.durationMs, redactor));
4128
+ }
4129
+ const slowest = slowestNode(nodes);
4130
+ if (slowest !== void 0) {
4131
+ facts.push(
4132
+ fact("run.slowestNode", "Slowest observed node", {
4133
+ name: slowest.node.event.name,
4134
+ kind: slowest.node.event.kind,
4135
+ durationMs: slowest.node.event.durationMs
4136
+ }, redactor)
4137
+ );
4138
+ }
4139
+ facts.push(...attributeFacts(nodes, redactor));
4140
+ return facts;
4141
+ }
4142
+ function buildInferences(run, facts) {
4143
+ const inferences = [];
4144
+ const errorFact = facts.find((item) => item.id === "run.errorNodeCount");
4145
+ const kindFact = facts.find((item) => item.id === "run.kinds");
4146
+ const durationFact = facts.find((item) => item.id === "run.durationMs");
4147
+ const errorNodeCount = typeof errorFact?.value === "number" ? errorFact.value : 0;
4148
+ if (run.status === "error" || errorNodeCount > 0) {
4149
+ inferences.push({
4150
+ id: "outcome.error",
4151
+ label: "Outcome",
4152
+ text: "The run recorded an error status or at least one error node.",
4153
+ evidence: ["run.status", "run.errorNodeCount"],
4154
+ confidence: "deterministic"
4155
+ });
4156
+ } else if (run.status === "ok") {
4157
+ inferences.push({
4158
+ id: "outcome.success",
4159
+ label: "Outcome",
4160
+ text: "The run completed without observed error nodes.",
4161
+ evidence: ["run.status", "run.errorNodeCount"],
4162
+ confidence: "deterministic"
4163
+ });
4164
+ }
4165
+ if (kindFact !== void 0) {
4166
+ inferences.push({
4167
+ id: "shape.kind-mix",
4168
+ label: "Trace shape",
4169
+ text: "The explanation is based on the observed event kind mix, not generated content.",
4170
+ evidence: [kindFact.id],
4171
+ confidence: "deterministic"
4172
+ });
4173
+ }
4174
+ if (durationFact !== void 0) {
4175
+ inferences.push({
4176
+ id: "timing.duration",
4177
+ label: "Timing",
4178
+ text: "Timing claims are limited to persisted duration fields in the trace.",
4179
+ evidence: [durationFact.id],
4180
+ confidence: "deterministic"
4181
+ });
4182
+ }
4183
+ return inferences;
4184
+ }
4185
+ function buildLocalExplanation(run, options = {}) {
4186
+ const redactionProfile = options.redactionProfile ?? "local";
4187
+ const resolved = resolveRedactionProfile(redactionProfile);
4188
+ const redactor = new Redactor({ extraKeys: resolved.extraKeys });
4189
+ const mode = options.mode ?? "local";
4190
+ const facts = buildFacts(run, redactor);
4191
+ return {
4192
+ mode,
4193
+ runId: String(redactValue(redactor, "runId", run.runId)),
4194
+ ...run.name !== void 0 ? { name: String(redactValue(redactor, "name", run.name)) } : {},
4195
+ ...run.status !== void 0 ? { status: run.status } : {},
4196
+ redactionProfile,
4197
+ facts,
4198
+ inferences: mode === "dry-run" ? [] : buildInferences(run, facts),
4199
+ notes: [
4200
+ "Generated locally without provider or network calls.",
4201
+ "Facts are observed from normalized trace data; inferences are deterministic labels."
4202
+ ]
4203
+ };
4204
+ }
4205
+
4061
4206
  // packages/core/src/stats.ts
4062
4207
  function percentile(sorted, p) {
4063
4208
  if (sorted.length === 0) return void 0;
@@ -8947,9 +9092,164 @@ async function readStdin(stdin) {
8947
9092
  }
8948
9093
  return content;
8949
9094
  }
9095
+ function isMissingFileError2(error) {
9096
+ return error !== null && typeof error === "object" && "code" in error && error.code === "ENOENT";
9097
+ }
9098
+ async function inputFromTarget(target, options, stdin) {
9099
+ if (target === "-") {
9100
+ return { type: "string", content: await readStdin(stdin) };
9101
+ }
9102
+ try {
9103
+ const stats2 = await stat(target);
9104
+ if (stats2.isDirectory()) return { type: "directory", path: target };
9105
+ return { type: "file", path: target };
9106
+ } catch (error) {
9107
+ if (!isMissingFileError2(error)) throw error;
9108
+ }
9109
+ const runPath = getTraceFilePath(target, resolveTraceDir({ dir: options.dir }));
9110
+ const stats = await stat(runPath);
9111
+ if (stats.isDirectory()) return { type: "directory", path: runPath };
9112
+ return { type: "file", path: runPath };
9113
+ }
9114
+
9115
+ // packages/cli/src/explain.ts
9116
+ function parseRedactionProfile3(value) {
9117
+ const profile = (value ?? "local").trim().toLowerCase();
9118
+ if (profile === "local" || profile === "share" || profile === "strict") {
9119
+ return profile;
9120
+ }
9121
+ throw new Error(
9122
+ `Unsupported --redaction-profile "${value ?? ""}". Use local, share, or strict.`
9123
+ );
9124
+ }
9125
+ function selectRun(result, runId) {
9126
+ if (runId !== void 0) {
9127
+ return result.runs.find((run) => run.runId === runId);
9128
+ }
9129
+ return result.runs.length === 1 ? result.runs[0] : void 0;
9130
+ }
9131
+ function printMultipleRuns(result) {
9132
+ console.error(
9133
+ `Trace contains ${result.runs.length} runs. Re-run with --run <run-id>.`
9134
+ );
9135
+ for (const run of result.runs) {
9136
+ console.error(`- ${run.runId}${run.name !== void 0 ? ` name=${run.name}` : ""}`);
9137
+ }
9138
+ }
9139
+ function renderHuman(result) {
9140
+ const lines = [
9141
+ `Explain: ${result.name ?? result.runId}`,
9142
+ `Mode: ${result.mode}`,
9143
+ `Status: ${result.status ?? "unknown"}`,
9144
+ `Redaction: ${result.redactionProfile}`,
9145
+ "",
9146
+ "Facts:"
9147
+ ];
9148
+ for (const fact2 of result.facts) {
9149
+ lines.push(`- ${fact2.id}: ${JSON.stringify(fact2.value)}`);
9150
+ }
9151
+ lines.push("", "Inferences:");
9152
+ if (result.inferences.length === 0) {
9153
+ lines.push("- none");
9154
+ } else {
9155
+ for (const inference of result.inferences) {
9156
+ lines.push(`- ${inference.label}: ${inference.text}`);
9157
+ }
9158
+ }
9159
+ lines.push("", "Notes:");
9160
+ for (const note of result.notes) {
9161
+ lines.push(`- ${note}`);
9162
+ }
9163
+ return lines.join("\n");
9164
+ }
9165
+ function writeJson(result) {
9166
+ console.log(JSON.stringify(result, null, 2));
9167
+ }
9168
+ function rejectProvider(provider, json) {
9169
+ process.exitCode = 1;
9170
+ const message = `Provider explain is not implemented in this build: ${provider}. Use --dry-run to inspect the redacted local payload.`;
9171
+ if (json) {
9172
+ writeJson({
9173
+ ok: false,
9174
+ error: { code: "PROVIDER_NOT_IMPLEMENTED", message }
9175
+ });
9176
+ return;
9177
+ }
9178
+ console.error(message);
9179
+ }
9180
+ async function explainCommand(target, options = {}, stdin = process.stdin) {
9181
+ if (options.provider !== void 0) {
9182
+ rejectProvider(options.provider, options.json);
9183
+ return;
9184
+ }
9185
+ let redactionProfile;
9186
+ try {
9187
+ redactionProfile = parseRedactionProfile3(options.redactionProfile);
9188
+ } catch (error) {
9189
+ process.exitCode = 1;
9190
+ console.error(error instanceof Error ? error.message : String(error));
9191
+ return;
9192
+ }
9193
+ try {
9194
+ const input3 = await inputFromTarget(target, options, stdin);
9195
+ const read = await openTrace(input3, {
9196
+ ...options.format !== void 0 ? { format: options.format } : {}
9197
+ });
9198
+ const selected = selectRun(read, options.run);
9199
+ if (selected === void 0) {
9200
+ process.exitCode = 1;
9201
+ const message = options.run !== void 0 ? `Run not found: ${options.run}` : `Trace contains ${read.runs.length} runs. Specify --run <run-id>.`;
9202
+ if (options.json) {
9203
+ writeJson({ ok: false, error: { message }, runs: read.runs });
9204
+ } else if (options.run !== void 0) {
9205
+ console.error(message);
9206
+ } else {
9207
+ printMultipleRuns(read);
9208
+ }
9209
+ return;
9210
+ }
9211
+ const mode = options.dryRun ? "dry-run" : "local";
9212
+ const explanation = buildLocalExplanation(selected, {
9213
+ mode,
9214
+ redactionProfile
9215
+ });
9216
+ if (options.json) {
9217
+ writeJson({
9218
+ ok: true,
9219
+ format: read.format,
9220
+ sourceFiles: read.sourceFiles,
9221
+ warnings: read.warnings,
9222
+ unsupportedFields: read.unsupportedFields,
9223
+ explanation
9224
+ });
9225
+ return;
9226
+ }
9227
+ console.log(renderHuman(explanation));
9228
+ } catch (error) {
9229
+ process.exitCode = 1;
9230
+ const message = error instanceof Error ? error.message : String(error);
9231
+ const code = error instanceof TraceReadError ? error.code : void 0;
9232
+ if (options.json) {
9233
+ writeJson({
9234
+ ok: false,
9235
+ error: { ...code !== void 0 ? { code } : {}, message }
9236
+ });
9237
+ return;
9238
+ }
9239
+ console.error(message);
9240
+ }
9241
+ }
9242
+ async function readStdin2(stdin) {
9243
+ stdin.setEncoding("utf8");
9244
+ let content = "";
9245
+ for await (const chunk of stdin) {
9246
+ content += typeof chunk === "string" ? chunk : String(chunk);
9247
+ }
9248
+ return content;
9249
+ }
8950
9250
  async function inputFromPathOrStdin(input3, stdin) {
8951
9251
  if (input3 === void 0 || input3 === "-") {
8952
- return { type: "string", content: await readStdin(stdin) };
9252
+ return { type: "string", content: await readStdin2(stdin) };
8953
9253
  }
8954
9254
  const stats = await stat(input3);
8955
9255
  if (stats.isDirectory()) return { type: "directory", path: input3 };
@@ -9000,13 +9300,13 @@ function printRun(result, run) {
9000
9300
  printNode(node, 0);
9001
9301
  }
9002
9302
  }
9003
- function selectRun(result, runId) {
9303
+ function selectRun2(result, runId) {
9004
9304
  if (runId !== void 0) {
9005
9305
  return result.runs.find((run) => run.runId === runId);
9006
9306
  }
9007
9307
  return result.runs.length === 1 ? result.runs[0] : void 0;
9008
9308
  }
9009
- function printMultipleRuns(result) {
9309
+ function printMultipleRuns2(result) {
9010
9310
  console.error(
9011
9311
  `Trace contains ${result.runs.length} runs. Re-run with --run <run-id>.`
9012
9312
  );
@@ -9020,7 +9320,7 @@ function printMultipleRuns(result) {
9020
9320
  console.error(`- ${bits.join(" ")}`);
9021
9321
  }
9022
9322
  }
9023
- function writeJson(output2) {
9323
+ function writeJson2(output2) {
9024
9324
  console.log(JSON.stringify(output2, null, 2));
9025
9325
  }
9026
9326
  async function openCommand(input3, options = {}, stdin = process.stdin) {
@@ -9029,12 +9329,12 @@ async function openCommand(input3, options = {}, stdin = process.stdin) {
9029
9329
  const result = await openTrace(traceInput, {
9030
9330
  ...options.format !== void 0 ? { format: options.format } : {}
9031
9331
  });
9032
- const selected = selectRun(result, options.run);
9332
+ const selected = selectRun2(result, options.run);
9033
9333
  if (selected === void 0) {
9034
9334
  process.exitCode = 1;
9035
9335
  const message = options.run !== void 0 ? `Run not found: ${options.run}` : `Trace contains ${result.runs.length} runs. Specify --run <run-id>.`;
9036
9336
  if (options.json) {
9037
- writeJson({
9337
+ writeJson2({
9038
9338
  format: result.format,
9039
9339
  sourceFiles: result.sourceFiles,
9040
9340
  warnings: result.warnings,
@@ -9045,12 +9345,12 @@ async function openCommand(input3, options = {}, stdin = process.stdin) {
9045
9345
  } else if (options.run !== void 0) {
9046
9346
  console.error(message);
9047
9347
  } else {
9048
- printMultipleRuns(result);
9348
+ printMultipleRuns2(result);
9049
9349
  }
9050
9350
  return;
9051
9351
  }
9052
9352
  if (options.json) {
9053
- writeJson({
9353
+ writeJson2({
9054
9354
  format: result.format,
9055
9355
  sourceFiles: result.sourceFiles,
9056
9356
  warnings: result.warnings,
@@ -9070,7 +9370,7 @@ async function openCommand(input3, options = {}, stdin = process.stdin) {
9070
9370
  const code = error instanceof TraceReadError ? error.code : void 0;
9071
9371
  const warnings = error instanceof TraceReadError ? error.warnings : [];
9072
9372
  if (options.json) {
9073
- writeJson({
9373
+ writeJson2({
9074
9374
  warnings,
9075
9375
  error: { ...code !== void 0 ? { code } : {}, message }
9076
9376
  });
@@ -9174,7 +9474,7 @@ function errorResult(input3, diagnostics, selectedRun) {
9174
9474
  function flattenNodes(nodes) {
9175
9475
  return nodes.flatMap((node) => [node, ...flattenNodes(node.children)]);
9176
9476
  }
9177
- function buildFacts(input3, selectedRun) {
9477
+ function buildFacts2(input3, selectedRun) {
9178
9478
  const scopedRuns = selectedRun ? [selectedRun] : input3.read.runs;
9179
9479
  const scopedRunIds = new Set(scopedRuns.map((run) => run.runId));
9180
9480
  const scopedEvents = selectedRun === void 0 ? input3.read.events : input3.read.events.filter((event) => scopedRunIds.has(event.runId));
@@ -10182,7 +10482,7 @@ function createBaselineRegressionRule(options) {
10182
10482
  )
10183
10483
  ];
10184
10484
  }
10185
- const baselineFacts = buildFacts(options.baseline, baselineSelection.run);
10485
+ const baselineFacts = buildFacts2(options.baseline, baselineSelection.run);
10186
10486
  const baselineContext = {
10187
10487
  ...baselineFacts,
10188
10488
  selectedRun: baselineSelection.run,
@@ -10301,7 +10601,7 @@ function runTraceChecks(input3, options = {}) {
10301
10601
  if (rules.diagnostics.length > 0) {
10302
10602
  return errorResult(input3, rules.diagnostics, selected.run);
10303
10603
  }
10304
- const facts = buildFacts(input3, selected.run);
10604
+ const facts = buildFacts2(input3, selected.run);
10305
10605
  const context = {
10306
10606
  ...facts,
10307
10607
  ...selected.run ? { selectedRun: selected.run } : {},
@@ -10336,33 +10636,6 @@ function runTraceChecks(input3, options = {}) {
10336
10636
  diagnostics
10337
10637
  };
10338
10638
  }
10339
- async function readStdin2(stdin) {
10340
- stdin.setEncoding("utf8");
10341
- let content = "";
10342
- for await (const chunk of stdin) {
10343
- content += typeof chunk === "string" ? chunk : String(chunk);
10344
- }
10345
- return content;
10346
- }
10347
- function isMissingFileError2(error) {
10348
- return error !== null && typeof error === "object" && "code" in error && error.code === "ENOENT";
10349
- }
10350
- async function inputFromTarget(target, options, stdin) {
10351
- if (target === "-") {
10352
- return { type: "string", content: await readStdin2(stdin) };
10353
- }
10354
- try {
10355
- const stats2 = await stat(target);
10356
- if (stats2.isDirectory()) return { type: "directory", path: target };
10357
- return { type: "file", path: target };
10358
- } catch (error) {
10359
- if (!isMissingFileError2(error)) throw error;
10360
- }
10361
- const runPath = getTraceFilePath(target, resolveTraceDir({ dir: options.dir }));
10362
- const stats = await stat(runPath);
10363
- if (stats.isDirectory()) return { type: "directory", path: runPath };
10364
- return { type: "file", path: runPath };
10365
- }
10366
10639
 
10367
10640
  // packages/cli/src/check.ts
10368
10641
  var DEFAULT_SELECT = ["run.status"];
@@ -10809,7 +11082,7 @@ function stable3(value) {
10809
11082
  Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable3(record[key])])
10810
11083
  );
10811
11084
  }
10812
- function writeJson2(value) {
11085
+ function writeJson3(value) {
10813
11086
  return `${JSON.stringify(stable3(value), null, 2)}
10814
11087
  `;
10815
11088
  }
@@ -10827,7 +11100,7 @@ function increment(record, key) {
10827
11100
  const label = key && key.trim() !== "" ? key : "unknown";
10828
11101
  record[label] = (record[label] ?? 0) + 1;
10829
11102
  }
10830
- function selectRun2(read, runId) {
11103
+ function selectRun3(read, runId) {
10831
11104
  if (runId !== void 0) {
10832
11105
  return read.runs.find((run) => run.runId === runId);
10833
11106
  }
@@ -10975,7 +11248,7 @@ async function artifactsCommand(target, options = {}, stdin = process.stdin) {
10975
11248
  process.exitCode = 1;
10976
11249
  return;
10977
11250
  }
10978
- const selectedRun = selectRun2(read, options.run);
11251
+ const selectedRun = selectRun3(read, options.run);
10979
11252
  const check = runTraceChecks(
10980
11253
  { read },
10981
11254
  {
@@ -11012,12 +11285,12 @@ async function artifactsCommand(target, options = {}, stdin = process.stdin) {
11012
11285
  }
11013
11286
  const files = [];
11014
11287
  await mkdir(outputDir, { recursive: true });
11015
- await writeArtifact(outputDir, "trace.json", writeJson2(trace), files);
11016
- await writeArtifact(outputDir, "check.json", writeJson2(check), files);
11288
+ await writeArtifact(outputDir, "trace.json", writeJson3(trace), files);
11289
+ await writeArtifact(outputDir, "check.json", writeJson3(check), files);
11017
11290
  await writeArtifact(
11018
11291
  outputDir,
11019
11292
  "diff.json",
11020
- writeJson2(diff ?? { status: "not_requested", findings: [], diagnostics: [] }),
11293
+ writeJson3(diff ?? { status: "not_requested", findings: [], diagnostics: [] }),
11021
11294
  files
11022
11295
  );
11023
11296
  await writeArtifact(outputDir, "summary.md", renderMarkdown(trace, check, diff), files);
@@ -11047,9 +11320,9 @@ ${renderMarkdown(trace, check, diff)}`, "utf-8");
11047
11320
  ...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary: path10.resolve(summaryTarget) } : {},
11048
11321
  note: NOTE
11049
11322
  };
11050
- await writeFile(path10.join(outputDir, "manifest.json"), writeJson2(manifest), "utf-8");
11323
+ await writeFile(path10.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
11051
11324
  if (options.json === true) {
11052
- console.log(writeJson2(manifest).trimEnd());
11325
+ console.log(writeJson3(manifest).trimEnd());
11053
11326
  } else {
11054
11327
  console.log(`Wrote AgentInspect artifacts to ${outputDir}`);
11055
11328
  console.log(`Status: ${manifest.status}`);
@@ -11268,6 +11541,23 @@ function createCliProgram() {
11268
11541
  ).action((runId, opts) => {
11269
11542
  runCommand(() => reportCommand(runId, opts));
11270
11543
  });
11544
+ program.command("explain").description("Explain a local trace with deterministic facts (no provider calls)").argument("<trace-path-or-run-id>", "trace file, directory, stdin -, or run id").option("--dir <path>", "trace directory for run-id lookup").addOption(
11545
+ new Option("--format <format>", "trace input format").choices([
11546
+ "agent-inspect-jsonl",
11547
+ "openinference-json",
11548
+ "otlp-json"
11549
+ ])
11550
+ ).option("--run <run-id>", "select a run when the trace contains multiple runs").option("--dry-run", "emit only the local facts payload that a provider could receive").option(
11551
+ "--provider <provider>",
11552
+ "reserved for explicit provider explain; currently rejected without network calls"
11553
+ ).option("--json", "print deterministic JSON explanation result").addOption(
11554
+ new Option(
11555
+ "--redaction-profile <profile>",
11556
+ "redaction profile for explanation payload: local, share, strict (default: local)"
11557
+ ).choices(["local", "share", "strict"])
11558
+ ).action((target, opts) => {
11559
+ runCommand(() => explainCommand(target, opts));
11560
+ });
11271
11561
  return program;
11272
11562
  }
11273
11563
  function isPrimaryModule() {