@deslop/stash 0.1.1076 → 0.1.1079

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env -S node --max-old-space-size=16384 --heapsnapshot-near-heap-limit=3 --report-on-fatalerror
2
- import { $d as identity, $n as value, $o as runForkWith, Ao as match$2, Ba as catchCauseIf, Bo as orDie, Bs as isEmpty, Cs as void_, Ct as Defect, D as option, Do as map$2, Dt as FalseLiterals, Ei as runHead, El as taggedEnum, Eo as makeSpanScoped, Fi as unwrap, Fl as filter$1, Fo as onError, Ft as NonEmptyArray, Fu as Reference, Ga as catchTag, Gi as bounded, Go as provideService, Ha as catchFilter, Hu as getUnsafe, I as layerJson, Ic as Scope, Iu as Service, J as isStreamSchema, Ja as context, Ji as failCause, Ju as exists, Ka as catchTags, Ks as replace, La as cached, Lc as addFinalizer, Ld as hasProperty, Ll as findFirst, Lu as add, Ml as empty$2, Ms as min, N as withRunClient, Na as annotateLogs, Nd as format, Ns as spaced, Os as withParentSpan, Ou as succeed$2, P as RpcSerialization, Pu as toMillis, Q as makeCollectorUnsafe, Qa as ensuring, Qn as make$2, R as RequestId, Ra as callback, Rc as addFinalizerExit, Rl as findFirstIndex, Ro as onInterrupt, Ru as empty$1, Sn as tag, So as logError, Ss as useSpan, Td as assignProperty, Ts as withFiber, Tt as Error$1, Tu as isSuccess, Un as empty, Uo as provide, Ut as TaggedError, Uu as make$3, V as constPing, Vd as isNotUndefined, Vs as isNonEmpty, Vt as String$6, Vu as getOrUndefinedUnsafe, W as exitSchema, Wn as fromInput, Wo as provideContext, Wt as TrueLiterals, X as spanName, Xa as delay, Xl as isReadonlyArrayNonEmpty, Y as spanAttributes, Yd as constVoid, Yo as result, Z as Collector, Zd as dual, Zi as offerAll, Zl as join, Zo as retryOrElse, Zr as filter, Zt as Union, _ as QuitError, _c as interruptors, _o as interrupt$1, _t as ArraySchema, aa as makeUnsafe, ad as isSome, ai as fromQueue, al as isFailure, as as succeed$1, bd as Prototype, bn as optional$2, c as NotesError, ca as interrupt$2, cd as map$3, cl as ConsoleRef, co as forever, cs as sync$1, do as forkScoped, ea as shutdownUnsafe, ed as fromUndefinedOr, ef as pipe, el as die, en as decodeSync, eo as fail$1, et as Socket, eu as map$4, fc as findError, fs as timeout, ft as HttpClientErrorSchema, g as layer, gl as sync, go as ignoreCause, h as errorReported, hc as hasInterrupts, ho as ignore, id as isNone, in as encodeEffect, is as serviceOption, it as SocketReadError, iu as reduce, j as Stdio, ja as andThen, jc as provide$1, jo as matchCauseEffect, js as exponential, jt as Literal, ko as mapError, ld as match$1, ln as is, m as errorExitCode, mo as gen, ms as timeoutOrElse, nc as round, nl as failCause$1, nn as decodeUnknownEffect, ns as scoped, nt as SocketErrorReason, oo as fnUntraced, ot as layerWebSocket, ou as some$1, p as runMain, pd as some, q as getStreamSchemas, qc as MinimumLogLevel, qi as end, qn as merge, qo as raceFirst, rc as Clock, rd as getOrUndefined, rl as interrupt, ro as flatMap$1, sa as getCurrent, so as forEach, ss as suspend, st as layerWebSocketConstructorGlobal, t as RpcContracts, ta as take, td as getOrElse, tf as pipeArguments, tl as fail, tt as SocketError, tu as match, u as LogToStderr, ud as none, uo as forkIn, us as tapCause, v as Terminal, vo as interruptible, w as String$7, wc as effect, wd as withFiber$1, wn as toCodecStringTree, wo as logInfo, ws as whileLoop, x as Crypto, xc as squash, xn as optionalKey, y as isQuitError, yo as isEffect, ys as uninterruptibleMask, yt as BooleanLiterals, yu as fail$2, za as catchCause, zl as findLast, zu as get } from "./contracts-DgOSCO2p.mjs";
3
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/workers/WorkerError.js
2
+ import { $a as catchCauseIf, $d as isNotUndefined, $l as findLast, $o as orDie, $u as getOrUndefinedUnsafe, Al as sync, Ao as interrupt$1, Bl as taggedEnum, Bo as map$2, Bu as succeed$2, Co as forkIn, Cs as tapCause, Ct as Defect, D as option, Do as gen, Ds as timeoutOrElse, Dt as FalseLiterals, Ec as findError, Fc as squash, Fo as logError, Fs as useSpan, Ft as NonEmptyArray, Gc as provide$1, Gd as format, Gs as exponential, Ho as mapError, Hs as withParentSpan, I as layerJson, Id as withFiber$1, Is as void_, J as isStreamSchema, Ji as bounded, Jo as onError, Ju as Service, Ka as annotateLogs, Kl as empty$2, Kn as empty, Ks as min, Ku as toMillis, Ld as assignProperty, Lo as logInfo, Md as Prototype, Mo as isEffect, Ms as uninterruptibleMask, N as withRunClient, Nu as fail$2, Oo as ignore, P as RpcSerialization, Q as makeCollectorUnsafe, Qa as catchCause, Qc as addFinalizerExit, Ql as findFirstIndex, R as RequestId, Rc as effect, Ri as unwrap, Rs as whileLoop, Ru as isSuccess, Sd as none, Sl as ConsoleRef, Sn as tag, Td as some, Ts as timeout, Tt as Error$1, Uo as match$2, Ut as TaggedError, V as constPing, Vt as String$6, W as exitSchema, Wa as andThen, Wo as matchCauseEffect, Wt as TrueLiterals, X as spanName, Xa as cached, Xc as Scope, Xi as end, Xn as merge, Xu as empty$1, Y as spanAttributes, Yd as hasProperty, Yl as filter$1, Yu as add, Z as Collector, Za as callback, Zc as addFinalizer, Zi as failCause, Zl as findFirst, Zo as onInterrupt, Zt as Union, Zu as get, _ as QuitError, _c as Clock, _d as isSome, _l as interrupt, _s as serviceOption, _t as ArraySchema, ao as catchTags, bd as map$3, bn as optional$2, bo as forEach, bs as suspend, bu as some$1, c as NotesError, ca as makeUnsafe, ci as fromQueue, cs as result, da as interrupt$2, df as identity, do as ensuring, du as join, ea as offerAll, ec as isEmpty, ed as getUnsafe, ei as filter, en as decodeSync, et as Socket, fd as fromUndefinedOr, ff as pipe, fs as runForkWith, ft as HttpClientErrorSchema, g as layer, gc as round, gd as isNone, gl as failCause$1, go as flatMap$1, h as errorReported, hd as getOrUndefined, hl as fail, hs as scoped, hu as match, ia as take, in as encodeEffect, io as catchTag, is as provideService, it as SocketReadError, j as Stdio, jc as interruptors, jo as interruptible, jt as Literal, kc as hasInterrupts, ki as runHead, ko as ignoreCause, lf as dual, ln as is, lo as delay, m as errorExitCode, ml as die, mu as map$4, nn as decodeUnknownEffect, nr as value, ns as provide, nt as SocketErrorReason, oc as replace, od as exists, os as raceFirst, ot as layerWebSocket, p as runMain, pd as getOrElse, pf as pipeArguments, po as fail$1, q as getStreamSchemas, qn as fromInput, qs as spaced, qu as Reference, ra as shutdownUnsafe, rs as provideContext, sf as constVoid, sl as MinimumLogLevel, so as context, st as layerWebSocketConstructorGlobal, t as RpcContracts, tc as isNonEmpty, td as make$3, to as catchFilter, tr as make$2, tt as SocketError, u as LogToStderr, ua as getCurrent, us as retryOrElse, uu as isReadonlyArrayNonEmpty, v as Terminal, vs as succeed$1, vu as reduce, w as String$7, wn as toCodecStringTree, wo as forkScoped, x as Crypto, xd as match$1, xn as optionalKey, xo as forever, xs as sync$1, y as isQuitError, yl as isFailure, yo as fnUntraced, yt as BooleanLiterals, zo as makeSpanScoped, zs as withFiber } from "./contracts-Cc_B2S3-.mjs";
3
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/workers/WorkerError.js
4
4
  /**
5
5
  * Worker error reason for failures while spawning or setting up a worker.
6
6
  *
@@ -64,7 +64,7 @@ const WorkerErrorReason = /*#__PURE__*/ Union([
64
64
  WorkerUnknownError
65
65
  ]);
66
66
  //#endregion
67
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/rpc/RpcClientError.js
67
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/rpc/RpcClientError.js
68
68
  /**
69
69
  * Client-side protocol failures reported by unstable RPC transports.
70
70
  *
@@ -119,7 +119,7 @@ var RpcClientError = class extends (/*#__PURE__*/ Error$1(TypeId$4)({
119
119
  }
120
120
  };
121
121
  //#endregion
122
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/rpc/RpcClient.js
122
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/rpc/RpcClient.js
123
123
  let requestIdCounter = 0;
