@duyquangnvx/create-agent-cli 0.5.0 → 0.6.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.
package/dist/bin.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { parseArgs, parseEnv } from "node:util";
3
3
  import { basename, delimiter, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
4
- import { access, chmod, link, lstat, mkdir, mkdtemp, open, readFile, readdir, realpath, rename, rm, stat, writeFile } from "node:fs/promises";
5
4
  import { constants, existsSync, readFileSync, realpathSync } from "node:fs";
5
+ import { access, chmod, link, lstat, mkdir, mkdtemp, open, readFile, readdir, realpath, rename, rm, stat, writeFile } from "node:fs/promises";
6
6
  import { constants as constants$1, homedir, tmpdir } from "node:os";
7
7
  import { spawn } from "node:child_process";
8
8
  import { setTimeout as setTimeout$1 } from "node:timers/promises";
@@ -2425,6 +2425,138 @@ function handleIntersectionResults(result, left, right) {
2425
2425
  result.value = merged.data;
2426
2426
  return result;
2427
2427
  }
2428
+ const $ZodRecord = /*@__PURE__*/ $constructor("$ZodRecord", (inst, def) => {
2429
+ $ZodType.init(inst, def);
2430
+ const memo = globalConfig.memoizer;
2431
+ memo?.attach(inst);
2432
+ inst._zod.parse = (payload, ctx) => {
2433
+ const input = payload.value;
2434
+ if (!isPlainObject(input)) {
2435
+ payload.issues.push({
2436
+ expected: "record",
2437
+ code: "invalid_type",
2438
+ input,
2439
+ inst
2440
+ });
2441
+ return payload;
2442
+ }
2443
+ const proms = [];
2444
+ const values = def.keyType._zod.values;
2445
+ if (values && !def.partial) {
2446
+ payload.value = memo ? memo.alloc(inst, payload, {}, ctx) : {};
2447
+ const recordKeys = /* @__PURE__ */ new Set();
2448
+ for (const key of values) if (typeof key === "string" || typeof key === "number" || typeof key === "symbol") {
2449
+ recordKeys.add(typeof key === "number" ? key.toString() : key);
2450
+ if (key === "__proto__") continue;
2451
+ const keyResult = def.keyType._zod.run({
2452
+ value: key,
2453
+ issues: []
2454
+ }, ctx);
2455
+ if (keyResult instanceof Promise) throw new Error("Async schemas not supported in object keys currently");
2456
+ if (keyResult.issues.length) {
2457
+ payload.issues.push({
2458
+ code: "invalid_key",
2459
+ origin: "record",
2460
+ issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())),
2461
+ input: key,
2462
+ path: [key],
2463
+ inst
2464
+ });
2465
+ continue;
2466
+ }
2467
+ const outKey = keyResult.value;
2468
+ if (outKey === "__proto__") continue;
2469
+ const result = def.valueType._zod.run({
2470
+ value: input[key],
2471
+ issues: []
2472
+ }, ctx);
2473
+ if (result instanceof Promise) proms.push(result.then((result) => {
2474
+ if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues));
2475
+ payload.value[outKey] = result.value;
2476
+ }));
2477
+ else {
2478
+ if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues));
2479
+ payload.value[outKey] = result.value;
2480
+ }
2481
+ }
2482
+ let unrecognized;
2483
+ for (const key in input) if (!recordKeys.has(key)) {
2484
+ if (def.mode === "loose") {
2485
+ if (key === "__proto__") continue;
2486
+ payload.value[key] = input[key];
2487
+ } else {
2488
+ unrecognized = unrecognized ?? [];
2489
+ unrecognized.push(key);
2490
+ }
2491
+ }
2492
+ if (unrecognized && unrecognized.length > 0) payload.issues.push({
2493
+ code: "unrecognized_keys",
2494
+ input,
2495
+ inst,
2496
+ keys: unrecognized,
2497
+ continue: true
2498
+ });
2499
+ } else {
2500
+ payload.value = memo ? memo.alloc(inst, payload, {}, ctx) : {};
2501
+ let unrecognized;
2502
+ for (const key of Reflect.ownKeys(input)) {
2503
+ if (key === "__proto__") continue;
2504
+ if (!Object.prototype.propertyIsEnumerable.call(input, key)) continue;
2505
+ let keyResult = def.keyType._zod.run({
2506
+ value: key,
2507
+ issues: []
2508
+ }, ctx);
2509
+ if (keyResult instanceof Promise) throw new Error("Async schemas not supported in object keys currently");
2510
+ if (typeof key === "string" && number$1.test(key) && keyResult.issues.length) {
2511
+ const retryResult = def.keyType._zod.run({
2512
+ value: Number(key),
2513
+ issues: []
2514
+ }, ctx);
2515
+ if (retryResult instanceof Promise) throw new Error("Async schemas not supported in object keys currently");
2516
+ if (retryResult.issues.length === 0) keyResult = retryResult;
2517
+ }
2518
+ if (keyResult.issues.length) {
2519
+ if (def.mode === "loose") payload.value[key] = input[key];
2520
+ else if (values) {
2521
+ unrecognized = unrecognized ?? [];
2522
+ unrecognized.push(key);
2523
+ } else payload.issues.push({
2524
+ code: "invalid_key",
2525
+ origin: "record",
2526
+ issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())),
2527
+ input: key,
2528
+ path: [key],
2529
+ inst
2530
+ });
2531
+ continue;
2532
+ }
2533
+ const outKey = keyResult.value;
2534
+ if (outKey === "__proto__") continue;
2535
+ const result = def.valueType._zod.run({
2536
+ value: input[key],
2537
+ issues: []
2538
+ }, ctx);
2539
+ if (result instanceof Promise) proms.push(result.then((result) => {
2540
+ if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues));
2541
+ payload.value[outKey] = result.value;
2542
+ }));
2543
+ else {
2544
+ if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues));
2545
+ payload.value[outKey] = result.value;
2546
+ }
2547
+ }
2548
+ if (unrecognized && unrecognized.length > 0) payload.issues.push({
2549
+ code: "unrecognized_keys",
2550
+ input,
2551
+ inst,
2552
+ keys: unrecognized,
2553
+ continue: true
2554
+ });
2555
+ }
2556
+ if (proms.length) return Promise.all(proms).then(() => payload);
2557
+ return payload;
2558
+ };
2559
+ });
2428
2560
  const $ZodEnum = /*@__PURE__*/ $constructor("$ZodEnum", (inst, def) => {
2429
2561
  $ZodType.init(inst, def);
2430
2562
  const values = getEnumValues(def.entries);
@@ -5093,6 +5225,9 @@ const ZodURL = /*@__PURE__*/ $constructor("ZodURL", (inst, def) => {
5093
5225
  $ZodURL.init(inst, def);
5094
5226
  ZodStringFormat.init(inst, def);
5095
5227
  });
5228
+ function url(params) {
5229
+ return /* @__PURE__ */ _url(ZodURL, params);
5230
+ }
5096
5231
  const ZodEmoji = /*@__PURE__*/ $constructor("ZodEmoji", (inst, def) => {
5097
5232
  $ZodEmoji.init(inst, def);
5098
5233
  ZodStringFormat.init(inst, def);
@@ -5367,6 +5502,28 @@ function intersection(left, right) {
5367
5502
  right
5368
5503
  });
5369
5504
  }
5505
+ const ZodRecord = /*@__PURE__*/ $constructor("ZodRecord", (inst, def) => {
5506
+ _ensureDefaultMemoizer();
5507
+ $ZodRecord.init(inst, def);
5508
+ ZodType.init(inst, def);
5509
+ inst._zod.processJSONSchema = (ctx, json, params) => recordProcessor(inst, ctx, json, params);
5510
+ inst.keyType = def.keyType;
5511
+ inst.valueType = def.valueType;
5512
+ });
5513
+ function record(keyType, valueType, params) {
5514
+ if (!valueType || !valueType._zod) return new ZodRecord({
5515
+ type: "record",
5516
+ keyType: string(),
5517
+ valueType: keyType,
5518
+ ...normalizeParams(valueType)
5519
+ });
5520
+ return new ZodRecord({
5521
+ type: "record",
5522
+ keyType,
5523
+ valueType,
5524
+ ...normalizeParams(params)
5525
+ });
5526
+ }
5370
5527
  const ZodEnum = /*@__PURE__*/ $constructor("ZodEnum", (inst, def) => {
5371
5528
  $ZodEnum.init(inst, def);
5372
5529
  ZodType.init(inst, def);
@@ -5582,6 +5739,146 @@ function untilAborted(signal) {
5582
5739
  });
5583
5740
  }
5584
5741
  //#endregion
5742
+ //#region ../agent-cli/dist/clock.js
5743
+ const realClock = {
5744
+ now: () => Date.now(),
5745
+ sleep: (ms, signal) => new Promise((resolve, reject) => {
5746
+ if (signal?.aborted === true) {
5747
+ reject(signal.reason);
5748
+ return;
5749
+ }
5750
+ const onAbort = () => {
5751
+ clearTimeout(timer);
5752
+ reject(signal?.reason);
5753
+ };
5754
+ const timer = setTimeout(() => {
5755
+ signal?.removeEventListener("abort", onAbort);
5756
+ resolve();
5757
+ }, ms);
5758
+ signal?.addEventListener("abort", onAbort, { once: true });
5759
+ })
5760
+ };
5761
+ /** Runs `then` once `ms` have passed on `clock`; aborting `cancel` drops it. */
5762
+ function after(clock, ms, cancel, then) {
5763
+ clock.sleep(ms, cancel).then(then, (error) => {
5764
+ if (!cancel.aborted) throw error;
5765
+ });
5766
+ }
5767
+ async function poll(clock, check, intervalMs, signal) {
5768
+ for (;;) {
5769
+ signal.throwIfAborted();
5770
+ const value = await check();
5771
+ if (value !== void 0) return value;
5772
+ await clock.sleep(intervalMs, signal);
5773
+ }
5774
+ }
5775
+ //#endregion
5776
+ //#region ../agent-cli/dist/errors.js
5777
+ var CliError = class extends Error {
5778
+ code;
5779
+ hint;
5780
+ details;
5781
+ retryAt;
5782
+ constructor({ code, message, hint, details, retryAt }, options) {
5783
+ super(message, options);
5784
+ this.name = "CliError";
5785
+ this.code = code;
5786
+ this.hint = hint;
5787
+ this.details = details;
5788
+ this.retryAt = retryAt;
5789
+ }
5790
+ };
5791
+ /** The caller called the Agent CLI wrong; the same call can't succeed. */
5792
+ var UsageError = class extends CliError {
5793
+ constructor(fields) {
5794
+ super(fields);
5795
+ this.name = "UsageError";
5796
+ }
5797
+ };
5798
+ const INTERNAL_CODE = "INTERNAL";
5799
+ function errnoOf(error) {
5800
+ return error instanceof Error && "code" in error && typeof error.code === "string" ? error.code : void 0;
5801
+ }
5802
+ function isMissingFile(error) {
5803
+ return errnoOf(error) === "ENOENT";
5804
+ }
5805
+ function isNothingThere(error) {
5806
+ return isMissingFile(error) || errnoOf(error) === "ENOTDIR";
5807
+ }
5808
+ function debugVariable(cliName) {
5809
+ return `${cliName.toUpperCase().replace(/[^A-Z0-9]/g, "_")}_DEBUG`;
5810
+ }
5811
+ function messageOf(error) {
5812
+ return error instanceof Error ? error.message : String(error);
5813
+ }
5814
+ function isDebug({ env, cliName }) {
5815
+ return Boolean(env[debugVariable(cliName)]);
5816
+ }
5817
+ function bugHint(format) {
5818
+ const bugs = format.bugs?.();
5819
+ if (isDebug(format)) {
5820
+ const where = "the stack trace shows where it failed";
5821
+ return bugs === void 0 ? where : `${where}; report it at ${bugs}`;
5822
+ }
5823
+ const rerun = `rerun with ${debugVariable(format.cliName)}=1 to see the stack trace`;
5824
+ return bugs === void 0 ? rerun : `${rerun}, then report it at ${bugs}`;
5825
+ }
5826
+ function fieldsOf$1(error, format) {
5827
+ if (error instanceof CliError) {
5828
+ const { code, message, hint, details, retryAt } = error;
5829
+ return {
5830
+ code,
5831
+ message,
5832
+ hint: format.isBug(error) ? bugHint(format) : hint,
5833
+ details,
5834
+ retryAt
5835
+ };
5836
+ }
5837
+ return {
5838
+ code: INTERNAL_CODE,
5839
+ message: messageOf(error),
5840
+ hint: bugHint(format)
5841
+ };
5842
+ }
5843
+ function causesOf(error) {
5844
+ return error instanceof Error && error.cause !== void 0 ? [error.cause, ...causesOf(error.cause)] : [];
5845
+ }
5846
+ function traceOf(error) {
5847
+ return error instanceof Error ? error.stack ?? error.message : String(error);
5848
+ }
5849
+ /** Under debug: a bug's stack trace, then every error's cause chain. */
5850
+ function debugTrace(error, format) {
5851
+ if (!isDebug(format)) return void 0;
5852
+ const lines = [...format.isBug(error) ? [traceOf(error)] : [], ...causesOf(error).map((cause) => `caused by: ${traceOf(cause)}`)];
5853
+ return lines.length === 0 ? void 0 : lines.join("\n");
5854
+ }
5855
+ /**
5856
+ * The errors a run failed with: the leaves of nested `AggregateError`s, or the one it threw. An
5857
+ * empty `AggregateError` is a leaf.
5858
+ */
5859
+ function errorsOf(error) {
5860
+ return error instanceof AggregateError && error.errors.length > 0 ? error.errors.flatMap(errorsOf) : [error];
5861
+ }
5862
+ function errorLines(error, format) {
5863
+ const fields = fieldsOf$1(error, format);
5864
+ const stack = debugTrace(error, format);
5865
+ const { style } = format;
5866
+ const label = style.red(format.isBug(error) ? "internal error:" : "error:");
5867
+ const trace = stack === void 0 ? "" : `${stack}\n`;
5868
+ return `${label} ${fields.message}\n${trace}${style.cyan("hint:")} ${fields.hint}\n`;
5869
+ }
5870
+ function formatRuntimeError(error, format) {
5871
+ const errors = errorsOf(error);
5872
+ if (format.json) {
5873
+ const printed = errors.map((each) => ({
5874
+ ...fieldsOf$1(each, format),
5875
+ stack: debugTrace(each, format)
5876
+ }));
5877
+ return `${JSON.stringify({ errors: printed })}\n`;
5878
+ }
5879
+ return errors.map((each) => errorLines(each, format)).join("");
5880
+ }
5881
+ //#endregion
5585
5882
  //#region ../agent-cli/dist/stdin.js
5586
5883
  const STDIN_META = "stdin";
5587
5884
  function isStdinSchema(schema) {
@@ -5597,13 +5894,37 @@ function readingLine(name, platform) {
5597
5894
  function isTerminal(source) {
5598
5895
  return typeof source !== "string" && "isTTY" in source && source.isTTY === true;
5599
5896
  }
5600
- /** The whole of `source` as UTF-8; rejects with the signal's reason once it aborts. */
5601
- function readStdin(source, signal) {
5897
+ const STDIN_STALLED = "STDIN_STALLED";
5898
+ /** How long a stdin that is not a terminal may send nothing, from the start of the read and from each chunk. */
5899
+ const STDIN_IDLE_MS = 3e4;
5900
+ function stdinStalled(callerLine) {
5901
+ return new CliError({
5902
+ code: STDIN_STALLED,
5903
+ message: `stdin sent nothing for ${STDIN_IDLE_MS} ms`,
5904
+ hint: `stdin never ended: close the pipe or heredoc that feeds \`${callerLine}\`, pass the text as an argument instead, or write a slow producer's output to a file and redirect it in`
5905
+ });
5906
+ }
5907
+ /**
5908
+ * The whole of `source` as UTF-8; rejects with the signal's reason once it aborts, and with
5909
+ * `idle.stalled()` once a stream that is not a terminal sends nothing for `STDIN_IDLE_MS`.
5910
+ */
5911
+ function readStdin(source, signal, idle) {
5602
5912
  if (typeof source === "string") return signal.aborted ? Promise.reject(signal.reason) : Promise.resolve(source);
5603
5913
  return new Promise((resolve, reject) => {
5604
5914
  const chunks = [];
5915
+ let idleWindow = new AbortController();
5916
+ const watchIdle = () => {
5917
+ idleWindow.abort();
5918
+ idleWindow = new AbortController();
5919
+ if (isTerminal(source)) return;
5920
+ after(idle.clock, STDIN_IDLE_MS, idleWindow.signal, () => {
5921
+ stop();
5922
+ reject(idle.stalled());
5923
+ });
5924
+ };
5605
5925
  const onData = (chunk) => {
5606
5926
  chunks.push(chunk instanceof Uint8Array ? chunk : Buffer.from(String(chunk)));
5927
+ watchIdle();
5607
5928
  };
5608
5929
  const onEnd = () => {
5609
5930
  stop();
@@ -5620,12 +5941,14 @@ function readStdin(source, signal) {
5620
5941
  const stop = () => {
5621
5942
  source.off("data", onData).off("end", onEnd).off("error", onError).pause();
5622
5943
  signal.removeEventListener("abort", onAbort);
5944
+ idleWindow.abort();
5623
5945
  };
5624
5946
  if (signal.aborted) {
5625
5947
  reject(signal.reason);
5626
5948
  return;
5627
5949
  }
5628
5950
  signal.addEventListener("abort", onAbort, { once: true });
5951
+ watchIdle();
5629
5952
  source.on("data", onData).once("end", onEnd).once("error", onError);
5630
5953
  });
5631
5954
  }
@@ -5699,11 +6022,11 @@ function optionField(key, schema) {
5699
6022
  usage
5700
6023
  };
5701
6024
  }
5702
- function fieldsOf$1(schema, toField) {
6025
+ function fieldsOf(schema, toField) {
5703
6026
  return schema === void 0 ? [] : Object.entries(schema.shape).map(([key, value]) => toField(key, value));
5704
6027
  }
5705
6028
  function argFields(schema) {
5706
- return fieldsOf$1(schema, argField);
6029
+ return fieldsOf(schema, argField);
5707
6030
  }
5708
6031
  function keysOf(fields) {
5709
6032
  return fields.map(({ key }) => `'${key}'`).join(", ");
@@ -5724,7 +6047,7 @@ function checkStdinFields(name, args, options) {
5724
6047
  }
5725
6048
  }
5726
6049
  function optionFields(schema) {
5727
- return fieldsOf$1(schema, optionField);
6050
+ return fieldsOf(schema, optionField);
5728
6051
  }
5729
6052
  /** Throws when an option is an array of booleans, which a switch cannot express. */
5730
6053
  function checkNoBooleanArrayOption(name, options) {
@@ -5732,116 +6055,19 @@ function checkNoBooleanArrayOption(name, options) {
5732
6055
  if (booleans.length > 0) throw new Error(`Command '${name}' declares boolean array option ${keysOf(booleans)}; a switch cannot repeat, use a boolean`);
5733
6056
  }
5734
6057
  //#endregion
5735
- //#region ../agent-cli/dist/errors.js
5736
- var CliError = class extends Error {
5737
- code;
5738
- hint;
5739
- details;
5740
- retryAt;
5741
- constructor({ code, message, hint, details, retryAt }, options) {
5742
- super(message, options);
5743
- this.name = "CliError";
5744
- this.code = code;
5745
- this.hint = hint;
5746
- this.details = details;
5747
- this.retryAt = retryAt;
5748
- }
5749
- };
5750
- /** The caller called the Agent CLI wrong; the same call can't succeed. */
5751
- var UsageError = class extends CliError {
5752
- constructor(fields) {
5753
- super(fields);
5754
- this.name = "UsageError";
5755
- }
5756
- };
5757
- const INTERNAL_CODE = "INTERNAL";
5758
- function errnoOf(error) {
5759
- return error instanceof Error && "code" in error && typeof error.code === "string" ? error.code : void 0;
5760
- }
5761
- function isMissingFile(error) {
5762
- return errnoOf(error) === "ENOENT";
5763
- }
5764
- function isNothingThere(error) {
5765
- return isMissingFile(error) || errnoOf(error) === "ENOTDIR";
5766
- }
5767
- function debugVariable(cliName) {
5768
- return `${cliName.toUpperCase().replace(/[^A-Z0-9]/g, "_")}_DEBUG`;
5769
- }
5770
- function messageOf(error) {
5771
- return error instanceof Error ? error.message : String(error);
5772
- }
5773
- function isDebug({ env, cliName }) {
5774
- return Boolean(env[debugVariable(cliName)]);
6058
+ //#region ../agent-cli/dist/tokenize.js
6059
+ const NEGATIVE_NUMBER = /^-(\d+|\d*\.\d+)(e[+-]?\d+)?$/;
6060
+ function isOptionLike(word) {
6061
+ return word !== void 0 && word.length > 1 && word[0] === "-" && !NEGATIVE_NUMBER.test(word);
5775
6062
  }
5776
- function bugHint(format) {
5777
- return isDebug(format) ? "the stack trace shows where it failed" : `rerun with ${debugVariable(format.cliName)}=1 to see the stack trace`;
6063
+ function parseArgsOptions(known) {
6064
+ return Object.fromEntries(known.map(({ flag, takes }) => [flag.slice(2), { type: takes === "value" ? "string" : "boolean" }]));
5778
6065
  }
5779
- function fieldsOf(error, format) {
5780
- if (error instanceof CliError) {
5781
- const { code, message, hint, details, retryAt } = error;
5782
- return {
5783
- code,
5784
- message,
5785
- hint: format.isBug(error) ? bugHint(format) : hint,
5786
- details,
5787
- retryAt
5788
- };
5789
- }
5790
- return {
5791
- code: INTERNAL_CODE,
5792
- message: messageOf(error),
5793
- hint: bugHint(format)
5794
- };
5795
- }
5796
- function causesOf(error) {
5797
- return error instanceof Error && error.cause !== void 0 ? [error.cause, ...causesOf(error.cause)] : [];
5798
- }
5799
- function traceOf(error) {
5800
- return error instanceof Error ? error.stack ?? error.message : String(error);
5801
- }
5802
- /** Under debug: a bug's stack trace, then every error's cause chain. */
5803
- function debugTrace(error, format) {
5804
- if (!isDebug(format)) return void 0;
5805
- const lines = [...format.isBug(error) ? [traceOf(error)] : [], ...causesOf(error).map((cause) => `caused by: ${traceOf(cause)}`)];
5806
- return lines.length === 0 ? void 0 : lines.join("\n");
5807
- }
5808
- /** The errors a run failed with: each one an `AggregateError` holds, or the one it threw. */
5809
- function errorsOf(error) {
5810
- return error instanceof AggregateError && error.errors.length > 0 ? error.errors : [error];
5811
- }
5812
- function errorLines(error, format) {
5813
- const fields = fieldsOf(error, format);
5814
- const stack = debugTrace(error, format);
5815
- const { style } = format;
5816
- const label = style.red(format.isBug(error) ? "internal error:" : "error:");
5817
- const trace = stack === void 0 ? "" : `${stack}\n`;
5818
- return `${label} ${fields.message}\n${trace}${style.cyan("hint:")} ${fields.hint}\n`;
5819
- }
5820
- function formatRuntimeError(error, format) {
5821
- const errors = errorsOf(error);
5822
- if (format.json) {
5823
- const printed = errors.map((each) => ({
5824
- ...fieldsOf(each, format),
5825
- stack: debugTrace(each, format)
5826
- }));
5827
- return `${JSON.stringify({ errors: printed })}\n`;
5828
- }
5829
- return errors.map((each) => errorLines(each, format)).join("");
5830
- }
5831
- //#endregion
5832
- //#region ../agent-cli/dist/tokenize.js
5833
- const NEGATIVE_NUMBER = /^-(\d+|\d*\.\d+)(e[+-]?\d+)?$/;
5834
- function isOptionLike(word) {
5835
- return word !== void 0 && word.length > 1 && word[0] === "-" && !NEGATIVE_NUMBER.test(word);
5836
- }
5837
- function parseArgsOptions(known) {
5838
- return Object.fromEntries(known.map(({ flag, takes }) => [flag.slice(2), { type: takes === "value" ? "string" : "boolean" }]));
5839
- }
5840
- function flagItem(token, { flag, takes }, words) {
5841
- if (takes !== "optional value" || token.inlineValue === true) return {
5842
- kind: "flag",
5843
- flag,
5844
- value: token.value ?? true
6066
+ function flagItem(token, { flag, takes }, words) {
6067
+ if (takes !== "optional value" || token.inlineValue === true) return {
6068
+ kind: "flag",
6069
+ flag,
6070
+ value: token.value ?? true
5845
6071
  };
5846
6072
  const took = token.index + 1;
5847
6073
  const next = words[took];
@@ -5986,6 +6212,18 @@ function unknownOptionError(commandLine, invocation, flag, suggestions) {
5986
6212
  listed: "options"
5987
6213
  });
5988
6214
  }
6215
+ /** Text opening with `-` was read as an option, where the Command could have read it from stdin. */
6216
+ function stdinTextError(commandLine, invocation, word) {
6217
+ const withStdin = commandLineOf(invocation, {
6218
+ remove: [word],
6219
+ add: ["-"]
6220
+ });
6221
+ return new UsageError({
6222
+ code: UNKNOWN_OPTION,
6223
+ message: `unknown option '${word}' for \`${commandLine}\``,
6224
+ hint: `to pass text opening with \`-\`, pass \`-\` and send the text on stdin through a heredoc: \`${withStdin} <<'EOF'\`, then the text, then \`EOF\``
6225
+ });
6226
+ }
5989
6227
  function unknownCommandError(commandLine, name, suggestions) {
5990
6228
  return unknownError({
5991
6229
  code: UNKNOWN_COMMAND,
@@ -6012,7 +6250,7 @@ const COLUMN_SEPARATOR = " ";
6012
6250
  const UNSAFE_IN_COLUMN = /[\t\n\r]/;
6013
6251
  const PAGE_INPUT = object({
6014
6252
  limit: number().int().positive().default(DEFAULT_PAGE_LIMIT),
6015
- cursor: number().int().nonnegative().optional()
6253
+ cursor: string().min(1).optional()
6016
6254
  });
6017
6255
  var Page = class {
6018
6256
  items;
@@ -6100,12 +6338,16 @@ function cell(value) {
6100
6338
  function renderRows(rows, fields) {
6101
6339
  return `${[fields, ...rows.map((row) => fields.map((field) => cell(row[field])))].map((line) => line.join(COLUMN_SEPARATOR)).join("\n")}\n`;
6102
6340
  }
6341
+ function cursorWords(cursor) {
6342
+ const { flag } = PAGE_FLAGS.cursor;
6343
+ return cursor.startsWith("-") ? [`${flag}=${cursor}`] : [flag, cursor];
6344
+ }
6103
6345
  function printedPage(page, invocation) {
6104
6346
  return page.nextCursor === void 0 ? { items: page.items } : {
6105
6347
  items: page.items,
6106
6348
  next: commandLineOf(invocation, {
6107
6349
  remove: [PAGE_FLAGS.cursor.flag],
6108
- add: [PAGE_FLAGS.cursor.flag, String(page.nextCursor)]
6350
+ add: cursorWords(page.nextCursor)
6109
6351
  })
6110
6352
  };
6111
6353
  }
@@ -6234,71 +6476,50 @@ function isCommand(node) {
6234
6476
  return typeof node.effect === "string";
6235
6477
  }
6236
6478
  //#endregion
6237
- //#region ../agent-cli/dist/semver.js
6238
- const VERSION = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/;
6239
- const ENGINE = /^>=\s*(\d+)(?:\.(\d+))?(?:\.(\d+))?$/;
6240
- function isVersion(text) {
6241
- return VERSION.test(text);
6242
- }
6243
- function compareIdentifiers(x, y) {
6244
- const xNumeric = /^\d+$/.test(x);
6245
- const yNumeric = /^\d+$/.test(y);
6246
- if (xNumeric && yNumeric) return Number(x) - Number(y);
6247
- if (xNumeric !== yNumeric) return xNumeric ? -1 : 1;
6248
- if (x === y) return 0;
6249
- return x < y ? -1 : 1;
6479
+ //#region ../agent-cli/dist/project.js
6480
+ const PROJECT_INVALID = "PROJECT_INVALID";
6481
+ function invalid(path, problem, options) {
6482
+ return new CliError({
6483
+ code: PROJECT_INVALID,
6484
+ message: `the Project file ${path} is invalid: ${problem}`,
6485
+ hint: `fix ${path}, then run the command again`
6486
+ }, options);
6250
6487
  }
6251
- function comparePrerelease(a, b) {
6252
- if (a === b) return 0;
6253
- if (a === void 0) return 1;
6254
- if (b === void 0) return -1;
6255
- const left = a.split(".");
6256
- const right = b.split(".");
6257
- for (let i = 0; i < Math.min(left.length, right.length); i += 1) {
6258
- const difference = compareIdentifiers(left[i] ?? "", right[i] ?? "");
6259
- if (difference !== 0) return difference;
6488
+ function readText(path, fileError) {
6489
+ try {
6490
+ return readFileSync(path, "utf8");
6491
+ } catch (error) {
6492
+ if (isMissingFile(error)) return void 0;
6493
+ throw fileError(error, {
6494
+ path,
6495
+ access: "read"
6496
+ });
6260
6497
  }
6261
- return left.length - right.length;
6262
6498
  }
6263
- /** Negative when `a` is older than `b`, positive when newer, 0 when the same release. */
6264
- function compareVersions(a, b) {
6265
- const left = VERSION.exec(a);
6266
- const right = VERSION.exec(b);
6267
- if (left === null || right === null) throw new Error(`cannot compare ${a} with ${b}: both must be X.Y.Z versions`);
6268
- for (const part of [
6269
- 1,
6270
- 2,
6271
- 3
6272
- ]) {
6273
- const difference = Number(left[part]) - Number(right[part]);
6274
- if (difference !== 0) return difference;
6499
+ function parsed(path, text, schema) {
6500
+ let json;
6501
+ try {
6502
+ json = JSON.parse(text);
6503
+ } catch (error) {
6504
+ throw invalid(path, messageOf(error), { cause: error });
6275
6505
  }
6276
- return comparePrerelease(left[4], right[4]);
6277
- }
6278
- /** Where `version` stands against `latest`. */
6279
- function standingOf(version, latest) {
6280
- const difference = compareVersions(version, latest);
6281
- if (difference < 0) return "behind";
6282
- return difference > 0 ? "ahead" : "current";
6283
- }
6284
- /** The minimum an `engines.node` range asks for, or undefined when it is not `>=X[.Y[.Z]]`. */
6285
- function engineMinimum(range) {
6286
- const match = ENGINE.exec(range.trim());
6287
- return match === null ? void 0 : match.slice(1).map((part) => Number(part ?? 0));
6506
+ const result = schema.safeParse(json);
6507
+ if (!result.success) throw invalid(path, prettifyError(result.error));
6508
+ return result.data;
6288
6509
  }
6289
- function meetsMinimum(version, minimum) {
6290
- const parts = version.split(".").map(Number);
6291
- for (const [i, wanted] of minimum.entries()) {
6292
- const found = parts[i] ?? 0;
6293
- if (found !== wanted) return found > wanted;
6294
- }
6295
- return true;
6510
+ function projectFrom(projectFile, folder, fileError) {
6511
+ const path = join(folder, projectFile.file);
6512
+ const text = readText(path, fileError);
6513
+ if (text !== void 0) return {
6514
+ root: folder,
6515
+ settings: parsed(path, text, projectFile.schema)
6516
+ };
6517
+ const parent = dirname(folder);
6518
+ return parent === folder ? void 0 : projectFrom(projectFile, parent, fileError);
6296
6519
  }
6297
- //#endregion
6298
- //#region ../agent-cli/dist/tail.js
6299
- /** The last `count` lines of a child's output, trimmed; empty when it wrote nothing. */
6300
- function lastLines(output, count) {
6301
- return output.trim().split("\n").slice(-count).join("\n");
6520
+ /** The nearest Project file at or above `cwd`, parsed by its schema; undefined when there is none. */
6521
+ function projectOf(projectFile, cwd, fileError) {
6522
+ return projectFrom(projectFile, resolve(cwd), fileError);
6302
6523
  }
6303
6524
  //#endregion
6304
6525
  //#region ../agent-cli/dist/tools.js
@@ -6363,6 +6584,18 @@ function toolRows(tools, commands) {
6363
6584
  }));
6364
6585
  }
6365
6586
  //#endregion
6587
+ //#region ../agent-cli/dist/version.js
6588
+ /** The first line of `--version`: the version, and the commit and time of a stamped build. */
6589
+ function versionLine({ version, build }) {
6590
+ return build === void 0 ? version : `${version} (${build.sha}${build.dirty ? "+dirty" : ""}) built ${build.builtAt}`;
6591
+ }
6592
+ //#endregion
6593
+ //#region ../agent-cli/dist/tail.js
6594
+ /** The last `count` lines of a child's output, trimmed; empty when it wrote nothing. */
6595
+ function lastLines(output, count) {
6596
+ return output.trim().split("\n").slice(-count).join("\n");
6597
+ }
6598
+ //#endregion
6366
6599
  //#region ../agent-cli/dist/spawn.js
6367
6600
  const TOOL_FAILED = "TOOL_FAILED";
6368
6601
  const STDERR_TAIL_LINES$1 = 20;
@@ -6537,7 +6770,68 @@ function contextSpawn(run, defaults, fileError) {
6537
6770
  };
6538
6771
  }
6539
6772
  //#endregion
6540
- //#region ../agent-cli/dist/npm.js
6773
+ //#region ../agent-cli/dist/built-ins/semver.js
6774
+ const VERSION = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/;
6775
+ const ENGINE = /^>=\s*(\d+)(?:\.(\d+))?(?:\.(\d+))?$/;
6776
+ function isVersion(text) {
6777
+ return VERSION.test(text);
6778
+ }
6779
+ function compareIdentifiers(x, y) {
6780
+ const xNumeric = /^\d+$/.test(x);
6781
+ const yNumeric = /^\d+$/.test(y);
6782
+ if (xNumeric && yNumeric) return Number(x) - Number(y);
6783
+ if (xNumeric !== yNumeric) return xNumeric ? -1 : 1;
6784
+ if (x === y) return 0;
6785
+ return x < y ? -1 : 1;
6786
+ }
6787
+ function comparePrerelease(a, b) {
6788
+ if (a === b) return 0;
6789
+ if (a === void 0) return 1;
6790
+ if (b === void 0) return -1;
6791
+ const left = a.split(".");
6792
+ const right = b.split(".");
6793
+ for (let i = 0; i < Math.min(left.length, right.length); i += 1) {
6794
+ const difference = compareIdentifiers(left[i] ?? "", right[i] ?? "");
6795
+ if (difference !== 0) return difference;
6796
+ }
6797
+ return left.length - right.length;
6798
+ }
6799
+ /** Negative when `a` is older than `b`, positive when newer, 0 when the same release. */
6800
+ function compareVersions(a, b) {
6801
+ const left = VERSION.exec(a);
6802
+ const right = VERSION.exec(b);
6803
+ if (left === null || right === null) throw new Error(`cannot compare ${a} with ${b}: both must be X.Y.Z versions`);
6804
+ for (const part of [
6805
+ 1,
6806
+ 2,
6807
+ 3
6808
+ ]) {
6809
+ const difference = Number(left[part]) - Number(right[part]);
6810
+ if (difference !== 0) return difference;
6811
+ }
6812
+ return comparePrerelease(left[4], right[4]);
6813
+ }
6814
+ /** Where `version` stands against `latest`. */
6815
+ function standingOf(version, latest) {
6816
+ const difference = compareVersions(version, latest);
6817
+ if (difference < 0) return "behind";
6818
+ return difference > 0 ? "ahead" : "current";
6819
+ }
6820
+ /** The minimum an `engines.node` range asks for, or undefined when it is not `>=X[.Y[.Z]]`. */
6821
+ function engineMinimum(range) {
6822
+ const match = ENGINE.exec(range.trim());
6823
+ return match === null ? void 0 : match.slice(1).map((part) => Number(part ?? 0));
6824
+ }
6825
+ function meetsMinimum(version, minimum) {
6826
+ const parts = version.split(".").map(Number);
6827
+ for (const [i, wanted] of minimum.entries()) {
6828
+ const found = parts[i] ?? 0;
6829
+ if (found !== wanted) return found > wanted;
6830
+ }
6831
+ return true;
6832
+ }
6833
+ //#endregion
6834
+ //#region ../agent-cli/dist/built-ins/npm.js
6541
6835
  const REGISTRY_UNREACHABLE = "REGISTRY_UNREACHABLE";
6542
6836
  const REGISTRY_AUTH = "REGISTRY_AUTH";
6543
6837
  const INSTALL_FAILED = "INSTALL_FAILED";
@@ -6714,7 +7008,7 @@ async function latestVersion(ctx) {
6714
7008
  return version;
6715
7009
  }
6716
7010
  //#endregion
6717
- //#region ../agent-cli/dist/global-install.js
7011
+ //#region ../agent-cli/dist/built-ins/global-install.js
6718
7012
  const NOT_GLOBAL_INSTALL = "NOT_GLOBAL_INSTALL";
6719
7013
  /** Where npm puts global packages under its global prefix. */
6720
7014
  function globalModulesDir(prefix) {
@@ -6755,46 +7049,671 @@ async function globalInstallOf(bin, ctx) {
6755
7049
  };
6756
7050
  }
6757
7051
  //#endregion
6758
- //#region ../agent-cli/dist/confirm.js
6759
- const CONFIRMATION_REQUIRED = "CONFIRMATION_REQUIRED";
6760
- const CONFIRMATION_MISMATCH = "CONFIRMATION_MISMATCH";
6761
- function checkConfirmation({ invocation, commandLine, given }, expected) {
6762
- if (given === expected) return;
6763
- const hint = `to confirm, run \`${commandLineOf(invocation, {
6764
- remove: [CONFIRM_FLAG.flag],
6765
- add: [CONFIRM_FLAG.flag, expected]
6766
- })}\``;
6767
- if (given === void 0) throw new UsageError({
6768
- code: CONFIRMATION_REQUIRED,
6769
- message: `\`${commandLine}\` is destructive and needs ${CONFIRM_FLAG.flag}`,
6770
- hint
6771
- });
6772
- throw new UsageError({
6773
- code: CONFIRMATION_MISMATCH,
6774
- message: `${CONFIRM_FLAG.flag} ${JSON.stringify(given)} does not match the target of \`${commandLine}\``,
6775
- hint
6776
- });
6777
- }
6778
- //#endregion
6779
- //#region ../agent-cli/dist/cost.js
6780
- const NOT_CONFIRMED = "NOT_CONFIRMED";
6781
- /** Refuses a run whose Plan states a cost the caller has not approved with `--yes`. */
6782
- function checkCost({ invocation, commandLine, yes }, cost) {
6783
- if (cost === void 0 || yes) return;
6784
- throw new CliError({
6785
- code: NOT_CONFIRMED,
6786
- message: `\`${commandLine}\` needs ${YES_FLAG.flag}: ${cost}`,
6787
- hint: `to approve the cost, run \`${commandLineOf(invocation, { add: [YES_FLAG.flag] })}\``
6788
- });
7052
+ //#region ../agent-cli/dist/manifest.js
7053
+ const link$1 = union([string(), object({ url: string() })]).transform((value) => typeof value === "string" ? value : value.url).optional().catch(void 0);
7054
+ const manifestSchema = object({
7055
+ repository: link$1,
7056
+ bugs: link$1
7057
+ });
7058
+ const NO_MANIFEST = {};
7059
+ function manifestAt(packageRoot) {
7060
+ let manifest;
7061
+ try {
7062
+ manifest = JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf8"));
7063
+ } catch {
7064
+ return NO_MANIFEST;
7065
+ }
7066
+ const parsed = manifestSchema.safeParse(manifest);
7067
+ return parsed.success ? parsed.data : NO_MANIFEST;
6789
7068
  }
6790
7069
  //#endregion
6791
- //#region ../agent-cli/dist/agent.js
6792
- const AGENT_NAME = /^[a-zA-Z0-9_-]+$/u;
6793
- const isSet = (name) => (env) => (env[name] ?? "") !== "";
6794
- const equals = (name, value) => (env) => env[name] === value;
6795
- const MARKERS = [
6796
- (env) => AGENT_NAME.test(env.AI_AGENT ?? ""),
6797
- equals("AGENT", "amp"),
7070
+ //#region ../agent-cli/dist/built-ins/skills.js
7071
+ const SKILL_DIRS = [[".claude", "skills"], [".agents", "skills"]];
7072
+ /** The branch a release moves to the released commit, which holds the skill of that version. */
7073
+ const RELEASE_BRANCH$1 = "release";
7074
+ const SHORTHAND = /^(?:(?:github:)?[\w.-]+\/[\w.-]+|gitlab:[\w.-]+(?:\/[\w.-]+)+)$/;
7075
+ const GIT_URL_PROTOCOLS = /* @__PURE__ */ new Set([
7076
+ "https:",
7077
+ "http:",
7078
+ "ssh:",
7079
+ "git:"
7080
+ ]);
7081
+ const SCP_STYLE = /^[\w.-]+@[\w.-]+:[\w./-]+$/;
7082
+ const FRONTMATTER = /^---\r?\n([\s\S]*?)\r?\n---/;
7083
+ const METADATA_VERSION = /^metadata:[ \t]*\r?\n(?:[ \t]+.*\r?\n)*?[ \t]+version:[ \t]*["']?([^"'\s]+)["']?[ \t]*$/m;
7084
+ /** The version a SKILL.md's frontmatter `metadata.version` states. */
7085
+ function skillVersionIn(skill) {
7086
+ const frontmatter = FRONTMATTER.exec(skill)?.[1];
7087
+ return frontmatter === void 0 ? void 0 : METADATA_VERSION.exec(`${frontmatter}\n`)?.[1];
7088
+ }
7089
+ function homeOf(env) {
7090
+ return env.HOME ?? env.USERPROFILE ?? homedir();
7091
+ }
7092
+ async function copyAt(path, version) {
7093
+ let skill;
7094
+ try {
7095
+ skill = await readFile(join(path, "SKILL.md"), "utf8");
7096
+ } catch (error) {
7097
+ if (isMissingFile(error)) return;
7098
+ return {
7099
+ path,
7100
+ version: void 0,
7101
+ state: "unreadable"
7102
+ };
7103
+ }
7104
+ const stated = skillVersionIn(skill);
7105
+ if (stated === void 0 || !isVersion(stated) || !isVersion(version)) return {
7106
+ path,
7107
+ version: stated,
7108
+ state: "unversioned"
7109
+ };
7110
+ return {
7111
+ path,
7112
+ version: stated,
7113
+ state: standingOf(stated, version)
7114
+ };
7115
+ }
7116
+ async function skillCopies(cliName, version, { cwd, env }) {
7117
+ const paths = [cwd, homeOf(env)].flatMap((root) => SKILL_DIRS.map((dir) => join(root, ...dir, cliName)));
7118
+ const seen = /* @__PURE__ */ new Set();
7119
+ const copies = [];
7120
+ for (const path of paths) {
7121
+ const copy = await copyAt(path, version);
7122
+ const real = copy === void 0 ? void 0 : await realpath(path);
7123
+ if (copy !== void 0 && real !== void 0 && !seen.has(real)) {
7124
+ seen.add(real);
7125
+ copies.push(copy);
7126
+ }
7127
+ }
7128
+ return copies;
7129
+ }
7130
+ function sourceFromRepository(repository) {
7131
+ if (SHORTHAND.test(repository)) return `${repository}#${RELEASE_BRANCH$1}`;
7132
+ const url = repository.replace(/^git\+/, "");
7133
+ if (!(URL.canParse(url) && GIT_URL_PROTOCOLS.has(new URL(url).protocol)) && !SCP_STYLE.test(url)) return void 0;
7134
+ return `${url.endsWith(".git") ? url : `${url}.git`}#${RELEASE_BRANCH$1}`;
7135
+ }
7136
+ /** What the installer installs the CLI's skill from: the declared source, else the package's repository. */
7137
+ function skillSource({ skill }, packageRoot) {
7138
+ if (skill !== void 0) return skill.source;
7139
+ const { repository } = manifestAt(packageRoot);
7140
+ return repository === void 0 ? void 0 : sourceFromRepository(repository);
7141
+ }
7142
+ function fixFor(cliName, copies, source) {
7143
+ const has = (wanted) => copies.some(({ state }) => state === wanted);
7144
+ const update = `npx -y skills update ${cliName}`;
7145
+ const add = source === void 0 ? void 0 : `npx -y skills add ${source} --skill ${cliName} -g`;
7146
+ if (copies.length === 0) return add;
7147
+ if (has("unversioned") && add !== void 0) return has("behind") ? `${update} && ${add}` : add;
7148
+ return has("behind") || has("unversioned") ? update : void 0;
7149
+ }
7150
+ async function skillReport(cli, version, ctx) {
7151
+ const copies = await skillCopies(cli.name, version, ctx);
7152
+ return {
7153
+ copies,
7154
+ fix: fixFor(cli.name, copies, skillSource(cli, ctx.packageRoot))
7155
+ };
7156
+ }
7157
+ //#endregion
7158
+ //#region ../agent-cli/dist/built-ins/doctor-rows.js
7159
+ function ok(message) {
7160
+ return {
7161
+ state: "ok",
7162
+ message
7163
+ };
7164
+ }
7165
+ function buildRow(cli) {
7166
+ return {
7167
+ name: "build",
7168
+ run: () => ok(versionLine(cli))
7169
+ };
7170
+ }
7171
+ function nodeRow(cli) {
7172
+ return {
7173
+ name: "node",
7174
+ run: () => {
7175
+ const found = process.versions.node;
7176
+ const range = cli.engines?.node;
7177
+ if (range === void 0) return ok(`Node ${found}; ${cli.name} declares no engines.node to check it against`);
7178
+ const minimum = engineMinimum(range);
7179
+ if (minimum === void 0) return {
7180
+ state: "problem",
7181
+ message: `${cli.name} declares engines.node "${range}", which doctor cannot read: only >=X.Y.Z is supported`
7182
+ };
7183
+ if (meetsMinimum(found, minimum)) return ok(`Node ${found} meets ${range}`);
7184
+ const major = minimum[0];
7185
+ return {
7186
+ state: "problem",
7187
+ message: `${cli.name} runs on Node ${found}, older than the ${range} it needs; install Node ${minimum.join(".")} or newer and make it the default`,
7188
+ fix: `nvm install ${major} && nvm alias default ${major}`
7189
+ };
7190
+ }
7191
+ };
7192
+ }
7193
+ function projectRow(projectFile) {
7194
+ const { file } = projectFile;
7195
+ return {
7196
+ name: "project",
7197
+ run: (ctx) => {
7198
+ let project;
7199
+ try {
7200
+ project = projectOf(projectFile, ctx.cwd, ctx.fileError);
7201
+ } catch (error) {
7202
+ if (error instanceof CliError && error.code === "PROJECT_INVALID") return {
7203
+ state: "problem",
7204
+ message: error.message
7205
+ };
7206
+ throw error;
7207
+ }
7208
+ return ok(project === void 0 ? `none found: no ${file} at or above ${ctx.cwd}` : join(project.root, file));
7209
+ }
7210
+ };
7211
+ }
7212
+ function installRow(cli, { bin, node }) {
7213
+ return {
7214
+ name: "install",
7215
+ advisory: true,
7216
+ run: async (ctx) => {
7217
+ const { install } = cli;
7218
+ if (install === void 0) return ok(`${cli.name} declares no install, so it has no \`update\``);
7219
+ try {
7220
+ return ok(`a global npm install under ${(await globalInstallOf(bin, npmContext(cli, install, ctx, node))).prefix}`);
7221
+ } catch (error) {
7222
+ if (error instanceof CliError && error.code === "NOT_GLOBAL_INSTALL") return {
7223
+ state: "problem",
7224
+ message: error.message,
7225
+ fix: installCommandLine(install)
7226
+ };
7227
+ throw error;
7228
+ }
7229
+ }
7230
+ };
7231
+ }
7232
+ function registryRow(cli, node) {
7233
+ return {
7234
+ name: "registry",
7235
+ advisory: true,
7236
+ run: async (ctx) => {
7237
+ const { install } = cli;
7238
+ if (install === void 0) return ok(`${cli.name} declares no registry to compare this build with`);
7239
+ const latest = await latestVersion(npmContext(cli, install, ctx, node));
7240
+ const standing = standingOf(cli.version, latest);
7241
+ const head = `${install.registry} has ${latest} as latest: this build`;
7242
+ if (standing === "behind") return {
7243
+ state: "problem",
7244
+ message: `${head} (${cli.version}) is older`,
7245
+ fix: `${cli.name} update`
7246
+ };
7247
+ return ok(`${head} is ${standing === "current" ? "current" : `newer (${cli.version})`}`);
7248
+ }
7249
+ };
7250
+ }
7251
+ const SKILL_STATE_NOTES = {
7252
+ current: "the same as this build",
7253
+ behind: "older than this build",
7254
+ ahead: "newer than this build",
7255
+ unversioned: "states no metadata.version",
7256
+ unreadable: "could not be read"
7257
+ };
7258
+ function describeCopy({ path, version, state }) {
7259
+ return `${path}${version === void 0 ? "" : ` ${version}`} (${SKILL_STATE_NOTES[state]})`;
7260
+ }
7261
+ function skillRow(cli) {
7262
+ return {
7263
+ name: "skill",
7264
+ run: async (ctx) => {
7265
+ const { copies, fix } = await skillReport(cli, cli.version, ctx);
7266
+ const message = copies.length === 0 ? `no copy of the ${cli.name} skill is installed` : copies.map(describeCopy).join("; ");
7267
+ return fix === void 0 ? ok(message) : {
7268
+ state: "ok",
7269
+ message,
7270
+ fix
7271
+ };
7272
+ }
7273
+ };
7274
+ }
7275
+ /** Every row `doctor` reports, in order: the fixed rows around the CLI's own and its tools'. */
7276
+ function doctorChecks(cli, launch) {
7277
+ return [
7278
+ buildRow(cli),
7279
+ nodeRow(cli),
7280
+ ...cli.project === void 0 ? [] : [projectRow(cli.project)],
7281
+ ...cli.doctor ?? [],
7282
+ ...toolRows(cli.tools ?? [], cli.commands),
7283
+ installRow(cli, launch),
7284
+ registryRow(cli, launch.node),
7285
+ skillRow(cli)
7286
+ ];
7287
+ }
7288
+ //#endregion
7289
+ //#region ../agent-cli/dist/built-ins/doctor.js
7290
+ const DOCTOR_PROBLEMS = "DOCTOR_PROBLEMS";
7291
+ const DEFAULT_DEADLINE_MS = 1e4;
7292
+ const MS_PER_SECOND = 1e3;
7293
+ const MIN_LABEL_WIDTH = 8;
7294
+ const reportSchema = object({
7295
+ rows: array(object({
7296
+ check: string(),
7297
+ state: _enum([
7298
+ "ok",
7299
+ "problem",
7300
+ "skipped"
7301
+ ]),
7302
+ message: string(),
7303
+ fix: string().optional(),
7304
+ code: string().optional()
7305
+ })),
7306
+ next: array(string())
7307
+ });
7308
+ function problemOf(check, error, { signal, deadline, ms }) {
7309
+ if (!signal.aborted && deadline.aborted && error === deadline.reason) return {
7310
+ state: "problem",
7311
+ message: `${check.name} did not answer within ${ms / MS_PER_SECOND} s`
7312
+ };
7313
+ if (error instanceof CliError) return {
7314
+ state: "problem",
7315
+ message: `${error.message}; ${error.hint}`,
7316
+ code: error.code
7317
+ };
7318
+ return {
7319
+ state: "problem",
7320
+ message: `the ${check.name} row hit a bug: ${messageOf(error)}`
7321
+ };
7322
+ }
7323
+ function withSignal(ctx, signal) {
7324
+ return Object.create(ctx, { signal: { value: signal } });
7325
+ }
7326
+ async function rowOf(check, ctx) {
7327
+ const ms = check.deadlineMs ?? DEFAULT_DEADLINE_MS;
7328
+ const signal = ctx.deadline(ms);
7329
+ let finding;
7330
+ try {
7331
+ finding = await Promise.race([Promise.resolve().then(() => check.run(withSignal(ctx, signal))), untilAborted(signal)]);
7332
+ } catch (error) {
7333
+ if (ctx.signal.aborted) return void 0;
7334
+ finding = problemOf(check, error, {
7335
+ signal: ctx.signal,
7336
+ deadline: signal,
7337
+ ms
7338
+ });
7339
+ }
7340
+ return {
7341
+ row: {
7342
+ check: check.name,
7343
+ ...finding
7344
+ },
7345
+ advisory: check.advisory === true
7346
+ };
7347
+ }
7348
+ function nextOf(rows) {
7349
+ return [...new Set(rows.flatMap(({ fix }) => fix === void 0 ? [] : [fix]))];
7350
+ }
7351
+ function render({ rows, next }, style) {
7352
+ const width = Math.max(MIN_LABEL_WIDTH, ...rows.map(({ check }) => check.length)) + 2;
7353
+ const stateWidth = Math.max(...rows.map(({ state }) => state.length)) + 2;
7354
+ return [...rows.map(({ check, state, message }) => {
7355
+ const label = state === "problem" ? style.red(state) : state;
7356
+ return `${check.padEnd(width)}${label}${" ".repeat(stateWidth - state.length)}${message}`;
7357
+ }), ...next.map((fix) => `${"next".padEnd(width)}${fix}`)].join("\n");
7358
+ }
7359
+ function failure(cliName, problems) {
7360
+ const errors = problems.map(({ check, message, fix, code }) => new CliError({
7361
+ code: code ?? "DOCTOR_PROBLEMS",
7362
+ message: `${cliName} doctor found a problem in ${check}: ${message}`,
7363
+ hint: fix === void 0 ? "the row says what is wrong" : `run ${fix}, then run doctor again`
7364
+ }));
7365
+ return new AggregateError(errors);
7366
+ }
7367
+ /** The built-in `doctor`: the fixed rows around the CLI's own, each under its own deadline. */
7368
+ function doctorCommand(cli, launch) {
7369
+ return defineCommand$1({
7370
+ name: "doctor",
7371
+ description: "check the setup and say what fixes each problem",
7372
+ examples: [{
7373
+ command: `${cli.name} doctor`,
7374
+ note: "check the setup and list the commands that fix it"
7375
+ }, {
7376
+ command: `${cli.name} doctor --json`,
7377
+ note: "get the rows and fixes as data"
7378
+ }],
7379
+ effect: "read",
7380
+ output: reportSchema,
7381
+ run: async (_input, ctx) => {
7382
+ const checked = (await Promise.all(doctorChecks(cli, launch).map((check) => rowOf(check, ctx)))).filter((row) => row !== void 0);
7383
+ const rows = checked.map(({ row }) => row);
7384
+ const report = {
7385
+ rows,
7386
+ next: nextOf(rows)
7387
+ };
7388
+ if (ctx.signal.aborted) {
7389
+ ctx.deliver(report);
7390
+ ctx.signal.throwIfAborted();
7391
+ }
7392
+ const problems = checked.filter(({ row, advisory }) => row.state === "problem" && !advisory).map(({ row }) => row);
7393
+ if (problems.length > 0) {
7394
+ ctx.deliver(report);
7395
+ throw failure(cli.name, problems);
7396
+ }
7397
+ return report;
7398
+ },
7399
+ render
7400
+ });
7401
+ }
7402
+ //#endregion
7403
+ //#region ../agent-cli/dist/interrupts.js
7404
+ const INTERRUPTED = "INTERRUPTED";
7405
+ const DEADLINE_EXCEEDED = "DEADLINE_EXCEEDED";
7406
+ /** How long an interrupted Command may take to settle before the run ends without it. */
7407
+ const GRACE_MS = 3e3;
7408
+ const GRACE_OVER = Symbol("grace over");
7409
+ function interruptedError() {
7410
+ return new CliError({
7411
+ code: INTERRUPTED,
7412
+ message: "interrupted before it finished",
7413
+ hint: "run the command again"
7414
+ });
7415
+ }
7416
+ const WAIT_HINT = "run it again later, when the service it waits on may answer faster";
7417
+ function deadlineError(commandLine, ms, hint, bound = "deadline") {
7418
+ return new CliError({
7419
+ code: DEADLINE_EXCEEDED,
7420
+ message: `${commandLine} ran past its ${ms} ms ${bound}`,
7421
+ hint
7422
+ });
7423
+ }
7424
+ /** One Command run's cancellation: its signal, its deadlines and the steps it must finish. */
7425
+ var RunControl = class {
7426
+ signal;
7427
+ #controller = new AbortController();
7428
+ #commandLine;
7429
+ #outer;
7430
+ #onOuterAbort = () => this.#controller.abort(interruptedError());
7431
+ /** Each running must-finish step, tracked until it settles, with its name. */
7432
+ #steps = /* @__PURE__ */ new Map();
7433
+ #progress;
7434
+ #clock;
7435
+ #disposed = new AbortController();
7436
+ /** The reasons this run's deadlines and timeouts aborted with, to tell them in a Command's error. */
7437
+ #abortReasons = /* @__PURE__ */ new WeakSet();
7438
+ #graceCancel = new AbortController();
7439
+ #endGrace = () => {};
7440
+ #graceOver = new Promise((resolve) => {
7441
+ this.#endGrace = resolve;
7442
+ });
7443
+ constructor({ commandLine, outer, clock, progress, runDeadline }) {
7444
+ this.#commandLine = commandLine;
7445
+ this.#outer = outer;
7446
+ this.#clock = clock;
7447
+ this.#progress = progress;
7448
+ this.signal = this.#controller.signal;
7449
+ this.signal.addEventListener("abort", () => this.#onStop(), { once: true });
7450
+ if (outer?.aborted === true) this.#onOuterAbort();
7451
+ else outer?.addEventListener("abort", this.#onOuterAbort, { once: true });
7452
+ if (runDeadline !== void 0) {
7453
+ const { ms, hint } = runDeadline;
7454
+ after(clock, ms, this.#disposed.signal, () => this.#controller.abort(deadlineError(commandLine, ms, hint())));
7455
+ }
7456
+ }
7457
+ deadline(ms) {
7458
+ return AbortSignal.any([this.signal, this.#abortsAfter(ms, "deadline")]);
7459
+ }
7460
+ timeout(ms) {
7461
+ return this.#abortsAfter(ms, "timeout");
7462
+ }
7463
+ #abortsAfter(ms, bound) {
7464
+ const controller = new AbortController();
7465
+ after(this.#clock, ms, this.#disposed.signal, () => {
7466
+ const reason = deadlineError(this.#commandLine, ms, WAIT_HINT, bound);
7467
+ this.#abortReasons.add(reason);
7468
+ controller.abort(reason);
7469
+ });
7470
+ return controller.signal;
7471
+ }
7472
+ async runToEnd(name, work) {
7473
+ this.#graceCancel.abort();
7474
+ if (this.signal.aborted) this.#finishing(name);
7475
+ const step = work();
7476
+ const settled = step.then(() => {}, () => {});
7477
+ this.#steps.set(settled, name);
7478
+ try {
7479
+ return await step;
7480
+ } finally {
7481
+ this.#steps.delete(settled);
7482
+ this.#startGrace();
7483
+ }
7484
+ }
7485
+ /** Waits for the Command, its must-finish steps, and no longer than the grace once interrupted. */
7486
+ async settle(work) {
7487
+ try {
7488
+ const value = await Promise.race([work, this.#graceOver]);
7489
+ if (this.signal.aborted || value === GRACE_OVER) throw this.signal.reason;
7490
+ return value;
7491
+ } finally {
7492
+ await this.#stepsDone();
7493
+ this.close();
7494
+ }
7495
+ }
7496
+ /**
7497
+ * The error a run ends with: an interrupt or the run deadline outranks what the Command threw,
7498
+ * unless the Command threw its own `INTERRUPTED`, saying what it finished before it stopped.
7499
+ * Otherwise each leaf that is not a `CliError` and whose cause chain holds a deadline's or timeout's
7500
+ * abort is reported as that abort, so a declared error keeps its own code.
7501
+ */
7502
+ errorAfter(error) {
7503
+ if (this.signal.aborted) return error instanceof CliError && error.code === "INTERRUPTED" ? error : this.signal.reason;
7504
+ const leaves = errorsOf(error).map((leaf) => this.#abortIn(leaf) ?? leaf);
7505
+ return leaves.length === 1 ? leaves[0] : new AggregateError(leaves);
7506
+ }
7507
+ #abortIn(error) {
7508
+ if (error instanceof CliError) return void 0;
7509
+ return causesOf(error).find((each) => each instanceof CliError && this.#abortReasons.has(each));
7510
+ }
7511
+ #onStop() {
7512
+ for (const name of this.#steps.values()) this.#finishing(name);
7513
+ this.#startGrace();
7514
+ }
7515
+ #finishing(name) {
7516
+ this.#progress(`finishing ${name}`);
7517
+ }
7518
+ #startGrace() {
7519
+ if (this.signal.aborted && this.#steps.size === 0) {
7520
+ this.#graceCancel.abort();
7521
+ this.#graceCancel = new AbortController();
7522
+ after(this.#clock, GRACE_MS, this.#graceCancel.signal, () => this.#endGrace(GRACE_OVER));
7523
+ }
7524
+ }
7525
+ async #stepsDone() {
7526
+ while (this.#steps.size > 0) await Promise.all(this.#steps.keys());
7527
+ }
7528
+ /** Stops the run's timers and its hold on the caller's signal, for a run that never settles. */
7529
+ close() {
7530
+ this.#graceCancel.abort();
7531
+ this.#disposed.abort();
7532
+ this.#outer?.removeEventListener("abort", this.#onOuterAbort);
7533
+ }
7534
+ };
7535
+ //#endregion
7536
+ //#region ../agent-cli/dist/built-ins/upgrade-notes.js
7537
+ const RELEASE_HEADING = /^## v?(\S+)/;
7538
+ function releasesIn(changelog) {
7539
+ const releases = [];
7540
+ let current;
7541
+ for (const line of changelog.split(/\r?\n/)) {
7542
+ const heading = RELEASE_HEADING.exec(line);
7543
+ if (heading !== null) {
7544
+ const version = heading[1] ?? "";
7545
+ current = isVersion(version) ? {
7546
+ version,
7547
+ lines: []
7548
+ } : void 0;
7549
+ if (current !== void 0) releases.push(current);
7550
+ } else current?.lines.push(line);
7551
+ }
7552
+ return releases.map(({ version, lines }) => ({
7553
+ version,
7554
+ notes: lines.join("\n").trim()
7555
+ }));
7556
+ }
7557
+ /**
7558
+ * What changed in each release after `from` up to `to`, oldest first, from the CHANGELOG.md in
7559
+ * `packageDir`; none when the package ships no CHANGELOG.
7560
+ */
7561
+ async function upgradeNotes(packageDir, from, to) {
7562
+ let changelog;
7563
+ try {
7564
+ changelog = await readFile(join(packageDir, "CHANGELOG.md"), "utf8");
7565
+ } catch (error) {
7566
+ if (isMissingFile(error)) return [];
7567
+ throw error;
7568
+ }
7569
+ return releasesIn(changelog).filter(({ version }) => compareVersions(version, from) > 0 && compareVersions(version, to) <= 0).sort((a, b) => compareVersions(a.version, b.version));
7570
+ }
7571
+ //#endregion
7572
+ //#region ../agent-cli/dist/built-ins/update.js
7573
+ const updateSchema = object({
7574
+ from: string(),
7575
+ latest: string(),
7576
+ installed: object({
7577
+ version: string(),
7578
+ prefix: string()
7579
+ }).nullable(),
7580
+ upgrades: array(object({
7581
+ version: string(),
7582
+ notes: string()
7583
+ })),
7584
+ next: array(string())
7585
+ });
7586
+ function nothingToInstall({ from, latest }) {
7587
+ return standingOf(from, latest) === "current" ? `already on ${from}, the latest release: nothing to install` : `${from} is newer than the latest release ${latest}: nothing to install`;
7588
+ }
7589
+ function renderUpdate(cli, install, update) {
7590
+ const { installed } = update;
7591
+ const head = installed === null ? [nothingToInstall(update)] : [`installed ${install.package}@${installed.version} with the npm under ${installed.prefix}, replacing ${update.from}`, ...update.upgrades.map(({ version, notes }) => `\nchanges in ${version}:\n${notes}`)];
7592
+ const next = update.next.map((command) => `next: ${command}, so the ${cli.name} skill describes ${update.latest}`);
7593
+ return (next.length === 0 ? head : [
7594
+ ...head,
7595
+ "",
7596
+ ...next
7597
+ ]).join("\n");
7598
+ }
7599
+ async function skillNext(cli, latest, ctx) {
7600
+ const { fix } = await skillReport(cli, latest, ctx);
7601
+ return fix === void 0 ? [] : [fix];
7602
+ }
7603
+ function interruptedAfterInstall(plan) {
7604
+ return new CliError({
7605
+ code: INTERRUPTED,
7606
+ message: `interrupted, but ${plan.package}@${plan.latest} had already been installed with the npm under ${plan.prefix}, replacing ${plan.from}`,
7607
+ hint: "nothing to run again: run the commands under next"
7608
+ });
7609
+ }
7610
+ /** The built-in `update`, for a CLI installed globally with npm. */
7611
+ function updateCommand(cli, install, { bin, node }) {
7612
+ return defineCommand$1({
7613
+ name: "update",
7614
+ description: "install the latest version of this CLI from its registry",
7615
+ examples: [{
7616
+ command: `${cli.name} update`,
7617
+ note: "install the latest version and show what changed"
7618
+ }, {
7619
+ command: `${cli.name} update --dry-run`,
7620
+ note: "show the version it would install"
7621
+ }],
7622
+ effect: "write",
7623
+ output: updateSchema,
7624
+ plan: async (_input, ctx) => {
7625
+ const npm = npmContext(cli, install, ctx, node);
7626
+ const copy = await globalInstallOf(bin, npm);
7627
+ return {
7628
+ package: install.package,
7629
+ from: cli.version,
7630
+ latest: await latestVersion(npm),
7631
+ prefix: copy.prefix,
7632
+ packageDir: copy.packageDir
7633
+ };
7634
+ },
7635
+ apply: async (plan, ctx) => {
7636
+ const { from, latest, prefix } = plan;
7637
+ if (standingOf(from, latest) !== "behind") return {
7638
+ from,
7639
+ latest,
7640
+ installed: null,
7641
+ upgrades: [],
7642
+ next: await skillNext(cli, latest, ctx)
7643
+ };
7644
+ ctx.signal.throwIfAborted();
7645
+ ctx.progress(`installing ${plan.package}@${latest} with the npm under ${prefix}…`);
7646
+ await ctx.runToEnd(`installing ${plan.package}@${latest}`, () => installGlobally(latest, npmContext(cli, install, ctx, node)));
7647
+ const update = {
7648
+ from,
7649
+ latest,
7650
+ installed: {
7651
+ version: latest,
7652
+ prefix
7653
+ },
7654
+ upgrades: await upgradeNotes(plan.packageDir, from, latest),
7655
+ next: await skillNext(cli, latest, ctx)
7656
+ };
7657
+ if (ctx.signal.aborted) {
7658
+ ctx.deliver(update);
7659
+ throw interruptedAfterInstall(plan);
7660
+ }
7661
+ return update;
7662
+ },
7663
+ render: (update) => renderUpdate(cli, install, update),
7664
+ renderPlan: (plan) => standingOf(plan.from, plan.latest) === "behind" ? `would install ${plan.package}@${plan.latest} with the npm under ${plan.prefix}, replacing ${plan.from}` : nothingToInstall(plan)
7665
+ });
7666
+ }
7667
+ //#endregion
7668
+ //#region ../agent-cli/dist/built-ins/commands.js
7669
+ /** The Commands the Runtime adds to a multi-Command CLI: `update` only when it declares an install. */
7670
+ function builtInCommands(cli, launch) {
7671
+ return {
7672
+ doctor: doctorCommand(cli, launch),
7673
+ ...cli.install === void 0 ? {} : { update: updateCommand(cli, cli.install, launch) }
7674
+ };
7675
+ }
7676
+ //#endregion
7677
+ //#region ../agent-cli/dist/confirm.js
7678
+ const CONFIRMATION_REQUIRED = "CONFIRMATION_REQUIRED";
7679
+ const CONFIRMATION_MISMATCH = "CONFIRMATION_MISMATCH";
7680
+ function checkConfirmation({ invocation, commandLine, given }, expected) {
7681
+ if (given === expected) return;
7682
+ const hint = `to confirm, run \`${commandLineOf(invocation, {
7683
+ remove: [CONFIRM_FLAG.flag],
7684
+ add: [CONFIRM_FLAG.flag, expected]
7685
+ })}\``;
7686
+ if (given === void 0) throw new UsageError({
7687
+ code: CONFIRMATION_REQUIRED,
7688
+ message: `\`${commandLine}\` is destructive and needs ${CONFIRM_FLAG.flag}`,
7689
+ hint
7690
+ });
7691
+ throw new UsageError({
7692
+ code: CONFIRMATION_MISMATCH,
7693
+ message: `${CONFIRM_FLAG.flag} ${JSON.stringify(given)} does not match the target of \`${commandLine}\``,
7694
+ hint
7695
+ });
7696
+ }
7697
+ //#endregion
7698
+ //#region ../agent-cli/dist/cost.js
7699
+ const NOT_CONFIRMED = "NOT_CONFIRMED";
7700
+ /** Refuses a run whose Plan states a cost the caller has not approved with `--yes`. */
7701
+ function checkCost({ invocation, commandLine, yes }, cost) {
7702
+ if (cost === void 0 || yes) return;
7703
+ throw new CliError({
7704
+ code: NOT_CONFIRMED,
7705
+ message: `\`${commandLine}\` needs ${YES_FLAG.flag}: ${cost}`,
7706
+ hint: `to approve the cost, run \`${commandLineOf(invocation, { add: [YES_FLAG.flag] })}\``
7707
+ });
7708
+ }
7709
+ //#endregion
7710
+ //#region ../agent-cli/dist/agent.js
7711
+ const AGENT_NAME = /^[a-zA-Z0-9_-]+$/u;
7712
+ const isSet = (name) => (env) => (env[name] ?? "") !== "";
7713
+ const equals = (name, value) => (env) => env[name] === value;
7714
+ const MARKERS = [
7715
+ (env) => AGENT_NAME.test(env.AI_AGENT ?? ""),
7716
+ equals("AGENT", "amp"),
6798
7717
  isSet("CODEX_SANDBOX"),
6799
7718
  isSet("CODEX_CI"),
6800
7719
  isSet("CODEX_THREAD_ID"),
@@ -6877,159 +7796,6 @@ function classifyErrno(error, context) {
6877
7796
  }
6878
7797
  }
6879
7798
  //#endregion
6880
- //#region ../agent-cli/dist/clock.js
6881
- const realClock = {
6882
- now: () => Date.now(),
6883
- sleep: (ms, signal) => new Promise((resolve, reject) => {
6884
- if (signal?.aborted === true) {
6885
- reject(signal.reason);
6886
- return;
6887
- }
6888
- const onAbort = () => {
6889
- clearTimeout(timer);
6890
- reject(signal?.reason);
6891
- };
6892
- const timer = setTimeout(() => {
6893
- signal?.removeEventListener("abort", onAbort);
6894
- resolve();
6895
- }, ms);
6896
- signal?.addEventListener("abort", onAbort, { once: true });
6897
- })
6898
- };
6899
- /** Runs `then` once `ms` have passed on `clock`; aborting `cancel` drops it. */
6900
- function after(clock, ms, cancel, then) {
6901
- clock.sleep(ms, cancel).then(then, (error) => {
6902
- if (!cancel.aborted) throw error;
6903
- });
6904
- }
6905
- async function poll(clock, check, intervalMs, signal) {
6906
- for (;;) {
6907
- signal.throwIfAborted();
6908
- const value = await check();
6909
- if (value !== void 0) return value;
6910
- await clock.sleep(intervalMs, signal);
6911
- }
6912
- }
6913
- //#endregion
6914
- //#region ../agent-cli/dist/interrupts.js
6915
- const INTERRUPTED = "INTERRUPTED";
6916
- const DEADLINE_EXCEEDED = "DEADLINE_EXCEEDED";
6917
- /** How long an interrupted Command may take to settle before the run ends without it. */
6918
- const GRACE_MS = 3e3;
6919
- const GRACE_OVER = Symbol("grace over");
6920
- function interruptedError() {
6921
- return new CliError({
6922
- code: INTERRUPTED,
6923
- message: "interrupted before it finished",
6924
- hint: "run the command again"
6925
- });
6926
- }
6927
- const WAIT_HINT = "run it again later, when the service it waits on may answer faster";
6928
- function deadlineError(commandLine, ms, hint) {
6929
- return new CliError({
6930
- code: DEADLINE_EXCEEDED,
6931
- message: `${commandLine} ran past its ${ms} ms deadline`,
6932
- hint
6933
- });
6934
- }
6935
- /** One Command run's cancellation: its signal, its deadlines and the steps it must finish. */
6936
- var RunControl = class {
6937
- signal;
6938
- #controller = new AbortController();
6939
- #commandLine;
6940
- #outer;
6941
- #onOuterAbort = () => this.#controller.abort(interruptedError());
6942
- /** Each running must-finish step, tracked until it settles, with its name. */
6943
- #steps = /* @__PURE__ */ new Map();
6944
- #progress;
6945
- #clock;
6946
- #disposed = new AbortController();
6947
- #deadlineHit;
6948
- #graceCancel = new AbortController();
6949
- #endGrace = () => {};
6950
- #graceOver = new Promise((resolve) => {
6951
- this.#endGrace = resolve;
6952
- });
6953
- constructor({ commandLine, outer, clock, progress, runDeadline }) {
6954
- this.#commandLine = commandLine;
6955
- this.#outer = outer;
6956
- this.#clock = clock;
6957
- this.#progress = progress;
6958
- this.signal = this.#controller.signal;
6959
- this.signal.addEventListener("abort", () => this.#onStop(), { once: true });
6960
- if (outer?.aborted === true) this.#onOuterAbort();
6961
- else outer?.addEventListener("abort", this.#onOuterAbort, { once: true });
6962
- if (runDeadline !== void 0) {
6963
- const { ms, hint } = runDeadline;
6964
- after(clock, ms, this.#disposed.signal, () => this.#controller.abort(deadlineError(commandLine, ms, hint())));
6965
- }
6966
- }
6967
- deadline(ms) {
6968
- const controller = new AbortController();
6969
- after(this.#clock, ms, this.#disposed.signal, () => {
6970
- this.#deadlineHit ??= deadlineError(this.#commandLine, ms, WAIT_HINT);
6971
- controller.abort(this.#deadlineHit);
6972
- });
6973
- return AbortSignal.any([this.signal, controller.signal]);
6974
- }
6975
- async runToEnd(name, work) {
6976
- this.#graceCancel.abort();
6977
- if (this.signal.aborted) this.#finishing(name);
6978
- const step = work();
6979
- const settled = step.then(() => {}, () => {});
6980
- this.#steps.set(settled, name);
6981
- try {
6982
- return await step;
6983
- } finally {
6984
- this.#steps.delete(settled);
6985
- this.#startGrace();
6986
- }
6987
- }
6988
- /** Waits for the Command, its must-finish steps, and no longer than the grace once interrupted. */
6989
- async settle(work) {
6990
- try {
6991
- const value = await Promise.race([work, this.#graceOver]);
6992
- if (this.signal.aborted || value === GRACE_OVER) throw this.signal.reason;
6993
- return value;
6994
- } finally {
6995
- await this.#stepsDone();
6996
- this.close();
6997
- }
6998
- }
6999
- /**
7000
- * The error a run ends with: an interrupt or a missed deadline outranks what the Command threw,
7001
- * unless the Command threw its own `INTERRUPTED`, saying what it finished before it stopped.
7002
- */
7003
- errorAfter(error) {
7004
- if (this.signal.aborted) return error instanceof CliError && error.code === "INTERRUPTED" ? error : this.signal.reason;
7005
- if (this.#deadlineHit !== void 0 && !(error instanceof CliError)) return this.#deadlineHit;
7006
- return error;
7007
- }
7008
- #onStop() {
7009
- for (const name of this.#steps.values()) this.#finishing(name);
7010
- this.#startGrace();
7011
- }
7012
- #finishing(name) {
7013
- this.#progress(`finishing ${name}`);
7014
- }
7015
- #startGrace() {
7016
- if (this.signal.aborted && this.#steps.size === 0) {
7017
- this.#graceCancel.abort();
7018
- this.#graceCancel = new AbortController();
7019
- after(this.#clock, GRACE_MS, this.#graceCancel.signal, () => this.#endGrace(GRACE_OVER));
7020
- }
7021
- }
7022
- async #stepsDone() {
7023
- while (this.#steps.size > 0) await Promise.all(this.#steps.keys());
7024
- }
7025
- /** Stops the run's timers and its hold on the caller's signal, for a run that never settles. */
7026
- close() {
7027
- this.#graceCancel.abort();
7028
- this.#disposed.abort();
7029
- this.#outer?.removeEventListener("abort", this.#onOuterAbort);
7030
- }
7031
- };
7032
- //#endregion
7033
7799
  //#region ../agent-cli/dist/operator.js
7034
7800
  const NEEDS_OPERATOR = "NEEDS_OPERATOR";
7035
7801
  /** Fails with `NEEDS_OPERATOR` when a Coding agent runs an Operator Command. */
@@ -7160,12 +7926,19 @@ function realFiles() {
7160
7926
  force: true
7161
7927
  }),
7162
7928
  mkdir: async (path, options) => {
7929
+ const mode = options?.mode;
7163
7930
  if (options?.exclusive !== true) {
7164
- await mkdir(path, { recursive: true });
7931
+ await mkdir(path, {
7932
+ recursive: true,
7933
+ mode
7934
+ });
7165
7935
  return;
7166
7936
  }
7167
- await mkdir(dirname(path), { recursive: true });
7168
- await mkdir(path);
7937
+ await mkdir(dirname(path), {
7938
+ recursive: true,
7939
+ mode
7940
+ });
7941
+ await mkdir(path, { mode });
7169
7942
  },
7170
7943
  stat: async (path) => {
7171
7944
  try {
@@ -7277,52 +8050,6 @@ async function probeOutputs({ files, cwd, fileError }, outputs) {
7277
8050
  }));
7278
8051
  }
7279
8052
  //#endregion
7280
- //#region ../agent-cli/dist/project.js
7281
- const PROJECT_INVALID = "PROJECT_INVALID";
7282
- function invalid(path, problem, options) {
7283
- return new CliError({
7284
- code: PROJECT_INVALID,
7285
- message: `the Project file ${path} is invalid: ${problem}`,
7286
- hint: `fix ${path}, then run the command again`
7287
- }, options);
7288
- }
7289
- function readText(path) {
7290
- try {
7291
- return readFileSync(path, "utf8");
7292
- } catch (error) {
7293
- if (isMissingFile(error)) return void 0;
7294
- throw error;
7295
- }
7296
- }
7297
- function parsed(path, text, schema) {
7298
- let json;
7299
- try {
7300
- json = JSON.parse(text);
7301
- } catch (error) {
7302
- throw invalid(path, messageOf(error), { cause: error });
7303
- }
7304
- const result = schema.safeParse(json);
7305
- if (!result.success) throw invalid(path, prettifyError(result.error));
7306
- return result.data;
7307
- }
7308
- function projectFrom({ file, schema }, folder) {
7309
- const path = join(folder, file);
7310
- const text = readText(path);
7311
- if (text !== void 0) return {
7312
- root: folder,
7313
- settings: parsed(path, text, schema)
7314
- };
7315
- const parent = dirname(folder);
7316
- return parent === folder ? void 0 : projectFrom({
7317
- file,
7318
- schema
7319
- }, parent);
7320
- }
7321
- /** The nearest Project file at or above `cwd`, parsed by its schema; undefined when there is none. */
7322
- function projectOf(projectFile, cwd) {
7323
- return projectFrom(projectFile, resolve(cwd));
7324
- }
7325
- //#endregion
7326
8053
  //#region ../agent-cli/dist/exit-classes.js
7327
8054
  const SIGNAL_EXIT_CODES = {
7328
8055
  SIGINT: 130,
@@ -7335,46 +8062,44 @@ const EXIT_CODES = {
7335
8062
  wait: 75,
7336
8063
  bug: 70
7337
8064
  };
7338
- /** The codes the Runtime and its built-in Commands raise, each with the class that must act on it. */
7339
- function runtimeCodes() {
7340
- return {
7341
- [INVALID_INPUT]: "caller",
7342
- [UNKNOWN_OPTION]: "caller",
7343
- [UNKNOWN_COMMAND]: "caller",
7344
- [UNKNOWN_FIELD]: "caller",
7345
- [CONFIRMATION_REQUIRED]: "caller",
7346
- [CONFIRMATION_MISMATCH]: "caller",
7347
- [NOT_CONFIRMED]: "operator",
7348
- [NEEDS_OPERATOR]: "operator",
7349
- [OUTPUT_EXISTS]: "caller",
7350
- [INTERRUPTED]: "interrupted",
7351
- [DEADLINE_EXCEEDED]: "wait",
7352
- [INTERNAL_CODE]: "bug",
7353
- [PERMISSION_DENIED]: "operator",
7354
- [DISK_FULL]: "operator",
7355
- [NOT_FOUND]: "caller",
7356
- [ALREADY_EXISTS]: "caller",
7357
- [NOT_A_FILE]: "caller",
7358
- [TOOL_FAILED]: "operator",
7359
- [TOOL_MISSING]: "operator",
7360
- [PROJECT_INVALID]: "operator",
7361
- [DOCTOR_PROBLEMS]: "operator",
7362
- [NOT_GLOBAL_INSTALL]: "operator",
7363
- [REGISTRY_UNREACHABLE]: "operator",
7364
- [REGISTRY_AUTH]: "operator",
7365
- [INSTALL_FAILED]: "operator",
7366
- [NPM_FAILED]: "operator",
7367
- [NO_LATEST]: "source"
7368
- };
7369
- }
8065
+ const RUNTIME_EXIT_CLASSES = {
8066
+ [INVALID_INPUT]: "caller",
8067
+ [UNKNOWN_OPTION]: "caller",
8068
+ [UNKNOWN_COMMAND]: "caller",
8069
+ [UNKNOWN_FIELD]: "caller",
8070
+ [CONFIRMATION_REQUIRED]: "caller",
8071
+ [CONFIRMATION_MISMATCH]: "caller",
8072
+ [NOT_CONFIRMED]: "operator",
8073
+ [NEEDS_OPERATOR]: "operator",
8074
+ [OUTPUT_EXISTS]: "caller",
8075
+ [STDIN_STALLED]: "caller",
8076
+ [INTERRUPTED]: "interrupted",
8077
+ [DEADLINE_EXCEEDED]: "wait",
8078
+ [INTERNAL_CODE]: "bug",
8079
+ [PERMISSION_DENIED]: "operator",
8080
+ [DISK_FULL]: "operator",
8081
+ [NOT_FOUND]: "caller",
8082
+ [ALREADY_EXISTS]: "caller",
8083
+ [NOT_A_FILE]: "caller",
8084
+ [TOOL_FAILED]: "operator",
8085
+ [TOOL_MISSING]: "operator",
8086
+ [PROJECT_INVALID]: "operator",
8087
+ [DOCTOR_PROBLEMS]: "operator",
8088
+ [NOT_GLOBAL_INSTALL]: "operator",
8089
+ [REGISTRY_UNREACHABLE]: "operator",
8090
+ [REGISTRY_AUTH]: "operator",
8091
+ [INSTALL_FAILED]: "operator",
8092
+ [NPM_FAILED]: "operator",
8093
+ [NO_LATEST]: "source"
8094
+ };
7370
8095
  /** The codes of `errors` that the Runtime already declares, which a CLI cannot redeclare. */
7371
8096
  function runtimeCodesIn(errors) {
7372
- return Object.keys(errors).filter((code) => Object.hasOwn(runtimeCodes(), code));
8097
+ return Object.keys(errors).filter((code) => Object.hasOwn(RUNTIME_EXIT_CLASSES, code));
7373
8098
  }
7374
8099
  function exitClassOfOne(error, errors) {
7375
8100
  if (!(error instanceof CliError)) return "bug";
7376
8101
  if (error instanceof UsageError) return "caller";
7377
- return runtimeCodes()[error.code] ?? errors[error.code]?.class ?? "bug";
8102
+ return RUNTIME_EXIT_CLASSES[error.code] ?? errors[error.code]?.class ?? "bug";
7378
8103
  }
7379
8104
  function isBug(error, errors) {
7380
8105
  return exitClassOfOne(error, errors) === "bug";
@@ -7418,6 +8143,50 @@ function exitCodeOf(error, errors, stop) {
7418
8143
  return exitClass === "interrupted" ? SIGNAL_EXIT_CODES[stopSignalOf(stop?.reason)] : EXIT_CODES[exitClass];
7419
8144
  }
7420
8145
  //#endregion
8146
+ //#region ../agent-cli/dist/agent-cli.js
8147
+ function checkOwnCodes(cli) {
8148
+ const redeclared = runtimeCodesIn(cli.errors ?? {});
8149
+ if (redeclared.length > 0) throw new Error(`${cli.name} declares ${redeclared.join(", ")}, an error code the Runtime already declares`);
8150
+ }
8151
+ function defineCli$1(cli) {
8152
+ checkOwnCodes(cli);
8153
+ if (cli.commands === void 0) return cli;
8154
+ const { commands } = cli;
8155
+ const taken = Object.keys(builtInCommands(cli, {
8156
+ bin: void 0,
8157
+ node: void 0
8158
+ })).filter((name) => commands[name] !== void 0);
8159
+ if (taken.length > 0) throw new Error(`${cli.name} defines ${taken.join(", ")}, a built-in Command it cannot replace`);
8160
+ return cli;
8161
+ }
8162
+ /**
8163
+ * Declares the CLI's ports and its Project file's settings once; the `defineCommand` and
8164
+ * `defineCli` it returns type `ctx.ports` and `ctx.project`.
8165
+ */
8166
+ function agentCli() {
8167
+ return {
8168
+ defineCommand: defineCommandFor(),
8169
+ defineCli: defineCli$1
8170
+ };
8171
+ }
8172
+ //#endregion
8173
+ //#region ../agent-cli/dist/error-table.js
8174
+ /** Keeps each code's literal class and `details` schema, so `cliError` can type its throw sites. */
8175
+ function defineErrors(table) {
8176
+ return table;
8177
+ }
8178
+ /**
8179
+ * A `CliError` for a code of `table`, whose `details` must match the code's schema. The `hint`
8180
+ * names the next command to run and says whether running it again can help; `retryAt` (ISO 8601)
8181
+ * is allowed only on a wait-class code.
8182
+ */
8183
+ function cliError(_table, code, init, options) {
8184
+ return new CliError({
8185
+ ...init,
8186
+ code
8187
+ }, options);
8188
+ }
8189
+ //#endregion
7421
8190
  //#region ../agent-cli/dist/command-spec.js
7422
8191
  /** The group's Commands and groups that help and suggestions may name: hidden Commands left out. */
7423
8192
  function visibleCommands({ commands }) {
@@ -7435,12 +8204,18 @@ function declaredOf(command) {
7435
8204
  cost: command.cost !== void 0
7436
8205
  };
7437
8206
  }
7438
- function commandSpec(commandLine, command) {
8207
+ const SINGLE_COMMAND = {
8208
+ path: [],
8209
+ builtIn: false
8210
+ };
8211
+ function commandSpec(commandLine, command, { path, builtIn } = SINGLE_COMMAND) {
7439
8212
  const list = command.rows === void 0 ? void 0 : listSpec(command.rows);
7440
8213
  return {
7441
8214
  kind: "command",
7442
8215
  commandLine,
8216
+ path,
7443
8217
  command,
8218
+ builtIn,
7444
8219
  description: command.description,
7445
8220
  help: command.help,
7446
8221
  hidden: command.hidden === true,
@@ -7454,15 +8229,34 @@ function commandSpec(commandLine, command) {
7454
8229
  output: list?.output ?? command.output
7455
8230
  };
7456
8231
  }
7457
- function groupSpec(commandLine, commands) {
8232
+ function group(commandLine, commands) {
7458
8233
  return {
7459
8234
  kind: "group",
7460
8235
  commandLine,
7461
- commands: Object.fromEntries(Object.entries(commands).map(([key, node]) => [key, specOf(`${commandLine} ${key}`, node)]))
8236
+ commands
7462
8237
  };
7463
8238
  }
7464
- function specOf(commandLine, node) {
7465
- return isCommand(node) ? commandSpec(commandLine, node) : groupSpec(commandLine, node);
8239
+ /** The root group of a multi-Command CLI: the author's Commands, then the Built-in Commands. */
8240
+ function groupSpec(commandLine, commands, builtIns) {
8241
+ return group(commandLine, {
8242
+ ...specsOf(commandLine, commands, {
8243
+ path: [],
8244
+ builtIn: false
8245
+ }),
8246
+ ...specsOf(commandLine, builtIns, {
8247
+ path: [],
8248
+ builtIn: true
8249
+ })
8250
+ });
8251
+ }
8252
+ function specsOf(commandLine, commands, { path, builtIn }) {
8253
+ return Object.fromEntries(Object.entries(commands).map(([key, node]) => [key, specOf(`${commandLine} ${key}`, node, {
8254
+ path: [...path, key],
8255
+ builtIn
8256
+ })]));
8257
+ }
8258
+ function specOf(commandLine, node, place) {
8259
+ return isCommand(node) ? commandSpec(commandLine, node, place) : group(commandLine, specsOf(commandLine, node, place));
7466
8260
  }
7467
8261
  //#endregion
7468
8262
  //#region ../agent-cli/dist/help.js
@@ -7487,9 +8281,10 @@ function commandRows(group) {
7487
8281
  function lines(...parts) {
7488
8282
  return `${parts.join("\n")}\n`;
7489
8283
  }
7490
- function listingLines(heading, group, style) {
8284
+ function listingLines(heading, group, style, description) {
7491
8285
  return [
7492
8286
  style.bold(heading),
8287
+ ...description === void 0 ? [] : [description],
7493
8288
  ...section("Commands", commandRows(group), style),
7494
8289
  "",
7495
8290
  `Run \`${group.commandLine} <command> --help\` for its examples and input.`
@@ -7522,7 +8317,7 @@ function examplesSection(examples, style) {
7522
8317
  }
7523
8318
  /** The CLI's own help: a listing or its single Command's help, ending with exit codes and examples. */
7524
8319
  function cliHelp(cli, root, style) {
7525
- return lines(...root.kind === "command" ? commandLines(root, style, { examples: false }) : listingLines(`${root.commandLine} ${cli.version}`, root, style), ...section("Exit codes", exitCodeRows(cli), style), ...examplesSection(rootExamples(root), style));
8320
+ return lines(...root.kind === "command" ? commandLines(root, style, { examples: false }) : listingLines(`${root.commandLine} ${cli.version}`, root, style, cli.description), ...section("Exit codes", exitCodeRows(cli), style), ...examplesSection(rootExamples(root), style));
7526
8321
  }
7527
8322
  function groupHelp(group, style) {
7528
8323
  return lines(...listingLines(group.commandLine, group, style));
@@ -7620,10 +8415,11 @@ function errorsData(errors) {
7620
8415
  details: declaration.details === void 0 ? null : toJSONSchema(declaration.details, { unrepresentable: "any" })
7621
8416
  }]));
7622
8417
  }
7623
- function cliHelpJson({ version, errors }, root) {
8418
+ function cliHelpJson({ version, description, errors }, root) {
7624
8419
  return printed$1({
7625
8420
  name: root.commandLine,
7626
8421
  version,
8422
+ description,
7627
8423
  ...nodeData(root),
7628
8424
  errors: errorsData(errors ?? {})
7629
8425
  });
@@ -7656,619 +8452,215 @@ function progressLine(message, json) {
7656
8452
  }
7657
8453
  function errorText(error, format) {
7658
8454
  const text = formatRuntimeError(error, {
7659
- ...format,
7660
- isBug: (each) => isBug(each, format.errors)
7661
- });
7662
- const { usageHelp, json } = format;
7663
- return usageHelp !== void 0 && !json && error instanceof UsageError ? `${text}\n${usageHelp}` : text;
7664
- }
7665
- function stdoutOf({ value, render }, format, spill) {
7666
- const text = printed(value, render, format);
7667
- return value instanceof Page ? text : spill(text, format.json);
7668
- }
7669
- /** What a serve Command prints the moment it starts. */
7670
- function startedOutput(outcome, format, spill) {
7671
- return stdoutOf(outcome, {
7672
- ...format,
7673
- fields: void 0
7674
- }, spill);
7675
- }
7676
- /** A serve Command stopped after it started: stopping it is how it is meant to end. */
7677
- const STOPPED_RESULT = {
7678
- stdout: "",
7679
- stderr: "",
7680
- exitCode: SUCCESS_EXIT_CODE
7681
- };
7682
- function errorResult(error, format) {
7683
- return {
7684
- stdout: "",
7685
- stderr: errorText(error, format),
7686
- exitCode: exitCodeOf(error, format.errors, format.stop)
7687
- };
7688
- }
7689
- async function commandResult(settled, format, spill) {
7690
- if (settled.ok) try {
7691
- return {
7692
- stdout: await stdoutOf(settled.outcome, format, spill),
7693
- stderr: "",
7694
- exitCode: SUCCESS_EXIT_CODE
7695
- };
7696
- } catch (spillError) {
7697
- return errorResult(spillError, format);
7698
- }
7699
- const { error, delivered } = settled;
7700
- const result = errorResult(error, format);
7701
- if (delivered === void 0) return result;
7702
- try {
7703
- return {
7704
- ...result,
7705
- stdout: await stdoutOf(delivered, format, spill)
7706
- };
7707
- } catch (spillError) {
7708
- const both = new AggregateError([...errorsOf(error), spillError]);
7709
- return {
7710
- ...result,
7711
- stderr: errorText(both, format)
7712
- };
7713
- }
7714
- }
7715
- function textHelp(node, root, cli, style) {
7716
- if (node === root) return cliHelp(cli, node, style);
7717
- return node.kind === "command" ? commandHelp(node, style) : groupHelp(node, style);
7718
- }
7719
- function helpOf(node, root, cli, style, json) {
7720
- if (!json) return textHelp(node, root, cli, style);
7721
- if (node === root) return cliHelpJson(cli, node);
7722
- return node.kind === "command" ? commandHelpJson(node) : groupHelpJson(node);
7723
- }
7724
- function helpResult(node, root, cli, { style, json }) {
7725
- return {
7726
- stdout: helpOf(node, root, cli, style, json),
7727
- stderr: "",
7728
- exitCode: SUCCESS_EXIT_CODE
7729
- };
7730
- }
7731
- /** The first line of `--version`: the version, and the commit and time of a stamped build. */
7732
- function versionLine({ version, build }) {
7733
- return build === void 0 ? version : `${version} (${build.sha}${build.dirty ? "+dirty" : ""}) built ${build.builtAt}`;
7734
- }
7735
- function versionResult(cli, packageRoot) {
7736
- return {
7737
- stdout: `${(cli.build === void 0 ? [versionLine(cli)] : [versionLine(cli), `changelog ${join(packageRoot, "CHANGELOG.md")}`]).join("\n")}\n`,
7738
- stderr: "",
7739
- exitCode: SUCCESS_EXIT_CODE
7740
- };
7741
- }
7742
- //#endregion
7743
- //#region ../agent-cli/dist/skill-source.js
7744
- /** The branch a release moves to the released commit, which holds the skill of that version. */
7745
- const RELEASE_BRANCH = "release";
7746
- const GITHUB_SHORTHAND = /^[\w.-]+\/[\w.-]+$/;
7747
- const GIT_URL_PROTOCOLS = /* @__PURE__ */ new Set([
7748
- "https:",
7749
- "http:",
7750
- "ssh:",
7751
- "git:"
7752
- ]);
7753
- const SCP_STYLE = /^[\w.-]+@[\w.-]+:[\w./-]+$/;
7754
- const manifestSchema = object({ repository: union([string(), object({ url: string() })]).optional() });
7755
- function sourceFromRepository(repository) {
7756
- if (GITHUB_SHORTHAND.test(repository)) return repository;
7757
- const url = repository.replace(/^git\+/, "");
7758
- if (!(URL.canParse(url) && GIT_URL_PROTOCOLS.has(new URL(url).protocol)) && !SCP_STYLE.test(url)) return void 0;
7759
- return `${url.endsWith(".git") ? url : `${url}.git`}#${RELEASE_BRANCH}`;
7760
- }
7761
- async function repositoryAt(packageRoot) {
7762
- let manifest;
7763
- try {
7764
- manifest = JSON.parse(await readFile(join(packageRoot, "package.json"), "utf8"));
7765
- } catch {
7766
- return;
7767
- }
7768
- const parsed = manifestSchema.safeParse(manifest);
7769
- const repository = parsed.success ? parsed.data.repository : void 0;
7770
- return typeof repository === "object" ? repository.url : repository;
7771
- }
7772
- /** What `npx skills add` installs the CLI's skill from: the declared source, else the package's repository. */
7773
- async function skillSource(declared, packageRoot) {
7774
- if (declared !== void 0) return declared.source;
7775
- const repository = await repositoryAt(packageRoot);
7776
- return repository === void 0 ? void 0 : sourceFromRepository(repository);
7777
- }
7778
- //#endregion
7779
- //#region ../agent-cli/dist/skills.js
7780
- /** Where the skills CLI (`npx skills add`) puts a skill, under a project and under home. */
7781
- const SKILL_DIRS = [[".claude", "skills"], [".agents", "skills"]];
7782
- function skillUpdateCommand(cliName) {
7783
- return `npx -y skills update ${cliName}`;
7784
- }
7785
- function skillAddCommand(source, cliName) {
7786
- return `npx -y skills add ${source} --skill ${cliName} -g`;
7787
- }
7788
- const FRONTMATTER = /^---\r?\n([\s\S]*?)\r?\n---/;
7789
- const METADATA_VERSION = /^metadata:[ \t]*\r?\n(?:[ \t]+.*\r?\n)*?[ \t]+version:[ \t]*["']?([^"'\s]+)["']?[ \t]*$/m;
7790
- /** The version a SKILL.md's frontmatter `metadata.version` states. */
7791
- function skillVersionIn(skill) {
7792
- const frontmatter = FRONTMATTER.exec(skill)?.[1];
7793
- return frontmatter === void 0 ? void 0 : METADATA_VERSION.exec(`${frontmatter}\n`)?.[1];
7794
- }
7795
- function homeOf(env) {
7796
- return env.HOME ?? env.USERPROFILE ?? homedir();
7797
- }
7798
- async function copyAt(path, cliVersion) {
7799
- let skill;
7800
- try {
7801
- skill = await readFile(join(path, "SKILL.md"), "utf8");
7802
- } catch (error) {
7803
- if (isMissingFile(error)) return;
7804
- return {
7805
- path,
7806
- version: void 0,
7807
- state: "unreadable"
7808
- };
7809
- }
7810
- const version = skillVersionIn(skill);
7811
- if (version === void 0 || !isVersion(version) || !isVersion(cliVersion)) return {
7812
- path,
7813
- version,
7814
- state: "unversioned"
7815
- };
7816
- return {
7817
- path,
7818
- version,
7819
- state: standingOf(version, cliVersion)
7820
- };
7821
- }
7822
- /** Every installed copy of the skill named after the CLI, in the project first, then under home. */
7823
- async function skillCopies(skillName, cliVersion, cwd, env) {
7824
- const paths = [cwd, homeOf(env)].flatMap((root) => SKILL_DIRS.map((dir) => join(root, ...dir, skillName)));
7825
- const seen = /* @__PURE__ */ new Set();
7826
- const copies = [];
7827
- for (const path of paths) {
7828
- const copy = await copyAt(path, cliVersion);
7829
- const real = copy === void 0 ? void 0 : await realpath(path);
7830
- if (copy !== void 0 && real !== void 0 && !seen.has(real)) {
7831
- seen.add(real);
7832
- copies.push(copy);
7833
- }
7834
- }
7835
- return copies;
7836
- }
7837
- //#endregion
7838
- //#region ../agent-cli/dist/doctor-rows.js
7839
- function ok(message) {
7840
- return {
7841
- state: "ok",
7842
- message
7843
- };
7844
- }
7845
- function buildRow(cli) {
7846
- return {
7847
- name: "build",
7848
- run: () => ok(versionLine(cli))
7849
- };
7850
- }
7851
- function nodeRow(cli) {
7852
- return {
7853
- name: "node",
7854
- run: () => {
7855
- const found = process.versions.node;
7856
- const range = cli.engines?.node;
7857
- if (range === void 0) return ok(`Node ${found}; ${cli.name} declares no engines.node to check it against`);
7858
- const minimum = engineMinimum(range);
7859
- if (minimum === void 0) return {
7860
- state: "problem",
7861
- message: `${cli.name} declares engines.node "${range}", which doctor cannot read: only >=X.Y.Z is supported`
7862
- };
7863
- if (meetsMinimum(found, minimum)) return ok(`Node ${found} meets ${range}`);
7864
- const major = minimum[0];
7865
- return {
7866
- state: "problem",
7867
- message: `${cli.name} runs on Node ${found}, older than the ${range} it needs; install Node ${minimum.join(".")} or newer and make it the default`,
7868
- fix: `nvm install ${major} && nvm alias default ${major}`
7869
- };
7870
- }
7871
- };
7872
- }
7873
- function projectRow(projectFile) {
7874
- const { file } = projectFile;
7875
- return {
7876
- name: "project",
7877
- run: (ctx) => {
7878
- let project;
7879
- try {
7880
- project = projectOf(projectFile, ctx.cwd);
7881
- } catch (error) {
7882
- if (error instanceof CliError && error.code === "PROJECT_INVALID") return {
7883
- state: "problem",
7884
- message: error.message
7885
- };
7886
- throw error;
7887
- }
7888
- return ok(project === void 0 ? `none found: no ${file} at or above ${ctx.cwd}` : join(project.root, file));
7889
- }
7890
- };
7891
- }
7892
- function installRow(cli, { bin, node }) {
7893
- return {
7894
- name: "install",
7895
- advisory: true,
7896
- run: async (ctx) => {
7897
- const { install } = cli;
7898
- if (install === void 0) return ok(`${cli.name} declares no install, so it has no \`update\``);
7899
- try {
7900
- return ok(`a global npm install under ${(await globalInstallOf(bin, npmContext(cli, install, ctx, node))).prefix}`);
7901
- } catch (error) {
7902
- if (error instanceof CliError && error.code === "NOT_GLOBAL_INSTALL") return {
7903
- state: "problem",
7904
- message: error.message,
7905
- fix: installCommandLine(install)
7906
- };
7907
- throw error;
7908
- }
7909
- }
7910
- };
7911
- }
7912
- function registryRow(cli, node) {
7913
- return {
7914
- name: "registry",
7915
- advisory: true,
7916
- run: async (ctx) => {
7917
- const { install } = cli;
7918
- if (install === void 0) return ok(`${cli.name} declares no registry to compare this build with`);
7919
- const latest = await latestVersion(npmContext(cli, install, ctx, node));
7920
- const standing = standingOf(cli.version, latest);
7921
- const head = `${install.registry} has ${latest} as latest: this build`;
7922
- if (standing === "behind") return {
7923
- state: "problem",
7924
- message: `${head} (${cli.version}) is older`,
7925
- fix: `${cli.name} update`
7926
- };
7927
- return ok(`${head} is ${standing === "current" ? "current" : `newer (${cli.version})`}`);
7928
- }
7929
- };
7930
- }
7931
- const SKILL_STATE_NOTES = {
7932
- current: "the same as this build",
7933
- behind: "older than this build",
7934
- ahead: "newer than this build",
7935
- unversioned: "states no metadata.version",
7936
- unreadable: "could not be read"
7937
- };
7938
- function describeCopy({ path, version, state }) {
7939
- return `${path}${version === void 0 ? "" : ` ${version}`} (${SKILL_STATE_NOTES[state]})`;
7940
- }
7941
- function skillFix(cli, copies) {
7942
- if (copies.some(({ state }) => state === "behind" || state === "unversioned")) return skillUpdateCommand(cli.name);
7943
- return copies.some(({ state }) => state === "ahead") ? `${cli.name} update` : void 0;
8455
+ ...format,
8456
+ isBug: (each) => isBug(each, format.errors)
8457
+ });
8458
+ const { usageHelp, json } = format;
8459
+ return usageHelp !== void 0 && !json && error instanceof UsageError ? `${text}\n${usageHelp}` : text;
7944
8460
  }
7945
- function skillRow(cli) {
7946
- return {
7947
- name: "skill",
7948
- run: async (ctx) => {
7949
- const copies = await skillCopies(cli.name, cli.version, ctx.cwd, ctx.env);
7950
- if (copies.length === 0) {
7951
- const message = `no copy of the ${cli.name} skill is installed`;
7952
- const source = await skillSource(cli.skill, ctx.packageRoot);
7953
- return source === void 0 ? ok(message) : {
7954
- state: "ok",
7955
- message,
7956
- fix: skillAddCommand(source, cli.name)
7957
- };
7958
- }
7959
- const fix = skillFix(cli, copies);
7960
- const message = copies.map(describeCopy).join("; ");
7961
- return fix === void 0 ? ok(message) : {
7962
- state: "ok",
7963
- message,
7964
- fix
7965
- };
7966
- }
7967
- };
8461
+ function stdoutOf({ value, render }, format, spill) {
8462
+ const text = printed(value, render, format);
8463
+ return value instanceof Page ? text : spill(text, format.json);
7968
8464
  }
7969
- /** Every row `doctor` reports, in order: the fixed rows around the CLI's own and its tools'. */
7970
- function doctorChecks(cli, launch) {
7971
- return [
7972
- buildRow(cli),
7973
- nodeRow(cli),
7974
- ...cli.project === void 0 ? [] : [projectRow(cli.project)],
7975
- ...cli.doctor ?? [],
7976
- ...toolRows(cli.tools ?? [], cli.commands),
7977
- installRow(cli, launch),
7978
- registryRow(cli, launch.node),
7979
- skillRow(cli)
7980
- ];
8465
+ /** What a serve Command prints the moment it starts. */
8466
+ function startedOutput(outcome, format, spill) {
8467
+ return stdoutOf(outcome, {
8468
+ ...format,
8469
+ fields: void 0
8470
+ }, spill);
7981
8471
  }
7982
- //#endregion
7983
- //#region ../agent-cli/dist/doctor.js
7984
- const DOCTOR_PROBLEMS = "DOCTOR_PROBLEMS";
7985
- const DEFAULT_DEADLINE_MS = 1e4;
7986
- const MS_PER_SECOND = 1e3;
7987
- const MIN_LABEL_WIDTH = 8;
7988
- const reportSchema = object({
7989
- rows: array(object({
7990
- check: string(),
7991
- state: _enum([
7992
- "ok",
7993
- "problem",
7994
- "skipped"
7995
- ]),
7996
- message: string(),
7997
- fix: string().optional(),
7998
- code: string().optional()
7999
- })),
8000
- next: array(string())
8001
- });
8002
- function problemOf(check, error, { signal, deadline, ms }) {
8003
- if (!signal.aborted && deadline.aborted && error === deadline.reason) return {
8004
- state: "problem",
8005
- message: `${check.name} did not answer within ${ms / MS_PER_SECOND} s`
8006
- };
8007
- if (error instanceof CliError) return {
8008
- state: "problem",
8009
- message: `${error.message}; ${error.hint}`,
8010
- code: error.code
8011
- };
8472
+ /** A serve Command stopped after it started: stopping it is how it is meant to end. */
8473
+ const STOPPED_RESULT = {
8474
+ stdout: "",
8475
+ stderr: "",
8476
+ exitCode: SUCCESS_EXIT_CODE
8477
+ };
8478
+ function errorResult(error, format) {
8012
8479
  return {
8013
- state: "problem",
8014
- message: `the ${check.name} row hit a bug: ${messageOf(error)}`
8480
+ stdout: "",
8481
+ stderr: errorText(error, format),
8482
+ exitCode: exitCodeOf(error, format.errors, format.stop)
8015
8483
  };
8016
8484
  }
8017
- function withSignal(ctx, signal) {
8018
- return Object.create(ctx, { signal: { value: signal } });
8019
- }
8020
- async function rowOf(check, ctx) {
8021
- const ms = check.deadlineMs ?? DEFAULT_DEADLINE_MS;
8022
- const signal = ctx.deadline(ms);
8023
- let finding;
8485
+ async function commandResult(settled, format, spill) {
8486
+ if (settled.ok) try {
8487
+ return {
8488
+ stdout: await stdoutOf(settled.outcome, format, spill),
8489
+ stderr: "",
8490
+ exitCode: SUCCESS_EXIT_CODE
8491
+ };
8492
+ } catch (spillError) {
8493
+ return errorResult(spillError, format);
8494
+ }
8495
+ const { error, delivered } = settled;
8496
+ const result = errorResult(error, format);
8497
+ if (delivered === void 0) return result;
8024
8498
  try {
8025
- finding = await Promise.race([Promise.resolve().then(() => check.run(withSignal(ctx, signal))), untilAborted(signal)]);
8026
- } catch (error) {
8027
- if (ctx.signal.aborted) return void 0;
8028
- finding = problemOf(check, error, {
8029
- signal: ctx.signal,
8030
- deadline: signal,
8031
- ms
8032
- });
8499
+ return {
8500
+ ...result,
8501
+ stdout: await stdoutOf(delivered, format, spill)
8502
+ };
8503
+ } catch (spillError) {
8504
+ const both = new AggregateError([...errorsOf(error), spillError]);
8505
+ return {
8506
+ ...result,
8507
+ stderr: errorText(both, format)
8508
+ };
8033
8509
  }
8034
- return {
8035
- row: {
8036
- check: check.name,
8037
- ...finding
8038
- },
8039
- advisory: check.advisory === true
8040
- };
8041
8510
  }
8042
- function nextOf(rows) {
8043
- return [...new Set(rows.flatMap(({ fix }) => fix === void 0 ? [] : [fix]))];
8511
+ function textHelp(node, root, cli, style) {
8512
+ if (node === root) return cliHelp(cli, node, style);
8513
+ return node.kind === "command" ? commandHelp(node, style) : groupHelp(node, style);
8044
8514
  }
8045
- function render({ rows, next }, style) {
8046
- const width = Math.max(MIN_LABEL_WIDTH, ...rows.map(({ check }) => check.length)) + 2;
8047
- const stateWidth = Math.max(...rows.map(({ state }) => state.length)) + 2;
8048
- return [...rows.map(({ check, state, message }) => {
8049
- const label = state === "problem" ? style.red(state) : state;
8050
- return `${check.padEnd(width)}${label}${" ".repeat(stateWidth - state.length)}${message}`;
8051
- }), ...next.map((fix) => `${"next".padEnd(width)}${fix}`)].join("\n");
8515
+ function helpOf(node, root, cli, style, json) {
8516
+ if (!json) return textHelp(node, root, cli, style);
8517
+ if (node === root) return cliHelpJson(cli, node);
8518
+ return node.kind === "command" ? commandHelpJson(node) : groupHelpJson(node);
8052
8519
  }
8053
- function failure(cliName, problems) {
8054
- const errors = problems.map(({ check, message, fix, code }) => new CliError({
8055
- code: code ?? "DOCTOR_PROBLEMS",
8056
- message: `${cliName} doctor found a problem in ${check}: ${message}`,
8057
- hint: fix === void 0 ? "the row says what is wrong" : `run ${fix}, then run doctor again`
8058
- }));
8059
- return new AggregateError(errors);
8520
+ function helpResult(node, root, cli, { style, json }) {
8521
+ return {
8522
+ stdout: helpOf(node, root, cli, style, json),
8523
+ stderr: "",
8524
+ exitCode: SUCCESS_EXIT_CODE
8525
+ };
8060
8526
  }
8061
- /** The built-in `doctor`: the fixed rows around the CLI's own, each under its own deadline. */
8062
- function doctorCommand(cli, launch) {
8063
- return defineCommand$1({
8064
- name: "doctor",
8065
- description: "check the setup and say what fixes each problem",
8066
- examples: [{
8067
- command: `${cli.name} doctor`,
8068
- note: "check the setup and list the commands that fix it"
8069
- }, {
8070
- command: `${cli.name} doctor --json`,
8071
- note: "get the rows and fixes as data"
8072
- }],
8073
- effect: "read",
8074
- output: reportSchema,
8075
- run: async (_input, ctx) => {
8076
- const checked = (await Promise.all(doctorChecks(cli, launch).map((check) => rowOf(check, ctx)))).filter((row) => row !== void 0);
8077
- const rows = checked.map(({ row }) => row);
8078
- const report = {
8079
- rows,
8080
- next: nextOf(rows)
8081
- };
8082
- if (ctx.signal.aborted) {
8083
- ctx.deliver(report);
8084
- ctx.signal.throwIfAborted();
8085
- }
8086
- const problems = checked.filter(({ row, advisory }) => row.state === "problem" && !advisory).map(({ row }) => row);
8087
- if (problems.length > 0) {
8088
- ctx.deliver(report);
8089
- throw failure(cli.name, problems);
8090
- }
8091
- return report;
8092
- },
8093
- render
8094
- });
8527
+ function versionResult(cli, packageRoot) {
8528
+ return {
8529
+ stdout: `${(cli.build === void 0 ? [versionLine(cli)] : [versionLine(cli), `changelog ${join(packageRoot, "CHANGELOG.md")}`]).join("\n")}\n`,
8530
+ stderr: "",
8531
+ exitCode: SUCCESS_EXIT_CODE
8532
+ };
8095
8533
  }
8096
8534
  //#endregion
8097
- //#region ../agent-cli/dist/upgrade-notes.js
8098
- const RELEASE_HEADING = /^## v?(\S+)/;
8099
- function releasesIn(changelog) {
8100
- const releases = [];
8101
- let current;
8102
- for (const line of changelog.split(/\r?\n/)) {
8103
- const heading = RELEASE_HEADING.exec(line);
8104
- if (heading !== null) {
8105
- const version = heading[1] ?? "";
8106
- current = isVersion(version) ? {
8107
- version,
8108
- lines: []
8109
- } : void 0;
8110
- if (current !== void 0) releases.push(current);
8111
- } else current?.lines.push(line);
8112
- }
8113
- return releases.map(({ version, lines }) => ({
8114
- version,
8115
- notes: lines.join("\n").trim()
8116
- }));
8117
- }
8535
+ //#region ../agent-cli/dist/package-root.js
8118
8536
  /**
8119
- * What changed in each release after `from` up to `to`, oldest first, from the CHANGELOG.md in
8120
- * `packageDir`; none when the package ships no CHANGELOG.
8537
+ * The nearest folder holding a `package.json`, searched upward from the bin or, run without one,
8538
+ * from `cwd`; the search's start when none holds one. The bin is resolved through links first,
8539
+ * since npm's global bin is a link to it.
8121
8540
  */
8122
- async function upgradeNotes(packageDir, from, to) {
8123
- let changelog;
8124
- try {
8125
- changelog = await readFile(join(packageDir, "CHANGELOG.md"), "utf8");
8126
- } catch (error) {
8127
- if (isMissingFile(error)) return [];
8128
- throw error;
8541
+ function packageRootOf(bin, cwd) {
8542
+ const start = bin === void 0 ? resolve(cwd) : dirname(realpathSync(bin));
8543
+ for (let dir = start;; dir = dirname(dir)) {
8544
+ if (existsSync(join(dir, "package.json"))) return dir;
8545
+ if (dirname(dir) === dir) return start;
8129
8546
  }
8130
- return releasesIn(changelog).filter(({ version }) => compareVersions(version, from) > 0 && compareVersions(version, to) <= 0).sort((a, b) => compareVersions(a.version, b.version));
8131
8547
  }
8132
8548
  //#endregion
8133
- //#region ../agent-cli/dist/update.js
8134
- const updateSchema = object({
8135
- from: string(),
8136
- latest: string(),
8137
- installed: object({
8138
- version: string(),
8139
- prefix: string()
8140
- }).nullable(),
8141
- upgrades: array(object({
8142
- version: string(),
8143
- notes: string()
8144
- })),
8145
- next: array(string())
8146
- });
8147
- function nothingToInstall({ from, latest }) {
8148
- return standingOf(from, latest) === "current" ? `already on ${from}, the latest release: nothing to install` : `${from} is newer than the latest release ${latest}: nothing to install`;
8549
+ //#region ../agent-cli/dist/suggest.js
8550
+ const MAX_DISTANCE = 3;
8551
+ const MIN_SIMILARITY = .4;
8552
+ function distance(a, b) {
8553
+ const width = b.length + 1;
8554
+ const d = Array.from({ length: (a.length + 1) * width }, (_, k) => {
8555
+ const i = Math.floor(k / width);
8556
+ const j = k % width;
8557
+ return i === 0 || j === 0 ? i + j : 0;
8558
+ });
8559
+ const at = (i, j) => d[i * width + j] ?? 0;
8560
+ for (let i = 1; i <= a.length; i++) for (let j = 1; j <= b.length; j++) {
8561
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
8562
+ const edit = Math.min(at(i - 1, j) + 1, at(i, j - 1) + 1, at(i - 1, j - 1) + cost);
8563
+ const transposed = i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1];
8564
+ d[i * width + j] = transposed ? Math.min(edit, at(i - 2, j - 2) + 1) : edit;
8565
+ }
8566
+ return at(a.length, b.length);
8149
8567
  }
8150
- function renderUpdate(cli, install, update) {
8151
- const { installed } = update;
8152
- if (installed === null) return nothingToInstall(update);
8153
- return [
8154
- `installed ${install.package}@${installed.version} with the npm under ${installed.prefix}, replacing ${update.from}`,
8155
- ...update.upgrades.map(({ version, notes }) => `\nchanges in ${version}:\n${notes}`),
8156
- "",
8157
- ...update.next.map((command) => `next: ${command}, so the ${cli.name} skill describes ${installed.version}`)
8158
- ].join("\n");
8568
+ function isClose(word, candidate) {
8569
+ const length = Math.max(word.length, candidate.length);
8570
+ const edits = distance(word, candidate);
8571
+ return candidate.length > 1 && edits < MAX_DISTANCE && (length - edits) / length > MIN_SIMILARITY;
8159
8572
  }
8160
- function interruptedAfterInstall(plan) {
8161
- return new CliError({
8162
- code: INTERRUPTED,
8163
- message: `interrupted, but ${plan.package}@${plan.latest} had already been installed with the npm under ${plan.prefix}, replacing ${plan.from}`,
8164
- hint: "nothing to run again: run the commands under next"
8165
- });
8573
+ /** The names closest to `word`, sorted, several when they tie, or none when nothing is close. */
8574
+ function closestNames(word, names) {
8575
+ const close = [...new Set(names)].filter((candidate) => isClose(word, candidate));
8576
+ const best = Math.min(...close.map((candidate) => distance(word, candidate)));
8577
+ return close.filter((candidate) => distance(word, candidate) === best).sort((a, b) => a.localeCompare(b));
8166
8578
  }
8167
- /** The built-in `update`, for a CLI installed globally with npm. */
8168
- function updateCommand(cli, install, { bin, node }) {
8169
- return defineCommand$1({
8170
- name: "update",
8171
- description: "install the latest version of this CLI from its registry",
8172
- examples: [{
8173
- command: `${cli.name} update`,
8174
- note: "install the latest version and show what changed"
8175
- }, {
8176
- command: `${cli.name} update --dry-run`,
8177
- note: "show the version it would install"
8178
- }],
8179
- effect: "write",
8180
- output: updateSchema,
8181
- plan: async (_input, ctx) => {
8182
- const npm = npmContext(cli, install, ctx, node);
8183
- const copy = await globalInstallOf(bin, npm);
8184
- return {
8185
- package: install.package,
8186
- from: cli.version,
8187
- latest: await latestVersion(npm),
8188
- prefix: copy.prefix,
8189
- packageDir: copy.packageDir
8190
- };
8191
- },
8192
- apply: async (plan, ctx) => {
8193
- const { from, latest, prefix } = plan;
8194
- if (standingOf(from, latest) !== "behind") return {
8195
- from,
8196
- latest,
8197
- installed: null,
8198
- upgrades: [],
8199
- next: []
8200
- };
8201
- ctx.signal.throwIfAborted();
8202
- ctx.progress(`installing ${plan.package}@${latest} with the npm under ${prefix}…`);
8203
- await ctx.runToEnd(`installing ${plan.package}@${latest}`, () => installGlobally(latest, npmContext(cli, install, ctx, node)));
8204
- const update = {
8205
- from,
8206
- latest,
8207
- installed: {
8208
- version: latest,
8209
- prefix
8210
- },
8211
- upgrades: await upgradeNotes(plan.packageDir, from, latest),
8212
- next: [skillUpdateCommand(cli.name)]
8213
- };
8214
- if (ctx.signal.aborted) {
8215
- ctx.deliver(update);
8216
- throw interruptedAfterInstall(plan);
8217
- }
8218
- return update;
8219
- },
8220
- render: (update) => renderUpdate(cli, install, update),
8221
- renderPlan: (plan) => standingOf(plan.from, plan.latest) === "behind" ? `would install ${plan.package}@${plan.latest} with the npm under ${plan.prefix}, replacing ${plan.from}` : nothingToInstall(plan)
8222
- });
8579
+ /** The long flags closest to `flag`, sorted, or none for a short flag or when nothing is close. */
8580
+ function closestFlags(flag, flags) {
8581
+ if (!flag.startsWith("--")) return [];
8582
+ const names = flags.map((candidate) => candidate.slice(2));
8583
+ return closestNames(flag.slice(2), names).map((name) => `--${name}`);
8223
8584
  }
8224
- //#endregion
8225
- //#region ../agent-cli/dist/built-ins.js
8226
- /** The Commands the Runtime adds to a multi-Command CLI: `update` only when it declares an install. */
8227
- function builtInCommands(cli, launch) {
8228
- return {
8229
- doctor: doctorCommand(cli, launch),
8230
- ...cli.install === void 0 ? {} : { update: updateCommand(cli, cli.install, launch) }
8231
- };
8585
+ /** The one long flag closest to `flag`, or none when nothing is close or several tie. */
8586
+ function closestFlag(flag, flags) {
8587
+ const closest = closestFlags(flag, flags);
8588
+ return closest.length === 1 ? closest[0] : void 0;
8232
8589
  }
8233
8590
  //#endregion
8234
- //#region ../agent-cli/dist/agent-cli.js
8235
- function checkOwnCodes(cli) {
8236
- const redeclared = runtimeCodesIn(cli.errors ?? {});
8237
- if (redeclared.length > 0) throw new Error(`${cli.name} declares ${redeclared.join(", ")}, an error code the Runtime already declares`);
8591
+ //#region ../agent-cli/dist/route.js
8592
+ const GROUP_FLAGS = [
8593
+ HELP_FLAG,
8594
+ VERSION_FLAG,
8595
+ JSON_FLAG.flag
8596
+ ];
8597
+ function beforeEnd(words) {
8598
+ const end = words.indexOf("--");
8599
+ return end === -1 ? words : words.slice(0, end);
8238
8600
  }
8239
- function defineCli$1(cli) {
8240
- checkOwnCodes(cli);
8241
- if (cli.commands === void 0) return cli;
8242
- const { commands } = cli;
8243
- const taken = Object.keys(builtInCommands(cli, {
8244
- bin: void 0,
8245
- node: void 0
8246
- })).filter((name) => commands[name] !== void 0);
8247
- if (taken.length > 0) throw new Error(`${cli.name} defines ${taken.join(", ")}, a built-in Command it cannot replace`);
8248
- return cli;
8601
+ function wantsHelp(words) {
8602
+ return beforeEnd(words).some((word) => word === "--help" || word === "-h");
8249
8603
  }
8250
- /**
8251
- * Declares the CLI's ports and its Project file's settings once; the `defineCommand` and
8252
- * `defineCli` it returns type `ctx.ports` and `ctx.project`.
8253
- */
8254
- function agentCli() {
8255
- return {
8256
- defineCommand: defineCommandFor(),
8257
- defineCli: defineCli$1
8604
+ function childOf(group, name) {
8605
+ return Object.hasOwn(group.commands, name) ? group.commands[name] : void 0;
8606
+ }
8607
+ function isFlagLike(word) {
8608
+ return word.length > 1 && word[0] === "-";
8609
+ }
8610
+ function walk(node, words, json, invocation) {
8611
+ const help = {
8612
+ kind: "help",
8613
+ node,
8614
+ json
8615
+ };
8616
+ if (node.kind === "command") return wantsHelp(words) ? help : {
8617
+ kind: "command",
8618
+ spec: node,
8619
+ words,
8620
+ json
8258
8621
  };
8622
+ const [first, ...rest] = words;
8623
+ if (first === void 0) return help;
8624
+ const child = childOf(node, first);
8625
+ if (child !== void 0) return walk(child, rest, json, invocation);
8626
+ if (first === "--") {
8627
+ const [name, ...after] = rest;
8628
+ if (name === void 0) return help;
8629
+ const named = childOf(node, name);
8630
+ if (named !== void 0) return walk(named, ["--", ...after], json, invocation);
8631
+ return unknownCommand(node, name, json);
8632
+ }
8633
+ if (wantsHelp(words)) return help;
8634
+ if (isFlagLike(first)) {
8635
+ const suggestions = closestFlags(first, GROUP_FLAGS);
8636
+ return {
8637
+ kind: "usage error",
8638
+ error: unknownOptionError(node.commandLine, invocation, first, suggestions),
8639
+ node,
8640
+ json
8641
+ };
8642
+ }
8643
+ return unknownCommand(node, first, json);
8259
8644
  }
8260
- //#endregion
8261
- //#region ../agent-cli/dist/error-table.js
8262
- /** Keeps each code's literal class and `details` schema, so `cliError` can type its throw sites. */
8263
- function defineErrors(table) {
8264
- return table;
8645
+ function unknownCommand(group, name, json) {
8646
+ const suggestions = closestNames(name, Object.keys(visibleCommands(group)));
8647
+ return {
8648
+ kind: "usage error",
8649
+ error: unknownCommandError(group.commandLine, name, suggestions),
8650
+ node: group,
8651
+ json
8652
+ };
8265
8653
  }
8266
- /** A `CliError` for a code of `table`, whose `details` must match the code's schema. */
8267
- function cliError(_table, code, init, options) {
8268
- return new CliError({
8269
- ...init,
8270
- code
8271
- }, options);
8654
+ /** Walks the caller's command line through the Commands to the one it names, or to a stop. */
8655
+ function route(root, invocation) {
8656
+ const { argv } = invocation;
8657
+ const options = beforeEnd(argv);
8658
+ const json = options.includes(JSON_FLAG.flag);
8659
+ if (options.includes("--version")) return {
8660
+ kind: "version",
8661
+ json
8662
+ };
8663
+ return walk(root, argv.filter((word, index) => !(index < options.length && word === JSON_FLAG.flag)), json, invocation);
8272
8664
  }
8273
8665
  //#endregion
8274
8666
  //#region ../agent-cli/dist/execute.js
@@ -8341,67 +8733,12 @@ async function execute(command, input, ctx, { dryRun, confirm, yes, page, invoca
8341
8733
  }, outputs);
8342
8734
  if (!ctx.force) guardOutputs(outputs, ctx.commandLine({ add: [FORCE_FLAG.flag] }));
8343
8735
  }
8344
- return outcomeOf(await command.apply(plan, ctx), (data, style) => command.render(data, style));
8345
- }
8346
- //#endregion
8347
- //#region ../agent-cli/dist/package-root.js
8348
- /**
8349
- * The nearest folder holding a `package.json`, searched upward from the bin or, run without one,
8350
- * from `cwd`; the search's start when none holds one. The bin is resolved through links first,
8351
- * since npm's global bin is a link to it.
8352
- */
8353
- function packageRootOf(bin, cwd) {
8354
- const start = bin === void 0 ? resolve(cwd) : dirname(realpathSync(bin));
8355
- for (let dir = start;; dir = dirname(dir)) {
8356
- if (existsSync(join(dir, "package.json"))) return dir;
8357
- if (dirname(dir) === dir) return start;
8358
- }
8359
- }
8360
- //#endregion
8361
- //#region ../agent-cli/dist/suggest.js
8362
- const MAX_DISTANCE = 3;
8363
- const MIN_SIMILARITY = .4;
8364
- function distance(a, b) {
8365
- const width = b.length + 1;
8366
- const d = Array.from({ length: (a.length + 1) * width }, (_, k) => {
8367
- const i = Math.floor(k / width);
8368
- const j = k % width;
8369
- return i === 0 || j === 0 ? i + j : 0;
8370
- });
8371
- const at = (i, j) => d[i * width + j] ?? 0;
8372
- for (let i = 1; i <= a.length; i++) for (let j = 1; j <= b.length; j++) {
8373
- const cost = a[i - 1] === b[j - 1] ? 0 : 1;
8374
- const edit = Math.min(at(i - 1, j) + 1, at(i, j - 1) + 1, at(i - 1, j - 1) + cost);
8375
- const transposed = i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1];
8376
- d[i * width + j] = transposed ? Math.min(edit, at(i - 2, j - 2) + 1) : edit;
8377
- }
8378
- return at(a.length, b.length);
8379
- }
8380
- function isClose(word, candidate) {
8381
- const length = Math.max(word.length, candidate.length);
8382
- const edits = distance(word, candidate);
8383
- return candidate.length > 1 && edits < MAX_DISTANCE && (length - edits) / length > MIN_SIMILARITY;
8384
- }
8385
- /** The names closest to `word`, sorted, several when they tie, or none when nothing is close. */
8386
- function closestNames(word, names) {
8387
- const close = [...new Set(names)].filter((candidate) => isClose(word, candidate));
8388
- const best = Math.min(...close.map((candidate) => distance(word, candidate)));
8389
- return close.filter((candidate) => distance(word, candidate) === best).sort((a, b) => a.localeCompare(b));
8390
- }
8391
- /** The long flags closest to `flag`, sorted, or none for a short flag or when nothing is close. */
8392
- function closestFlags(flag, flags) {
8393
- if (!flag.startsWith("--")) return [];
8394
- const names = flags.map((candidate) => candidate.slice(2));
8395
- return closestNames(flag.slice(2), names).map((name) => `--${name}`);
8396
- }
8397
- /** The one long flag closest to `flag`, or none when nothing is close or several tie. */
8398
- function closestFlag(flag, flags) {
8399
- const closest = closestFlags(flag, flags);
8400
- return closest.length === 1 ? closest[0] : void 0;
8736
+ return outcomeOf(await command.apply(plan, ctx), (data, style) => command.render(data, style));
8401
8737
  }
8402
8738
  //#endregion
8403
8739
  //#region ../agent-cli/dist/parse-input.js
8404
8740
  const NO_INPUT = object({});
8741
+ const WHITESPACE = /\s/;
8405
8742
  function knownFlags(spec) {
8406
8743
  return [...spec.options.map((field) => ({
8407
8744
  flag: field.label,
@@ -8538,6 +8875,8 @@ async function parseInput(spec, words, invocation, readStdin) {
8538
8875
  page: page.data,
8539
8876
  values
8540
8877
  };
8878
+ const [onlyWord] = unknownOptions;
8879
+ if (onlyWord !== void 0 && unknownOptions.length === 1 && WHITESPACE.test(onlyWord) && argFields.some((field) => field.stdin && argValues.get(field) === void 0)) throw stdinTextError(spec.commandLine, invocation, onlyWord);
8541
8880
  const [only] = unknown;
8542
8881
  if (only !== void 0 && unknown.length === 1 && otherLines.length === 0) throw unknownOptionError(spec.commandLine, invocation, only.flag, only.suggestion === void 0 ? [] : [only.suggestion]);
8543
8882
  throw invalidInput(spec.commandLine, invocation, unknown, otherLines);
@@ -8563,83 +8902,9 @@ async function parseCommand({ spec, words, json }, invocation, readStdin) {
8563
8902
  };
8564
8903
  }
8565
8904
  //#endregion
8566
- //#region ../agent-cli/dist/route.js
8567
- const GROUP_FLAGS = [
8568
- HELP_FLAG,
8569
- VERSION_FLAG,
8570
- JSON_FLAG.flag
8571
- ];
8572
- function beforeEnd(words) {
8573
- const end = words.indexOf("--");
8574
- return end === -1 ? words : words.slice(0, end);
8575
- }
8576
- function wantsHelp(words) {
8577
- return beforeEnd(words).some((word) => word === "--help" || word === "-h");
8578
- }
8579
- function childOf(group, name) {
8580
- return Object.hasOwn(group.commands, name) ? group.commands[name] : void 0;
8581
- }
8582
- function isFlagLike(word) {
8583
- return word.length > 1 && word[0] === "-";
8584
- }
8585
- function walk(node, words, json, invocation) {
8586
- const help = {
8587
- kind: "help",
8588
- node,
8589
- json
8590
- };
8591
- if (node.kind === "command") return wantsHelp(words) ? help : {
8592
- kind: "command",
8593
- spec: node,
8594
- words,
8595
- json
8596
- };
8597
- const [first, ...rest] = words;
8598
- if (first === void 0) return help;
8599
- const child = childOf(node, first);
8600
- if (child !== void 0) return walk(child, rest, json, invocation);
8601
- if (first === "--") {
8602
- const [name, ...after] = rest;
8603
- if (name === void 0) return help;
8604
- const named = childOf(node, name);
8605
- if (named !== void 0) return walk(named, ["--", ...after], json, invocation);
8606
- return unknownCommand(node, name, json);
8607
- }
8608
- if (wantsHelp(words)) return help;
8609
- if (isFlagLike(first)) {
8610
- const suggestions = closestFlags(first, GROUP_FLAGS);
8611
- return {
8612
- kind: "usage error",
8613
- error: unknownOptionError(node.commandLine, invocation, first, suggestions),
8614
- node,
8615
- json
8616
- };
8617
- }
8618
- return unknownCommand(node, first, json);
8619
- }
8620
- function unknownCommand(group, name, json) {
8621
- const suggestions = closestNames(name, Object.keys(visibleCommands(group)));
8622
- return {
8623
- kind: "usage error",
8624
- error: unknownCommandError(group.commandLine, name, suggestions),
8625
- node: group,
8626
- json
8627
- };
8628
- }
8629
- /** Walks the caller's command line through the Commands to the one it names, or to a stop. */
8630
- function route(root, invocation) {
8631
- const { argv } = invocation;
8632
- const options = beforeEnd(argv);
8633
- const json = options.includes(JSON_FLAG.flag);
8634
- if (options.includes("--version")) return {
8635
- kind: "version",
8636
- json
8637
- };
8638
- return walk(root, argv.filter((word, index) => !(index < options.length && word === JSON_FLAG.flag)), json, invocation);
8639
- }
8640
- //#endregion
8641
8905
  //#region ../agent-cli/dist/secrets.js
8642
- function dotenvPath(cliName, env) {
8906
+ /** `$XDG_CONFIG_HOME/<cli>/.env`, with `~/.config` when the variable is unset or empty. */
8907
+ function envFileOf(cliName, env) {
8643
8908
  const config = env.XDG_CONFIG_HOME || join(env.HOME || homedir(), ".config");
8644
8909
  return join(config, cliName, ".env");
8645
8910
  }
@@ -8656,24 +8921,50 @@ function readDotenv(path, fileError) {
8656
8921
  }
8657
8922
  return parseEnv(text);
8658
8923
  }
8659
- /** Looks `name` up in the env, then in `$XDG_CONFIG_HOME/<cli>/.env`; an empty value counts as unset. */
8660
- function secretOf({ cliName, env, fileError }, name) {
8924
+ /** Looks `name` up in the env, then in `envFile`; an empty value counts as unset. */
8925
+ function secretOf({ envFile, env, fileError }, name) {
8661
8926
  const fromEnv = env[name];
8662
8927
  if (fromEnv) return {
8663
8928
  value: fromEnv,
8664
8929
  origin: { kind: "env" }
8665
8930
  };
8666
- const path = dotenvPath(cliName, env);
8667
- const fromFile = readDotenv(path, fileError)[name];
8931
+ const fromFile = readDotenv(envFile, fileError)[name];
8668
8932
  return fromFile ? {
8669
8933
  value: fromFile,
8670
8934
  origin: {
8671
8935
  kind: "file",
8672
- path
8936
+ path: envFile
8673
8937
  }
8674
8938
  } : void 0;
8675
8939
  }
8676
8940
  //#endregion
8941
+ //#region ../agent-cli/dist/side-task.js
8942
+ /** How long a run waits for its Side task once its output is written. */
8943
+ const SIDE_TASK_WAIT_MS = 1e3;
8944
+ const noSideTask = async () => {};
8945
+ function waitOver() {
8946
+ return new DOMException(`the side task ran past its ${SIDE_TASK_WAIT_MS} ms wait`, "TimeoutError");
8947
+ }
8948
+ function startSideTask(sideTask, runWith, { clock, failed }) {
8949
+ if (sideTask === void 0) return noSideTask;
8950
+ const controller = new AbortController();
8951
+ const { signal } = controller;
8952
+ const running = (async () => sideTask(runWith(signal)))().catch((error) => {
8953
+ if (!(signal.aborted && error === signal.reason)) failed(error);
8954
+ });
8955
+ return async () => {
8956
+ const waited = new AbortController();
8957
+ const capped = new Promise((resolve) => after(clock, SIDE_TASK_WAIT_MS, waited.signal, () => {
8958
+ const over = waitOver();
8959
+ failed(over);
8960
+ controller.abort(over);
8961
+ resolve();
8962
+ }));
8963
+ await Promise.race([running, capped]);
8964
+ waited.abort();
8965
+ };
8966
+ }
8967
+ //#endregion
8677
8968
  //#region ../agent-cli/dist/spill.js
8678
8969
  const STDOUT_BUDGET_CHARS = 3e4;
8679
8970
  const SPILL_RETENTION_MS = 6048e5;
@@ -8726,47 +9017,91 @@ function spillTo(target) {
8726
9017
  };
8727
9018
  }
8728
9019
  //#endregion
8729
- //#region ../agent-cli/dist/style.js
8730
- function colourEnabled(env, stdoutIsTTY) {
8731
- if (env.NO_COLOR !== void 0 && env.NO_COLOR !== "") return false;
8732
- return env.FORCE_COLOR !== void 0 && env.FORCE_COLOR !== "" && env.FORCE_COLOR !== "0" || stdoutIsTTY && !isAgent(env);
9020
+ //#region ../agent-cli/dist/run-command.js
9021
+ function stdinNeverEndedHint(callerLine) {
9022
+ return `stdin never ended: pipe the text into \`${callerLine}\`, or redirect a file into it`;
8733
9023
  }
8734
- function sgr(open, close) {
8735
- return (text) => `\u001b[${open}m${text}\u001b[${close}m`;
9024
+ function selfOf(name, bin) {
9025
+ return bin === void 0 ? [name] : [
9026
+ process.execPath,
9027
+ ...process.execArgv,
9028
+ bin
9029
+ ];
8736
9030
  }
8737
- const COLOURED = {
8738
- bold: sgr(1, 22),
8739
- dim: sgr(2, 22),
8740
- red: sgr(31, 39),
8741
- green: sgr(32, 39),
8742
- yellow: sgr(33, 39),
8743
- cyan: sgr(36, 39)
8744
- };
8745
- const plain = (text) => text;
8746
- const PLAIN = {
8747
- bold: plain,
8748
- dim: plain,
8749
- red: plain,
8750
- green: plain,
8751
- yellow: plain,
8752
- cyan: plain
8753
- };
8754
- function styleFor(env, stdoutIsTTY) {
8755
- return colourEnabled(env, stdoutIsTTY) ? COLOURED : PLAIN;
9031
+ function portsOf(cli, replacement) {
9032
+ if (replacement !== void 0) return () => replacement;
9033
+ return cli.ports ?? (() => ({}));
8756
9034
  }
8757
- //#endregion
8758
- //#region ../agent-cli/dist/run-cli.js
8759
- function stdinNeverEndedHint(callerLine) {
8760
- return `stdin never ended: pipe the text into \`${callerLine}\`, or redirect a file into it`;
9035
+ function portsBaseOf(scope, signal) {
9036
+ const { cli, options, packageRoot, progress, fileError, clock, files } = scope;
9037
+ const { cwd, env } = options;
9038
+ const envFile = envFileOf(cli.name, env);
9039
+ return {
9040
+ cwd,
9041
+ env,
9042
+ packageRoot,
9043
+ progress,
9044
+ secret: (name) => secretOf({
9045
+ envFile,
9046
+ env,
9047
+ fileError
9048
+ }, name),
9049
+ envFile,
9050
+ fileError,
9051
+ version: cli.version,
9052
+ build: cli.build,
9053
+ self: selfOf(cli.name, options.bin),
9054
+ signal,
9055
+ clock,
9056
+ files,
9057
+ spawn: contextSpawn(options.spawn ?? realSpawn, {
9058
+ cwd,
9059
+ env,
9060
+ signal,
9061
+ progress
9062
+ }, fileError)
9063
+ };
9064
+ }
9065
+ function contextOf(portsBase, control, parts) {
9066
+ const { ports, project, force, commandLine, deliver } = parts;
9067
+ return {
9068
+ ...portsBase,
9069
+ deadline: (ms) => control.deadline(ms),
9070
+ timeout: (ms) => control.timeout(ms),
9071
+ runToEnd: (name, work) => control.runToEnd(name, work),
9072
+ get ports() {
9073
+ return ports();
9074
+ },
9075
+ project,
9076
+ force,
9077
+ commandLine,
9078
+ poll: (check, { intervalMs, signal: stop }) => poll(portsBase.clock, check, intervalMs, stop === void 0 ? control.signal : AbortSignal.any([control.signal, stop])),
9079
+ deliver
9080
+ };
8761
9081
  }
8762
- async function runCommand(routed, { base, writeStdout, signal, format: baseFormat, ports, clock, files, spawn, projectFile, stdin, platform }) {
8763
- const { command, commandLine } = routed.spec;
9082
+ /** Leaves the Side task running, so the caller writes the result before it waits for it. */
9083
+ async function runCommand(cli, routed, options, write, baseFormat) {
9084
+ const { command, commandLine, builtIn } = routed.spec;
9085
+ const { cwd, env } = options;
9086
+ const clock = options.clock ?? realClock;
9087
+ const files = options.files ?? realFiles();
9088
+ const stdin = options.stdin ?? "";
9089
+ const platform = options.platform ?? process.platform;
9090
+ const ports = portsOf(cli, options.ports);
9091
+ const packageRoot = packageRootOf(options.bin, cwd);
9092
+ const fileError = fileErrorOf({
9093
+ callerLine: commandLineOf(baseFormat.invocation),
9094
+ env,
9095
+ platform
9096
+ });
9097
+ const progress = (message) => write.stderr(progressLine(message, routed.json));
8764
9098
  const invocation = {
8765
9099
  ...baseFormat.invocation,
8766
9100
  flags: knownFlags(routed.spec)
8767
9101
  };
8768
9102
  const format = {
8769
9103
  ...baseFormat,
9104
+ bugs: () => manifestAt(packageRoot).bugs,
8770
9105
  json: routed.json,
8771
9106
  invocation
8772
9107
  };
@@ -8774,71 +9109,91 @@ async function runCommand(routed, { base, writeStdout, signal, format: baseForma
8774
9109
  let resumeHint;
8775
9110
  const control = new RunControl({
8776
9111
  commandLine,
8777
- outer: signal,
9112
+ outer: options.signal,
8778
9113
  clock,
8779
- progress: base.progress,
9114
+ progress,
8780
9115
  runDeadline: command.deadline === void 0 ? void 0 : {
8781
9116
  ms: command.deadline.ms,
8782
9117
  hint: () => resumeHint ?? stdinNeverEndedHint(typedLine())
8783
9118
  }
8784
9119
  });
9120
+ const failed = (error, finishSideTask) => {
9121
+ control.close();
9122
+ return {
9123
+ result: errorResult(error, format),
9124
+ finishSideTask
9125
+ };
9126
+ };
8785
9127
  let parsed;
8786
- let project;
8787
9128
  try {
8788
- checkOperator(routed.spec, base.env, typedLine());
9129
+ checkOperator(routed.spec, env, typedLine());
8789
9130
  parsed = await parseCommand(routed, invocation, (field) => {
8790
- if (isTerminal(stdin)) base.progress(readingLine(field.name, platform));
8791
- return readStdin(stdin, control.signal);
9131
+ if (isTerminal(stdin)) progress(readingLine(field.name, platform));
9132
+ return readStdin(stdin, control.signal, {
9133
+ clock,
9134
+ stalled: () => stdinStalled(typedLine())
9135
+ });
8792
9136
  });
8793
- project = projectFile === void 0 ? void 0 : projectOf(projectFile, base.cwd);
8794
9137
  } catch (error) {
8795
- control.close();
8796
- return errorResult(error, format);
9138
+ return failed(error, noSideTask);
8797
9139
  }
8798
9140
  const { input, flags } = parsed;
8799
9141
  resumeHint = command.deadline?.resume(input, typedLine);
8800
- let delivered;
8801
- const { fileError } = base;
8802
9142
  const outputs = outputsGuard(classifiedFiles(files, {
8803
- cwd: base.cwd,
8804
- fileError
8805
- }), base.cwd);
8806
- const spill = spillTo({
8807
- cliName: format.cliName,
8808
- commandName: command.name,
8809
- env: base.env,
8810
- clock,
8811
- files: outputs.files,
9143
+ cwd,
8812
9144
  fileError
8813
- });
8814
- const portsBase = {
8815
- ...base,
8816
- signal: control.signal,
9145
+ }), cwd);
9146
+ const scope = {
9147
+ cli,
9148
+ options,
9149
+ packageRoot,
9150
+ progress,
9151
+ fileError,
8817
9152
  clock,
8818
- files: outputs.files,
8819
- spawn: contextSpawn(spawn, {
8820
- cwd: base.cwd,
8821
- env: base.env,
8822
- signal: control.signal,
8823
- progress: base.progress
8824
- }, fileError)
9153
+ files: outputs.files
8825
9154
  };
8826
- const builtPorts = once(() => ports(portsBase));
8827
- const ctx = {
8828
- ...portsBase,
8829
- deadline: (ms) => control.deadline(ms),
8830
- runToEnd: (name, work) => control.runToEnd(name, work),
8831
- get ports() {
8832
- return builtPorts();
8833
- },
9155
+ const portsBase = portsBaseOf(scope, control.signal);
9156
+ const finishSideTask = startSideTask(builtIn ? void 0 : cli.sideTask?.bind(cli), (sideSignal) => {
9157
+ const sideBase = portsBaseOf(scope, sideSignal);
9158
+ const sidePorts = once(() => ports(sideBase));
9159
+ return {
9160
+ ...sideBase,
9161
+ command: routed.spec.path,
9162
+ dryRun: flags.dryRun,
9163
+ get ports() {
9164
+ return sidePorts();
9165
+ }
9166
+ };
9167
+ }, {
9168
+ clock,
9169
+ failed: (error) => {
9170
+ if (isDebug(baseFormat)) progress(`side task failed: ${traceOf(error)}`);
9171
+ }
9172
+ });
9173
+ let project;
9174
+ try {
9175
+ project = builtIn || cli.project === void 0 ? void 0 : projectOf(cli.project, cwd, fileError);
9176
+ } catch (error) {
9177
+ return failed(error, finishSideTask);
9178
+ }
9179
+ let delivered;
9180
+ const ctx = contextOf(portsBase, control, {
9181
+ ports: once(() => ports(portsBase)),
8834
9182
  project,
8835
9183
  force: flags.force,
8836
9184
  commandLine: typedLine,
8837
- poll: (check, { intervalMs, signal: stop }) => poll(clock, check, intervalMs, stop === void 0 ? control.signal : AbortSignal.any([control.signal, stop])),
8838
9185
  deliver: (data) => {
8839
9186
  delivered = deliveredOutcome(command, data);
8840
9187
  }
8841
- };
9188
+ });
9189
+ const spill = spillTo({
9190
+ cliName: format.cliName,
9191
+ commandName: command.name,
9192
+ env,
9193
+ clock,
9194
+ files: outputs.files,
9195
+ fileError
9196
+ });
8842
9197
  let served = false;
8843
9198
  let settled;
8844
9199
  try {
@@ -8852,7 +9207,7 @@ async function runCommand(routed, { base, writeStdout, signal, format: baseForma
8852
9207
  invocation,
8853
9208
  commandLine,
8854
9209
  started: async (outcome) => {
8855
- writeStdout(await startedOutput(outcome, format, spill));
9210
+ write.stdout(await startedOutput(outcome, format, spill));
8856
9211
  served = true;
8857
9212
  },
8858
9213
  files,
@@ -8860,17 +9215,23 @@ async function runCommand(routed, { base, writeStdout, signal, format: baseForma
8860
9215
  }))
8861
9216
  };
8862
9217
  } catch (error) {
8863
- if (served && control.signal.aborted) return STOPPED_RESULT;
9218
+ if (served && control.signal.aborted) return {
9219
+ result: STOPPED_RESULT,
9220
+ finishSideTask
9221
+ };
8864
9222
  settled = {
8865
9223
  ok: false,
8866
9224
  error: control.errorAfter(error),
8867
9225
  delivered
8868
9226
  };
8869
9227
  }
8870
- return commandResult(settled, {
8871
- ...format,
8872
- fields: flags.fields
8873
- }, spill);
9228
+ return {
9229
+ result: await commandResult(settled, {
9230
+ ...format,
9231
+ fields: flags.fields
9232
+ }, spill),
9233
+ finishSideTask
9234
+ };
8874
9235
  }
8875
9236
  /** `build` runs on the first call; later calls give its value or throw its error again. */
8876
9237
  function once(build) {
@@ -8891,17 +9252,37 @@ function once(build) {
8891
9252
  throw outcome.error;
8892
9253
  };
8893
9254
  }
8894
- function selfOf(name, bin) {
8895
- return bin === void 0 ? [name] : [
8896
- process.execPath,
8897
- ...process.execArgv,
8898
- bin
8899
- ];
9255
+ //#endregion
9256
+ //#region ../agent-cli/dist/style.js
9257
+ function colourEnabled(env, stdoutIsTTY) {
9258
+ if (env.NO_COLOR !== void 0 && env.NO_COLOR !== "") return false;
9259
+ return env.FORCE_COLOR !== void 0 && env.FORCE_COLOR !== "" && env.FORCE_COLOR !== "0" || stdoutIsTTY && !isAgent(env);
8900
9260
  }
8901
- function portsOf(cli, replacement) {
8902
- if (replacement !== void 0) return () => replacement;
8903
- return cli.ports ?? (() => ({}));
9261
+ function sgr(open, close) {
9262
+ return (text) => `\u001b[${open}m${text}\u001b[${close}m`;
9263
+ }
9264
+ const COLOURED = {
9265
+ bold: sgr(1, 22),
9266
+ dim: sgr(2, 22),
9267
+ red: sgr(31, 39),
9268
+ green: sgr(32, 39),
9269
+ yellow: sgr(33, 39),
9270
+ cyan: sgr(36, 39)
9271
+ };
9272
+ const plain = (text) => text;
9273
+ const PLAIN = {
9274
+ bold: plain,
9275
+ dim: plain,
9276
+ red: plain,
9277
+ green: plain,
9278
+ yellow: plain,
9279
+ cyan: plain
9280
+ };
9281
+ function styleFor(env, stdoutIsTTY) {
9282
+ return colourEnabled(env, stdoutIsTTY) ? COLOURED : PLAIN;
8904
9283
  }
9284
+ //#endregion
9285
+ //#region ../agent-cli/dist/run-cli.js
8905
9286
  function stopLine(notice, json) {
8906
9287
  return json ? progressLine(notice, true) : `\n${notice}\n`;
8907
9288
  }
@@ -8915,7 +9296,14 @@ async function whileStopping(signal, onStop, work) {
8915
9296
  signal.removeEventListener("abort", onStop);
8916
9297
  }
8917
9298
  }
9299
+ /** Runs the CLI, writes its output, then waits for the Side task it started. */
8918
9300
  async function runWithProgress(cli, argv, options, write, stopNotice) {
9301
+ const { result, finishSideTask } = await routeAndRun(cli, argv, options, write, stopNotice);
9302
+ await write.result(result);
9303
+ await finishSideTask();
9304
+ return result;
9305
+ }
9306
+ async function routeAndRun(cli, argv, options, write, stopNotice) {
8919
9307
  const format = {
8920
9308
  cliName: cli.name,
8921
9309
  env: options.env,
@@ -8929,64 +9317,37 @@ async function runWithProgress(cli, argv, options, write, stopNotice) {
8929
9317
  errors: cli.errors ?? {},
8930
9318
  stop: options.signal
8931
9319
  };
8932
- const builtIns = cli.commands === void 0 ? {} : builtInCommands(cli, {
9320
+ const root = cli.commands === void 0 ? {
9321
+ ...commandSpec(cli.name, cli.command),
9322
+ description: cli.description
9323
+ } : groupSpec(cli.name, cli.commands, builtInCommands(cli, {
8933
9324
  bin: options.bin,
8934
9325
  node: options.node
8935
- });
8936
- const root = cli.commands === void 0 ? commandSpec(cli.name, cli.command) : groupSpec(cli.name, {
8937
- ...cli.commands,
8938
- ...builtIns
8939
- });
9326
+ }));
8940
9327
  const routed = route(root, format.invocation);
8941
- const platform = options.platform ?? process.platform;
8942
- const fileError = fileErrorOf({
8943
- callerLine: commandLineOf(format.invocation),
8944
- env: options.env,
8945
- platform
8946
- });
8947
9328
  const misused = (node) => isAgent(options.env) ? {
8948
9329
  ...format,
8949
9330
  usageHelp: textHelp(node, root, cli, format.style)
8950
9331
  } : format;
8951
9332
  switch (routed.kind) {
8952
- case "version": return versionResult(cli, packageRootOf(options.bin, options.cwd));
8953
- case "help": return helpResult(routed.node, root, cli, {
9333
+ case "version": return ranAlone(versionResult(cli, packageRootOf(options.bin, options.cwd)));
9334
+ case "help": return ranAlone(helpResult(routed.node, root, cli, {
8954
9335
  ...format,
8955
9336
  json: routed.json
8956
- });
8957
- case "usage error": return errorResult(routed.error, {
9337
+ }));
9338
+ case "usage error": return ranAlone(errorResult(routed.error, {
8958
9339
  ...misused(routed.node),
8959
9340
  json: routed.json
8960
- });
8961
- case "command": return whileStopping(options.signal, stopNotice === void 0 ? void 0 : () => write.stderr(stopLine(stopNotice, routed.json)), () => runCommand(routed, {
8962
- base: {
8963
- cwd: options.cwd,
8964
- env: options.env,
8965
- packageRoot: packageRootOf(options.bin, options.cwd),
8966
- progress: (message) => write.stderr(progressLine(message, routed.json)),
8967
- secret: (name) => secretOf({
8968
- cliName: cli.name,
8969
- env: options.env,
8970
- fileError
8971
- }, name),
8972
- fileError,
8973
- version: cli.version,
8974
- build: cli.build,
8975
- self: selfOf(cli.name, options.bin)
8976
- },
8977
- writeStdout: (text) => write.stdout(text),
8978
- signal: options.signal,
8979
- format: misused(routed.spec),
8980
- ports: portsOf(cli, options.ports),
8981
- clock: options.clock ?? realClock,
8982
- files: options.files ?? realFiles(),
8983
- spawn: options.spawn ?? realSpawn,
8984
- projectFile: Object.values(builtIns).includes(routed.spec.command) ? void 0 : cli.project,
8985
- stdin: options.stdin ?? "",
8986
- platform
8987
9341
  }));
9342
+ case "command": return whileStopping(options.signal, stopNotice === void 0 ? void 0 : () => write.stderr(stopLine(stopNotice, routed.json)), () => runCommand(cli, routed, options, write, misused(routed.spec)));
8988
9343
  }
8989
9344
  }
9345
+ async function ranAlone(result) {
9346
+ return {
9347
+ result: await result,
9348
+ finishSideTask: noSideTask
9349
+ };
9350
+ }
8990
9351
  //#endregion
8991
9352
  //#region ../agent-cli/dist/run-process.js
8992
9353
  function written(stream, text) {
@@ -9011,10 +9372,12 @@ async function runProcess(cli) {
9011
9372
  stdin: process.stdin
9012
9373
  }, {
9013
9374
  stdout: (text) => process.stdout.write(text),
9014
- stderr: (text) => process.stderr.write(text)
9375
+ stderr: (text) => process.stderr.write(text),
9376
+ result: async ({ stdout, stderr }) => {
9377
+ await written(process.stdout, stdout);
9378
+ await written(process.stderr, stderr);
9379
+ }
9015
9380
  }, "stopping… (Ctrl-C again to quit now)");
9016
- await written(process.stdout, result.stdout);
9017
- await written(process.stderr, result.stderr);
9018
9381
  process.exitCode = result.exitCode;
9019
9382
  } finally {
9020
9383
  process.off("SIGINT", onSignal);
@@ -9023,11 +9386,15 @@ async function runProcess(cli) {
9023
9386
  process.exit();
9024
9387
  }
9025
9388
  //#endregion
9389
+ //#region package.json
9390
+ var version$1 = "0.6.0";
9391
+ var description = "Creates a new Agent CLI repository wired to @duyquangnvx/agent-cli.";
9392
+ //#endregion
9026
9393
  //#region src/build.ts
9027
9394
  const build = {
9028
- "sha": "c325cae",
9395
+ "sha": "6821473",
9029
9396
  "dirty": false,
9030
- "builtAt": "2026-10-19T14:33:32.022Z"
9397
+ "builtAt": "2026-10-20T02:08:46.888Z"
9031
9398
  };
9032
9399
  //#endregion
9033
9400
  //#region src/steps.ts
@@ -9156,11 +9523,13 @@ async function writeTemplate(root, files, values) {
9156
9523
  }
9157
9524
  //#endregion
9158
9525
  //#region src/version.ts
9159
- const version = "0.5.0";
9526
+ const version = version$1;
9160
9527
  //#endregion
9161
9528
  //#region src/create.ts
9162
9529
  const { defineCommand } = agentCli();
9163
9530
  const PACKAGE_NAME = /^(?:@[a-z0-9][a-z0-9._-]*\/)?([a-z0-9][a-z0-9._-]*)$/;
9531
+ const RELEASE_BRANCH = "release";
9532
+ const NO_REPOSITORY = "<!-- Set `repository` in package.json, then put here the `! npx -y skills add` line that `node dist/bin.js doctor` gives as the `skill` row's fix. -->";
9164
9533
  function errorCode(error) {
9165
9534
  return error instanceof Error && "code" in error ? error.code : void 0;
9166
9535
  }
@@ -9173,6 +9542,17 @@ async function isFree(path) {
9173
9542
  throw error;
9174
9543
  }
9175
9544
  }
9545
+ function skillInstallLine(repository, binName) {
9546
+ if (repository === void 0) return NO_REPOSITORY;
9547
+ return `\`! npx -y skills add ${`${repository.endsWith(".git") ? repository : `${repository}.git`}#${RELEASE_BRANCH}`} --skill ${binName} -g\``;
9548
+ }
9549
+ const MANIFEST = record(string(), unknown());
9550
+ async function setRepository(root, repository) {
9551
+ const path = join(root, "package.json");
9552
+ const manifest = MANIFEST.parse(JSON.parse(await readFile(path, "utf8")));
9553
+ const entries = Object.entries(manifest).flatMap((entry) => entry[0] === "description" ? [entry, ["repository", repository]] : [entry]);
9554
+ await writeFile(path, `${JSON.stringify(Object.fromEntries(entries), null, 2)}\n`);
9555
+ }
9176
9556
  async function ensureFree(path) {
9177
9557
  if (!await isFree(path)) throw new UsageError({
9178
9558
  code: "TARGET_NOT_EMPTY",
@@ -9192,9 +9572,10 @@ const create = defineCommand({
9192
9572
  options: object({
9193
9573
  description: string().default("An Agent CLI.").describe("one line saying what the CLI does"),
9194
9574
  install: boolean().default(true).describe("run pnpm install"),
9195
- git: boolean().default(true).describe("create a git repository with an initial commit")
9575
+ git: boolean().default(true).describe("create a git repository with an initial commit"),
9576
+ repository: url({ protocol: /^https$/ }).optional().describe("the https URL of the CLI's git repository, where its skill is installed from")
9196
9577
  }),
9197
- plan: async ({ name, description, install, git }, ctx) => {
9578
+ plan: async ({ name, description, install, git, repository }, ctx) => {
9198
9579
  const binName = PACKAGE_NAME.exec(name)?.[1] ?? name;
9199
9580
  const path = resolve(ctx.cwd, binName);
9200
9581
  await ensureFree(path);
@@ -9203,7 +9584,8 @@ const create = defineCommand({
9203
9584
  binName,
9204
9585
  description,
9205
9586
  debugVariable: debugVariable(binName),
9206
- runtimeVersion: version
9587
+ runtimeVersion: version,
9588
+ skillInstall: skillInstallLine(repository, binName)
9207
9589
  };
9208
9590
  return {
9209
9591
  path,
@@ -9213,12 +9595,14 @@ const create = defineCommand({
9213
9595
  install,
9214
9596
  git
9215
9597
  }),
9216
- install
9598
+ install,
9599
+ repository
9217
9600
  };
9218
9601
  },
9219
9602
  apply: async (plan, ctx) => {
9220
9603
  await mkdir(plan.path, { recursive: true });
9221
9604
  await writeTemplate(plan.path, plan.files, plan.values);
9605
+ if (plan.repository !== void 0) await setRepository(plan.path, plan.repository);
9222
9606
  await runSteps(plan.steps, plan.path, ctx);
9223
9607
  return {
9224
9608
  path: plan.path,
@@ -9240,6 +9624,7 @@ const { defineCli } = agentCli();
9240
9624
  await runProcess(defineCli({
9241
9625
  name: "create-agent-cli",
9242
9626
  version,
9627
+ description,
9243
9628
  build,
9244
9629
  errors: stepErrors,
9245
9630
  command: create