124
124
  /**
125
125
  * Creates an RPC client for an already-decoded message channel, returning the
@@ -620,16 +620,19 @@ const makePinger = /*#__PURE__*/ fnUntraced(function* (writePing, options) {
620
620
  const interval = options?.pingInterval ?? "5 seconds";
621
621
  const timeoutMillis = toMillis(options?.pingTimeout ?? interval);
622
622
  let lastSeen = clock.currentTimeMillisUnsafe();
623
+ let awaitingResponse = false;
623
624
  const latch = makeUnsafe();
624
625
  const onFrame = () => {
625
626
  lastSeen = clock.currentTimeMillisUnsafe();
627
+ awaitingResponse = false;
626
628
  };
627
629
  const reset = () => {
628
630
  onFrame();
629
631
  latch.closeUnsafe();
630
632
  };
631
633
  yield* suspend(() => {
632
- if (clock.currentTimeMillisUnsafe() - lastSeen > timeoutMillis) return latch.open;
634
+ if (awaitingResponse && clock.currentTimeMillisUnsafe() - lastSeen > timeoutMillis) return latch.open;
635
+ awaitingResponse = true;
633
636
  return writePing;
634
637
  }).pipe(delay(interval), ignore, forever, interruptible, forkScoped);
635
638
  return {
@@ -669,7 +672,7 @@ const layerProtocolSocket = (options) => effect(Protocol)(makeProtocolSocket(opt
669
672
  */
670
673
  var ConnectionHooks = class extends (/*#__PURE__*/ Service()("effect/rpc/RpcClient/ConnectionHooks")) {};
671
674
  //#endregion
672
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/Console.js
675
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/Console.js
673
676
  /**
674
677
  * Context reference for the current console service in the Effect system, allowing access to the active console implementation from within the Effect context.
675
678
  *
@@ -808,7 +811,7 @@ const log = (...args) => consoleWith((console) => sync(() => {
808
811
  console.log(...args);
809
812
  }));
810
813
  //#endregion
811
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/cli/CliError.js
814
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/cli/CliError.js
812
815
  /**
813
816
  * Defines structured errors for the unstable CLI parser and runner.
814
817
  *
@@ -1338,7 +1341,7 @@ var ShowHelp = class extends (/*#__PURE__*/ TaggedError(`${TypeId$3}/ShowHelp`)(
1338
1341
  }
1339
1342
  };
1340
1343
  //#endregion
1341
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/cli/Primitive.js
1344
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/cli/Primitive.js
1342
1345
  /**
1343
1346
  * Parses raw command-line strings into typed values.
1344
1347
  *
@@ -1577,7 +1580,7 @@ const getChoiceKeys = (primitive) => primitive._tag === "Choice" ? primitive.cho
1577
1580
  */
1578
1581
  const getPathType = (primitive) => primitive._tag === "Path" ? primitive.pathType : void 0;
1579
1582
  //#endregion
1580
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/cli/internal/ansi.js
1583
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/cli/internal/ansi.js
1581
1584
  /**
1582
1585
  * Internal ANSI escape sequence helpers used by the unstable CLI rendering
1583
1586
  * implementation. This module centralizes the control codes for text styling,
@@ -1717,7 +1720,7 @@ const eraseLines = (rows) => {
1717
1720
  return command;
1718
1721
  };
1719
1722
  //#endregion
1720
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/cli/Prompt.js
1723
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/cli/Prompt.js
1721
1724
  /**
1722
1725
  * Builds interactive terminal prompts for CLI applications.
1723
1726
  *
@@ -3224,7 +3227,7 @@ const entriesToDisplay = (cursor, total, maxVisible) => {
3224
3227
  };
3225
3228
  };
3226
3229
  //#endregion
3227
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/cli/Param.js
3230
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/cli/Param.js
3228
3231
  /**
3229
3232
  * Defines the shared parameter model for CLI arguments and flags.
3230
3233
  *
@@ -3933,7 +3936,7 @@ const getParamMetadata = (param) => {
3933
3936
  });
3934
3937
  };
3935
3938
  //#endregion
3936
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/cli/Argument.js
3939
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/cli/Argument.js
3937
3940
  /**
3938
3941
  * Creates a positional string argument.
3939
3942
  *
@@ -3971,7 +3974,7 @@ const String$2 = (name) => String$3(argumentKind, name);
3971
3974
  */
3972
3975
  const withDescription$2 = /*#__PURE__*/ dual(2, (self, description) => withDescription$3(self, description));
3973
3976
  //#endregion
3974
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/cli/CliOutput.js
3977
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/cli/CliOutput.js
3975
3978
  /**
3976
3979
  * Formats CLI help and errors as text.
3977
3980
  *
@@ -4263,484 +4266,916 @@ const formatHelpDocImpl = (doc, colors) => {
4263
4266
  return sections.join("\n");
4264
4267
  };
4265
4268
  //#endregion
4266
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/cli/internal/completions/bash.js
4267
- const escapeForBash = (s) => s.replace(/'/g, "'\\''");
4268
- const sanitizeFunctionName = (s) => s.replace(/[^a-zA-Z0-9_]/g, "_");
4269
- const flagNamesForWordlist = (flag) => {
4270
- const names = [`--${flag.name}`];
4271
- for (const alias of flag.aliases) names.push(alias.length === 1 ? `-${alias}` : `--${alias}`);
4272
- if (flag.type._tag === "Boolean") names.push(`--no-${flag.name}`);
4273
- return names;
4274
- };
4275
- /** Emit a Bash 3.2-compatible used-flag filter. */
4276
- const buildFlagGroupDeclarations = (flags, lines) => {
4277
- if (flags.length === 0) return;
4278
- const groups = flags.map(flagNamesForWordlist);
4279
- lines.push(` local ${groups.map((_, index) => `_used_${index}=""`).join(" ")}`);
4280
- lines.push(` for ((i = 1; i < cword; i++)); do`);
4281
- lines.push(` case "\${words[i]%%=*}" in`);
4282
- groups.forEach((forms, index) => {
4283
- lines.push(` ${forms.join("|")}) _used_${index}=1 ;;`);
4284
- });
4285
- lines.push(` esac`);
4286
- lines.push(` done`);
4287
- lines.push(` local _filtered_flags=""`);
4288
- groups.forEach((forms, index) => {
4289
- lines.push(` [[ -n "$_used_${index}" ]] || _filtered_flags+=" ${forms.join(" ")}"`);
4290
- });
4291
- lines.push(``);
4292
- };
4269
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/cli/internal/config.js
4293
4270
  /**
4294
- * Complete choices without `compgen -W`, which reparses quoted values. Escape
4295
- * only the portion readline replaces for the active quote context.
4271
+ * Config Internal
4272
+ * ================
4296
4273
  *
4297
- * `!` cannot be escaped inside a user-opened double quote without changing the
4298
- * resulting argument.
4274
+ * The processed internal representation of a Command.Config declaration.
4275
+ * Separates the user's declared config shape from the flat parsing representation.
4276
+ *
4277
+ * Key concepts:
4278
+ * - ConfigInternal: The full processed form (flags, arguments, tree)
4279
+ * - ConfigInternal.Tree: Maps declaration keys to nodes
4280
+ * - ConfigInternal.Node: Param reference, Array, or Nested subtree
4281
+ *
4282
+ * Example transformation from Command.Config to Command.Config.Internal:
4283
+ *
4284
+ * ```ts
4285
+ * // User declares:
4286
+ * const config = {
4287
+ * verbose: Flag.Boolean("verbose").pipe(Flag.withDefault(false)),
4288
+ * server: {
4289
+ * host: Flag.String("host"),
4290
+ * port: Flag.Int("port")
4291
+ * },
4292
+ * files: Argument.String("files").pipe(Argument.variadic)
4293
+ * }
4294
+ *
4295
+ * // Becomes Config.Internal:
4296
+ * {
4297
+ * arguments: [filesParam], // Flat array of arguments
4298
+ * flags: [verboseParam, hostParam, portParam], // Flat array of flags
4299
+ * orderedParams: [verboseParam, hostParam, portParam, filesParam],
4300
+ * tree: { // Preserves nested structure
4301
+ * verbose: { _tag: "Param", index: 0 },
4302
+ * server: {
4303
+ * _tag: "Nested",
4304
+ * tree: {
4305
+ * host: { _tag: "Param", index: 1 },
4306
+ * port: { _tag: "Param", index: 2 }
4307
+ * }
4308
+ * },
4309
+ * files: { _tag: "Param", index: 3 }
4310
+ * }
4311
+ * }
4312
+ * ```
4313
+ *
4314
+ * This separation allows:
4315
+ * 1. Flat iteration over all params for parsing/validation
4316
+ * 2. Reconstruction of original nested shape for handler input
4299
4317
  */
4300
- const choicesHelper = (helperName, lines) => {
4301
- lines.push(`${helperName}()`);
4302
- lines.push(`{`);
4303
- lines.push(` local _cur="$1" _word="$2"; shift 2`);
4304
- lines.push(``);
4305
- lines.push(` local _head="\${_cur%"$_word"}"`);
4306
- lines.push(` local _open=""`);
4307
- lines.push(` case "$_head" in`);
4308
- lines.push(` *\\') _open="'" ;;`);
4309
- lines.push(` *\\") _open='"' ;;`);
4310
- lines.push(` esac`);
4311
- lines.push(``);
4312
- lines.push(` local _prefix="$_cur" _committed="$_head"`);
4313
- lines.push(` _prefix=\${_prefix//\\\\/}; _prefix=\${_prefix//\\"/}; _prefix=\${_prefix//\\'/}`);
4314
- lines.push(` _committed=\${_committed//\\\\/}; _committed=\${_committed//\\"/}; _committed=\${_committed//\\'/}`);
4315
- lines.push(``);
4316
- lines.push(` COMPREPLY=()`);
4317
- lines.push(` local _choice _rest _match`);
4318
- lines.push(` for _choice in "$@"; do`);
4319
- lines.push(` [[ "$_choice" == "$_prefix"* ]] || continue`);
4320
- lines.push(` _rest="\${_choice#"$_committed"}"`);
4321
- lines.push(` case "$_open" in`);
4322
- lines.push(` "'")`);
4323
- lines.push(` if [[ "$_head" == "'" ]]; then`);
4324
- lines.push(` _match=\${_rest//\\'/\\'\\\\\\'\\'}`);
4325
- lines.push(` else`);
4326
- lines.push(` [[ "$_rest" == *\\'* ]] && continue`);
4327
- lines.push(` _match="$_rest"`);
4328
- lines.push(` fi`);
4329
- lines.push(` ;;`);
4330
- lines.push(` '"')`);
4331
- lines.push(` _match="\${_rest//\\\\/\\\\\\\\}"`);
4332
- lines.push(` _match="\${_match//\\$/\\\\$}"`);
4333
- lines.push(" _match=\"${_match//\\`/\\\\\\`}\"");
4334
- lines.push(` _match="\${_match//\\"/\\\\\\"}"`);
4335
- lines.push(` ;;`);
4336
- lines.push(` *)`);
4337
- lines.push(` printf -v _match '%q' "$_rest"`);
4338
- lines.push(` [[ -z "$_head" && "$_match" == '~'* ]] && _match="\\\\$_match"`);
4339
- lines.push(` ;;`);
4340
- lines.push(` esac`);
4341
- lines.push(` [[ -n "$_open" && "$_match" == *"$_open" ]] && _match+="$_open"`);
4342
- lines.push(` COMPREPLY+=("$_match")`);
4343
- lines.push(` done`);
4344
- lines.push(`}`);
4345
- lines.push(``);
4346
- };
4347
- const choiceCompletion = (helperName, values) => `${helperName} "$cur" "$_comp_word" ${values.map((value) => `'${escapeForBash(value)}'`).join(" ")}`;
4348
- const flagValueCompletion = (type, helperName) => {
4349
- switch (type._tag) {
4350
- case "Boolean": return;
4351
- case "Choice": return choiceCompletion(helperName, type.values);
4352
- case "Path":
4353
- if (type.pathType === "directory") return `COMPREPLY=( $(compgen -d -- "$cur") )`;
4354
- return `COMPREPLY=( $(compgen -f -- "$cur") )`;
4355
- default: return;
4318
+ const ConfigInternalTypeId = "~effect/cli/Command/Config/Internal";
4319
+ /**
4320
+ * Parses a Command.Config into a ConfigInternal.
4321
+ *
4322
+ * Walks the config structure and:
4323
+ * 1. Extracts all Params into flat arrays (flags, arguments, orderedParams)
4324
+ * 2. Builds a tree that remembers the original nested structure
4325
+ * 3. Assigns each Param an index to link parsed values back
4326
+ *
4327
+ * @internal
4328
+ */
4329
+ const parseConfig = (config) => {
4330
+ const orderedParams = [];
4331
+ const flags = [];
4332
+ const args = [];
4333
+ function parse(config) {
4334
+ const tree = Object.create(null);
4335
+ for (const key of Object.keys(config)) tree[key] = parseValue(config[key]);
4336
+ return tree;
4356
4337
  }
4357
- };
4358
- const argCompletion = (type, helperName) => {
4359
- switch (type._tag) {
4360
- case "Choice": return choiceCompletion(helperName, type.values);
4361
- case "Path":
4362
- if (type.pathType === "directory") return `COMPREPLY=( $(compgen -d -- "$cur") )`;
4363
- return `COMPREPLY=( $(compgen -f -- "$cur") )`;
4364
- default: return;
4338
+ function parseValue(value) {
4339
+ if (Array.isArray(value)) return {
4340
+ _tag: "Array",
4341
+ children: value.map((v) => parseValue(v))
4342
+ };
4343
+ else if (isParam(value)) {
4344
+ const index = orderedParams.length;
4345
+ orderedParams.push(value);
4346
+ if (value.kind === "argument") args.push(value);
4347
+ else flags.push(value);
4348
+ return {
4349
+ _tag: "Param",
4350
+ index
4351
+ };
4352
+ } else return {
4353
+ _tag: "Nested",
4354
+ tree: parse(value)
4355
+ };
4365
4356
  }
4357
+ return {
4358
+ [ConfigInternalTypeId]: ConfigInternalTypeId,
4359
+ flags,
4360
+ arguments: args,
4361
+ orderedParams,
4362
+ tree: parse(config)
4363
+ };
4366
4364
  };
4367
- const generateFunction$1 = (descriptor, parentPath, lines, helperName) => {
4368
- const currentPath = [...parentPath, descriptor.name];
4369
- const funcName = `_${currentPath.map(sanitizeFunctionName).join("_")}`;
4370
- lines.push(`${funcName}()`);
4371
- lines.push(`{`);
4372
- lines.push(` local cur prev words cword i`);
4373
- lines.push(parentPath.length === 0 ? ` local _command_index=0` : ` local _command_index="$1"`);
4374
- lines.push(` _init_completion -n "$COMP_WORDBREAKS" || return`);
4375
- if (parentPath.length === 0) lines.push(` local _comp_word="$2"`);
4376
- lines.push(``);
4377
- const flagsWithValues = descriptor.flags.filter((f) => f.type._tag !== "Boolean");
4378
- if (flagsWithValues.length > 0) {
4379
- lines.push(` # Flag value completions`);
4380
- lines.push(` case "$prev" in`);
4381
- for (const flag of flagsWithValues) {
4382
- const longNames = [`--${flag.name}`];
4383
- for (const alias of flag.aliases) longNames.push(alias.length === 1 ? `-${alias}` : `--${alias}`);
4384
- const completion = flagValueCompletion(flag.type, helperName);
4385
- if (completion) {
4386
- lines.push(` ${longNames.join("|")})`);
4387
- lines.push(` ${completion}`);
4388
- lines.push(` return`);
4389
- lines.push(` ;;`);
4390
- }
4391
- }
4392
- lines.push(` esac`);
4393
- lines.push(``);
4394
- }
4395
- if (descriptor.subcommands.length > 0) {
4396
- lines.push(` # Subcommand dispatch`);
4397
- lines.push(` local cmd _skip_next=0`);
4398
- lines.push(` for ((i = _command_index + 1; i < cword; i++)); do`);
4399
- lines.push(` if (( _skip_next )); then`);
4400
- lines.push(` _skip_next=0`);
4401
- lines.push(` continue`);
4402
- lines.push(` fi`);
4403
- lines.push(` case "\${words[i]}" in`);
4404
- for (const flag of descriptor.flags) {
4405
- if (flag.type._tag === "Boolean") continue;
4406
- const forms = flagNamesForWordlist(flag);
4407
- lines.push(` ${forms.join("|")}) _skip_next=1 ;;`);
4408
- lines.push(` ${forms.map((form) => `${form}=*`).join("|")}) ;;`);
4409
- }
4410
- for (const sub of descriptor.subcommands) {
4411
- const subFuncName = `_${[...currentPath, sub.name].map(sanitizeFunctionName).join("_")}`;
4412
- lines.push(` ${sub.name})`);
4413
- lines.push(` ${subFuncName} "$i"`);
4414
- lines.push(` return`);
4415
- lines.push(` ;;`);
4365
+ /**
4366
+ * @internal
4367
+ */
4368
+ const emptyConfig = /*#__PURE__*/ parseConfig({});
4369
+ /**
4370
+ * Reconstructs the original nested config shape from parsed values.
4371
+ *
4372
+ * Uses the tree as a blueprint to place each parsed value back into
4373
+ * its original position in the nested structure.
4374
+ *
4375
+ * @internal
4376
+ */
4377
+ const reconstructTree = (tree, results) => {
4378
+ const output = {};
4379
+ for (const key of Object.keys(tree)) assignProperty(output, key, nodeValue(tree[key]));
4380
+ return output;
4381
+ function nodeValue(node) {
4382
+ switch (node._tag) {
4383
+ case "Param": return results[node.index];
4384
+ case "Array": return node.children.map((child) => nodeValue(child));
4385
+ case "Nested": return reconstructTree(node.tree, results);
4416
4386
  }
4417
- lines.push(` esac`);
4418
- lines.push(` done`);
4419
- lines.push(``);
4420
4387
  }
4421
- buildFlagGroupDeclarations(descriptor.flags, lines);
4422
- if (descriptor.flags.length > 0 || descriptor.subcommands.length > 0) {
4423
- lines.push(` # Complete flags (filtered) and subcommands`);
4424
- lines.push(` if [[ "$cur" == -* ]]; then`);
4425
- if (descriptor.flags.length > 0) lines.push(` COMPREPLY=( $(compgen -W "$_filtered_flags" -- "$cur") )`);
4426
- lines.push(` return`);
4427
- lines.push(` fi`);
4428
- lines.push(``);
4388
+ };
4389
+ //#endregion
4390
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/cli/internal/command.js
4391
+ /**
4392
+ * Command Implementation
4393
+ * ======================
4394
+ *
4395
+ * Internal implementation details for CLI commands.
4396
+ * Public API is in ../Command.ts
4397
+ */
4398
+ const TypeId = "~effect/cli/Command";
4399
+ /**
4400
+ * Casts a Command to its internal implementation.
4401
+ * For use by internal modules that need access to config, parse, handle, etc.
4402
+ */
4403
+ const toImpl = (self) => self;
4404
+ const Proto = { .../*#__PURE__*/ Prototype({
4405
+ label: "Command",
4406
+ evaluate() {
4407
+ return toImpl(this).service;
4429
4408
  }
4430
- const argsWithCompletions = descriptor.arguments.flatMap((argument, index) => {
4431
- const completion = argCompletion(argument.type, helperName);
4432
- return completion === void 0 ? [] : [{
4433
- argument,
4434
- completion,
4435
- index
4436
- }];
4437
- });
4438
- if (argsWithCompletions.length > 0) {
4439
- lines.push(` # Positional argument completions`);
4440
- lines.push(` local _position=0 _skip_next=0 _end_of_options=0`);
4441
- lines.push(` for ((i = _command_index + 1; i < cword; i++)); do`);
4442
- lines.push(` if (( _skip_next )); then`);
4443
- lines.push(` _skip_next=0`);
4444
- lines.push(` continue`);
4445
- lines.push(` fi`);
4446
- lines.push(` if (( _end_of_options )); then`);
4447
- lines.push(` ((_position += 1))`);
4448
- lines.push(` continue`);
4449
- lines.push(` fi`);
4450
- lines.push(` case "\${words[i]}" in`);
4451
- lines.push(` --) _end_of_options=1 ;;`);
4452
- for (const flag of descriptor.flags) {
4453
- const forms = flagNamesForWordlist(flag);
4454
- if (flag.type._tag === "Boolean") lines.push(` ${forms.join("|")}) ;;`);
4455
- else {
4456
- lines.push(` ${forms.join("|")}) _skip_next=1 ;;`);
4457
- lines.push(` ${forms.map((form) => `${form}=*`).join("|")}) ;;`);
4458
- }
4409
+ }) };
4410
+ /**
4411
+ * Internal command constructor. Only accepts already-parsed ConfigInternal.
4412
+ */
4413
+ const makeCommand = (options) => {
4414
+ const config = options.config;
4415
+ const contextConfig = options.contextConfig ?? emptyConfig;
4416
+ const service = options.service ?? Service(`~effect/cli/Command/${options.name}`);
4417
+ const annotations = options.annotations ?? empty$1();
4418
+ const globalFlags = options.globalFlags ?? [];
4419
+ const subcommands = options.subcommands ?? [];
4420
+ const handle = (input, commandPath) => isNotUndefined(options.handle) ? options.handle(input, commandPath) : fail$1(new ShowHelp({
4421
+ commandPath,
4422
+ errors: []
4423
+ }));
4424
+ const parse = options.parse ?? makeParser(config);
4425
+ const parseContext = options.parseContext ?? makeParser(contextConfig, { allowLeftovers: true });
4426
+ const buildHelpDoc = (commandPath) => {
4427
+ const args = [];
4428
+ const flags = [];
4429
+ for (const arg of config.arguments) {
4430
+ const singles = extractSingleParams(arg);
4431
+ const metadata = getParamMetadata(arg);
4432
+ for (const single of singles) args.push({
4433
+ name: single.name,
4434
+ type: single.typeName ?? getTypeName(single.primitiveType),
4435
+ description: single.description,
4436
+ required: !metadata.isOptional && (!metadata.isVariadic || exists(metadata.variadicMin, (min) => min > 0)),
4437
+ variadic: metadata.isVariadic
4438
+ });
4459
4439
  }
4460
- lines.push(` -*) ;;`);
4461
- lines.push(` *) ((_position += 1)) ;;`);
4462
- lines.push(` esac`);
4463
- lines.push(` done`);
4464
- lines.push(` case "$_position" in`);
4465
- for (const { argument, completion, index } of argsWithCompletions) {
4466
- if (argument.variadic) continue;
4467
- lines.push(` ${index})`);
4468
- lines.push(` ${completion}`);
4469
- lines.push(` return`);
4470
- lines.push(` ;;`);
4440
+ let usage = commandPath.length > 0 ? commandPath.join(" ") : options.name;
4441
+ if (subcommands.some((group) => group.commands.some((c) => !c.unlisted))) usage += " <subcommand>";
4442
+ usage += " [flags]";
4443
+ for (const arg of args) {
4444
+ const argName = arg.variadic ? `<${arg.name}...>` : `<${arg.name}>`;
4445
+ usage += ` ${arg.required ? argName : `[${argName}]`}`;
4471
4446
  }
4472
- lines.push(` esac`);
4473
- const variadic = argsWithCompletions.find(({ argument }) => argument.variadic);
4474
- if (variadic !== void 0) {
4475
- lines.push(` if (( _position >= ${variadic.index} )); then`);
4476
- lines.push(` ${variadic.completion}`);
4477
- lines.push(` return`);
4478
- lines.push(` fi`);
4447
+ for (const option of config.flags) {
4448
+ const singles = extractSingleParams(option);
4449
+ const metadata = getParamMetadata(option);
4450
+ for (const single of singles) {
4451
+ if (single.hidden) continue;
4452
+ flags.push(toFlagDoc(single, metadata));
4453
+ }
4479
4454
  }
4480
- } else if (descriptor.subcommands.length > 0) {
4481
- const subNames = descriptor.subcommands.map((s) => s.name);
4482
- lines.push(` COMPREPLY=( $(compgen -W '${subNames.join(" ")}' -- "$cur") )`);
4483
- }
4484
- lines.push(`}`);
4485
- lines.push(``);
4486
- for (const sub of descriptor.subcommands) generateFunction$1(sub, currentPath, lines, helperName);
4455
+ const subcommandDocs = [];
4456
+ for (const group of subcommands) {
4457
+ const visible = group.commands.filter((c) => !c.unlisted);
4458
+ if (visible.length === 0) continue;
4459
+ subcommandDocs.push({
4460
+ group: group.group,
4461
+ commands: map$4(visible, (subcommand) => ({
4462
+ name: subcommand.name,
4463
+ alias: subcommand.alias,
4464
+ shortDescription: subcommand.shortDescription,
4465
+ description: subcommand.description ?? ""
4466
+ }))
4467
+ });
4468
+ }
4469
+ const examples = options.examples ?? [];
4470
+ return {
4471
+ description: options.description ?? "",
4472
+ usage,
4473
+ flags,
4474
+ annotations,
4475
+ ...args.length > 0 && { args },
4476
+ ...subcommandDocs.length > 0 && { subcommands: subcommandDocs },
4477
+ ...examples.length > 0 && { examples }
4478
+ };
4479
+ };
4480
+ return Object.assign(Object.create(Proto), {
4481
+ [TypeId]: TypeId,
4482
+ name: options.name,
4483
+ examples: options.examples ?? [],
4484
+ annotations,
4485
+ globalFlags,
4486
+ subcommands,
4487
+ unlisted: options.unlisted ?? false,
4488
+ config,
4489
+ contextConfig,
4490
+ service,
4491
+ parse,
4492
+ parseContext,
4493
+ handle,
4494
+ buildHelpDoc,
4495
+ ...isNotUndefined(options.description) ? { description: options.description } : {},
4496
+ ...isNotUndefined(options.shortDescription) ? { shortDescription: options.shortDescription } : {},
4497
+ ...isNotUndefined(options.alias) ? { alias: options.alias } : {}
4498
+ });
4487
4499
  };
4488
4500
  /**
4501
+ * Converts a single flag param into a FlagDoc for help display.
4502
+ *
4489
4503
  * @internal
4490
4504
  */
4491
- const generate$4 = (executableName, descriptor) => {
4492
- const lines = [];
4493
- const safeName = sanitizeFunctionName(executableName);
4494
- const helperName = `_${safeName}--choices`;
4495
- lines.push(`###-begin-${escapeForBash(executableName)}-completions-###`);
4496
- lines.push(`#`);
4497
- lines.push(`# Static completion script for Bash`);
4498
- lines.push(`#`);
4499
- lines.push(`# Installation:`);
4500
- lines.push(`# ${escapeForBash(executableName)} --completions bash >> ~/.bashrc`);
4501
- lines.push(`#`);
4502
- lines.push(``);
4503
- lines.push(`if ! type _init_completion &>/dev/null; then`);
4504
- lines.push(` _init_completion()`);
4505
- lines.push(` {`);
4506
- lines.push(` COMPREPLY=()`);
4507
- lines.push(` local _i _j=0 _piece _line="$COMP_LINE"`);
4508
- lines.push(` words=("\${COMP_WORDS[0]}")`);
4509
- lines.push(` cword=0`);
4510
- lines.push(` _line="\${_line#*"\${COMP_WORDS[0]}"}"`);
4511
- lines.push(` for ((_i = 1; _i < \${#COMP_WORDS[@]}; _i++)); do`);
4512
- lines.push(` _piece="\${COMP_WORDS[_i]}"`);
4513
- lines.push(` if [[ "$_line" == [[:blank:]]* ]]; then`);
4514
- lines.push(` ((_j++))`);
4515
- lines.push(` words[_j]="$_piece"`);
4516
- lines.push(` else`);
4517
- lines.push(` words[_j]="\${words[_j]}$_piece"`);
4518
- lines.push(` fi`);
4519
- lines.push(` ((_i == COMP_CWORD)) && cword=$_j`);
4520
- lines.push(` _line="\${_line#*"$_piece"}"`);
4521
- lines.push(` done`);
4522
- lines.push(` cur="\${words[cword]}"`);
4523
- lines.push(` prev=""`);
4524
- lines.push(` ((cword > 0)) && prev="\${words[cword-1]}"`);
4525
- lines.push(` return 0`);
4526
- lines.push(` }`);
4527
- lines.push(`fi`);
4528
- lines.push(``);
4529
- choicesHelper(helperName, lines);
4530
- generateFunction$1(descriptor, [], lines, helperName);
4531
- lines.push(`complete -F _${safeName} ${escapeForBash(executableName)}`);
4532
- lines.push(`###-end-${escapeForBash(executableName)}-completions-###`);
4533
- return lines.join("\n");
4505
+ const toFlagDoc = (single, metadata) => {
4506
+ const formattedAliases = single.aliases.map((alias) => alias.length === 1 ? `-${alias}` : `--${alias}`);
4507
+ const type = single.typeName ?? getTypeName(single.primitiveType);
4508
+ return {
4509
+ name: single.name,
4510
+ aliases: formattedAliases,
4511
+ type: single.optionalValue === void 0 ? type : `[=${type}]`,
4512
+ description: appendChoiceKeys(single.description, getChoiceKeys(single.primitiveType)),
4513
+ required: single.primitiveType._tag !== "Boolean" && !metadata.isOptional
4514
+ };
4534
4515
  };
4535
- //#endregion
4536
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/cli/internal/completions/fish.js
4537
- const escapeFishString = (s) => s.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
4538
- /** Escape choices for Fish's second expansion of `complete -a`. */
4539
- const escapeFishChoice = (s) => escapeFishString(s.replace(/[^A-Za-z0-9_.,/@%+-]/gu, "\\$&"));
4540
- /**
4541
- * Build a Fish condition that checks the current subcommand context.
4542
- *
4543
- * For root-level completions with subcommands: `__fish_use_subcommand`
4544
- * For nested commands: verify the full parent path is active AND none of its
4545
- * child subcommands have been entered yet.
4546
- */
4547
- const subcommandCondition = (parentPath, childSubcommandNames) => {
4548
- if (parentPath.length === 0) {
4549
- if (childSubcommandNames.length > 0) return `__fish_use_subcommand`;
4550
- return ``;
4551
- }
4552
- const parentCondition = parentPath.map((parent) => `__fish_seen_subcommand_from ${parent}`).join("; and ");
4553
- if (childSubcommandNames.length > 0) return `${parentCondition}; and not __fish_seen_subcommand_from ${childSubcommandNames.join(" ")}`;
4554
- return parentCondition;
4516
+ const appendChoiceKeys = (description, choiceKeys) => {
4517
+ if (choiceKeys === void 0 || choiceKeys.length === 0) return description;
4518
+ const choiceSuffix = `(choices: ${choiceKeys.join(", ")})`;
4519
+ return match$1(description, {
4520
+ onNone: () => some(choiceSuffix),
4521
+ onSome: (value) => some(`${value} ${choiceSuffix}`)
4522
+ });
4555
4523
  };
4556
4524
  /**
4557
- * Build a __fish_contains_opt condition that checks whether any form of this
4558
- * flag has already been typed. Returns the condition string without wrapping
4559
- * quotes (the caller adds those).
4525
+ * Creates a parser for a given config. Used as the default for both `parse`
4526
+ * and `parseContext`, and also by `withSharedFlags` to avoid constructing a
4527
+ * full throwaway command.
4560
4528
  */
4561
- const flagContainsOptCondition = (flag) => {
4562
- const optArgs = [];
4563
- for (const alias of flag.aliases) if (alias.length === 1) optArgs.push(`-s ${alias}`);
4564
- optArgs.push(flag.name);
4565
- for (const alias of flag.aliases) if (alias.length > 1) optArgs.push(alias);
4566
- if (flag.type._tag === "Boolean") optArgs.push(`no-${flag.name}`);
4567
- return `not __fish_contains_opt ${optArgs.join(" ")}`;
4568
- };
4569
- /** Hide used value flags without suppressing their value completions. */
4570
- const valueFlagDedupCondition = (flag) => {
4571
- const forms = [`--${flag.name}`];
4572
- for (const alias of flag.aliases) forms.push(alias.length === 1 ? `-${alias}` : `--${alias}`);
4573
- return `begin; ${flagContainsOptCondition(flag)}; or contains -- (commandline -poc)[-1] ${forms.join(" ")}; end`;
4574
- };
4575
- const flagCompletionArgs = (flag) => {
4576
- const args = [`-l ${flag.name}`];
4577
- for (const alias of flag.aliases) if (alias.length === 1) args.push(`-s ${alias}`);
4578
- else args.push(`-l ${alias}`);
4579
- if (flag.description) args.push(`-d '${escapeFishString(flag.description)}'`);
4580
- const valueArgs = flagValueArgs(flag.type);
4581
- if (valueArgs) args.push(valueArgs);
4582
- return args;
4583
- };
4584
- const flagValueArgs = (type) => {
4585
- switch (type._tag) {
4586
- case "Boolean": return;
4587
- case "Choice": return `-r -f -a '${type.values.map(escapeFishChoice).join(" ")}'`;
4588
- case "Path":
4589
- if (type.pathType === "directory") return `-r -F`;
4590
- return `-r -F`;
4591
- default: return `-r -f`;
4529
+ const makeParser = (cfg, options) => fnUntraced(function* (input) {
4530
+ const parsedArgs = {
4531
+ flags: input.flags,
4532
+ arguments: input.arguments
4533
+ };
4534
+ const [remainingArguments, values] = yield* parseParams(parsedArgs, cfg.orderedParams);
4535
+ if (options?.allowLeftovers !== true && remainingArguments.length > 0) return yield* new UnexpectedArgument({ arguments: remainingArguments });
4536
+ return reconstructTree(cfg.tree, values);
4537
+ });
4538
+ /**
4539
+ * Parses param values from parsed command arguments into their typed
4540
+ * representations.
4541
+ */
4542
+ const parseParams = /*#__PURE__*/ fnUntraced(function* (parsedArgs, params) {
4543
+ const results = [];
4544
+ let currentArguments = parsedArgs.arguments;
4545
+ for (const option of params) {
4546
+ const [remainingArguments, parsed] = yield* option.parse({
4547
+ flags: parsedArgs.flags,
4548
+ arguments: currentArguments
4549
+ });
4550
+ results.push(parsed);
4551
+ currentArguments = remainingArguments;
4592
4552
  }
4593
- };
4594
- const argValueArgs = (type) => {
4595
- switch (type._tag) {
4596
- case "Choice": return `-r -f -a '${type.values.map(escapeFishChoice).join(" ")}'`;
4597
- case "Path": return `-r -F`;
4598
- default: return;
4553
+ return [currentArguments, results];
4554
+ });
4555
+ /**
4556
+ * Checks that inherited parent context flags do not reuse names declared by
4557
+ * child command flags.
4558
+ *
4559
+ * When `contextConfig` is supplied, it is used as the inherited flag set;
4560
+ * otherwise the parent's current context config is checked.
4561
+ */
4562
+ const checkForDuplicateFlags = (parent, subcommands, options) => {
4563
+ const parentImpl = toImpl(parent);
4564
+ const parentOptionNames = /* @__PURE__ */ new Set();
4565
+ const extractNames = (flags) => {
4566
+ for (const option of flags) {
4567
+ const singles = extractSingleParams(option);
4568
+ for (const single of singles) parentOptionNames.add(single.name);
4569
+ }
4570
+ };
4571
+ extractNames((options?.contextConfig ?? parentImpl.contextConfig).flags);
4572
+ for (const subcommand of subcommands) {
4573
+ const subImpl = toImpl(subcommand);
4574
+ for (const option of subImpl.config.flags) {
4575
+ const singles = extractSingleParams(option);
4576
+ for (const single of singles) if (parentOptionNames.has(single.name)) throw new DuplicateOption({
4577
+ option: single.name,
4578
+ parentCommand: parent.name,
4579
+ childCommand: subcommand.name
4580
+ });
4581
+ }
4599
4582
  }
4600
4583
  };
4601
- const generateCompletions = (executableName, descriptor, parentPath, lines) => {
4602
- const allSubNames = descriptor.subcommands.map((s) => s.name);
4603
- const condition = subcommandCondition(parentPath, allSubNames);
4604
- const conditionArg = condition ? `-n '${condition}'` : ``;
4605
- if (!descriptor.arguments.some((a) => a.type._tag === "Path")) {
4606
- const parts = [`complete -c ${executableName}`];
4607
- if (conditionArg) parts.push(conditionArg);
4608
- parts.push(`-f`);
4609
- lines.push(parts.join(" "));
4584
+ //#endregion
4585
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/cli/internal/completions/descriptor.js
4586
+ /**
4587
+ * CommandDescriptor — pure-data representation of a command tree for
4588
+ * shell completion generation.
4589
+ *
4590
+ * @internal
4591
+ */
4592
+ const toFlagType = (single) => {
4593
+ switch (single.primitiveType._tag) {
4594
+ case "Boolean": return { _tag: "Boolean" };
4595
+ case "Int": return { _tag: "Int" };
4596
+ case "Finite": return { _tag: "Finite" };
4597
+ case "Date": return { _tag: "Date" };
4598
+ case "Choice": return {
4599
+ _tag: "Choice",
4600
+ values: getChoiceKeys(single.primitiveType) ?? []
4601
+ };
4602
+ case "Path": return {
4603
+ _tag: "Path",
4604
+ pathType: getPathType(single.primitiveType) ?? "either"
4605
+ };
4606
+ case "FileText":
4607
+ case "FileParse":
4608
+ case "FileSchema": return {
4609
+ _tag: "Path",
4610
+ pathType: "file"
4611
+ };
4612
+ default: return { _tag: "String" };
4610
4613
  }
4611
- for (const sub of descriptor.subcommands) {
4612
- const parts = [`complete -c ${executableName}`];
4613
- if (conditionArg) parts.push(conditionArg);
4614
- parts.push(`-f -a '${escapeFishString(sub.name)}'`);
4615
- if (sub.description) parts.push(`-d '${escapeFishString(sub.description)}'`);
4616
- lines.push(parts.join(" "));
4614
+ };
4615
+ const toArgumentType = (single) => {
4616
+ switch (single.primitiveType._tag) {
4617
+ case "Int": return { _tag: "Int" };
4618
+ case "Finite": return { _tag: "Finite" };
4619
+ case "Date": return { _tag: "Date" };
4620
+ case "Choice": return {
4621
+ _tag: "Choice",
4622
+ values: getChoiceKeys(single.primitiveType) ?? []
4623
+ };
4624
+ case "Path": return {
4625
+ _tag: "Path",
4626
+ pathType: getPathType(single.primitiveType) ?? "either"
4627
+ };
4628
+ case "FileText":
4629
+ case "FileParse":
4630
+ case "FileSchema": return {
4631
+ _tag: "Path",
4632
+ pathType: "file"
4633
+ };
4634
+ default: return { _tag: "String" };
4617
4635
  }
4618
- for (const flag of descriptor.flags) {
4619
- const isBoolean = flag.type._tag === "Boolean";
4620
- const dedup = isBoolean ? flagContainsOptCondition(flag) : valueFlagDedupCondition(flag);
4621
- const flagCondition = condition ? `${condition}; and ${dedup}` : dedup;
4622
- const flagCondArg = flagCondition ? `-n '${flagCondition}'` : ``;
4623
- const parts = [`complete -c ${executableName}`];
4624
- if (flagCondArg) parts.push(flagCondArg);
4625
- parts.push(...flagCompletionArgs(flag));
4626
- lines.push(parts.join(" "));
4627
- if (isBoolean) {
4628
- const negParts = [`complete -c ${executableName}`];
4629
- if (flagCondArg) negParts.push(flagCondArg);
4630
- negParts.push(`-l no-${flag.name}`);
4631
- if (flag.description) negParts.push(`-d '${escapeFishString(`Disable ${flag.name}`)}'`);
4632
- lines.push(negParts.join(" "));
4636
+ };
4637
+ /**
4638
+ * @internal
4639
+ */
4640
+ const fromCommand = (cmd, inheritedFlags = []) => {
4641
+ const impl = toImpl(cmd);
4642
+ const config = impl.config;
4643
+ const flags = [];
4644
+ const seen = /* @__PURE__ */ new Set();
4645
+ for (const [index, flag] of [...config.flags, ...inheritedFlags].entries()) {
4646
+ const singles = extractSingleParams(flag);
4647
+ for (const single of singles) {
4648
+ if (single.kind !== "flag") continue;
4649
+ if (single.hidden) continue;
4650
+ if (index >= config.flags.length && seen.has(single.name)) continue;
4651
+ seen.add(single.name);
4652
+ flags.push({
4653
+ name: single.name,
4654
+ aliases: single.aliases,
4655
+ description: getOrUndefined(single.description),
4656
+ type: toFlagType(single),
4657
+ optionalValue: single.optionalValue !== void 0
4658
+ });
4633
4659
  }
4634
4660
  }
4635
- if (descriptor.flags.length > 0) {
4636
- const notDash = `not string match -q -- "-*" (commandline -ct)`;
4637
- const bareBase = condition ? `${condition}; and ${notDash}` : notDash;
4638
- for (const flag of descriptor.flags) {
4639
- const bareCondition = `${bareBase}; and ${flagContainsOptCondition(flag)}`;
4640
- const isBoolean = flag.type._tag === "Boolean";
4641
- const parts = [`complete -c ${executableName}`];
4642
- parts.push(`-n '${bareCondition}'`);
4643
- parts.push(`-f -a '--${flag.name}'`);
4644
- if (flag.description) parts.push(`-d '${escapeFishString(flag.description)}'`);
4645
- lines.push(parts.join(" "));
4646
- if (isBoolean) {
4647
- const negParts = [`complete -c ${executableName}`];
4648
- negParts.push(`-n '${bareCondition}'`);
4649
- negParts.push(`-f -a '--no-${flag.name}'`);
4650
- if (flag.description) negParts.push(`-d '${escapeFishString(`Disable ${flag.name}`)}'`);
4651
- lines.push(negParts.join(" "));
4652
- }
4661
+ const args = [];
4662
+ for (const arg of config.arguments) {
4663
+ const singles = extractSingleParams(arg);
4664
+ const metadata = getParamMetadata(arg);
4665
+ for (const single of singles) {
4666
+ if (single.kind !== "argument") continue;
4667
+ args.push({
4668
+ name: single.name,
4669
+ description: getOrUndefined(single.description),
4670
+ required: !metadata.isOptional,
4671
+ variadic: metadata.isVariadic,
4672
+ type: toArgumentType(single)
4673
+ });
4653
4674
  }
4654
4675
  }
4655
- for (const arg of descriptor.arguments) {
4656
- const valueArg = argValueArgs(arg.type);
4657
- if (valueArg) {
4658
- const parts = [`complete -c ${executableName}`];
4659
- if (conditionArg) parts.push(conditionArg);
4660
- parts.push(valueArg);
4661
- if (arg.description) parts.push(`-d '${escapeFishString(arg.description)}'`);
4662
- lines.push(parts.join(" "));
4663
- }
4676
+ const subcommands = [];
4677
+ const sharedFlags = [...inheritedFlags, ...impl.contextConfig.flags];
4678
+ for (const group of cmd.subcommands) for (const subcommand of group.commands) {
4679
+ if (subcommand.unlisted) continue;
4680
+ const descriptor = fromCommand(subcommand, sharedFlags);
4681
+ subcommands.push(descriptor);
4682
+ if (subcommand.alias && subcommand.alias !== subcommand.name) subcommands.push({
4683
+ ...descriptor,
4684
+ name: subcommand.alias
4685
+ });
4664
4686
  }
4665
- for (const sub of descriptor.subcommands) generateCompletions(executableName, sub, [...parentPath, sub.name], lines);
4687
+ return {
4688
+ name: cmd.name,
4689
+ description: cmd.shortDescription ?? cmd.description,
4690
+ flags,
4691
+ arguments: args,
4692
+ subcommands
4693
+ };
4666
4694
  };
4667
4695
  /**
4696
+ * Whether the flag reads its value from the next word.
4697
+ *
4668
4698
  * @internal
4669
4699
  */
4670
- const generate$3 = (executableName, descriptor) => {
4671
- const lines = [];
4672
- lines.push(`###-begin-${executableName}-completions-###`);
4673
- lines.push(`#`);
4674
- lines.push(`# Static completion script for Fish`);
4675
- lines.push(`#`);
4676
- lines.push(`# Installation:`);
4677
- lines.push(`# ${executableName} --completions fish > ~/.config/fish/completions/${executableName}.fish`);
4678
- lines.push(`#`);
4679
- lines.push(``);
4680
- generateCompletions(executableName, descriptor, [], lines);
4681
- lines.push(``);
4682
- lines.push(`###-end-${executableName}-completions-###`);
4683
- return lines.join("\n");
4684
- };
4700
+ const takesSeparateValue = (flag) => flag.type._tag !== "Boolean" && flag.optionalValue !== true;
4685
4701
  //#endregion
4686
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/cli/internal/completions/powershell.js
4687
- /**
4688
- * Encode non-ASCII and control characters as `[char]` code units. Windows
4689
- * PowerShell 5.1 can misread BOM-less UTF-8 as ANSI, turning some bytes into
4690
- * PowerShell quote delimiters.
4702
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/cli/internal/completions/bash.js
4703
+ const escapeForBash = (s) => s.replace(/'/g, "'\\''");
4704
+ const sanitizeFunctionName = (s) => s.replace(/[^a-zA-Z0-9_]/g, "_");
4705
+ const flagNamesForWordlist = (flag) => {
4706
+ const names = [`--${flag.name}`];
4707
+ for (const alias of flag.aliases) names.push(alias.length === 1 ? `-${alias}` : `--${alias}`);
4708
+ if (flag.type._tag === "Boolean") names.push(`--no-${flag.name}`);
4709
+ return names;
4710
+ };
4711
+ /** Emit a Bash 3.2-compatible used-flag filter. */
4712
+ const buildFlagGroupDeclarations = (flags, lines) => {
4713
+ if (flags.length === 0) return;
4714
+ const groups = flags.map(flagNamesForWordlist);
4715
+ lines.push(` local ${groups.map((_, index) => `_used_${index}=""`).join(" ")}`);
4716
+ lines.push(` for ((i = 1; i < cword; i++)); do`);
4717
+ lines.push(` case "\${words[i]%%=*}" in`);
4718
+ groups.forEach((forms, index) => {
4719
+ lines.push(` ${forms.join("|")}) _used_${index}=1 ;;`);
4720
+ });
4721
+ lines.push(` esac`);
4722
+ lines.push(` done`);
4723
+ lines.push(` local _filtered_flags=""`);
4724
+ groups.forEach((forms, index) => {
4725
+ lines.push(` [[ -n "$_used_${index}" ]] || _filtered_flags+=" ${forms.join(" ")}"`);
4726
+ });
4727
+ lines.push(``);
4728
+ };
4729
+ /**
4730
+ * Complete choices without `compgen -W`, which reparses quoted values. Escape
4731
+ * only the portion readline replaces for the active quote context.
4732
+ *
4733
+ * `!` cannot be escaped inside a user-opened double quote without changing the
4734
+ * resulting argument.
4691
4735
  */
4692
- const quotePs = (s) => {
4693
- const parts = [];
4694
- let literal = "";
4695
- for (let i = 0; i < s.length; i++) {
4696
- const code = s.charCodeAt(i);
4697
- if (code >= 32 && code < 128) {
4698
- literal += s[i] === "'" ? "''" : s[i];
4699
- continue;
4700
- }
4701
- if (literal !== "" || parts.length === 0) parts.push(`'${literal}'`);
4702
- literal = "";
4703
- parts.push(`[char]0x${code.toString(16).toUpperCase().padStart(4, "0")}`);
4736
+ const choicesHelper = (helperName, lines) => {
4737
+ lines.push(`${helperName}()`);
4738
+ lines.push(`{`);
4739
+ lines.push(` local _cur="$1" _word="$2"; shift 2`);
4740
+ lines.push(``);
4741
+ lines.push(` local _head="\${_cur%"$_word"}"`);
4742
+ lines.push(` local _open=""`);
4743
+ lines.push(` case "$_head" in`);
4744
+ lines.push(` *\\') _open="'" ;;`);
4745
+ lines.push(` *\\") _open='"' ;;`);
4746
+ lines.push(` esac`);
4747
+ lines.push(``);
4748
+ lines.push(` local _prefix="$_cur" _committed="$_head"`);
4749
+ lines.push(` _prefix=\${_prefix//\\\\/}; _prefix=\${_prefix//\\"/}; _prefix=\${_prefix//\\'/}`);
4750
+ lines.push(` _committed=\${_committed//\\\\/}; _committed=\${_committed//\\"/}; _committed=\${_committed//\\'/}`);
4751
+ lines.push(``);
4752
+ lines.push(` COMPREPLY=()`);
4753
+ lines.push(` local _choice _rest _match`);
4754
+ lines.push(` for _choice in "$@"; do`);
4755
+ lines.push(` [[ "$_choice" == "$_prefix"* ]] || continue`);
4756
+ lines.push(` _rest="\${_choice#"$_committed"}"`);
4757
+ lines.push(` case "$_open" in`);
4758
+ lines.push(` "'")`);
4759
+ lines.push(` if [[ "$_head" == "'" ]]; then`);
4760
+ lines.push(` _match=\${_rest//\\'/\\'\\\\\\'\\'}`);
4761
+ lines.push(` else`);
4762
+ lines.push(` [[ "$_rest" == *\\'* ]] && continue`);
4763
+ lines.push(` _match="$_rest"`);
4764
+ lines.push(` fi`);
4765
+ lines.push(` ;;`);
4766
+ lines.push(` '"')`);
4767
+ lines.push(` _match="\${_rest//\\\\/\\\\\\\\}"`);
4768
+ lines.push(` _match="\${_match//\\$/\\\\$}"`);
4769
+ lines.push(" _match=\"${_match//\\`/\\\\\\`}\"");
4770
+ lines.push(` _match="\${_match//\\"/\\\\\\"}"`);
4771
+ lines.push(` ;;`);
4772
+ lines.push(` *)`);
4773
+ lines.push(` printf -v _match '%q' "$_rest"`);
4774
+ lines.push(` [[ -z "$_head" && "$_match" == '~'* ]] && _match="\\\\$_match"`);
4775
+ lines.push(` ;;`);
4776
+ lines.push(` esac`);
4777
+ lines.push(` [[ -n "$_open" && "$_match" == *"$_open" ]] && _match+="$_open"`);
4778
+ lines.push(` COMPREPLY+=("$_match")`);
4779
+ lines.push(` done`);
4780
+ lines.push(`}`);
4781
+ lines.push(``);
4782
+ };
4783
+ const choiceCompletion = (helperName, values) => `${helperName} "$cur" "$_comp_word" ${values.map((value) => `'${escapeForBash(value)}'`).join(" ")}`;
4784
+ const flagValueCompletion = (type, helperName) => {
4785
+ switch (type._tag) {
4786
+ case "Boolean": return;
4787
+ case "Choice": return choiceCompletion(helperName, type.values);
4788
+ case "Path":
4789
+ if (type.pathType === "directory") return `COMPREPLY=( $(compgen -d -- "$cur") )`;
4790
+ return `COMPREPLY=( $(compgen -f -- "$cur") )`;
4791
+ default: return;
4704
4792
  }
4705
- if (literal !== "" || parts.length === 0) parts.push(`'${literal}'`);
4706
- return parts.length === 1 ? parts[0] : `(${parts.join(" + ")})`;
4707
4793
  };
4708
- const psArray = (items) => `@(${items.map(quotePs).join(", ")})`;
4709
- const psOptional = (s) => s ? quotePs(s) : "$null";
4710
- const sanitize$1 = (s) => s.replace(/[^a-zA-Z0-9_]/g, "_");
4711
- const flagForms = (flag) => [`--${flag.name}`, ...flag.aliases.map((alias) => alias.length === 1 ? `-${alias}` : `--${alias}`)];
4712
- const valueFields = (type) => `values = ${psArray(type._tag === "Choice" ? type.values : [])}; pathType = ${type._tag === "Path" ? quotePs(type.pathType) : "$null"}`;
4713
- const flagEntry = (flag) => `@{ name = ${quotePs(flag.name)}; forms = ${psArray(flagForms(flag))}; takesValue = $${flag.type._tag !== "Boolean"}; ${valueFields(flag.type)}; description = ${psOptional(flag.description)} }`;
4714
- const argumentEntry = (argument) => `@{ name = ${quotePs(argument.name)}; variadic = $${argument.variadic}; ${valueFields(argument.type)}; description = ${psOptional(argument.description)} }`;
4715
- const pushList = (lines, field, entries) => {
4716
- if (entries.length === 0) {
4717
- lines.push(` ${field} = @()`);
4718
- return;
4794
+ const argCompletion = (type, helperName) => {
4795
+ switch (type._tag) {
4796
+ case "Choice": return choiceCompletion(helperName, type.values);
4797
+ case "Path":
4798
+ if (type.pathType === "directory") return `COMPREPLY=( $(compgen -d -- "$cur") )`;
4799
+ return `COMPREPLY=( $(compgen -f -- "$cur") )`;
4800
+ default: return;
4719
4801
  }
4720
- lines.push(` ${field} = @(`);
4721
- for (const entry of entries) lines.push(` ${entry}`);
4722
- lines.push(` )`);
4723
4802
  };
4724
- /**
4725
- * Emit one context per subcommand path. Subcommands are case-sensitive, so
4726
- * contexts go in an ordinal hashtable instead of a hash literal, whose keys
4727
- * ignore case.
4728
- */
4729
- const generateContexts = (dataName, descriptor, path, lines, seen) => {
4730
- const key = path.join(" ");
4731
- if (seen.has(key)) return;
4732
- seen.add(key);
4733
- lines.push(`${dataName}[${quotePs(key)}] = @{`);
4734
- pushList(lines, "subcommands", descriptor.subcommands.map((sub) => `@{ name = ${quotePs(sub.name)}; description = ${psOptional(sub.description)} }`));
4735
- pushList(lines, "flags", descriptor.flags.map(flagEntry));
4736
- pushList(lines, "arguments", descriptor.arguments.map(argumentEntry));
4803
+ const generateFunction$1 = (descriptor, parentPath, lines, helperName) => {
4804
+ const currentPath = [...parentPath, descriptor.name];
4805
+ const funcName = `_${currentPath.map(sanitizeFunctionName).join("_")}`;
4806
+ lines.push(`${funcName}()`);
4807
+ lines.push(`{`);
4808
+ lines.push(` local cur prev words cword i`);
4809
+ lines.push(parentPath.length === 0 ? ` local _command_index=0` : ` local _command_index="$1"`);
4810
+ lines.push(` _init_completion -n "$COMP_WORDBREAKS" || return`);
4811
+ if (parentPath.length === 0) lines.push(` local _comp_word="$2"`);
4812
+ lines.push(``);
4813
+ const flagsWithValues = descriptor.flags.filter(takesSeparateValue);
4814
+ if (flagsWithValues.length > 0) {
4815
+ lines.push(` # Flag value completions`);
4816
+ lines.push(` case "$prev" in`);
4817
+ for (const flag of flagsWithValues) {
4818
+ const longNames = [`--${flag.name}`];
4819
+ for (const alias of flag.aliases) longNames.push(alias.length === 1 ? `-${alias}` : `--${alias}`);
4820
+ const completion = flagValueCompletion(flag.type, helperName);
4821
+ if (completion) {
4822
+ lines.push(` ${longNames.join("|")})`);
4823
+ lines.push(` ${completion}`);
4824
+ lines.push(` return`);
4825
+ lines.push(` ;;`);
4826
+ }
4827
+ }
4828
+ lines.push(` esac`);
4829
+ lines.push(``);
4830
+ }
4831
+ if (descriptor.subcommands.length > 0) {
4832
+ lines.push(` # Subcommand dispatch`);
4833
+ lines.push(` local cmd _skip_next=0`);
4834
+ lines.push(` for ((i = _command_index + 1; i < cword; i++)); do`);
4835
+ lines.push(` if (( _skip_next )); then`);
4836
+ lines.push(` _skip_next=0`);
4837
+ lines.push(` continue`);
4838
+ lines.push(` fi`);
4839
+ lines.push(` case "\${words[i]}" in`);
4840
+ for (const flag of descriptor.flags) {
4841
+ if (!takesSeparateValue(flag)) continue;
4842
+ const forms = flagNamesForWordlist(flag);
4843
+ lines.push(` ${forms.join("|")}) _skip_next=1 ;;`);
4844
+ lines.push(` ${forms.map((form) => `${form}=*`).join("|")}) ;;`);
4845
+ }
4846
+ for (const sub of descriptor.subcommands) {
4847
+ const subFuncName = `_${[...currentPath, sub.name].map(sanitizeFunctionName).join("_")}`;
4848
+ lines.push(` ${sub.name})`);
4849
+ lines.push(` ${subFuncName} "$i"`);
4850
+ lines.push(` return`);
4851
+ lines.push(` ;;`);
4852
+ }
4853
+ lines.push(` esac`);
4854
+ lines.push(` done`);
4855
+ lines.push(``);
4856
+ }
4857
+ buildFlagGroupDeclarations(descriptor.flags, lines);
4858
+ if (descriptor.flags.length > 0 || descriptor.subcommands.length > 0) {
4859
+ lines.push(` # Complete flags (filtered) and subcommands`);
4860
+ lines.push(` if [[ "$cur" == -* ]]; then`);
4861
+ if (descriptor.flags.length > 0) lines.push(` COMPREPLY=( $(compgen -W "$_filtered_flags" -- "$cur") )`);
4862
+ lines.push(` return`);
4863
+ lines.push(` fi`);
4864
+ lines.push(``);
4865
+ }
4866
+ const argsWithCompletions = descriptor.arguments.flatMap((argument, index) => {
4867
+ const completion = argCompletion(argument.type, helperName);
4868
+ return completion === void 0 ? [] : [{
4869
+ argument,
4870
+ completion,
4871
+ index
4872
+ }];
4873
+ });
4874
+ if (argsWithCompletions.length > 0) {
4875
+ lines.push(` # Positional argument completions`);
4876
+ lines.push(` local _position=0 _skip_next=0 _end_of_options=0`);
4877
+ lines.push(` for ((i = _command_index + 1; i < cword; i++)); do`);
4878
+ lines.push(` if (( _skip_next )); then`);
4879
+ lines.push(` _skip_next=0`);
4880
+ lines.push(` continue`);
4881
+ lines.push(` fi`);
4882
+ lines.push(` if (( _end_of_options )); then`);
4883
+ lines.push(` ((_position += 1))`);
4884
+ lines.push(` continue`);
4885
+ lines.push(` fi`);
4886
+ lines.push(` case "\${words[i]}" in`);
4887
+ lines.push(` --) _end_of_options=1 ;;`);
4888
+ for (const flag of descriptor.flags) {
4889
+ const forms = flagNamesForWordlist(flag);
4890
+ if (!takesSeparateValue(flag)) lines.push(` ${forms.join("|")}) ;;`);
4891
+ else {
4892
+ lines.push(` ${forms.join("|")}) _skip_next=1 ;;`);
4893
+ lines.push(` ${forms.map((form) => `${form}=*`).join("|")}) ;;`);
4894
+ }
4895
+ }
4896
+ lines.push(` -*) ;;`);
4897
+ lines.push(` *) ((_position += 1)) ;;`);
4898
+ lines.push(` esac`);
4899
+ lines.push(` done`);
4900
+ lines.push(` case "$_position" in`);
4901
+ for (const { argument, completion, index } of argsWithCompletions) {
4902
+ if (argument.variadic) continue;
4903
+ lines.push(` ${index})`);
4904
+ lines.push(` ${completion}`);
4905
+ lines.push(` return`);
4906
+ lines.push(` ;;`);
4907
+ }
4908
+ lines.push(` esac`);
4909
+ const variadic = argsWithCompletions.find(({ argument }) => argument.variadic);
4910
+ if (variadic !== void 0) {
4911
+ lines.push(` if (( _position >= ${variadic.index} )); then`);
4912
+ lines.push(` ${variadic.completion}`);
4913
+ lines.push(` return`);
4914
+ lines.push(` fi`);
4915
+ }
4916
+ } else if (descriptor.subcommands.length > 0) {
4917
+ const subNames = descriptor.subcommands.map((s) => s.name);
4918
+ lines.push(` COMPREPLY=( $(compgen -W '${subNames.join(" ")}' -- "$cur") )`);
4919
+ }
4737
4920
  lines.push(`}`);
4738
- for (const sub of descriptor.subcommands) generateContexts(dataName, sub, [...path, sub.name], lines, seen);
4921
+ lines.push(``);
4922
+ for (const sub of descriptor.subcommands) generateFunction$1(sub, currentPath, lines, helperName);
4739
4923
  };
4740
4924
  /**
4741
- * Replay the committed words with the CLI lexer and parser rules: `--`, short
4742
- * flag clusters, inline values, boolean literals, negative numbers, and
4743
- * subcommand selection by the first value only.
4925
+ * @internal
4926
+ */
4927
+ const generate$4 = (executableName, descriptor) => {
4928
+ const lines = [];
4929
+ const safeName = sanitizeFunctionName(executableName);
4930
+ const helperName = `_${safeName}--choices`;
4931
+ lines.push(`###-begin-${escapeForBash(executableName)}-completions-###`);
4932
+ lines.push(`#`);
4933
+ lines.push(`# Static completion script for Bash`);
4934
+ lines.push(`#`);
4935
+ lines.push(`# Installation:`);
4936
+ lines.push(`# ${escapeForBash(executableName)} --completions bash >> ~/.bashrc`);
4937
+ lines.push(`#`);
4938
+ lines.push(``);
4939
+ lines.push(`if ! type _init_completion &>/dev/null; then`);
4940
+ lines.push(` _init_completion()`);
4941
+ lines.push(` {`);
4942
+ lines.push(` COMPREPLY=()`);
4943
+ lines.push(` local _i _j=0 _piece _line="$COMP_LINE"`);
4944
+ lines.push(` words=("\${COMP_WORDS[0]}")`);
4945
+ lines.push(` cword=0`);
4946
+ lines.push(` _line="\${_line#*"\${COMP_WORDS[0]}"}"`);
4947
+ lines.push(` for ((_i = 1; _i < \${#COMP_WORDS[@]}; _i++)); do`);
4948
+ lines.push(` _piece="\${COMP_WORDS[_i]}"`);
4949
+ lines.push(` if [[ "$_line" == [[:blank:]]* ]]; then`);
4950
+ lines.push(` ((_j++))`);
4951
+ lines.push(` words[_j]="$_piece"`);
4952
+ lines.push(` else`);
4953
+ lines.push(` words[_j]="\${words[_j]}$_piece"`);
4954
+ lines.push(` fi`);
4955
+ lines.push(` ((_i == COMP_CWORD)) && cword=$_j`);
4956
+ lines.push(` _line="\${_line#*"$_piece"}"`);
4957
+ lines.push(` done`);
4958
+ lines.push(` cur="\${words[cword]}"`);
4959
+ lines.push(` prev=""`);
4960
+ lines.push(` ((cword > 0)) && prev="\${words[cword-1]}"`);
4961
+ lines.push(` return 0`);
4962
+ lines.push(` }`);
4963
+ lines.push(`fi`);
4964
+ lines.push(``);
4965
+ choicesHelper(helperName, lines);
4966
+ generateFunction$1(descriptor, [], lines, helperName);
4967
+ lines.push(`complete -F _${safeName} ${escapeForBash(executableName)}`);
4968
+ lines.push(`###-end-${escapeForBash(executableName)}-completions-###`);
4969
+ return lines.join("\n");
4970
+ };
4971
+ //#endregion
4972
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/cli/internal/completions/fish.js
4973
+ const escapeFishString = (s) => s.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
4974
+ /** Escape choices for Fish's second expansion of `complete -a`. */
4975
+ const escapeFishChoice = (s) => escapeFishString(s.replace(/[^A-Za-z0-9_.,/@%+-]/gu, "\\$&"));
4976
+ /**
4977
+ * Build a Fish condition that checks the current subcommand context.
4978
+ *
4979
+ * For root-level completions with subcommands: `__fish_use_subcommand`
4980
+ * For nested commands: verify the full parent path is active AND none of its
4981
+ * child subcommands have been entered yet.
4982
+ */
4983
+ const subcommandCondition = (parentPath, childSubcommandNames) => {
4984
+ if (parentPath.length === 0) {
4985
+ if (childSubcommandNames.length > 0) return `__fish_use_subcommand`;
4986
+ return ``;
4987
+ }
4988
+ const parentCondition = parentPath.map((parent) => `__fish_seen_subcommand_from ${parent}`).join("; and ");
4989
+ if (childSubcommandNames.length > 0) return `${parentCondition}; and not __fish_seen_subcommand_from ${childSubcommandNames.join(" ")}`;
4990
+ return parentCondition;
4991
+ };
4992
+ /**
4993
+ * Build a __fish_contains_opt condition that checks whether any form of this
4994
+ * flag has already been typed. Returns the condition string without wrapping
4995
+ * quotes (the caller adds those).
4996
+ */
4997
+ const flagContainsOptCondition = (flag) => {
4998
+ const optArgs = [];
4999
+ for (const alias of flag.aliases) if (alias.length === 1) optArgs.push(`-s ${alias}`);
5000
+ optArgs.push(flag.name);
5001
+ for (const alias of flag.aliases) if (alias.length > 1) optArgs.push(alias);
5002
+ if (flag.type._tag === "Boolean") optArgs.push(`no-${flag.name}`);
5003
+ return `not __fish_contains_opt ${optArgs.join(" ")}`;
5004
+ };
5005
+ /** Hide used value flags without suppressing their value completions. */
5006
+ const valueFlagDedupCondition = (flag) => {
5007
+ const forms = [`--${flag.name}`];
5008
+ for (const alias of flag.aliases) forms.push(alias.length === 1 ? `-${alias}` : `--${alias}`);
5009
+ return `begin; ${flagContainsOptCondition(flag)}; or contains -- (commandline -poc)[-1] ${forms.join(" ")}; end`;
5010
+ };
5011
+ const flagCompletionArgs = (flag) => {
5012
+ const args = [`-l ${flag.name}`];
5013
+ for (const alias of flag.aliases) if (alias.length === 1) args.push(`-s ${alias}`);
5014
+ else args.push(`-l ${alias}`);
5015
+ if (flag.description) args.push(`-d '${escapeFishString(flag.description)}'`);
5016
+ const valueArgs = takesSeparateValue(flag) ? flagValueArgs(flag.type) : void 0;
5017
+ if (valueArgs) args.push(valueArgs);
5018
+ return args;
5019
+ };
5020
+ const flagValueArgs = (type) => {
5021
+ switch (type._tag) {
5022
+ case "Boolean": return;
5023
+ case "Choice": return `-r -f -a '${type.values.map(escapeFishChoice).join(" ")}'`;
5024
+ case "Path":
5025
+ if (type.pathType === "directory") return `-r -F`;
5026
+ return `-r -F`;
5027
+ default: return `-r -f`;
5028
+ }
5029
+ };
5030
+ const argValueArgs = (type) => {
5031
+ switch (type._tag) {
5032
+ case "Choice": return `-r -f -a '${type.values.map(escapeFishChoice).join(" ")}'`;
5033
+ case "Path": return `-r -F`;
5034
+ default: return;
5035
+ }
5036
+ };
5037
+ const generateCompletions = (executableName, descriptor, parentPath, lines) => {
5038
+ const allSubNames = descriptor.subcommands.map((s) => s.name);
5039
+ const condition = subcommandCondition(parentPath, allSubNames);
5040
+ const conditionArg = condition ? `-n '${condition}'` : ``;
5041
+ if (!descriptor.arguments.some((a) => a.type._tag === "Path")) {
5042
+ const parts = [`complete -c ${executableName}`];
5043
+ if (conditionArg) parts.push(conditionArg);
5044
+ parts.push(`-f`);
5045
+ lines.push(parts.join(" "));
5046
+ }
5047
+ for (const sub of descriptor.subcommands) {
5048
+ const parts = [`complete -c ${executableName}`];
5049
+ if (conditionArg) parts.push(conditionArg);
5050
+ parts.push(`-f -a '${escapeFishString(sub.name)}'`);
5051
+ if (sub.description) parts.push(`-d '${escapeFishString(sub.description)}'`);
5052
+ lines.push(parts.join(" "));
5053
+ }
5054
+ for (const flag of descriptor.flags) {
5055
+ const dedup = takesSeparateValue(flag) ? valueFlagDedupCondition(flag) : flagContainsOptCondition(flag);
5056
+ const flagCondition = condition ? `${condition}; and ${dedup}` : dedup;
5057
+ const flagCondArg = flagCondition ? `-n '${flagCondition}'` : ``;
5058
+ const parts = [`complete -c ${executableName}`];
5059
+ if (flagCondArg) parts.push(flagCondArg);
5060
+ parts.push(...flagCompletionArgs(flag));
5061
+ lines.push(parts.join(" "));
5062
+ if (flag.type._tag === "Boolean") {
5063
+ const negParts = [`complete -c ${executableName}`];
5064
+ if (flagCondArg) negParts.push(flagCondArg);
5065
+ negParts.push(`-l no-${flag.name}`);
5066
+ if (flag.description) negParts.push(`-d '${escapeFishString(`Disable ${flag.name}`)}'`);
5067
+ lines.push(negParts.join(" "));
5068
+ }
5069
+ }
5070
+ if (descriptor.flags.length > 0) {
5071
+ const notDash = `not string match -q -- "-*" (commandline -ct)`;
5072
+ const bareBase = condition ? `${condition}; and ${notDash}` : notDash;
5073
+ for (const flag of descriptor.flags) {
5074
+ const bareCondition = `${bareBase}; and ${flagContainsOptCondition(flag)}`;
5075
+ const isBoolean = flag.type._tag === "Boolean";
5076
+ const parts = [`complete -c ${executableName}`];
5077
+ parts.push(`-n '${bareCondition}'`);
5078
+ parts.push(`-f -a '--${flag.name}'`);
5079
+ if (flag.description) parts.push(`-d '${escapeFishString(flag.description)}'`);
5080
+ lines.push(parts.join(" "));
5081
+ if (isBoolean) {
5082
+ const negParts = [`complete -c ${executableName}`];
5083
+ negParts.push(`-n '${bareCondition}'`);
5084
+ negParts.push(`-f -a '--no-${flag.name}'`);
5085
+ if (flag.description) negParts.push(`-d '${escapeFishString(`Disable ${flag.name}`)}'`);
5086
+ lines.push(negParts.join(" "));
5087
+ }
5088
+ }
5089
+ }
5090
+ for (const arg of descriptor.arguments) {
5091
+ const valueArg = argValueArgs(arg.type);
5092
+ if (valueArg) {
5093
+ const parts = [`complete -c ${executableName}`];
5094
+ if (conditionArg) parts.push(conditionArg);
5095
+ parts.push(valueArg);
5096
+ if (arg.description) parts.push(`-d '${escapeFishString(arg.description)}'`);
5097
+ lines.push(parts.join(" "));
5098
+ }
5099
+ }
5100
+ for (const sub of descriptor.subcommands) generateCompletions(executableName, sub, [...parentPath, sub.name], lines);
5101
+ };
5102
+ /**
5103
+ * @internal
5104
+ */
5105
+ const generate$3 = (executableName, descriptor) => {
5106
+ const lines = [];
5107
+ lines.push(`###-begin-${executableName}-completions-###`);
5108
+ lines.push(`#`);
5109
+ lines.push(`# Static completion script for Fish`);
5110
+ lines.push(`#`);
5111
+ lines.push(`# Installation:`);
5112
+ lines.push(`# ${executableName} --completions fish > ~/.config/fish/completions/${executableName}.fish`);
5113
+ lines.push(`#`);
5114
+ lines.push(``);
5115
+ generateCompletions(executableName, descriptor, [], lines);
5116
+ lines.push(``);
5117
+ lines.push(`###-end-${executableName}-completions-###`);
5118
+ return lines.join("\n");
5119
+ };
5120
+ //#endregion
5121
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/cli/internal/completions/powershell.js
5122
+ /**
5123
+ * Encode non-ASCII and control characters as `[char]` code units. Windows
5124
+ * PowerShell 5.1 can misread BOM-less UTF-8 as ANSI, turning some bytes into
5125
+ * PowerShell quote delimiters.
5126
+ */
5127
+ const quotePs = (s) => {
5128
+ const parts = [];
5129
+ let literal = "";
5130
+ for (let i = 0; i < s.length; i++) {
5131
+ const code = s.charCodeAt(i);
5132
+ if (code >= 32 && code < 128) {
5133
+ literal += s[i] === "'" ? "''" : s[i];
5134
+ continue;
5135
+ }
5136
+ if (literal !== "" || parts.length === 0) parts.push(`'${literal}'`);
5137
+ literal = "";
5138
+ parts.push(`[char]0x${code.toString(16).toUpperCase().padStart(4, "0")}`);
5139
+ }
5140
+ if (literal !== "" || parts.length === 0) parts.push(`'${literal}'`);
5141
+ return parts.length === 1 ? parts[0] : `(${parts.join(" + ")})`;
5142
+ };
5143
+ const psArray = (items) => `@(${items.map(quotePs).join(", ")})`;
5144
+ const psOptional = (s) => s ? quotePs(s) : "$null";
5145
+ const sanitize$1 = (s) => s.replace(/[^a-zA-Z0-9_]/g, "_");
5146
+ const flagForms = (flag) => [`--${flag.name}`, ...flag.aliases.map((alias) => alias.length === 1 ? `-${alias}` : `--${alias}`)];
5147
+ const valueFields = (type) => `values = ${psArray(type._tag === "Choice" ? type.values : [])}; pathType = ${type._tag === "Path" ? quotePs(type.pathType) : "$null"}`;
5148
+ const flagEntry = (flag) => `@{ name = ${quotePs(flag.name)}; forms = ${psArray(flagForms(flag))}; takesValue = $${flag.type._tag !== "Boolean"}; ` + (flag.optionalValue === true ? `optionalValue = $true; ` : "") + `${valueFields(flag.type)}; description = ${psOptional(flag.description)} }`;
5149
+ const argumentEntry = (argument) => `@{ name = ${quotePs(argument.name)}; variadic = $${argument.variadic}; ${valueFields(argument.type)}; description = ${psOptional(argument.description)} }`;
5150
+ const pushList = (lines, field, entries) => {
5151
+ if (entries.length === 0) {
5152
+ lines.push(` ${field} = @()`);
5153
+ return;
5154
+ }
5155
+ lines.push(` ${field} = @(`);
5156
+ for (const entry of entries) lines.push(` ${entry}`);
5157
+ lines.push(` )`);
5158
+ };
5159
+ /**
5160
+ * Emit one context per subcommand path. Subcommands are case-sensitive, so
5161
+ * contexts go in an ordinal hashtable instead of a hash literal, whose keys
5162
+ * ignore case.
5163
+ */
5164
+ const generateContexts = (dataName, descriptor, path, lines, seen) => {
5165
+ const key = path.join(" ");
5166
+ if (seen.has(key)) return;
5167
+ seen.add(key);
5168
+ lines.push(`${dataName}[${quotePs(key)}] = @{`);
5169
+ pushList(lines, "subcommands", descriptor.subcommands.map((sub) => `@{ name = ${quotePs(sub.name)}; description = ${psOptional(sub.description)} }`));
5170
+ pushList(lines, "flags", descriptor.flags.map(flagEntry));
5171
+ pushList(lines, "arguments", descriptor.arguments.map(argumentEntry));
5172
+ lines.push(`}`);
5173
+ for (const sub of descriptor.subcommands) generateContexts(dataName, sub, [...path, sub.name], lines, seen);
5174
+ };
5175
+ /**
5176
+ * Replay the committed words with the CLI lexer and parser rules: `--`, short
5177
+ * flag clusters, inline values, boolean literals, negative numbers, and
5178
+ * subcommand selection by the first value only.
4744
5179
  */
4745
5180
  const completer = (dataName) => String.raw` param($wordToComplete, $commandAst, $cursorPosition)
4746
5181
 
@@ -4873,7 +5308,8 @@ const completer = (dataName) => String.raw` param($wordToComplete, $commandAst,
4873
5308
  continue
4874
5309
  }
4875
5310
  $used[$flag.name] = $true
4876
- if (-not $hasValue) { $pending = $flag }
5311
+ # A flag with an optional value only takes a value attached with '='.
5312
+ if (-not $hasValue -and -not $flag.optionalValue) { $pending = $flag }
4877
5313
  }
4878
5314
  continue
4879
5315
  }
@@ -4942,863 +5378,440 @@ const generate$2 = (executableName, descriptor) => {
4942
5378
  lines.push(``);
4943
5379
  lines.push(`${dataName} = [hashtable]::new([System.StringComparer]::Ordinal)`);
4944
5380
  generateContexts(dataName, descriptor, [], lines, /* @__PURE__ */ new Set());
4945
- lines.push(``);
4946
- lines.push(`Register-ArgumentCompleter -Native -CommandName ${quotePs(executableName)} -ScriptBlock {`);
4947
- lines.push(completer(dataName));
4948
- lines.push(`}`);
4949
- lines.push(``);
4950
- lines.push(`###-end-${executableName}-completions-###`);
4951
- return lines.join("\n");
4952
- };
4953
- //#endregion
4954
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/cli/internal/completions/zsh.js
4955
- const escapeZsh = (s) => s.replace(/\\/g, "\\\\").replace(/'/g, "'\\''").replace(/:/g, "\\:");
4956
- const escapeZshExplanation = (s) => escapeZsh(s).replace(/]/g, "\\]");
4957
- /** Escape choices for the second parse of a Zsh `_arguments` action. */
4958
- const escapeZshChoice = (s) => s.replace(/[^A-Za-z0-9_.,/@%+-]/gu, "\\$&").replace(/'/g, "'\\''");
4959
- const sanitize = (s) => s.replace(/[^a-zA-Z0-9_]/g, "_");
4960
- /**
4961
- * All forms of a flag (--name, -alias, --no-name) for the exclusion group.
4962
- */
4963
- const allForms = (flag) => {
4964
- const forms = [`--${flag.name}`];
4965
- for (const alias of flag.aliases) forms.push(alias.length === 1 ? `-${alias}` : `--${alias}`);
4966
- if (flag.type._tag === "Boolean") forms.push(`--no-${flag.name}`);
4967
- return forms;
4968
- };
4969
- const valueAction = (type) => {
4970
- switch (type._tag) {
4971
- case "Boolean": return "";
4972
- case "Choice": return `:value:(${type.values.map(escapeZshChoice).join(" ")})`;
4973
- case "Path": return type.pathType === "directory" ? `:directory:_directories` : `:file:_files`;
4974
- case "Int": return `:integer:`;
4975
- case "Finite": return `:float:`;
4976
- case "Date": return `:date:`;
4977
- default: return `:value:`;
4978
- }
4979
- };
4980
- const argAction = (type) => {
4981
- switch (type._tag) {
4982
- case "Choice": return `(${type.values.map(escapeZshChoice).join(" ")})`;
4983
- case "Path": return type.pathType === "directory" ? `_directories` : `_files`;
4984
- default: return ``;
4985
- }
4986
- };
4987
- /**
4988
- * Produce _arguments optspecs for a single flag. Each spec is a complete,
4989
- * single-quoted string — no brace expansion, no line continuations.
4990
- */
4991
- const flagSpecs = (flag) => {
4992
- const specs = [];
4993
- const desc = flag.description ? `[${escapeZshExplanation(flag.description)}]` : "";
4994
- const action = valueAction(flag.type);
4995
- const excl = `(${allForms(flag).join(" ")})`;
4996
- specs.push(`'${excl}--${flag.name}${desc}${action}'`);
4997
- for (const alias of flag.aliases) {
4998
- const prefix = alias.length === 1 ? "-" : "--";
4999
- specs.push(`'${excl}${prefix}${alias}${desc}${action}'`);
5000
- }
5001
- if (flag.type._tag === "Boolean") {
5002
- const negDesc = flag.description ? `[${escapeZshExplanation(`Disable ${flag.name}`)}]` : "";
5003
- specs.push(`'${excl}--no-${flag.name}${negDesc}'`);
5004
- }
5005
- return specs;
5006
- };
5007
- const argSpec = (arg) => {
5008
- const desc = arg.description ? escapeZsh(arg.description) : arg.name;
5009
- const action = argAction(arg.type);
5010
- return `'${arg.variadic ? "*" : ""}:${desc}:${action}'`;
5011
- };
5012
- const generateFunction = (descriptor, parentPath, lines) => {
5013
- const currentPath = [...parentPath, descriptor.name];
5014
- const funcName = `_${currentPath.map(sanitize).join("_")}`;
5015
- lines.push(`${funcName}() {`);
5016
- if (descriptor.subcommands.length > 0) {
5017
- lines.push(` local context state state_descr line`);
5018
- lines.push(` typeset -A opt_args`);
5019
- lines.push(``);
5020
- lines.push(` local -a commands`);
5021
- lines.push(` commands=(`);
5022
- for (const sub of descriptor.subcommands) {
5023
- const desc = sub.description ? escapeZsh(sub.description) : "";
5024
- lines.push(` '${sub.name}:${desc}'`);
5025
- }
5026
- lines.push(` )`);
5027
- lines.push(``);
5028
- lines.push(` local -a specs`);
5029
- lines.push(` specs=(`);
5030
- for (const flag of descriptor.flags) for (const spec of flagSpecs(flag)) lines.push(` ${spec}`);
5031
- if (descriptor.arguments.length > 0) {
5032
- lines.push(` -`);
5033
- lines.push(` parent-arguments`);
5034
- for (const arg of descriptor.arguments) lines.push(` ${argSpec(arg)}`);
5035
- lines.push(` -`);
5036
- lines.push(` subcommands`);
5037
- }
5038
- lines.push(` '1:command:->command'`);
5039
- lines.push(` '*::arg:->args'`);
5040
- lines.push(` )`);
5041
- lines.push(``);
5042
- lines.push(` _arguments -C "\${specs[@]}"`);
5043
- lines.push(``);
5044
- lines.push(` case "$state" in`);
5045
- lines.push(` command)`);
5046
- lines.push(` _describe -t commands 'commands' commands`);
5047
- lines.push(` ;;`);
5048
- lines.push(` args)`);
5049
- lines.push(` case "$words[1]" in`);
5050
- for (const sub of descriptor.subcommands) {
5051
- const subFunc = `_${[...currentPath, sub.name].map(sanitize).join("_")}`;
5052
- lines.push(` ${sub.name})`);
5053
- lines.push(` ${subFunc}`);
5054
- lines.push(` ;;`);
5055
- }
5056
- lines.push(` esac`);
5057
- lines.push(` ;;`);
5058
- lines.push(` esac`);
5059
- } else {
5060
- const allSpecs = [];
5061
- for (const flag of descriptor.flags) allSpecs.push(...flagSpecs(flag));
5062
- for (const arg of descriptor.arguments) allSpecs.push(argSpec(arg));
5063
- if (allSpecs.length > 0) {
5064
- lines.push(` local -a specs`);
5065
- lines.push(` specs=(`);
5066
- for (const spec of allSpecs) lines.push(` ${spec}`);
5067
- lines.push(` )`);
5068
- lines.push(` _arguments "\${specs[@]}"`);
5069
- }
5070
- }
5071
- lines.push(`}`);
5072
- lines.push(``);
5073
- for (const sub of descriptor.subcommands) generateFunction(sub, currentPath, lines);
5074
- };
5075
- /**
5076
- * @internal
5077
- */
5078
- const generate$1 = (executableName, descriptor) => {
5079
- const lines = [];
5080
- const safeName = sanitize(executableName);
5081
- lines.push(`#compdef ${executableName}`);
5082
- lines.push(`###-begin-${executableName}-completions-###`);
5083
- lines.push(`#`);
5084
- lines.push(`# Static completion script for Zsh`);
5085
- lines.push(`#`);
5086
- lines.push(`# Installation:`);
5087
- lines.push(`# ${executableName} --completions zsh > ~/.zsh/completions/_${executableName}`);
5088
- lines.push(`# then add ~/.zsh/completions to your fpath`);
5089
- lines.push(`#`);
5090
- lines.push(``);
5091
- generateFunction(descriptor, [], lines);
5092
- lines.push(`# Handle both direct invocation and autoload`);
5093
- lines.push(`if [[ "\${zsh_eval_context[-1]}" == "loadautofunc" ]]; then`);
5094
- lines.push(` _${safeName} "$@"`);
5095
- lines.push(`else`);
5096
- lines.push(` compdef _${safeName} ${executableName}`);
5097
- lines.push(`fi`);
5098
- lines.push(`###-end-${executableName}-completions-###`);
5099
- return lines.join("\n");
5100
- };
5101
- //#endregion
5102
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/cli/Completions.js
5103
- /**
5104
- * The `Completions` module turns a plain description of an Effect CLI command
5105
- * tree into shell completion scripts for Bash, Zsh, Fish, and PowerShell. It
5106
- * is the low-level script generation surface used by the unstable CLI package
5107
- * and by the built-in completions global flag.
5108
- *
5109
- * @stability unstable
5110
- * @since 4.0.0
5111
- */
5112
- /**
5113
- * Generates a shell completion script for a command descriptor.
5114
- *
5115
- * **When to use**
5116
- *
5117
- * Use when you need an installable completion script from an existing
5118
- * `CommandDescriptor`.
5119
- *
5120
- * **Details**
5121
- *
5122
- * Dispatches by `shell` to Bash, Zsh, Fish, or PowerShell generation and
5123
- * returns a static script string for `executableName`.
5124
- *
5125
- * @see {@link Shell} for supported shell names
5126
- * @see {@link CommandDescriptor} for the command shape used by completion generation
5127
- *
5128
- * @stability unstable
5129
- * @category constructors
5130
- * @since 4.0.0
5131
- */
5132
- const generate = (executableName, shell, descriptor) => {
5133
- switch (shell) {
5134
- case "bash": return generate$4(executableName, descriptor);
5135
- case "zsh": return generate$1(executableName, descriptor);
5136
- case "fish": return generate$3(executableName, descriptor);
5137
- case "powershell": return generate$2(executableName, descriptor);
5138
- }
5139
- };
5140
- //#endregion
5141
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/cli/Flag.js
5142
- /**
5143
- * Creates a string flag that accepts text input.
5144
- *
5145
- * **Example** (Creating string flags)
5146
- *
5147
- * ```ts import.meta.vitest
5148
- * import { Flag } from "effect/cli"
5149
- *
5150
- * const nameFlag = Flag.String("name")
5151
- * // Usage: --name "John Doe"
5152
- * nameFlag.kind // => "flag"
5153
- * ```
5154
- *
5155
- * @stability unstable
5156
- * @category constructors
5157
- * @since 4.0.0
5158
- */
5159
- const String$1 = (name) => String$3(flagKind, name);
5160
- /**
5161
- * Creates a boolean flag that can be enabled or disabled.
5162
- *
5163
- * **Example** (Creating boolean flags)
5164
- *
5165
- * ```ts import.meta.vitest
5166
- * import { Flag } from "effect/cli"
5167
- *
5168
- * const verboseFlag = Flag.Boolean("verbose")
5169
- * // Usage: --verbose (true) or --no-verbose (false)
5170
- * // Omission fails unless the flag is made optional or given a fallback.
5171
- * verboseFlag.kind // => "flag"
5172
- * ```
5173
- *
5174
- * @stability unstable
5175
- * @category constructors
5176
- * @since 4.0.0
5177
- */
5178
- const Boolean = (name) => Boolean$1(flagKind, name);
5179
- /**
5180
- * Constructs option parameters that represent a choice between several inputs.
5181
- * Each tuple maps a string flag value to an associated typed value.
5182
- *
5183
- * **Example** (Creating flag choices with values)
5184
- *
5185
- * ```ts import.meta.vitest
5186
- * import { Flag } from "effect/cli"
5187
- *
5188
- * // simple enum like choice mapping directly to string union
5189
- * const color = Flag.Literals("color", ["red", "green", "blue"])
5190
- *
5191
- * // choice with custom value mapping
5192
- * const logLevel = Flag.ChoiceWithValue("log-level", [
5193
- * ["debug", "Debug" as const],
5194
- * ["info", "Info" as const],
5195
- * ["error", "Error" as const]
5196
- * ])
5197
- * const kinds = [color.kind, logLevel.kind] // => ["flag", "flag"]
5198
- * ```
5199
- *
5200
- * @stability unstable
5201
- * @category constructors
5202
- * @since 4.0.0
5203
- */
5204
- const ChoiceWithValue = (name, choices) => ChoiceWithValue$1(flagKind, name, choices);
5205
- /**
5206
- * Adds an alias to a flag, allowing it to be referenced by multiple names.
5207
- *
5208
- * **Example** (Adding flag aliases)
5209
- *
5210
- * ```ts import.meta.vitest
5211
- * import { Flag } from "effect/cli"
5212
- *
5213
- * // Flag can be used as both --verbose and -v
5214
- * const verboseFlag = Flag.Boolean("verbose").pipe(
5215
- * Flag.withAlias("v")
5216
- * )
5217
- *
5218
- * // Multiple aliases can be chained
5219
- * const helpFlag = Flag.Boolean("help").pipe(
5220
- * Flag.withAlias("h"),
5221
- * Flag.withAlias("?")
5222
- * )
5223
- * const kinds = [verboseFlag.kind, helpFlag.kind] // => ["flag", "flag"]
5224
- * ```
5225
- *
5226
- * @stability unstable
5227
- * @category aliasing
5228
- * @since 4.0.0
5229
- */
5230
- const withAlias = /*#__PURE__*/ dual(2, (self, alias) => withAlias$1(self, alias));
5231
- /**
5232
- * Adds a description to a flag for help documentation.
5233
- *
5234
- * **Example** (Adding help descriptions)
5235
- *
5236
- * ```ts import.meta.vitest
5237
- * import { Flag } from "effect/cli"
5238
- *
5239
- * const portFlag = Flag.Int("port").pipe(
5240
- * Flag.withDescription("The port number to listen on")
5241
- * )
5242
- *
5243
- * const configFlag = Flag.File("config").pipe(
5244
- * Flag.withDescription("Path to the configuration file")
5245
- * )
5246
- * const kinds = [portFlag.kind, configFlag.kind] // => ["flag", "flag"]
5247
- * ```
5248
- *
5249
- * @stability unstable
5250
- * @category metadata
5251
- * @since 4.0.0
5252
- */
5253
- const withDescription$1 = /*#__PURE__*/ dual(2, (self, description) => withDescription$3(self, description));
5254
- /**
5255
- * Sets a custom metavar (placeholder name) for the flag in help documentation.
5256
- *
5257
- * **Details**
5258
- *
5259
- * The metavar is displayed in usage text to indicate what value the user should
5260
- * provide. For example, `--output FILE` shows `FILE` as the metavar.
5261
- *
5262
- * **Example** (Setting metavars)
5263
- *
5264
- * ```ts import.meta.vitest
5265
- * import { Flag } from "effect/cli"
5266
- *
5267
- * const databaseFlag = Flag.String("database-url").pipe(
5268
- * Flag.withMetavar("URL"),
5269
- * Flag.withDescription("Database connection URL")
5270
- * )
5271
- * // In help: --database-url URL
5272
- *
5273
- * const timeoutFlag = Flag.Int("timeout").pipe(
5274
- * Flag.withMetavar("SECONDS")
5275
- * )
5276
- * // In help: --timeout SECONDS
5277
- * const kinds = [databaseFlag.kind, timeoutFlag.kind] // => ["flag", "flag"]
5278
- * ```
5279
- *
5280
- * @stability unstable
5281
- * @category metadata
5282
- * @since 4.0.0
5283
- */
5284
- const withMetavar = /*#__PURE__*/ dual(2, (self, metavar) => withMetavar$1(self, metavar));
5285
- /**
5286
- * Makes a flag optional, returning an Option type that can be None if not provided.
5287
- *
5288
- * **Example** (Making flags optional)
5289
- *
5290
- * ```ts import.meta.vitest
5291
- * import { Effect, FileSystem, Layer, Option, Path, Stdio, Terminal } from "effect"
5292
- * import { Flag } from "effect/cli"
5293
- * import { ChildProcessSpawner } from "effect/process"
5294
- *
5295
- * const CliTestLayer = Layer.mergeAll(
5296
- * FileSystem.layerNoop({}),
5297
- * Path.layer,
5298
- * Stdio.layerTest({}),
5299
- * Layer.succeed(Terminal.Terminal, Terminal.make({
5300
- * columns: Effect.succeed(80),
5301
- * rows: Effect.succeed(24),
5302
- * readInput: Effect.die("unused"),
5303
- * readLine: Effect.die("unused"),
5304
- * display: () => Effect.void
5305
- * })),
5306
- * Layer.succeed(
5307
- * ChildProcessSpawner.ChildProcessSpawner,
5308
- * ChildProcessSpawner.make(() => Effect.die("unused"))
5309
- * )
5310
- * )
5311
- *
5312
- * const optionalPort = Flag.optional(Flag.Int("port"))
5313
- *
5314
- * const program = Effect.gen(function*() {
5315
- * const [, port] = yield* optionalPort.parse({
5316
- * arguments: [],
5317
- * flags: { "port": ["4000"] }
5318
- * })
5319
- * return port
5320
- * })
5321
- *
5322
- * await Effect.runPromise(program.pipe(Effect.provide(CliTestLayer))) // => Option.some(4000)
5323
- * ```
5324
- *
5325
- * @stability unstable
5326
- * @category optionality
5327
- * @since 4.0.0
5328
- */
5329
- const optional = (param) => optional$1(param);
5330
- /**
5331
- * Provides a default value for a flag when it's not specified.
5332
- *
5333
- * **Example** (Providing default values)
5334
- *
5335
- * ```ts import.meta.vitest
5336
- * import { Flag } from "effect/cli"
5337
- *
5338
- * const portFlag = Flag.Int("port").pipe(
5339
- * Flag.withDefault(8080)
5340
- * )
5341
- * // If --port is not provided, defaults to 8080
5342
- *
5343
- * const hostFlag = Flag.String("host").pipe(
5344
- * Flag.withDefault("localhost")
5345
- * )
5346
- * // If --host is not provided, defaults to "localhost"
5347
- * const kinds = [portFlag.kind, hostFlag.kind] // => ["flag", "flag"]
5348
- * ```
5349
- *
5350
- * @stability unstable
5351
- * @category optionality
5352
- * @since 4.0.0
5353
- */
5354
- const withDefault = withDefault$1;
5355
- /**
5356
- * Adds a fallback config that is loaded when a required flag is missing.
5357
- *
5358
- * **Example** (Falling back to config)
5359
- *
5360
- * ```ts import.meta.vitest
5361
- * import { Config } from "effect"
5362
- * import { Flag } from "effect/cli"
5363
- *
5364
- * const verbose = Flag.Boolean("verbose").pipe(
5365
- * Flag.withFallbackConfig(Config.Boolean("VERBOSE"))
5366
- * )
5367
- * verbose.kind // => "flag"
5368
- * ```
5369
- *
5370
- * @stability unstable
5371
- * @category combinators
5372
- * @since 4.0.0
5373
- */
5374
- const withFallbackConfig = /*#__PURE__*/ dual(2, (self, config) => withFallbackConfig$1(self, config));
5381
+ lines.push(``);
5382
+ lines.push(`Register-ArgumentCompleter -Native -CommandName ${quotePs(executableName)} -ScriptBlock {`);
5383
+ lines.push(completer(dataName));
5384
+ lines.push(`}`);
5385
+ lines.push(``);
5386
+ lines.push(`###-end-${executableName}-completions-###`);
5387
+ return lines.join("\n");
5388
+ };
5375
5389
  //#endregion
5376
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/cli/internal/config.js
5390
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/cli/internal/completions/zsh.js
5391
+ const escapeZsh = (s) => s.replace(/\\/g, "\\\\").replace(/'/g, "'\\''").replace(/:/g, "\\:");
5392
+ const escapeZshExplanation = (s) => escapeZsh(s).replace(/]/g, "\\]");
5393
+ /** Escape choices for the second parse of a Zsh `_arguments` action. */
5394
+ const escapeZshChoice = (s) => s.replace(/[^A-Za-z0-9_.,/@%+-]/gu, "\\$&").replace(/'/g, "'\\''");
5395
+ const sanitize = (s) => s.replace(/[^a-zA-Z0-9_]/g, "_");
5377
5396
  /**
5378
- * Config Internal
5379
- * ================
5380
- *
5381
- * The processed internal representation of a Command.Config declaration.
5382
- * Separates the user's declared config shape from the flat parsing representation.
5383
- *
5384
- * Key concepts:
5385
- * - ConfigInternal: The full processed form (flags, arguments, tree)
5386
- * - ConfigInternal.Tree: Maps declaration keys to nodes
5387
- * - ConfigInternal.Node: Param reference, Array, or Nested subtree
5388
- *
5389
- * Example transformation from Command.Config to Command.Config.Internal:
5390
- *
5391
- * ```ts
5392
- * // User declares:
5393
- * const config = {
5394
- * verbose: Flag.Boolean("verbose").pipe(Flag.withDefault(false)),
5395
- * server: {
5396
- * host: Flag.String("host"),
5397
- * port: Flag.Int("port")
5398
- * },
5399
- * files: Argument.String("files").pipe(Argument.variadic)
5400
- * }
5401
- *
5402
- * // Becomes Config.Internal:
5403
- * {
5404
- * arguments: [filesParam], // Flat array of arguments
5405
- * flags: [verboseParam, hostParam, portParam], // Flat array of flags
5406
- * orderedParams: [verboseParam, hostParam, portParam, filesParam],
5407
- * tree: { // Preserves nested structure
5408
- * verbose: { _tag: "Param", index: 0 },
5409
- * server: {
5410
- * _tag: "Nested",
5411
- * tree: {
5412
- * host: { _tag: "Param", index: 1 },
5413
- * port: { _tag: "Param", index: 2 }
5414
- * }
5415
- * },
5416
- * files: { _tag: "Param", index: 3 }
5417
- * }
5418
- * }
5419
- * ```
5420
- *
5421
- * This separation allows:
5422
- * 1. Flat iteration over all params for parsing/validation
5423
- * 2. Reconstruction of original nested shape for handler input
5397
+ * All forms of a flag (--name, -alias, --no-name) for the exclusion group.
5424
5398
  */
5425
- const ConfigInternalTypeId = "~effect/cli/Command/Config/Internal";
5399
+ const allForms = (flag) => {
5400
+ const forms = [`--${flag.name}`];
5401
+ for (const alias of flag.aliases) forms.push(alias.length === 1 ? `-${alias}` : `--${alias}`);
5402
+ if (flag.type._tag === "Boolean") forms.push(`--no-${flag.name}`);
5403
+ return forms;
5404
+ };
5405
+ const valueAction = (type) => {
5406
+ switch (type._tag) {
5407
+ case "Boolean": return "";
5408
+ case "Choice": return `:value:(${type.values.map(escapeZshChoice).join(" ")})`;
5409
+ case "Path": return type.pathType === "directory" ? `:directory:_directories` : `:file:_files`;
5410
+ case "Int": return `:integer:`;
5411
+ case "Finite": return `:float:`;
5412
+ case "Date": return `:date:`;
5413
+ default: return `:value:`;
5414
+ }
5415
+ };
5416
+ const argAction = (type) => {
5417
+ switch (type._tag) {
5418
+ case "Choice": return `(${type.values.map(escapeZshChoice).join(" ")})`;
5419
+ case "Path": return type.pathType === "directory" ? `_directories` : `_files`;
5420
+ default: return ``;
5421
+ }
5422
+ };
5426
5423
  /**
5427
- * Parses a Command.Config into a ConfigInternal.
5428
- *
5429
- * Walks the config structure and:
5430
- * 1. Extracts all Params into flat arrays (flags, arguments, orderedParams)
5431
- * 2. Builds a tree that remembers the original nested structure
5432
- * 3. Assigns each Param an index to link parsed values back
5433
- *
5434
- * @internal
5424
+ * Produce _arguments optspecs for a single flag. Each spec is a complete,
5425
+ * single-quoted string — no brace expansion, no line continuations.
5435
5426
  */
5436
- const parseConfig = (config) => {
5437
- const orderedParams = [];
5438
- const flags = [];
5439
- const args = [];
5440
- function parse(config) {
5441
- const tree = Object.create(null);
5442
- for (const key of Object.keys(config)) tree[key] = parseValue(config[key]);
5443
- return tree;
5427
+ const flagSpecs = (flag) => {
5428
+ const specs = [];
5429
+ const desc = flag.description ? `[${escapeZshExplanation(flag.description)}]` : "";
5430
+ const optional = flag.optionalValue === true && flag.type._tag !== "Boolean";
5431
+ const valueSuffix = optional ? "=-" : "";
5432
+ const action = optional ? `:${valueAction(flag.type)}` : valueAction(flag.type);
5433
+ const excl = `(${allForms(flag).join(" ")})`;
5434
+ specs.push(`'${excl}--${flag.name}${valueSuffix}${desc}${action}'`);
5435
+ for (const alias of flag.aliases) {
5436
+ const prefix = alias.length === 1 ? "-" : "--";
5437
+ specs.push(`'${excl}${prefix}${alias}${valueSuffix}${desc}${action}'`);
5444
5438
  }
5445
- function parseValue(value) {
5446
- if (Array.isArray(value)) return {
5447
- _tag: "Array",
5448
- children: value.map((v) => parseValue(v))
5449
- };
5450
- else if (isParam(value)) {
5451
- const index = orderedParams.length;
5452
- orderedParams.push(value);
5453
- if (value.kind === "argument") args.push(value);
5454
- else flags.push(value);
5455
- return {
5456
- _tag: "Param",
5457
- index
5458
- };
5459
- } else return {
5460
- _tag: "Nested",
5461
- tree: parse(value)
5462
- };
5439
+ if (flag.type._tag === "Boolean") {
5440
+ const negDesc = flag.description ? `[${escapeZshExplanation(`Disable ${flag.name}`)}]` : "";
5441
+ specs.push(`'${excl}--no-${flag.name}${negDesc}'`);
5463
5442
  }
5464
- return {
5465
- [ConfigInternalTypeId]: ConfigInternalTypeId,
5466
- flags,
5467
- arguments: args,
5468
- orderedParams,
5469
- tree: parse(config)
5470
- };
5443
+ return specs;
5444
+ };
5445
+ const argSpec = (arg) => {
5446
+ const desc = arg.description ? escapeZsh(arg.description) : arg.name;
5447
+ const action = argAction(arg.type);
5448
+ return `'${arg.variadic ? "*" : ""}:${desc}:${action}'`;
5449
+ };
5450
+ const generateFunction = (descriptor, parentPath, lines) => {
5451
+ const currentPath = [...parentPath, descriptor.name];
5452
+ const funcName = `_${currentPath.map(sanitize).join("_")}`;
5453
+ lines.push(`${funcName}() {`);
5454
+ if (descriptor.subcommands.length > 0) {
5455
+ lines.push(` local context state state_descr line`);
5456
+ lines.push(` typeset -A opt_args`);
5457
+ lines.push(``);
5458
+ lines.push(` local -a commands`);
5459
+ lines.push(` commands=(`);
5460
+ for (const sub of descriptor.subcommands) {
5461
+ const desc = sub.description ? escapeZsh(sub.description) : "";
5462
+ lines.push(` '${sub.name}:${desc}'`);
5463
+ }
5464
+ lines.push(` )`);
5465
+ lines.push(``);
5466
+ lines.push(` local -a specs`);
5467
+ lines.push(` specs=(`);
5468
+ for (const flag of descriptor.flags) for (const spec of flagSpecs(flag)) lines.push(` ${spec}`);
5469
+ if (descriptor.arguments.length > 0) {
5470
+ lines.push(` -`);
5471
+ lines.push(` parent-arguments`);
5472
+ for (const arg of descriptor.arguments) lines.push(` ${argSpec(arg)}`);
5473
+ lines.push(` -`);
5474
+ lines.push(` subcommands`);
5475
+ }
5476
+ lines.push(` '1:command:->command'`);
5477
+ lines.push(` '*::arg:->args'`);
5478
+ lines.push(` )`);
5479
+ lines.push(``);
5480
+ lines.push(` _arguments -C "\${specs[@]}"`);
5481
+ lines.push(``);
5482
+ lines.push(` case "$state" in`);
5483
+ lines.push(` command)`);
5484
+ lines.push(` _describe -t commands 'commands' commands`);
5485
+ lines.push(` ;;`);
5486
+ lines.push(` args)`);
5487
+ lines.push(` case "$words[1]" in`);
5488
+ for (const sub of descriptor.subcommands) {
5489
+ const subFunc = `_${[...currentPath, sub.name].map(sanitize).join("_")}`;
5490
+ lines.push(` ${sub.name})`);
5491
+ lines.push(` ${subFunc}`);
5492
+ lines.push(` ;;`);
5493
+ }
5494
+ lines.push(` esac`);
5495
+ lines.push(` ;;`);
5496
+ lines.push(` esac`);
5497
+ } else {
5498
+ const allSpecs = [];
5499
+ for (const flag of descriptor.flags) allSpecs.push(...flagSpecs(flag));
5500
+ for (const arg of descriptor.arguments) allSpecs.push(argSpec(arg));
5501
+ if (allSpecs.length > 0) {
5502
+ lines.push(` local -a specs`);
5503
+ lines.push(` specs=(`);
5504
+ for (const spec of allSpecs) lines.push(` ${spec}`);
5505
+ lines.push(` )`);
5506
+ lines.push(` _arguments "\${specs[@]}"`);
5507
+ }
5508
+ }
5509
+ lines.push(`}`);
5510
+ lines.push(``);
5511
+ for (const sub of descriptor.subcommands) generateFunction(sub, currentPath, lines);
5471
5512
  };
5472
5513
  /**
5473
5514
  * @internal
5474
5515
  */
5475
- const emptyConfig = /*#__PURE__*/ parseConfig({});
5516
+ const generate$1 = (executableName, descriptor) => {
5517
+ const lines = [];
5518
+ const safeName = sanitize(executableName);
5519
+ lines.push(`#compdef ${executableName}`);
5520
+ lines.push(`###-begin-${executableName}-completions-###`);
5521
+ lines.push(`#`);
5522
+ lines.push(`# Static completion script for Zsh`);
5523
+ lines.push(`#`);
5524
+ lines.push(`# Installation:`);
5525
+ lines.push(`# ${executableName} --completions zsh > ~/.zsh/completions/_${executableName}`);
5526
+ lines.push(`# then add ~/.zsh/completions to your fpath`);
5527
+ lines.push(`#`);
5528
+ lines.push(``);
5529
+ generateFunction(descriptor, [], lines);
5530
+ lines.push(`# Handle both direct invocation and autoload`);
5531
+ lines.push(`if [[ "\${zsh_eval_context[-1]}" == "loadautofunc" ]]; then`);
5532
+ lines.push(` _${safeName} "$@"`);
5533
+ lines.push(`else`);
5534
+ lines.push(` compdef _${safeName} ${executableName}`);
5535
+ lines.push(`fi`);
5536
+ lines.push(`###-end-${executableName}-completions-###`);
5537
+ return lines.join("\n");
5538
+ };
5539
+ //#endregion
5540
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/cli/Completions.js
5476
5541
  /**
5477
- * Reconstructs the original nested config shape from parsed values.
5542
+ * The `Completions` module turns a plain description of an Effect CLI command
5543
+ * tree into shell completion scripts for Bash, Zsh, Fish, and PowerShell. It
5544
+ * is the low-level script generation surface used by the unstable CLI package
5545
+ * and by the built-in completions global flag.
5478
5546
  *
5479
- * Uses the tree as a blueprint to place each parsed value back into
5480
- * its original position in the nested structure.
5547
+ * @stability unstable
5548
+ * @since 4.0.0
5549
+ */
5550
+ /**
5551
+ * Generates a shell completion script for a command descriptor.
5552
+ *
5553
+ * **When to use**
5554
+ *
5555
+ * Use when you need an installable completion script from an existing
5556
+ * `CommandDescriptor`.
5557
+ *
5558
+ * **Details**
5559
+ *
5560
+ * Dispatches by `shell` to Bash, Zsh, Fish, or PowerShell generation and
5561
+ * returns a static script string for `executableName`.
5562
+ *
5563
+ * @see {@link Shell} for supported shell names
5564
+ * @see {@link CommandDescriptor} for the command shape used by completion generation
5481
5565
  *
5482
- * @internal
5566
+ * @stability unstable
5567
+ * @category constructors
5568
+ * @since 4.0.0
5483
5569
  */
5484
- const reconstructTree = (tree, results) => {
5485
- const output = {};
5486
- for (const key of Object.keys(tree)) assignProperty(output, key, nodeValue(tree[key]));
5487
- return output;
5488
- function nodeValue(node) {
5489
- switch (node._tag) {
5490
- case "Param": return results[node.index];
5491
- case "Array": return node.children.map((child) => nodeValue(child));
5492
- case "Nested": return reconstructTree(node.tree, results);
5493
- }
5570
+ const generate = (executableName, shell, descriptor) => {
5571
+ switch (shell) {
5572
+ case "bash": return generate$4(executableName, descriptor);
5573
+ case "zsh": return generate$1(executableName, descriptor);
5574
+ case "fish": return generate$3(executableName, descriptor);
5575
+ case "powershell": return generate$2(executableName, descriptor);
5494
5576
  }
5495
5577
  };
5496
5578
  //#endregion
5497
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/cli/internal/command.js
5579
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/cli/Flag.js
5498
5580
  /**
5499
- * Command Implementation
5500
- * ======================
5581
+ * Creates a string flag that accepts text input.
5501
5582
  *
5502
- * Internal implementation details for CLI commands.
5503
- * Public API is in ../Command.ts
5583
+ * **Example** (Creating string flags)
5584
+ *
5585
+ * ```ts import.meta.vitest
5586
+ * import { Flag } from "effect/cli"
5587
+ *
5588
+ * const nameFlag = Flag.String("name")
5589
+ * // Usage: --name "John Doe"
5590
+ * nameFlag.kind // => "flag"
5591
+ * ```
5592
+ *
5593
+ * @stability unstable
5594
+ * @category constructors
5595
+ * @since 4.0.0
5504
5596
  */
5505
- const TypeId = "~effect/cli/Command";
5597
+ const String$1 = (name) => String$3(flagKind, name);
5506
5598
  /**
5507
- * Casts a Command to its internal implementation.
5508
- * For use by internal modules that need access to config, parse, handle, etc.
5599
+ * Creates a boolean flag that can be enabled or disabled.
5600
+ *
5601
+ * **Example** (Creating boolean flags)
5602
+ *
5603
+ * ```ts import.meta.vitest
5604
+ * import { Flag } from "effect/cli"
5605
+ *
5606
+ * const verboseFlag = Flag.Boolean("verbose")
5607
+ * // Usage: --verbose (true) or --no-verbose (false)
5608
+ * // Omission fails unless the flag is made optional or given a fallback.
5609
+ * verboseFlag.kind // => "flag"
5610
+ * ```
5611
+ *
5612
+ * @stability unstable
5613
+ * @category constructors
5614
+ * @since 4.0.0
5509
5615
  */
5510
- const toImpl = (self) => self;
5511
- const Proto = { .../*#__PURE__*/ Prototype({
5512
- label: "Command",
5513
- evaluate() {
5514
- return toImpl(this).service;
5515
- }
5516
- }) };
5616
+ const Boolean = (name) => Boolean$1(flagKind, name);
5517
5617
  /**
5518
- * Internal command constructor. Only accepts already-parsed ConfigInternal.
5618
+ * Constructs option parameters that represent a choice between several inputs.
5619
+ * Each tuple maps a string flag value to an associated typed value.
5620
+ *
5621
+ * **Example** (Creating flag choices with values)
5622
+ *
5623
+ * ```ts import.meta.vitest
5624
+ * import { Flag } from "effect/cli"
5625
+ *
5626
+ * // simple enum like choice mapping directly to string union
5627
+ * const color = Flag.Literals("color", ["red", "green", "blue"])
5628
+ *
5629
+ * // choice with custom value mapping
5630
+ * const logLevel = Flag.ChoiceWithValue("log-level", [
5631
+ * ["debug", "Debug" as const],
5632
+ * ["info", "Info" as const],
5633
+ * ["error", "Error" as const]
5634
+ * ])
5635
+ * const kinds = [color.kind, logLevel.kind] // => ["flag", "flag"]
5636
+ * ```
5637
+ *
5638
+ * @stability unstable
5639
+ * @category constructors
5640
+ * @since 4.0.0
5519
5641
  */
5520
- const makeCommand = (options) => {
5521
- const config = options.config;
5522
- const contextConfig = options.contextConfig ?? emptyConfig;
5523
- const service = options.service ?? Service(`~effect/cli/Command/${options.name}`);
5524
- const annotations = options.annotations ?? empty$1();
5525
- const globalFlags = options.globalFlags ?? [];
5526
- const subcommands = options.subcommands ?? [];
5527
- const handle = (input, commandPath) => isNotUndefined(options.handle) ? options.handle(input, commandPath) : fail$1(new ShowHelp({
5528
- commandPath,
5529
- errors: []
5530
- }));
5531
- const parse = options.parse ?? makeParser(config);
5532
- const parseContext = options.parseContext ?? makeParser(contextConfig, { allowLeftovers: true });
5533
- const buildHelpDoc = (commandPath) => {
5534
- const args = [];
5535
- const flags = [];
5536
- for (const arg of config.arguments) {
5537
- const singles = extractSingleParams(arg);
5538
- const metadata = getParamMetadata(arg);
5539
- for (const single of singles) args.push({
5540
- name: single.name,
5541
- type: single.typeName ?? getTypeName(single.primitiveType),
5542
- description: single.description,
5543
- required: !metadata.isOptional && (!metadata.isVariadic || exists(metadata.variadicMin, (min) => min > 0)),
5544
- variadic: metadata.isVariadic
5545
- });
5546
- }
5547
- let usage = commandPath.length > 0 ? commandPath.join(" ") : options.name;
5548
- if (subcommands.some((group) => group.commands.some((c) => !c.unlisted))) usage += " <subcommand>";
5549
- usage += " [flags]";
5550
- for (const arg of args) {
5551
- const argName = arg.variadic ? `<${arg.name}...>` : `<${arg.name}>`;
5552
- usage += ` ${arg.required ? argName : `[${argName}]`}`;
5553
- }
5554
- for (const option of config.flags) {
5555
- const singles = extractSingleParams(option);
5556
- const metadata = getParamMetadata(option);
5557
- for (const single of singles) {
5558
- if (single.hidden) continue;
5559
- flags.push(toFlagDoc(single, metadata));
5560
- }
5561
- }
5562
- const subcommandDocs = [];
5563
- for (const group of subcommands) {
5564
- const visible = group.commands.filter((c) => !c.unlisted);
5565
- if (visible.length === 0) continue;
5566
- subcommandDocs.push({
5567
- group: group.group,
5568
- commands: map$4(visible, (subcommand) => ({
5569
- name: subcommand.name,
5570
- alias: subcommand.alias,
5571
- shortDescription: subcommand.shortDescription,
5572
- description: subcommand.description ?? ""
5573
- }))
5574
- });
5575
- }
5576
- const examples = options.examples ?? [];
5577
- return {
5578
- description: options.description ?? "",
5579
- usage,
5580
- flags,
5581
- annotations,
5582
- ...args.length > 0 && { args },
5583
- ...subcommandDocs.length > 0 && { subcommands: subcommandDocs },
5584
- ...examples.length > 0 && { examples }
5585
- };
5586
- };
5587
- return Object.assign(Object.create(Proto), {
5588
- [TypeId]: TypeId,
5589
- name: options.name,
5590
- examples: options.examples ?? [],
5591
- annotations,
5592
- globalFlags,
5593
- subcommands,
5594
- unlisted: options.unlisted ?? false,
5595
- config,
5596
- contextConfig,
5597
- service,
5598
- parse,
5599
- parseContext,
5600
- handle,
5601
- buildHelpDoc,
5602
- ...isNotUndefined(options.description) ? { description: options.description } : {},
5603
- ...isNotUndefined(options.shortDescription) ? { shortDescription: options.shortDescription } : {},
5604
- ...isNotUndefined(options.alias) ? { alias: options.alias } : {}
5605
- });
5606
- };
5642
+ const ChoiceWithValue = (name, choices) => ChoiceWithValue$1(flagKind, name, choices);
5607
5643
  /**
5608
- * Converts a single flag param into a FlagDoc for help display.
5644
+ * Adds an alias to a flag, allowing it to be referenced by multiple names.
5609
5645
  *
5610
- * @internal
5646
+ * **Example** (Adding flag aliases)
5647
+ *
5648
+ * ```ts import.meta.vitest
5649
+ * import { Flag } from "effect/cli"
5650
+ *
5651
+ * // Flag can be used as both --verbose and -v
5652
+ * const verboseFlag = Flag.Boolean("verbose").pipe(
5653
+ * Flag.withAlias("v")
5654
+ * )
5655
+ *
5656
+ * // Multiple aliases can be chained
5657
+ * const helpFlag = Flag.Boolean("help").pipe(
5658
+ * Flag.withAlias("h"),
5659
+ * Flag.withAlias("?")
5660
+ * )
5661
+ * const kinds = [verboseFlag.kind, helpFlag.kind] // => ["flag", "flag"]
5662
+ * ```
5663
+ *
5664
+ * @stability unstable
5665
+ * @category aliasing
5666
+ * @since 4.0.0
5611
5667
  */
5612
- const toFlagDoc = (single, metadata) => {
5613
- const formattedAliases = single.aliases.map((alias) => alias.length === 1 ? `-${alias}` : `--${alias}`);
5614
- return {
5615
- name: single.name,
5616
- aliases: formattedAliases,
5617
- type: single.typeName ?? getTypeName(single.primitiveType),
5618
- description: appendChoiceKeys(single.description, getChoiceKeys(single.primitiveType)),
5619
- required: single.primitiveType._tag !== "Boolean" && !metadata.isOptional
5620
- };
5621
- };
5622
- const appendChoiceKeys = (description, choiceKeys) => {
5623
- if (choiceKeys === void 0 || choiceKeys.length === 0) return description;
5624
- const choiceSuffix = `(choices: ${choiceKeys.join(", ")})`;
5625
- return match$1(description, {
5626
- onNone: () => some(choiceSuffix),
5627
- onSome: (value) => some(`${value} ${choiceSuffix}`)
5628
- });
5629
- };
5668
+ const withAlias = /*#__PURE__*/ dual(2, (self, alias) => withAlias$1(self, alias));
5630
5669
  /**
5631
- * Creates a parser for a given config. Used as the default for both `parse`
5632
- * and `parseContext`, and also by `withSharedFlags` to avoid constructing a
5633
- * full throwaway command.
5670
+ * Adds a description to a flag for help documentation.
5671
+ *
5672
+ * **Example** (Adding help descriptions)
5673
+ *
5674
+ * ```ts import.meta.vitest
5675
+ * import { Flag } from "effect/cli"
5676
+ *
5677
+ * const portFlag = Flag.Int("port").pipe(
5678
+ * Flag.withDescription("The port number to listen on")
5679
+ * )
5680
+ *
5681
+ * const configFlag = Flag.File("config").pipe(
5682
+ * Flag.withDescription("Path to the configuration file")
5683
+ * )
5684
+ * const kinds = [portFlag.kind, configFlag.kind] // => ["flag", "flag"]
5685
+ * ```
5686
+ *
5687
+ * @stability unstable
5688
+ * @category metadata
5689
+ * @since 4.0.0
5634
5690
  */
5635
- const makeParser = (cfg, options) => fnUntraced(function* (input) {
5636
- const parsedArgs = {
5637
- flags: input.flags,
5638
- arguments: input.arguments
5639
- };
5640
- const [remainingArguments, values] = yield* parseParams(parsedArgs, cfg.orderedParams);
5641
- if (options?.allowLeftovers !== true && remainingArguments.length > 0) return yield* new UnexpectedArgument({ arguments: remainingArguments });
5642
- return reconstructTree(cfg.tree, values);
5643
- });
5691
+ const withDescription$1 = /*#__PURE__*/ dual(2, (self, description) => withDescription$3(self, description));
5644
5692
  /**
5645
- * Parses param values from parsed command arguments into their typed
5646
- * representations.
5693
+ * Sets a custom metavar (placeholder name) for the flag in help documentation.
5694
+ *
5695
+ * **Details**
5696
+ *
5697
+ * The metavar is displayed in usage text to indicate what value the user should
5698
+ * provide. For example, `--output FILE` shows `FILE` as the metavar.
5699
+ *
5700
+ * **Example** (Setting metavars)
5701
+ *
5702
+ * ```ts import.meta.vitest
5703
+ * import { Flag } from "effect/cli"
5704
+ *
5705
+ * const databaseFlag = Flag.String("database-url").pipe(
5706
+ * Flag.withMetavar("URL"),
5707
+ * Flag.withDescription("Database connection URL")
5708
+ * )
5709
+ * // In help: --database-url URL
5710
+ *
5711
+ * const timeoutFlag = Flag.Int("timeout").pipe(
5712
+ * Flag.withMetavar("SECONDS")
5713
+ * )
5714
+ * // In help: --timeout SECONDS
5715
+ * const kinds = [databaseFlag.kind, timeoutFlag.kind] // => ["flag", "flag"]
5716
+ * ```
5717
+ *
5718
+ * @stability unstable
5719
+ * @category metadata
5720
+ * @since 4.0.0
5647
5721
  */
5648
- const parseParams = /*#__PURE__*/ fnUntraced(function* (parsedArgs, params) {
5649
- const results = [];
5650
- let currentArguments = parsedArgs.arguments;
5651
- for (const option of params) {
5652
- const [remainingArguments, parsed] = yield* option.parse({
5653
- flags: parsedArgs.flags,
5654
- arguments: currentArguments
5655
- });
5656
- results.push(parsed);
5657
- currentArguments = remainingArguments;
5658
- }
5659
- return [currentArguments, results];
5660
- });
5722
+ const withMetavar = /*#__PURE__*/ dual(2, (self, metavar) => withMetavar$1(self, metavar));
5661
5723
  /**
5662
- * Checks that inherited parent context flags do not reuse names declared by
5663
- * child command flags.
5724
+ * Makes a flag optional, returning an Option type that can be None if not provided.
5664
5725
  *
5665
- * When `contextConfig` is supplied, it is used as the inherited flag set;
5666
- * otherwise the parent's current context config is checked.
5726
+ * **Example** (Making flags optional)
5727
+ *
5728
+ * ```ts import.meta.vitest
5729
+ * import { Effect, FileSystem, Layer, Option, Path, Stdio, Terminal } from "effect"
5730
+ * import { Flag } from "effect/cli"
5731
+ * import { ChildProcessSpawner } from "effect/process"
5732
+ *
5733
+ * const CliTestLayer = Layer.mergeAll(
5734
+ * FileSystem.layerNoop({}),
5735
+ * Path.layer,
5736
+ * Stdio.layerTest({}),
5737
+ * Layer.succeed(Terminal.Terminal, Terminal.make({
5738
+ * columns: Effect.succeed(80),
5739
+ * rows: Effect.succeed(24),
5740
+ * readInput: Effect.die("unused"),
5741
+ * readLine: Effect.die("unused"),
5742
+ * display: () => Effect.void
5743
+ * })),
5744
+ * Layer.succeed(
5745
+ * ChildProcessSpawner.ChildProcessSpawner,
5746
+ * ChildProcessSpawner.make(() => Effect.die("unused"))
5747
+ * )
5748
+ * )
5749
+ *
5750
+ * const optionalPort = Flag.optional(Flag.Int("port"))
5751
+ *
5752
+ * const program = Effect.gen(function*() {
5753
+ * const [, port] = yield* optionalPort.parse({
5754
+ * arguments: [],
5755
+ * flags: { "port": ["4000"] }
5756
+ * })
5757
+ * return port
5758
+ * })
5759
+ *
5760
+ * await Effect.runPromise(program.pipe(Effect.provide(CliTestLayer))) // => Option.some(4000)
5761
+ * ```
5762
+ *
5763
+ * @stability unstable
5764
+ * @category optionality
5765
+ * @since 4.0.0
5667
5766
  */
5668
- const checkForDuplicateFlags = (parent, subcommands, options) => {
5669
- const parentImpl = toImpl(parent);
5670
- const parentOptionNames = /* @__PURE__ */ new Set();
5671
- const extractNames = (flags) => {
5672
- for (const option of flags) {
5673
- const singles = extractSingleParams(option);
5674
- for (const single of singles) parentOptionNames.add(single.name);
5675
- }
5676
- };
5677
- extractNames((options?.contextConfig ?? parentImpl.contextConfig).flags);
5678
- for (const subcommand of subcommands) {
5679
- const subImpl = toImpl(subcommand);
5680
- for (const option of subImpl.config.flags) {
5681
- const singles = extractSingleParams(option);
5682
- for (const single of singles) if (parentOptionNames.has(single.name)) throw new DuplicateOption({
5683
- option: single.name,
5684
- parentCommand: parent.name,
5685
- childCommand: subcommand.name
5686
- });
5687
- }
5688
- }
5689
- };
5690
- //#endregion
5691
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/cli/internal/completions/descriptor.js
5767
+ const optional = (param) => optional$1(param);
5692
5768
  /**
5693
- * CommandDescriptor — pure-data representation of a command tree for
5694
- * shell completion generation.
5769
+ * Provides a default value for a flag when it's not specified.
5695
5770
  *
5696
- * @internal
5771
+ * **Example** (Providing default values)
5772
+ *
5773
+ * ```ts import.meta.vitest
5774
+ * import { Flag } from "effect/cli"
5775
+ *
5776
+ * const portFlag = Flag.Int("port").pipe(
5777
+ * Flag.withDefault(8080)
5778
+ * )
5779
+ * // If --port is not provided, defaults to 8080
5780
+ *
5781
+ * const hostFlag = Flag.String("host").pipe(
5782
+ * Flag.withDefault("localhost")
5783
+ * )
5784
+ * // If --host is not provided, defaults to "localhost"
5785
+ * const kinds = [portFlag.kind, hostFlag.kind] // => ["flag", "flag"]
5786
+ * ```
5787
+ *
5788
+ * @stability unstable
5789
+ * @category optionality
5790
+ * @since 4.0.0
5697
5791
  */
5698
- const toFlagType = (single) => {
5699
- switch (single.primitiveType._tag) {
5700
- case "Boolean": return { _tag: "Boolean" };
5701
- case "Int": return { _tag: "Int" };
5702
- case "Finite": return { _tag: "Finite" };
5703
- case "Date": return { _tag: "Date" };
5704
- case "Choice": return {
5705
- _tag: "Choice",
5706
- values: getChoiceKeys(single.primitiveType) ?? []
5707
- };
5708
- case "Path": return {
5709
- _tag: "Path",
5710
- pathType: getPathType(single.primitiveType) ?? "either"
5711
- };
5712
- case "FileText":
5713
- case "FileParse":
5714
- case "FileSchema": return {
5715
- _tag: "Path",
5716
- pathType: "file"
5717
- };
5718
- default: return { _tag: "String" };
5719
- }
5720
- };
5721
- const toArgumentType = (single) => {
5722
- switch (single.primitiveType._tag) {
5723
- case "Int": return { _tag: "Int" };
5724
- case "Finite": return { _tag: "Finite" };
5725
- case "Date": return { _tag: "Date" };
5726
- case "Choice": return {
5727
- _tag: "Choice",
5728
- values: getChoiceKeys(single.primitiveType) ?? []
5729
- };
5730
- case "Path": return {
5731
- _tag: "Path",
5732
- pathType: getPathType(single.primitiveType) ?? "either"
5733
- };
5734
- case "FileText":
5735
- case "FileParse":
5736
- case "FileSchema": return {
5737
- _tag: "Path",
5738
- pathType: "file"
5739
- };
5740
- default: return { _tag: "String" };
5741
- }
5742
- };
5792
+ const withDefault = withDefault$1;
5743
5793
  /**
5744
- * @internal
5794
+ * Adds a fallback config that is loaded when a required flag is missing.
5795
+ *
5796
+ * **Example** (Falling back to config)
5797
+ *
5798
+ * ```ts import.meta.vitest
5799
+ * import { Config } from "effect"
5800
+ * import { Flag } from "effect/cli"
5801
+ *
5802
+ * const verbose = Flag.Boolean("verbose").pipe(
5803
+ * Flag.withFallbackConfig(Config.Boolean("VERBOSE"))
5804
+ * )
5805
+ * verbose.kind // => "flag"
5806
+ * ```
5807
+ *
5808
+ * @stability unstable
5809
+ * @category combinators
5810
+ * @since 4.0.0
5745
5811
  */
5746
- const fromCommand = (cmd, inheritedFlags = []) => {
5747
- const impl = toImpl(cmd);
5748
- const config = impl.config;
5749
- const flags = [];
5750
- const seen = /* @__PURE__ */ new Set();
5751
- for (const [index, flag] of [...config.flags, ...inheritedFlags].entries()) {
5752
- const singles = extractSingleParams(flag);
5753
- for (const single of singles) {
5754
- if (single.kind !== "flag") continue;
5755
- if (single.hidden) continue;
5756
- if (index >= config.flags.length && seen.has(single.name)) continue;
5757
- seen.add(single.name);
5758
- flags.push({
5759
- name: single.name,
5760
- aliases: single.aliases,
5761
- description: getOrUndefined(single.description),
5762
- type: toFlagType(single)
5763
- });
5764
- }
5765
- }
5766
- const args = [];
5767
- for (const arg of config.arguments) {
5768
- const singles = extractSingleParams(arg);
5769
- const metadata = getParamMetadata(arg);
5770
- for (const single of singles) {
5771
- if (single.kind !== "argument") continue;
5772
- args.push({
5773
- name: single.name,
5774
- description: getOrUndefined(single.description),
5775
- required: !metadata.isOptional,
5776
- variadic: metadata.isVariadic,
5777
- type: toArgumentType(single)
5778
- });
5779
- }
5780
- }
5781
- const subcommands = [];
5782
- const sharedFlags = [...inheritedFlags, ...impl.contextConfig.flags];
5783
- for (const group of cmd.subcommands) for (const subcommand of group.commands) {
5784
- if (subcommand.unlisted) continue;
5785
- const descriptor = fromCommand(subcommand, sharedFlags);
5786
- subcommands.push(descriptor);
5787
- if (subcommand.alias && subcommand.alias !== subcommand.name) subcommands.push({
5788
- ...descriptor,
5789
- name: subcommand.alias
5790
- });
5791
- }
5792
- return {
5793
- name: cmd.name,
5794
- description: cmd.shortDescription ?? cmd.description,
5795
- flags,
5796
- arguments: args,
5797
- subcommands
5798
- };
5799
- };
5812
+ const withFallbackConfig = /*#__PURE__*/ dual(2, (self, config) => withFallbackConfig$1(self, config));
5800
5813
  //#endregion
5801
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/cli/internal/help.js
5814
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/cli/internal/help.js
5802
5815
  /**
5803
5816
  * Help Documentation
5804
5817
  * ================
@@ -5908,7 +5921,7 @@ const getHelpForCommandPath = (command, commandPath, builtIns) => gen(function*
5908
5921
  };
5909
5922
  });
5910
5923
  //#endregion
5911
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/cli/GlobalFlag.js
5924
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/cli/GlobalFlag.js
5912
5925
  /**
5913
5926
  * Global flags for Effect CLI command trees. Global flags are parsed outside a
5914
5927
  * single command's local flags and can apply to a command and its descendants.
@@ -6091,7 +6104,7 @@ const BuiltIns = [
6091
6104
  LogLevel
6092
6105
  ];
6093
6106
  //#endregion
6094
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/cli/CliConfig.js
6107
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/cli/CliConfig.js
6095
6108
  /**
6096
6109
  * Configuration for Effect CLI command execution.
6097
6110
  *
@@ -6121,7 +6134,7 @@ var CliConfig = class extends (/*#__PURE__*/ Reference("effect/cli/CliConfig", {
6121
6134
  */
6122
6135
  const defaults = { builtIns: BuiltIns };
6123
6136
  //#endregion
6124
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/cli/internal/lexer.js
6137
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/cli/internal/lexer.js
6125
6138
  /**
6126
6139
  * @internal
6127
6140
  */
@@ -6183,7 +6196,7 @@ const lexTokens = (args) => {
6183
6196
  return tokens;
6184
6197
  };
6185
6198
  //#endregion
6186
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/cli/internal/auto-suggest.js
6199
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/cli/internal/auto-suggest.js
6187
6200
  /**
6188
6201
  * Simple Levenshtein distance implementation (small N, no perf worries)
6189
6202
  */
@@ -6211,7 +6224,7 @@ const suggest = (input, candidates) => {
6211
6224
  return distances.filter(([d]) => d === minDistance).map(([, c]) => c);
6212
6225
  };
6213
6226
  //#endregion
6214
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/cli/internal/parser.js
6227
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/cli/internal/parser.js
6215
6228
  /**
6216
6229
  * Parsing Pipeline for CLI Commands
6217
6230
  * ==================================
@@ -6397,8 +6410,9 @@ const asBooleanLiteral = (token) => token?._tag === "Value" && (isTrueLiteral(to
6397
6410
  *
6398
6411
  * Value resolution order:
6399
6412
  * 1. Inline value: --flag=value or -f=value
6400
- * 2. Boolean special case: implicit "true" or explicit boolean literal
6401
- * 3. Next token: consume following Value token if present
6413
+ * 2. Optional value: the flag's configured value, without consuming a token
6414
+ * 3. Boolean special case: implicit "true" or explicit boolean literal
6415
+ * 4. Next token: consume following Value token if present
6402
6416
  */
6403
6417
  const consumeFlagValue = (cursor, token, spec, negated = false) => {
6404
6418
  const consumed = consumeFlagValueWithTokens(cursor, token, spec, negated);
@@ -6420,7 +6434,7 @@ const consumeFlagValueWithTokens = (cursor, token, spec, negated = false) => {
6420
6434
  error: invalidNegatedFlagValue(token, spec, token.value),
6421
6435
  tokens: []
6422
6436
  };
6423
- const literal = asBooleanLiteral(cursor.peek());
6437
+ const literal = spec.optionalValue === void 0 ? asBooleanLiteral(cursor.peek()) : void 0;
6424
6438
  if (literal !== void 0) {
6425
6439
  const literalToken = cursor.take();
6426
6440
  return {
@@ -6440,6 +6454,11 @@ const consumeFlagValueWithTokens = (cursor, token, spec, negated = false) => {
6440
6454
  value: token.value,
6441
6455
  tokens: []
6442
6456
  };
6457
+ if (spec.optionalValue !== void 0) return {
6458
+ _tag: "Value",
6459
+ value: spec.optionalValue,
6460
+ tokens: []
6461
+ };
6443
6462
  if (isBoolean(spec.primitiveType)) {
6444
6463
  const literal = asBooleanLiteral(cursor.peek());
6445
6464
  const literalToken = literal !== void 0 ? cursor.take() : void 0;
@@ -6743,7 +6762,7 @@ const scanCommandLevel = (tokens, context) => {
6743
6762
  return toLeafResult(state);
6744
6763
  };
6745
6764
  //#endregion
6746
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/cli/internal/wizard.js
6765
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/cli/internal/wizard.js
6747
6766
  const run$1 = /*#__PURE__*/ fnUntraced(function* (command, options) {
6748
6767
  const commandPath = options?.commandPath ?? [command.name];
6749
6768
  const selected = getCommandAtPath(command, commandPath);
@@ -6826,7 +6845,7 @@ const promptParam = /*#__PURE__*/ fnUntraced(function* (param) {
6826
6845
  yield* param.parse(parsed);
6827
6846
  yield* log();
6828
6847
  if (single.kind === "argument") return values;
6829
- return values.flatMap((value) => value.value.startsWith("-") && value.value.length > 1 ? [commandLineArg(`--${single.name}=${value.value}`, `--${single.name}=${value.displayValue}`)] : [commandLineArg(`--${single.name}`), value]);
6848
+ return values.flatMap((value) => single.optionalValue !== void 0 || value.value.startsWith("-") && value.value.length > 1 ? [commandLineArg(`--${single.name}=${value.value}`, `--${single.name}=${value.displayValue}`)] : [commandLineArg(`--${single.name}`), value]);
6830
6849
  });
6831
6850
  const promptSingle = (single) => {
6832
6851
  const message = renderParamMessage(single);
@@ -6914,7 +6933,7 @@ const wrapCommand = (commandLine) => {
6914
6933
  };
6915
6934
  const formatShellArg = (arg) => /^[A-Za-z0-9_./:@%+=,-]+$/.test(arg) ? arg : `'${arg.replaceAll("'", `'"'"'`)}'`;
6916
6935
  //#endregion
6917
- //#region ../../node_modules/.pnpm/effect@4.0.4/node_modules/effect/dist/cli/Command.js
6936
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/cli/Command.js
6918
6937
  /**
6919
6938
  * Returns `true` if the provided value is a `Command`.
6920
6939
  *
@@ -7523,11 +7542,12 @@ const runWith = (command, config) => {
7523
7542
  };
7524
7543
  //#endregion
7525
7544
  //#region package.json
7526
- var version = "0.1.1076";
7545
+ var version = "0.1.1079";
7527
7546
  //#endregion
7528
7547
  //#region src/main.cli.ts
7529
7548
  function section(title, text) {
7530
- return isEmpty(text) ? "" : `## ${title}\n\n${text}`;
7549
+ if (isEmpty(text)) return "";
7550
+ return `## ${title}\n\n${text}`;
7531
7551
  }
7532
7552
  const save = pipe(make("save", {
7533
7553
  entry: pipe(String$2("text"), withDescription$2("A link, or the text of a note")),