@savvy-web/silk 3.4.1 → 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import { builtinModules, createRequire } from "node:module";
2
- import { Context, Data, Duration, Effect, Equal, Exit, FileSystem, Function, Hash, HashMap, Layer, Option, Order, Path, Pipeable, PlatformError, Predicate, Result, Schema, SchemaIssue, SchemaTransformation, Stream } from "effect";
2
+ import { Context, Data, Duration, Effect, Equal, Exit, FileSystem, Function, Hash, HashMap, Layer, Option, Order, Path, Pipeable, PlatformError, Predicate, Redacted, Ref, Result, Schema, SchemaIssue, SchemaTransformation, Stdio, Stream } from "effect";
3
3
  import * as path$1 from "node:path";
4
4
  import { basename, delimiter, dirname, isAbsolute, join, normalize, relative, resolve } from "node:path";
5
5
  import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
@@ -2352,7 +2352,7 @@ var GlobSet = class GlobSet extends Schema.Class("GlobSet")(Schema.Struct({ patt
2352
2352
  };
2353
2353
 
2354
2354
  //#endregion
2355
- //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._ff048038a9678f5144f817ad24d8f96e/node_modules/@effected/lockfiles/BunExtension.js
2355
+ //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._3c1784fba62fde9a5bac4cf15387fd04/node_modules/@effected/lockfiles/BunExtension.js
2356
2356
  /**
2357
2357
  * Extension data specific to bun lockfiles, attached to `Lockfile.extension`
2358
2358
  * when the format is `"bun"`.
@@ -2374,7 +2374,7 @@ var BunExtension = class extends Schema.Class("BunExtension")({
2374
2374
  }) {};
2375
2375
 
2376
2376
  //#endregion
2377
- //#region ../../node_modules/.pnpm/@effected+npm@0.8.2_@effected+semver@0.3.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/npm/CatalogResolver.js
2377
+ //#region ../../node_modules/.pnpm/@effected+npm@0.8.3_@effected+semver@0.3.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/npm/CatalogResolver.js
2378
2378
  /**
2379
2379
  * Contract for resolving pnpm `catalog:` dependency specifiers to concrete
2380
2380
  * version ranges.
@@ -2421,7 +2421,7 @@ var CatalogResolver = class CatalogResolver extends Context.Service()("@effected
2421
2421
  };
2422
2422
 
2423
2423
  //#endregion
2424
- //#region ../../node_modules/.pnpm/@effected+npm@0.8.2_@effected+semver@0.3.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/npm/WorkspaceResolver.js
2424
+ //#region ../../node_modules/.pnpm/@effected+npm@0.8.3_@effected+semver@0.3.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/npm/WorkspaceResolver.js
2425
2425
  /**
2426
2426
  * Raised when a `catalog:` or `workspace:` specifier cannot be resolved
2427
2427
  * because the resolution mechanism itself failed — not for an ordinary
@@ -2483,7 +2483,7 @@ var WorkspaceResolver = class WorkspaceResolver extends Context.Service()("@effe
2483
2483
  };
2484
2484
 
2485
2485
  //#endregion
2486
- //#region ../../node_modules/.pnpm/@effected+npm@0.8.2_@effected+semver@0.3.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/npm/CatalogAssemblyError.js
2486
+ //#region ../../node_modules/.pnpm/@effected+npm@0.8.3_@effected+semver@0.3.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/npm/CatalogAssemblyError.js
2487
2487
  /**
2488
2488
  * Raised when a workspace's catalogs cannot be assembled — a `pnpm-workspace.yaml`
2489
2489
  * that is unreadable or not valid YAML, a root `package.json` `workspaces` field
@@ -2528,7 +2528,7 @@ var CatalogAssemblyError = class extends Schema.TaggedErrorClass()("CatalogAssem
2528
2528
  };
2529
2529
 
2530
2530
  //#endregion
2531
- //#region ../../node_modules/.pnpm/@effected+npm@0.8.2_@effected+semver@0.3.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/npm/DependencySection.js
2531
+ //#region ../../node_modules/.pnpm/@effected+npm@0.8.3_@effected+semver@0.3.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/npm/DependencySection.js
2532
2532
  /**
2533
2533
  * The short dependency kind: which dependency map an entry came from, named the
2534
2534
  * way consumers branch on it.
@@ -4152,7 +4152,7 @@ const isComparatorSetSubset = (sub, sup) => {
4152
4152
  };
4153
4153
 
4154
4154
  //#endregion
4155
- //#region ../../node_modules/.pnpm/@effected+npm@0.8.2_@effected+semver@0.3.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/npm/DependencySpecifier.js
4155
+ //#region ../../node_modules/.pnpm/@effected+npm@0.8.3_@effected+semver@0.3.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/npm/DependencySpecifier.js
4156
4156
  /**
4157
4157
  * Indicates that a string could not be parsed as a valid dependency specifier.
4158
4158
  *
@@ -4360,7 +4360,7 @@ const DependencySpecifier = Object.assign(brandedSpecifier, {
4360
4360
  });
4361
4361
 
4362
4362
  //#endregion
4363
- //#region ../../node_modules/.pnpm/@effected+npm@0.8.2_@effected+semver@0.3.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/npm/IntegrityHash.js
4363
+ //#region ../../node_modules/.pnpm/@effected+npm@0.8.3_@effected+semver@0.3.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/npm/IntegrityHash.js
4364
4364
  const SRI_RE = /^(sha1|sha256|sha384|sha512)-[A-Za-z0-9+/]+={0,2}$/;
4365
4365
  const COREPACK_RE = /^(sha1|sha224|sha256|sha384|sha512)\.[0-9a-f]+$/;
4366
4366
  const YARN_RE = /^[0-9]+(c[0-9]+)?\/[0-9a-f]+$/;
@@ -4466,7 +4466,7 @@ const IntegrityHash = Object.assign(brandedIntegrity, {
4466
4466
  const CorepackIntegrityHash = brandedIntegrity.pipe(Schema.check(Schema.makeFilter((value) => isCorepack(value) ? void 0 : "Expected a corepack (<algo>.<hex>) integrity hash")));
4467
4467
 
4468
4468
  //#endregion
4469
- //#region ../../node_modules/.pnpm/@effected+commands@0.2.1_effect@4.0.0-beta.101/node_modules/@effected/commands/LocalExec.js
4469
+ //#region ../../node_modules/.pnpm/@effected+commands@0.3.1_effect@4.0.0-beta.101/node_modules/@effected/commands/LocalExec.js
4470
4470
  /**
4471
4471
  * The package managers whose project-local exec argv this package knows.
4472
4472
  *
@@ -4675,7 +4675,681 @@ var LocalExec = class LocalExec extends Context.Service()("@effected/commands/Lo
4675
4675
  };
4676
4676
 
4677
4677
  //#endregion
4678
- //#region ../../node_modules/.pnpm/@effected+npm@0.8.2_@effected+semver@0.3.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/npm/ReleaseAgeGate.js
4678
+ //#region ../../node_modules/.pnpm/@effected+commands@0.3.1_effect@4.0.0-beta.101/node_modules/@effected/commands/Redaction.js
4679
+ /**
4680
+ * Argument tokens whose *following* positional (or `=`-joined value) is a
4681
+ * secret. Lowercase; matching is case-insensitive.
4682
+ *
4683
+ * @remarks
4684
+ * This is the heuristic backstop, not the primary mechanism — it can only know
4685
+ * about flags someone thought to list. The primary mechanism is
4686
+ * {@link Redaction.applyArgs}, which redacts by **value**: the caller says what
4687
+ * its secrets are and every occurrence goes, whatever flag carried it.
4688
+ *
4689
+ * @public
4690
+ */
4691
+ const SECRET_FLAGS = /* @__PURE__ */ new Set([
4692
+ "--access-token",
4693
+ "--api-key",
4694
+ "--auth",
4695
+ "--auth-token",
4696
+ "--otp",
4697
+ "--password",
4698
+ "--registry-token",
4699
+ "--token"
4700
+ ]);
4701
+ /**
4702
+ * npm config keys whose value is a credential (`//registry/:_authToken`,
4703
+ * `//registry/:_password`).
4704
+ */
4705
+ const AUTH_KEY = /:(?:_authtoken|_password)$/i;
4706
+ /**
4707
+ * The distinct, non-empty secret values, longest first.
4708
+ *
4709
+ * @remarks
4710
+ * Longest-first is load-bearing: redacting `"ab"` before `"abcd"` rewrites
4711
+ * `"abcd"` to `"***cd"`, leaking `"cd"` — a fragment of the longer secret.
4712
+ * Empty values are dropped because `"abc".split("").join("***")` would insert
4713
+ * the placeholder between every character.
4714
+ */
4715
+ const prepare = (secrets) => [...new Set(secrets.map(Redacted.value))].filter((value) => value.length > 0).sort((a, b) => b.length - a.length);
4716
+ /** Replaces each prepared value with {@link REDACTED}, literally (never as a pattern). */
4717
+ const replaceAll = (text, values) => {
4718
+ let out = text;
4719
+ for (const value of values) out = out.split(value).join("***");
4720
+ return out;
4721
+ };
4722
+ const apply = (text, secrets) => secrets.length === 0 ? text : replaceAll(text, prepare(secrets));
4723
+ const applyArgs = (args, secrets) => {
4724
+ if (secrets.length === 0) return args;
4725
+ const values = prepare(secrets);
4726
+ return args.map((arg) => replaceAll(arg, values));
4727
+ };
4728
+ /** Whether `name` introduces a credential value. */
4729
+ const isSecretName = (name, extra) => {
4730
+ const lower = name.toLowerCase();
4731
+ return SECRET_FLAGS.has(lower) || extra.has(lower) || AUTH_KEY.test(name);
4732
+ };
4733
+ const scrubArgs = (args, options) => {
4734
+ const extra = new Set((options?.flags ?? []).map((flag) => flag.toLowerCase()));
4735
+ const out = [];
4736
+ for (let index = 0; index < args.length; index++) {
4737
+ const arg = args[index] ?? "";
4738
+ const equals = arg.indexOf("=");
4739
+ if (equals > 0 && isSecretName(arg.slice(0, equals), extra)) {
4740
+ out.push(`${arg.slice(0, equals)}=***`);
4741
+ continue;
4742
+ }
4743
+ out.push(arg);
4744
+ if (isSecretName(arg, extra) && index + 1 < args.length) {
4745
+ out.push("***");
4746
+ index++;
4747
+ }
4748
+ }
4749
+ return out;
4750
+ };
4751
+ /**
4752
+ * Secret scrubbing for command arguments and captured output.
4753
+ *
4754
+ * @remarks
4755
+ * Two mechanisms, deliberately layered. {@link Redaction.apply} and
4756
+ * {@link Redaction.applyArgs} redact **by value** — the caller declares its
4757
+ * secrets as `Redacted` and every occurrence is removed wherever it appears.
4758
+ * {@link Redaction.scrubArgs} is a **flag heuristic** that runs in addition, for
4759
+ * the secrets a caller forgot to declare.
4760
+ *
4761
+ * @public
4762
+ */
4763
+ var Redaction = class {
4764
+ constructor() {}
4765
+ /**
4766
+ * Replaces every occurrence of every secret's value in `text` with
4767
+ * {@link REDACTED}.
4768
+ *
4769
+ * @remarks
4770
+ * Exact, literal matching — no pattern compilation, no encoding-aware search. A
4771
+ * secret that reaches the text base64-encoded, URL-encoded, or split across a
4772
+ * line break is **not** found; declare the encoded form as a secret too if that
4773
+ * is a real risk.
4774
+ *
4775
+ * A secret composed only of the placeholder's own characters (`*`, `**`, `***`)
4776
+ * cannot be fully removed, because the replacement reintroduces it. That is a
4777
+ * documented limitation, not a defect.
4778
+ */
4779
+ static apply = apply;
4780
+ /**
4781
+ * {@link Redaction.apply} over each entry of an argv array. An entry is
4782
+ * redacted whether it *is* a secret or merely *contains* one
4783
+ * (`--url=https://u:s3cr3t@host`).
4784
+ */
4785
+ static applyArgs = applyArgs;
4786
+ /**
4787
+ * Heuristic backstop: redact any argv value that is introduced by a known
4788
+ * secret-bearing flag or npm auth key, in either the separated
4789
+ * (`--token abc`) or inline (`--token=abc`) form.
4790
+ *
4791
+ * @remarks
4792
+ * This catches secrets the caller forgot to declare; it cannot catch a flag
4793
+ * nobody listed. Prefer {@link Redaction.applyArgs} with the actual
4794
+ * `Redacted` values — this runs *in addition*, never instead.
4795
+ */
4796
+ static scrubArgs = scrubArgs;
4797
+ /** Flags treated as secret-bearing by {@link Redaction.scrubArgs}. See {@link SECRET_FLAGS}. */
4798
+ static SECRET_FLAGS = SECRET_FLAGS;
4799
+ };
4800
+
4801
+ //#endregion
4802
+ //#region ../../node_modules/.pnpm/@effected+commands@0.3.1_effect@4.0.0-beta.101/node_modules/@effected/commands/internal/capture.js
4803
+ /**
4804
+ * Raised when a captured stream exceeds its byte budget.
4805
+ *
4806
+ * @remarks
4807
+ * Internal and never exported from the package: `Run` maps it to the public
4808
+ * `CommandOutputError`. `Data.TaggedError` is appropriate precisely because it
4809
+ * never escapes — it is an in-process signal, not a contract.
4810
+ */
4811
+ var OutputTooLarge = class extends Data.TaggedError("OutputTooLarge") {};
4812
+ /**
4813
+ * Collects a byte stream into a string, failing once more than `limit` bytes
4814
+ * have arrived.
4815
+ *
4816
+ * @remarks
4817
+ * The budget is enforced **during** accumulation, not after: checking the
4818
+ * length of an already-collected string would mean the memory was already
4819
+ * spent, which is the exact failure the budget exists to prevent. Counting is
4820
+ * on raw bytes, before decoding, because bytes are what the process actually
4821
+ * produced.
4822
+ */
4823
+ const collectBounded = (stream, limit) => Effect.gen(function* () {
4824
+ const seen = yield* Ref.make(0);
4825
+ const bounded = Stream.mapEffect(stream, (chunk) => Effect.flatMap(Ref.updateAndGet(seen, (total) => total + chunk.length), (total) => total > limit ? Effect.fail(new OutputTooLarge({ limit })) : Effect.succeed(chunk)));
4826
+ return yield* Stream.mkString(Stream.decodeText(bounded));
4827
+ });
4828
+
4829
+ //#endregion
4830
+ //#region ../../node_modules/.pnpm/@effected+commands@0.3.1_effect@4.0.0-beta.101/node_modules/@effected/commands/Run.js
4831
+ /**
4832
+ * Default ceiling on captured bytes per stream (16 MiB).
4833
+ *
4834
+ * @remarks
4835
+ * Collecting a child's output without a bound is a memory-exhaustion vector.
4836
+ * Output genuinely larger than this belongs on {@link Run.stream}, which never
4837
+ * accumulates.
4838
+ *
4839
+ * @public
4840
+ */
4841
+ const DEFAULT_MAX_OUTPUT_BYTES = 16777216;
4842
+ /** Characters shown from the tail of captured output in an error message. */
4843
+ const MAX_MESSAGE_CHARS = 2e3;
4844
+ /**
4845
+ * What one completed run produced.
4846
+ *
4847
+ * @public
4848
+ */
4849
+ var CommandOutput = class extends Schema.Class("CommandOutput")({
4850
+ /** Captured standard output, redacted. */
4851
+ stdout: Schema.String,
4852
+ /** Captured standard error, redacted. */
4853
+ stderr: Schema.String,
4854
+ /** The process exit code. A non-zero value is NOT an error at this level. */
4855
+ exitCode: Schema.Number
4856
+ }) {
4857
+ /** Whether the process exited zero. */
4858
+ get succeeded() {
4859
+ return this.exitCode === 0;
4860
+ }
4861
+ };
4862
+ /** The executable and argv an error should report for `command`. */
4863
+ const describeCommand = (command) => {
4864
+ if (ChildProcess.isStandardCommand(command)) return {
4865
+ command: command.command,
4866
+ args: command.args
4867
+ };
4868
+ const left = describeCommand(command.left);
4869
+ const right = describeCommand(command.right);
4870
+ return {
4871
+ command: `${left.command} | ${right.command}`,
4872
+ args: []
4873
+ };
4874
+ };
4875
+ /** argv as an error should store it: declared secrets removed, then the flag heuristic. */
4876
+ const safeArgs = (args, secrets) => Redaction.scrubArgs(Redaction.applyArgs(args, secrets ?? []));
4877
+ /** Captured text as an error should store it. */
4878
+ const safeText = (text, secrets) => Redaction.apply(text, secrets ?? []);
4879
+ /** Tail-bounded rendering: tools write warnings first and the real error last. */
4880
+ const tail = (text) => {
4881
+ const trimmed = text.trim();
4882
+ if (trimmed.length <= MAX_MESSAGE_CHARS) return trimmed;
4883
+ return `...[${trimmed.length - MAX_MESSAGE_CHARS} chars truncated from head]...\n${trimmed.slice(-2e3)}`;
4884
+ };
4885
+ /**
4886
+ * A command that could not be run, or that ran and failed.
4887
+ *
4888
+ * @remarks
4889
+ * `kind` is the routing surface, never the message: `"nonZero"` (the process
4890
+ * ran and exited non-zero), `"spawn"` (it never started — the executable is
4891
+ * missing, or the platform refused), `"timeout"` (a caller-supplied ceiling
4892
+ * elapsed). Composed retry and fallback logic branches on `kind`; nothing in
4893
+ * this package asks a caller to match on prose.
4894
+ *
4895
+ * `args` is **always** stored redacted.
4896
+ *
4897
+ * @public
4898
+ */
4899
+ var CommandFailedError = class CommandFailedError extends Schema.TaggedErrorClass()("CommandFailedError", {
4900
+ /** Why it failed. */
4901
+ kind: Schema.Literals([
4902
+ "nonZero",
4903
+ "spawn",
4904
+ "timeout"
4905
+ ]),
4906
+ /** The executable (or `"a | b"` for a pipeline). */
4907
+ command: Schema.String,
4908
+ /** argv, redacted. */
4909
+ args: Schema.Array(Schema.String),
4910
+ /** The exit code, when the process ran. */
4911
+ exitCode: Schema.optionalKey(Schema.Number),
4912
+ /** Captured standard error, redacted, when the process ran. */
4913
+ stderr: Schema.optionalKey(Schema.String),
4914
+ /** Captured standard output, redacted, when the process ran. */
4915
+ stdout: Schema.optionalKey(Schema.String),
4916
+ /** The absorbed platform failure, for `"spawn"`. */
4917
+ cause: Schema.optionalKey(Schema.Defect())
4918
+ }) {
4919
+ /** The process ran and exited non-zero. */
4920
+ static nonZero = (command, output, secrets) => {
4921
+ const described = describeCommand(command);
4922
+ return new CommandFailedError({
4923
+ kind: "nonZero",
4924
+ command: described.command,
4925
+ args: safeArgs(described.args, secrets),
4926
+ exitCode: output.exitCode,
4927
+ stderr: output.stderr,
4928
+ stdout: output.stdout
4929
+ });
4930
+ };
4931
+ /** The process never started. */
4932
+ static spawn = (command, cause, secrets) => {
4933
+ const described = describeCommand(command);
4934
+ return new CommandFailedError({
4935
+ kind: "spawn",
4936
+ command: described.command,
4937
+ args: safeArgs(described.args, secrets),
4938
+ cause
4939
+ });
4940
+ };
4941
+ /** A caller-supplied ceiling elapsed; the child was killed with its scope. */
4942
+ static timedOut = (command, secrets) => {
4943
+ const described = describeCommand(command);
4944
+ return new CommandFailedError({
4945
+ kind: "timeout",
4946
+ command: described.command,
4947
+ args: safeArgs(described.args, secrets)
4948
+ });
4949
+ };
4950
+ /**
4951
+ * Whether this is a spawn failure caused by the executable not existing —
4952
+ * the structural "tool is not installed" signal.
4953
+ */
4954
+ get notFound() {
4955
+ return this.kind === "spawn" && this.cause instanceof PlatformError.PlatformError && this.cause.reason._tag === "NotFound";
4956
+ }
4957
+ /** Names the command and surfaces the tail of whichever stream carries the cause. */
4958
+ get message() {
4959
+ const parts = [`Command "${this.args.length > 0 ? `${this.command} ${this.args.join(" ")}` : this.command}" failed`];
4960
+ if (this.kind === "timeout") parts.push("(timed out)");
4961
+ if (this.exitCode !== void 0) parts.push(`(exit ${this.exitCode})`);
4962
+ const stream = this.stderr?.trim() ? this.stderr : this.stdout?.trim() ? this.stdout : void 0;
4963
+ if (stream !== void 0) parts.push(`:\n${tail(stream)}`);
4964
+ return parts.join(" ");
4965
+ }
4966
+ };
4967
+ /**
4968
+ * A command ran, but its output could not be used.
4969
+ *
4970
+ * @remarks
4971
+ * Separate from {@link CommandFailedError} because the process itself
4972
+ * succeeded: `"notJson"` (stdout is not JSON), `"schema"` (it is JSON but does
4973
+ * not decode), `"tooLarge"` (capture exceeded its byte budget). Keeping the two
4974
+ * distinguishable is the point — a schema drift and a crashed tool call for
4975
+ * different responses.
4976
+ *
4977
+ * The context fields (`exitCode`, `stderr`, `stdout`) are populated by
4978
+ * {@link Run.jsonLine}, whose payload framing parses regardless of exit code —
4979
+ * when no payload arrives, the exit code and captured streams are the only
4980
+ * evidence of what actually went wrong. Both streams are **always** stored
4981
+ * redacted.
4982
+ *
4983
+ * @public
4984
+ */
4985
+ var CommandOutputError = class extends Schema.TaggedErrorClass()("CommandOutputError", {
4986
+ /** Which way the output was unusable. */
4987
+ kind: Schema.Literals([
4988
+ "notJson",
4989
+ "schema",
4990
+ "tooLarge"
4991
+ ]),
4992
+ /** The executable that produced it. */
4993
+ command: Schema.String,
4994
+ /** The underlying parse or decode failure. */
4995
+ cause: Schema.optionalKey(Schema.Defect()),
4996
+ /** The exit code, when the combinator parses independently of it. */
4997
+ exitCode: Schema.optionalKey(Schema.Number),
4998
+ /** Captured standard error, redacted, when the process ran. */
4999
+ stderr: Schema.optionalKey(Schema.String),
5000
+ /** Captured standard output, redacted, when the process ran. */
5001
+ stdout: Schema.optionalKey(Schema.String)
5002
+ }) {
5003
+ get message() {
5004
+ const parts = [];
5005
+ if (this.kind === "notJson") parts.push(`Command "${this.command}" did not produce JSON`);
5006
+ else if (this.kind === "schema") parts.push(`Command "${this.command}" produced JSON that did not match the expected schema`);
5007
+ else parts.push(`Command "${this.command}" produced more output than the configured limit`);
5008
+ if (this.exitCode !== void 0) parts.push(`(exit ${this.exitCode})`);
5009
+ if (this.stderr !== void 0 && this.stderr.trim().length > 0) parts.push(`:\n${tail(this.stderr)}`);
5010
+ return parts.join(" ");
5011
+ }
5012
+ };
5013
+ /** Spawns, collects both streams concurrently, and awaits exit. */
5014
+ const collectRaw = (command, options, tee) => Effect.scoped(Effect.gen(function* () {
5015
+ const handle = yield* (yield* ChildProcessSpawner.ChildProcessSpawner).spawn(command);
5016
+ const limit = options?.maxOutputBytes ?? 16777216;
5017
+ const out = tee === void 0 ? handle.stdout : Stream.tapSink(handle.stdout, tee.stdout());
5018
+ const err = tee === void 0 ? handle.stderr : Stream.tapSink(handle.stderr, tee.stderr());
5019
+ const [stdout, stderr, exitCode] = yield* Effect.all([
5020
+ collectBounded(out, limit),
5021
+ collectBounded(err, limit),
5022
+ handle.exitCode
5023
+ ], { concurrency: "unbounded" });
5024
+ const secrets = options?.redact;
5025
+ return CommandOutput.make({
5026
+ stdout: safeText(stdout, secrets),
5027
+ stderr: safeText(stderr, secrets),
5028
+ exitCode: Number(exitCode)
5029
+ });
5030
+ }));
5031
+ /** Maps the raw failure modes onto this package's taxonomy, and applies any ceiling. */
5032
+ const collectClassified = (command, options, tee) => {
5033
+ const described = describeCommand(command);
5034
+ const classified = collectRaw(command, options, tee).pipe(Effect.catch((error) => Effect.fail(error instanceof OutputTooLarge ? new CommandOutputError({
5035
+ kind: "tooLarge",
5036
+ command: described.command,
5037
+ cause: error
5038
+ }) : CommandFailedError.spawn(command, error, options?.redact))));
5039
+ return options?.timeout === void 0 ? classified : Effect.timeoutOrElse(classified, {
5040
+ duration: options.timeout,
5041
+ orElse: () => Effect.fail(CommandFailedError.timedOut(command, options.redact))
5042
+ });
5043
+ };
5044
+ /** Fails a run whose process exited non-zero. */
5045
+ const requireZero = (command, output, options) => output.succeeded ? Effect.succeed(output) : Effect.fail(CommandFailedError.nonZero(command, output, options?.redact));
5046
+ /** Span attributes: what ran and how many arguments — never the arguments. */
5047
+ const annotate = (command) => {
5048
+ const described = describeCommand(command);
5049
+ return Effect.annotateCurrentSpan({
5050
+ command: described.command,
5051
+ argc: described.args.length
5052
+ });
5053
+ };
5054
+ const collect = Effect.fn("Run.collect")(function* (command, options) {
5055
+ yield* annotate(command);
5056
+ return yield* collectClassified(command, options, void 0);
5057
+ });
5058
+ const collectTee = Effect.fn("Run.collectTee")(function* (command, options) {
5059
+ yield* annotate(command);
5060
+ const stdio = yield* Stdio.Stdio;
5061
+ return yield* collectClassified(command, options, stdio);
5062
+ });
5063
+ const text$4 = Effect.fn("Run.text")(function* (command, options) {
5064
+ yield* annotate(command);
5065
+ const output = yield* collectClassified(command, options, void 0);
5066
+ return (yield* requireZero(command, output, options)).stdout.trim();
5067
+ });
5068
+ const lines = Effect.fn("Run.lines")(function* (command, options) {
5069
+ yield* annotate(command);
5070
+ const output = yield* collectClassified(command, options, void 0);
5071
+ return (yield* requireZero(command, output, options)).stdout.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
5072
+ });
5073
+ const json = Effect.fn("Run.json")(function* (command, schema, options) {
5074
+ yield* annotate(command);
5075
+ const described = describeCommand(command);
5076
+ const output = yield* collectClassified(command, options, void 0);
5077
+ const checked = yield* requireZero(command, output, options);
5078
+ const parsed = yield* Effect.try({
5079
+ try: () => JSON.parse(checked.stdout),
5080
+ catch: (cause) => new CommandOutputError({
5081
+ kind: "notJson",
5082
+ command: described.command,
5083
+ cause
5084
+ })
5085
+ });
5086
+ return yield* Schema.decodeUnknownEffect(schema)(parsed).pipe(Effect.catch((cause) => Effect.fail(new CommandOutputError({
5087
+ kind: "schema",
5088
+ command: described.command,
5089
+ cause
5090
+ }))));
5091
+ });
5092
+ const jsonLine = Effect.fn("Run.jsonLine")(function* (command, schema, options) {
5093
+ yield* annotate(command);
5094
+ const described = describeCommand(command);
5095
+ const output = yield* collectClassified(command, options, void 0);
5096
+ const context = {
5097
+ exitCode: output.exitCode,
5098
+ stderr: output.stderr,
5099
+ stdout: output.stdout
5100
+ };
5101
+ const candidates = output.stdout.split(/\r?\n/).filter((candidate) => candidate.trim().length > 0);
5102
+ if (candidates.length === 0) return yield* Effect.fail(new CommandOutputError({
5103
+ kind: "notJson",
5104
+ command: described.command,
5105
+ cause: /* @__PURE__ */ new Error("stdout carried no non-empty line"),
5106
+ ...context
5107
+ }));
5108
+ let notJsonCause;
5109
+ let schemaCause;
5110
+ for (let index = candidates.length - 1; index >= 0; index--) {
5111
+ const candidate = candidates[index];
5112
+ if (candidate === void 0) continue;
5113
+ let parsed;
5114
+ try {
5115
+ parsed = JSON.parse(candidate);
5116
+ } catch (cause) {
5117
+ notJsonCause ??= cause;
5118
+ continue;
5119
+ }
5120
+ const decoded = yield* Effect.result(Schema.decodeUnknownEffect(schema)(parsed));
5121
+ if (Result.isSuccess(decoded)) return decoded.success;
5122
+ schemaCause ??= decoded.failure;
5123
+ }
5124
+ return yield* Effect.fail(schemaCause !== void 0 ? new CommandOutputError({
5125
+ kind: "schema",
5126
+ command: described.command,
5127
+ cause: schemaCause,
5128
+ ...context
5129
+ }) : new CommandOutputError({
5130
+ kind: "notJson",
5131
+ command: described.command,
5132
+ cause: notJsonCause,
5133
+ ...context
5134
+ }));
5135
+ });
5136
+ const exitCode = Effect.fn("Run.exitCode")(function* (command, options) {
5137
+ yield* annotate(command);
5138
+ return (yield* collectClassified(command, options, void 0)).exitCode;
5139
+ });
5140
+ const succeeds = Effect.fn("Run.succeeds")(function* (command, options) {
5141
+ yield* annotate(command);
5142
+ return yield* collectClassified(command, options, void 0).pipe(Effect.map((output) => output.succeeded), Effect.catch(() => Effect.succeed(false)));
5143
+ });
5144
+ const detach = Effect.fn("Run.detach")(function* (command) {
5145
+ yield* annotate(command);
5146
+ return yield* Effect.scoped(Effect.gen(function* () {
5147
+ const handle = yield* (yield* ChildProcessSpawner.ChildProcessSpawner).spawn(command);
5148
+ yield* handle.unref;
5149
+ return handle.pid;
5150
+ })).pipe(Effect.catch((error) => Effect.fail(CommandFailedError.spawn(command, error))));
5151
+ });
5152
+ const stream = (command, options) => Stream.unwrap(Effect.map(ChildProcessSpawner.ChildProcessSpawner, (spawner) => spawner.streamLines(command, { includeStderr: options?.includeStderr ?? false }))).pipe(Stream.mapError((error) => CommandFailedError.spawn(command, error)));
5153
+ const extendEnv = Function.dual(2, (self, env) => {
5154
+ if (ChildProcess.isStandardCommand(self)) {
5155
+ const merged = self.options.env === void 0 ? env : {
5156
+ ...self.options.env,
5157
+ ...env
5158
+ };
5159
+ return ChildProcess.make(self.command, self.args, {
5160
+ ...self.options,
5161
+ env: merged,
5162
+ extendEnv: true
5163
+ });
5164
+ }
5165
+ return ChildProcess.pipeTo(extendEnv(self.left, env), extendEnv(self.right, env), self.options);
5166
+ });
5167
+ /**
5168
+ * Structured running of core `ChildProcess.Command` values.
5169
+ *
5170
+ * @remarks
5171
+ * These are free functions over core's contract, **not** a service: core's
5172
+ * `ChildProcessSpawner` already is the subprocess service, and wrapping it in a
5173
+ * second one is the re-declaration this package exists not to repeat. Tests
5174
+ * stub the spawner (`ChildProcessSpawner.make(mockSpawn)`), not these.
5175
+ *
5176
+ * A non-zero exit is a *result* for {@link Run.collect}, {@link Run.exitCode},
5177
+ * {@link Run.succeeds} and {@link Run.jsonLine}, and a typed *failure* for
5178
+ * {@link Run.text}, {@link Run.lines} and {@link Run.json} — the split is
5179
+ * deliberate, matching core (where a non-zero exit is a success) at the
5180
+ * reporting level while giving the interpreting helpers the ergonomics callers
5181
+ * actually want.
5182
+ *
5183
+ * The interpreting helpers also **trim**: {@link Run.text} strips leading and
5184
+ * trailing whitespace from the whole result — not just a trailing newline —
5185
+ * and {@link Run.lines} trims each line. Fixed-column output whose first
5186
+ * column can be whitespace (`git status --porcelain`) silently loses that
5187
+ * column through either, producing plausible wrong values rather than an
5188
+ * error. Parse that kind of output from the untrimmed `stdout` of
5189
+ * {@link Run.collect}'s {@link CommandOutput} instead.
5190
+ *
5191
+ * @public
5192
+ */
5193
+ var Run = class {
5194
+ constructor() {}
5195
+ /**
5196
+ * Spawns `command`, collects stdout and stderr concurrently, and resolves
5197
+ * with the {@link CommandOutput} once the process exits.
5198
+ *
5199
+ * @remarks
5200
+ * A non-zero exit is a *result* here, not a failure — see {@link Run}'s
5201
+ * remarks for the split against {@link Run.text}, {@link Run.lines} and
5202
+ * {@link Run.json}.
5203
+ */
5204
+ static collect = collect;
5205
+ /**
5206
+ * Like {@link Run.collect}, but also tees each stream to the `Stdio` in `R`
5207
+ * as it arrives, for a caller that wants live output alongside the captured
5208
+ * {@link CommandOutput}.
5209
+ */
5210
+ static collectTee = collectTee;
5211
+ /**
5212
+ * Runs `command` and resolves with trimmed stdout on a zero exit.
5213
+ *
5214
+ * @remarks
5215
+ * A non-zero exit is a typed failure here — {@link CommandFailedError} —
5216
+ * unlike {@link Run.collect}, {@link Run.exitCode} and {@link Run.succeeds},
5217
+ * which treat it as a result.
5218
+ *
5219
+ * The trim strips **leading and trailing whitespace**, not just the trailing
5220
+ * newline. For parse-sensitive output where leading whitespace is data
5221
+ * (`git status --porcelain`, whose first entry's status column it would
5222
+ * silently eat), use {@link Run.collect} and read its {@link CommandOutput}'s
5223
+ * untrimmed `stdout` instead.
5224
+ */
5225
+ static text = text$4;
5226
+ /**
5227
+ * Runs `command` and resolves with stdout split into trimmed, non-empty
5228
+ * lines on a zero exit.
5229
+ *
5230
+ * @remarks
5231
+ * A non-zero exit is a typed failure here — {@link CommandFailedError} —
5232
+ * matching {@link Run.text} and {@link Run.json}.
5233
+ */
5234
+ static lines = lines;
5235
+ /**
5236
+ * Runs `command`, parses stdout as JSON and decodes it against `schema` on
5237
+ * a zero exit.
5238
+ *
5239
+ * @remarks
5240
+ * Fails with {@link CommandOutputError} when stdout is not JSON or does not
5241
+ * decode; a non-zero exit fails with {@link CommandFailedError}, matching
5242
+ * {@link Run.text} and {@link Run.lines}.
5243
+ *
5244
+ * This parses the **whole** of stdout and requires a zero exit. For a
5245
+ * protocol payload located by scanning stdout lines from the end — tolerant
5246
+ * of noise around it and of a non-zero exit — use {@link Run.jsonLine}
5247
+ * instead.
5248
+ */
5249
+ static json = json;
5250
+ /**
5251
+ * Runs `command` and, **scanning stdout lines from the end**, resolves with
5252
+ * the first line that both parses as JSON and decodes against `schema` —
5253
+ * the framing variant of {@link Run.json}, for a child that reports through
5254
+ * a single JSON protocol payload near the end of its output.
5255
+ *
5256
+ * @remarks
5257
+ * The framing tolerates noise on **both sides** of the payload: noise before
5258
+ * it (a subprocess-loaded hook's own `console.log`, a tool's warnings) and
5259
+ * noise after it (a hook logging from `process.on("exit", ...)` fires after
5260
+ * the payload has flushed — the trigger for widening the old "last non-empty
5261
+ * line must decode" contract, spencerbeggs/effected#292). Lines are split on
5262
+ * `\r?\n`, whitespace-only lines are dropped, and the scan runs from the last
5263
+ * line backwards until one decodes. The tolerance is positional, not
5264
+ * volumetric: the whole of stdout is still captured under
5265
+ * {@link RunOptions.maxOutputBytes} (default
5266
+ * {@link DEFAULT_MAX_OUTPUT_BYTES}, 16 MiB), so a child whose noise exceeds
5267
+ * the ceiling fails typed as `"tooLarge"` before any line is examined —
5268
+ * raise the ceiling for a child known to be loud in volume.
5269
+ *
5270
+ * The scan's consequence: when **multiple** lines decode under `schema`, the
5271
+ * **last** one wins. A child must therefore never emit two schema-valid
5272
+ * lines, and a consumer schema should be shaped so an accidental log line
5273
+ * cannot satisfy it — a discriminated envelope with a required literal field
5274
+ * (`ok: true | false`, the shape `@effected/workspaces`' `ReplayPayload`
5275
+ * uses) rather than a permissive record a stray `console.log(someObject)`
5276
+ * might match.
5277
+ *
5278
+ * Unlike {@link Run.json}, this parses **regardless of the exit code** — a
5279
+ * deliberate posture, not an oversight. A protocol payload discriminates
5280
+ * success in-band (its own `ok` field, its own error shape), so the payload
5281
+ * outranks the exit code: a child that crashes *after* flushing its payload
5282
+ * still reported, and a caller that wants exit-code semantics has
5283
+ * {@link Run.json}. When no line decodes anywhere, the typed
5284
+ * {@link CommandOutputError} carries the exit code and both captured streams
5285
+ * (redacted) as context, so the failure is diagnosable without re-running.
5286
+ * Its `kind` preserves the near-miss diagnostic: `"schema"` when at least
5287
+ * one line parsed as JSON but none decoded — with the **last parseable
5288
+ * line's** decode failure as `cause`, that line being the most probable
5289
+ * intended payload — and `"notJson"` only when no non-empty line was JSON at
5290
+ * all (carrying the last non-empty line's parse error). A spawn failure or
5291
+ * an opted-in timeout still fails with {@link CommandFailedError}.
5292
+ */
5293
+ static jsonLine = jsonLine;
5294
+ /**
5295
+ * Runs `command` and resolves with its exit code alone.
5296
+ *
5297
+ * @remarks
5298
+ * A non-zero exit is a *result* here, not a failure — see {@link Run}'s
5299
+ * remarks for the split against {@link Run.text}, {@link Run.lines} and
5300
+ * {@link Run.json}.
5301
+ */
5302
+ static exitCode = exitCode;
5303
+ /**
5304
+ * Runs `command` and resolves with whether it exited zero, collapsing a
5305
+ * spawn or other classified failure to `false` rather than propagating it.
5306
+ */
5307
+ static succeeds = succeeds;
5308
+ /** Decoded stdout lines as they arrive, for output too large or too long-lived to collect. */
5309
+ static stream = stream;
5310
+ /**
5311
+ * Spawns `command` and resolves with its pid without waiting for exit.
5312
+ *
5313
+ * @remarks
5314
+ * Unrefs the child **before** this scope closes, so it survives the
5315
+ * caller's scope closing — the Node backend's release skips the kill for an
5316
+ * unref'd child, and reversing that order kills it with the scope instead.
5317
+ * Fails with {@link CommandFailedError} if the process never starts.
5318
+ */
5319
+ static detach = detach;
5320
+ /**
5321
+ * Adds environment variables to a command WITHOUT losing the parent
5322
+ * environment: merges `env` over any existing command environment (new values
5323
+ * win, matching core's `ChildProcess.setEnv`) and sets `extendEnv: true`.
5324
+ *
5325
+ * @remarks
5326
+ * This combinator exists because of a core trap: `ChildProcess.setEnv` merges
5327
+ * into `options.env` but never sets `extendEnv`, and the Node spawner resolves
5328
+ * the child environment as `extendEnv ? { ...process.env, ...env } : env` — so
5329
+ * a command built with bare `setEnv({ SOME_VAR: x })` spawns a child whose
5330
+ * ENTIRE environment is that one variable: no `PATH`, no `HOME`. The failure is
5331
+ * silent at the type level and surfaces as "spawned tool cannot find its own
5332
+ * binary" at runtime.
5333
+ *
5334
+ * Deliberately forces `extendEnv: true` even where construction set it `false`
5335
+ * — inheriting the parent environment is this combinator's entire purpose. A
5336
+ * caller who wants a hermetic environment uses core's `setEnv` or construction
5337
+ * options (`ChildProcess.make(cmd, args, { env, extendEnv: false })`) directly.
5338
+ *
5339
+ * For a pipeline, applies to every command in the pipeline (mirroring core's
5340
+ * `setEnv`), preserving the pipe's own options. Composes core's public
5341
+ * vocabulary (`ChildProcess.make`, `ChildProcess.pipeTo`) — it re-declares
5342
+ * nothing.
5343
+ */
5344
+ static extendEnv = extendEnv;
5345
+ /** Default ceiling on captured bytes per stream. See {@link DEFAULT_MAX_OUTPUT_BYTES}. */
5346
+ static DEFAULT_MAX_OUTPUT_BYTES = DEFAULT_MAX_OUTPUT_BYTES;
5347
+ /** The placeholder written in place of a redacted secret. See {@link REDACTED}. */
5348
+ static REDACTED = "***";
5349
+ };
5350
+
5351
+ //#endregion
5352
+ //#region ../../node_modules/.pnpm/@effected+npm@0.8.3_@effected+semver@0.3.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/npm/ReleaseAgeGate.js
4679
5353
  const MS_PER_MINUTE = 6e4;
4680
5354
  /**
4681
5355
  * A source's partial contribution to a {@link ReleaseAgeGate}: the effective
@@ -4846,7 +5520,7 @@ var ReleaseAgeGate = class ReleaseAgeGate extends Schema.Class("ReleaseAgeGate")
4846
5520
  };
4847
5521
 
4848
5522
  //#endregion
4849
- //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._ff048038a9678f5144f817ad24d8f96e/node_modules/@effected/lockfiles/ImporterDependency.js
5523
+ //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._3c1784fba62fde9a5bac4cf15387fd04/node_modules/@effected/lockfiles/ImporterDependency.js
4850
5524
  /**
4851
5525
  * One declared dependency of one workspace importer, as the lockfile records it.
4852
5526
  *
@@ -4885,7 +5559,7 @@ var ImporterDependency = class extends Schema.Class("ImporterDependency")({
4885
5559
  }) {};
4886
5560
 
4887
5561
  //#endregion
4888
- //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._ff048038a9678f5144f817ad24d8f96e/node_modules/@effected/lockfiles/LockfileImporter.js
5562
+ //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._3c1784fba62fde9a5bac4cf15387fd04/node_modules/@effected/lockfiles/LockfileImporter.js
4889
5563
  /**
4890
5564
  * One workspace importer's declared dependencies, as the lockfile records them.
4891
5565
  *
@@ -4910,7 +5584,7 @@ var LockfileImporter = class extends Schema.Class("LockfileImporter")({
4910
5584
  }) {};
4911
5585
 
4912
5586
  //#endregion
4913
- //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._ff048038a9678f5144f817ad24d8f96e/node_modules/@effected/lockfiles/ResolvedPackage.js
5587
+ //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._3c1784fba62fde9a5bac4cf15387fd04/node_modules/@effected/lockfiles/ResolvedPackage.js
4914
5588
  const EMPTY_DEPENDENCIES = {};
4915
5589
  /**
4916
5590
  * A package resolved from a lockfile.
@@ -4946,7 +5620,7 @@ var ResolvedPackage = class extends Schema.Class("ResolvedPackage")({
4946
5620
  }) {};
4947
5621
 
4948
5622
  //#endregion
4949
- //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._ff048038a9678f5144f817ad24d8f96e/node_modules/@effected/lockfiles/WorkspaceDependency.js
5623
+ //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._3c1784fba62fde9a5bac4cf15387fd04/node_modules/@effected/lockfiles/WorkspaceDependency.js
4950
5624
  /**
4951
5625
  * A directed dependency edge between two workspace packages as recorded in
4952
5626
  * the lockfile.
@@ -4969,7 +5643,7 @@ var WorkspaceDependency = class extends Schema.Class("WorkspaceDependency")({
4969
5643
  }) {};
4970
5644
 
4971
5645
  //#endregion
4972
- //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._ff048038a9678f5144f817ad24d8f96e/node_modules/@effected/lockfiles/PnpmExtension.js
5646
+ //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._3c1784fba62fde9a5bac4cf15387fd04/node_modules/@effected/lockfiles/PnpmExtension.js
4973
5647
  /**
4974
5648
  * Extension data specific to pnpm lockfiles, attached to `Lockfile.extension`
4975
5649
  * when the format is `"pnpm"`.
@@ -4995,7 +5669,7 @@ var PnpmExtension = class extends Schema.Class("PnpmExtension")({
4995
5669
  }) {};
4996
5670
 
4997
5671
  //#endregion
4998
- //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._ff048038a9678f5144f817ad24d8f96e/node_modules/@effected/lockfiles/LockfileFormat.js
5672
+ //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._3c1784fba62fde9a5bac4cf15387fd04/node_modules/@effected/lockfiles/LockfileFormat.js
4999
5673
  /**
5000
5674
  * The lockfile formats this package parses: bun's `bun.lock` (JSONC), npm's
5001
5675
  * `package-lock.json` (v2/v3 JSON), pnpm's `pnpm-lock.yaml` and yarn Berry's
@@ -5034,7 +5708,7 @@ const FILENAMES = {
5034
5708
  const filenameFor = (format) => FILENAMES[format][0];
5035
5709
 
5036
5710
  //#endregion
5037
- //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._ff048038a9678f5144f817ad24d8f96e/node_modules/@effected/lockfiles/internal/shared.js
5711
+ //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._3c1784fba62fde9a5bac4cf15387fd04/node_modules/@effected/lockfiles/internal/shared.js
5038
5712
  /**
5039
5713
  * The four dependency sections of a manifest, in a stable order — the shared
5040
5714
  * dependency-sections table (v3's `DEP_SECTIONS`). Each entry is both the
@@ -7006,7 +7680,7 @@ var JsoncModifier = class {
7006
7680
  };
7007
7681
 
7008
7682
  //#endregion
7009
- //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._ff048038a9678f5144f817ad24d8f96e/node_modules/@effected/lockfiles/internal/bun.js
7683
+ //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._3c1784fba62fde9a5bac4cf15387fd04/node_modules/@effected/lockfiles/internal/bun.js
7010
7684
  const DepRecord$2 = Schema.optionalKey(Schema.Record(Schema.String, Schema.String));
7011
7685
  const BunWorkspaceEntry = Schema.Struct({
7012
7686
  name: Schema.optionalKey(Schema.String),
@@ -7100,7 +7774,7 @@ const toFields$3 = (raw) => Effect.gen(function* () {
7100
7774
  });
7101
7775
 
7102
7776
  //#endregion
7103
- //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._ff048038a9678f5144f817ad24d8f96e/node_modules/@effected/lockfiles/internal/npm.js
7777
+ //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._3c1784fba62fde9a5bac4cf15387fd04/node_modules/@effected/lockfiles/internal/npm.js
7104
7778
  const DepRecord$1 = Schema.optionalKey(Schema.Record(Schema.String, Schema.String));
7105
7779
  const NpmPackageEntry = Schema.Struct({
7106
7780
  name: Schema.optionalKey(Schema.String),
@@ -14128,7 +14802,7 @@ function deepEqualValues(a, b) {
14128
14802
  }
14129
14803
 
14130
14804
  //#endregion
14131
- //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._ff048038a9678f5144f817ad24d8f96e/node_modules/@effected/lockfiles/internal/documents.js
14805
+ //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._3c1784fba62fde9a5bac4cf15387fd04/node_modules/@effected/lockfiles/internal/documents.js
14132
14806
  /**
14133
14807
  * An empty YAML document composes to `null` (`Yaml.parseAll("")` is `[null]`,
14134
14808
  * and the trailing document of an env-only `pnpm-lock.yaml` is `null` too).
@@ -14199,7 +14873,7 @@ const selectSoleDocument = (content) => Effect.gen(function* () {
14199
14873
  });
14200
14874
 
14201
14875
  //#endregion
14202
- //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._ff048038a9678f5144f817ad24d8f96e/node_modules/@effected/lockfiles/internal/pnpm.js
14876
+ //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._3c1784fba62fde9a5bac4cf15387fd04/node_modules/@effected/lockfiles/internal/pnpm.js
14203
14877
  const PnpmImporterDeps = Schema.optionalKey(Schema.Record(Schema.String, Schema.Struct({
14204
14878
  specifier: Schema.String,
14205
14879
  version: Schema.String
@@ -14325,7 +14999,7 @@ const toFields$1 = (raw) => Effect.gen(function* () {
14325
14999
  });
14326
15000
 
14327
15001
  //#endregion
14328
- //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._ff048038a9678f5144f817ad24d8f96e/node_modules/@effected/lockfiles/internal/yarn.js
15002
+ //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._3c1784fba62fde9a5bac4cf15387fd04/node_modules/@effected/lockfiles/internal/yarn.js
14329
15003
  const YarnLockfileRaw = Schema.Record(Schema.String, Schema.Unknown);
14330
15004
  const DepRecord = Schema.optionalKey(Schema.Record(Schema.String, Schema.String));
14331
15005
  const YarnEntry = Schema.Struct({
@@ -14449,7 +15123,7 @@ const cleanYarnDeps = (deps) => {
14449
15123
  };
14450
15124
 
14451
15125
  //#endregion
14452
- //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._ff048038a9678f5144f817ad24d8f96e/node_modules/@effected/lockfiles/Lockfile.js
15126
+ //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._3c1784fba62fde9a5bac4cf15387fd04/node_modules/@effected/lockfiles/Lockfile.js
14453
15127
  const EMPTY_IMPORTERS = [];
14454
15128
  /**
14455
15129
  * Failure of `Lockfile.parse`: the given content is not a valid lockfile of
@@ -14694,7 +15368,7 @@ var Lockfile = class Lockfile extends Schema.Class("Lockfile")({
14694
15368
  };
14695
15369
 
14696
15370
  //#endregion
14697
- //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._ff048038a9678f5144f817ad24d8f96e/node_modules/@effected/lockfiles/LockfileIntegrity.js
15371
+ //#region ../../node_modules/.pnpm/@effected+lockfiles@0.3.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+npm@0._3c1784fba62fde9a5bac4cf15387fd04/node_modules/@effected/lockfiles/LockfileIntegrity.js
14698
15372
  /**
14699
15373
  * The minimal manifest shape {@link LockfileIntegrity.compare} checks a
14700
15374
  * lockfile against: a package name plus the four optional dependency maps.
@@ -17555,7 +18229,7 @@ var Package = class Package extends Schema.Class("Package")({
17555
18229
  };
17556
18230
 
17557
18231
  //#endregion
17558
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.9.5_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/WorkspacePackage.js
18232
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.10.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+semv_feff9e309e6abeafa28f7ea259b8a9bf/node_modules/@effected/workspaces/WorkspacePackage.js
17559
18233
  const EMPTY$1 = Object.freeze(Object.create(null));
17560
18234
  const EMPTY_MANIFEST = Object.freeze(Object.create(null));
17561
18235
  /**
@@ -18157,7 +18831,7 @@ var Walker$1 = class {
18157
18831
  };
18158
18832
 
18159
18833
  //#endregion
18160
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.9.5_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/WorkspaceRoot.js
18834
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.10.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+semv_feff9e309e6abeafa28f7ea259b8a9bf/node_modules/@effected/workspaces/WorkspaceRoot.js
18161
18835
  /**
18162
18836
  * The marker filenames {@link WorkspaceRoot} probes for, in priority order.
18163
18837
  *
@@ -18345,7 +19019,7 @@ var WorkspaceRoot = class WorkspaceRoot extends Context.Service()("@effected/wor
18345
19019
  };
18346
19020
 
18347
19021
  //#endregion
18348
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.9.5_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/internal/limits.js
19022
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.10.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+semv_feff9e309e6abeafa28f7ea259b8a9bf/node_modules/@effected/workspaces/internal/limits.js
18349
19023
  /**
18350
19024
  * Hard ceiling on directories the enumerator will visit for one pattern set.
18351
19025
  * Guards the pathological case a depth cap alone does not: a wide, shallow
@@ -18364,7 +19038,7 @@ const MAX_ENUMERATION_ENTRIES = 1e5;
18364
19038
  const PRUNED_DIRECTORIES = /* @__PURE__ */ new Set([".git", "node_modules"]);
18365
19039
 
18366
19040
  //#endregion
18367
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.9.5_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/internal/traverse.js
19041
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.10.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+semv_feff9e309e6abeafa28f7ea259b8a9bf/node_modules/@effected/workspaces/internal/traverse.js
18368
19042
  /** Directory names never descended into. */
18369
19043
  const isPruned = (entry) => PRUNED_DIRECTORIES.has(entry);
18370
19044
  /** Join root-relative POSIX segments; `""` is the root itself. */
@@ -18455,7 +19129,7 @@ var Traversal = class {
18455
19129
  };
18456
19130
 
18457
19131
  //#endregion
18458
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.9.5_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/internal/enumerate.js
19132
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.10.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+semv_feff9e309e6abeafa28f7ea259b8a9bf/node_modules/@effected/workspaces/internal/enumerate.js
18459
19133
  /** Strip a trailing slash from `GlobPattern.enumerationPrefix` to get a relative directory. */
18460
19134
  const baseOf = (pattern) => pattern.enumerationPrefix.replace(/\/$/, "");
18461
19135
  /**
@@ -18526,7 +19200,7 @@ const enumerate = (root, globs, options) => Effect.gen(function* () {
18526
19200
  });
18527
19201
 
18528
19202
  //#endregion
18529
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.9.5_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/internal/patterns.js
19203
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.10.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+semv_feff9e309e6abeafa28f7ea259b8a9bf/node_modules/@effected/workspaces/internal/patterns.js
18530
19204
  const stringsOf = (value) => Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : void 0;
18531
19205
  /** The `packages:` list of a `pnpm-workspace.yaml` document. Total on a parsed document. */
18532
19206
  const pnpmPatternsOf = (document) => {
@@ -18584,7 +19258,7 @@ const readPatterns = (root) => Effect.gen(function* () {
18584
19258
  });
18585
19259
 
18586
19260
  //#endregion
18587
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.9.5_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/WorkspaceDiscovery.js
19261
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.10.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+semv_feff9e309e6abeafa28f7ea259b8a9bf/node_modules/@effected/workspaces/WorkspaceDiscovery.js
18588
19262
  /**
18589
19263
  * Raised when a workspace member's `package.json` cannot be read, parsed, or
18590
19264
  * used — it is missing, malformed, or lacks a `name` or `version`.
@@ -18837,6 +19511,15 @@ var WorkspaceDiscovery = class WorkspaceDiscovery extends Context.Service()("@ef
18837
19511
  for (const entry of index) if (filePath.startsWith(entry.prefix)) return Option.some(entry.package);
18838
19512
  return Option.none();
18839
19513
  };
19514
+ const packageIndexes = /* @__PURE__ */ new WeakMap();
19515
+ const packagesByName = (all) => {
19516
+ const cached = packageIndexes.get(all);
19517
+ if (cached !== void 0) return cached;
19518
+ const index = /* @__PURE__ */ new Map();
19519
+ for (const pkg of all) if (!index.has(pkg.name)) index.set(pkg.name, pkg);
19520
+ packageIndexes.set(all, index);
19521
+ return index;
19522
+ };
18840
19523
  return {
18841
19524
  info: Effect.fn("WorkspaceDiscovery.info")(function* () {
18842
19525
  return (yield* memo).info;
@@ -18850,7 +19533,7 @@ var WorkspaceDiscovery = class WorkspaceDiscovery extends Context.Service()("@ef
18850
19533
  }),
18851
19534
  getPackage: Effect.fn("WorkspaceDiscovery.getPackage")(function* (name) {
18852
19535
  const all = yield* packages;
18853
- const found = all.find((pkg) => pkg.name === name);
19536
+ const found = packagesByName(all).get(name);
18854
19537
  if (found !== void 0) return found;
18855
19538
  return yield* Effect.fail(new PackageNotFoundError({
18856
19539
  name,
@@ -19014,7 +19697,16 @@ var WorkspaceDiscovery = class WorkspaceDiscovery extends Context.Service()("@ef
19014
19697
  */
19015
19698
  static workspaceResolver = Layer.effect(WorkspaceResolver, Effect.gen(function* () {
19016
19699
  const discovery = yield* WorkspaceDiscovery;
19017
- return { versionOf: (packageName) => discovery.listPackages().pipe(Effect.map((all) => Option.fromUndefinedOr(all.find((pkg) => pkg.name === packageName)?.version)), Effect.mapError((cause) => new DependencyResolutionError({
19700
+ const versionIndexes = /* @__PURE__ */ new WeakMap();
19701
+ const versionsByName = (all) => {
19702
+ const cached = versionIndexes.get(all);
19703
+ if (cached !== void 0) return cached;
19704
+ const index = /* @__PURE__ */ new Map();
19705
+ for (const pkg of all) if (!index.has(pkg.name)) index.set(pkg.name, pkg.version);
19706
+ versionIndexes.set(all, index);
19707
+ return index;
19708
+ };
19709
+ return { versionOf: (packageName) => discovery.listPackages().pipe(Effect.map((all) => Option.fromUndefinedOr(versionsByName(all).get(packageName))), Effect.mapError((cause) => new DependencyResolutionError({
19018
19710
  specifier: `workspace:${packageName}`,
19019
19711
  cause
19020
19712
  }))) };
@@ -19023,7 +19715,7 @@ var WorkspaceDiscovery = class WorkspaceDiscovery extends Context.Service()("@ef
19023
19715
  const isStringRecord$2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value) && Object.values(value).every((entry) => typeof entry === "string");
19024
19716
 
19025
19717
  //#endregion
19026
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.9.5_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/DependencyGraph.js
19718
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.10.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+semv_feff9e309e6abeafa28f7ea259b8a9bf/node_modules/@effected/workspaces/DependencyGraph.js
19027
19719
  /**
19028
19720
  * Raised when the workspace dependency graph cannot be topologically ordered
19029
19721
  * because it contains a cycle.
@@ -19257,10 +19949,32 @@ const kahn = (edges) => {
19257
19949
  };
19258
19950
 
19259
19951
  //#endregion
19260
- //#region ../../node_modules/.pnpm/@effected+git@0.5.2_effect@4.0.0-beta.101/node_modules/@effected/git/GitCommand.js
19952
+ //#region ../../node_modules/.pnpm/@effected+git@0.6.0_effect@4.0.0-beta.101/node_modules/@effected/git/GitCommand.js
19953
+ /** The mask every whole-value sensitive positional is replaced with. */
19954
+ const REDACTED = "<redacted>";
19955
+ const secretValue = (value) => ({
19956
+ redact: "value",
19957
+ value
19958
+ });
19959
+ const secretUrl = (value) => ({
19960
+ redact: "url",
19961
+ value
19962
+ });
19963
+ /**
19964
+ * Masks the userinfo component of a URL (`scheme://user:token@host/...` →
19965
+ * `scheme://<redacted>@host/...`). A value carrying no embedded userinfo — a
19966
+ * remote name, a credential-free URL, an scp-style `host:path` — passes
19967
+ * through untouched, so the common case stays fully debuggable.
19968
+ *
19969
+ * The userinfo match is greedy (`[^/]*@` — everything through the LAST `@`
19970
+ * before the first path slash): URL authorities split at the last `@`, so a
19971
+ * password containing a literal `@` (`user:p\@ss\@host/...`) must be
19972
+ * consumed whole or its tail would survive into `redactedArgs`.
19973
+ */
19974
+ const redactUrlUserinfo = (value) => value.replace(/^([a-z][a-z0-9+.-]*:\/\/)[^/]*@/i, `$1${REDACTED}@`);
19261
19975
  /**
19262
- * Builds a `git` `ChildProcess.StandardCommand` with the argv this package
19263
- * classifies against.
19976
+ * Builds a `git` {@link GitInvocation} with the argv this package classifies
19977
+ * against.
19264
19978
  *
19265
19979
  * @remarks
19266
19980
  * `LC_ALL=C` is pinned on every invocation because git's stderr
@@ -19276,10 +19990,18 @@ const kahn = (edges) => {
19276
19990
  * the working directory per invocation via `ChildProcess.setCwd`, which
19277
19991
  * returns a new command and leaves this one unchanged.
19278
19992
  */
19279
- const git = (args) => ChildProcess.make("git", args, {
19280
- env: { LC_ALL: "C" },
19281
- extendEnv: true
19282
- });
19993
+ const git = (args, stdin) => {
19994
+ const raw = args.map((arg) => typeof arg === "string" ? arg : arg.value);
19995
+ const redactedArgs = args.map((arg) => typeof arg === "string" ? arg : arg.redact === "value" ? REDACTED : redactUrlUserinfo(arg.value));
19996
+ return {
19997
+ command: ChildProcess.make("git", raw, {
19998
+ env: { LC_ALL: "C" },
19999
+ extendEnv: true,
20000
+ ...stdin !== void 0 ? { stdin: Stream.make(new TextEncoder().encode(stdin)) } : {}
20001
+ }),
20002
+ redactedArgs
20003
+ };
20004
+ };
19283
20005
  const show = (ref, path) => git(["show", `${ref}:${path}`]);
19284
20006
  const lsTree = (ref, pathspec = []) => git([
19285
20007
  "ls-tree",
@@ -19338,7 +20060,7 @@ const checkout = (ref, detach = false) => git([
19338
20060
  const fetch$1 = (remote, ref, depth, tag = false) => git([
19339
20061
  "fetch",
19340
20062
  ...depth !== void 0 ? ["--depth", String(depth)] : [],
19341
- remote,
20063
+ secretUrl(remote),
19342
20064
  ...tag ? ["tag"] : [],
19343
20065
  ref
19344
20066
  ]);
@@ -19354,7 +20076,7 @@ const submoduleAdd = (url, path, depth) => git([
19354
20076
  "add",
19355
20077
  ...depth !== void 0 ? ["--depth", String(depth)] : [],
19356
20078
  "--",
19357
- url,
20079
+ secretUrl(url),
19358
20080
  path
19359
20081
  ]);
19360
20082
  const sparseCheckoutSet = (patterns, cone) => git([
@@ -19367,13 +20089,55 @@ const configSet = (key, value, file) => git([
19367
20089
  "config",
19368
20090
  ...file !== void 0 ? ["-f", file] : [],
19369
20091
  key,
19370
- value
20092
+ secretValue(value)
19371
20093
  ]);
19372
20094
  const add = (paths) => git([
19373
20095
  "add",
19374
20096
  "--",
19375
20097
  ...paths
19376
20098
  ]);
20099
+ const reset = (mode = "mixed", ref) => git([
20100
+ "reset",
20101
+ `--${mode}`,
20102
+ ...ref !== void 0 ? [ref] : []
20103
+ ]);
20104
+ const clean = (directories = false, ignored = false, paths = []) => git([
20105
+ "clean",
20106
+ "--force",
20107
+ ...directories ? ["-d"] : [],
20108
+ ...ignored ? ["-x"] : [],
20109
+ ...paths.length > 0 ? ["--", ...paths] : []
20110
+ ]);
20111
+ const restore = (paths, source, staged = false, worktree = false) => git([
20112
+ "restore",
20113
+ ...source !== void 0 ? ["--source", source] : [],
20114
+ ...staged ? ["--staged"] : [],
20115
+ ...worktree ? ["--worktree"] : [],
20116
+ "--",
20117
+ ...paths
20118
+ ]);
20119
+ const branchCreate = (name, startPoint, checkout = false, force = false) => checkout ? git([
20120
+ "checkout",
20121
+ force ? "-B" : "-b",
20122
+ name,
20123
+ ...startPoint !== void 0 ? [startPoint] : []
20124
+ ]) : git([
20125
+ "branch",
20126
+ ...force ? ["-f"] : [],
20127
+ name,
20128
+ ...startPoint !== void 0 ? [startPoint] : []
20129
+ ]);
20130
+ const branchDelete = (name, force = false) => git([
20131
+ "branch",
20132
+ force ? "-D" : "-d",
20133
+ name
20134
+ ]);
20135
+ const isShallow = () => git(["rev-parse", "--is-shallow-repository"]);
20136
+ const fetchUnshallow = (remote = "origin") => git([
20137
+ "fetch",
20138
+ "--unshallow",
20139
+ secretUrl(remote)
20140
+ ]);
19377
20141
  const nameStatus = (base, head, relative = false) => git([
19378
20142
  "diff",
19379
20143
  "--name-status",
@@ -19414,37 +20178,273 @@ const status = () => git([
19414
20178
  "--porcelain",
19415
20179
  "-z"
19416
20180
  ]);
19417
- /**
19418
- * Pure constructors for the `git` `ChildProcess.Command` values this package
19419
- * spawns.
19420
- *
19421
- * @remarks
19422
- * Every constructor returns a cwd-less, argv-only `Command` — no spawning,
19423
- * no working directory baked in. `Git` applies the working directory per
19424
- * call with `ChildProcess.setCwd` and owns the actual spawn, timeout, and
19425
- * error classification.
19426
- *
19427
- * @public
19428
- */
19429
- var GitCommand = class {
19430
- constructor() {}
19431
- /**
19432
- * `git show <ref>:<path>` the contents of `path` as it existed at `ref`,
19433
- * without checking anything out.
19434
- */
19435
- static show = show;
19436
- /**
19437
- * `git ls-tree -r -z <ref> [-- <pathspec>...]` every path in the tree at
19438
- * `ref`, recursively, NUL-terminated, optionally scoped to `pathspec`.
19439
- *
19440
- * @remarks
19441
- * `-z` is load-bearing: git paths may themselves contain newlines, so the
19442
- * caller must split on `"\0"`, never on `"\n"`. When `pathspec` is provided,
19443
- * a literal `--` separator is inserted before the pathspec entries to prevent
19444
- * git from interpreting pathspec values as options.
19445
- */
19446
- static lsTree = lsTree;
19447
- /**
20181
+ const submoduleStatus = (paths = [], recursive = false) => git([
20182
+ "submodule",
20183
+ "status",
20184
+ ...recursive ? ["--recursive"] : [],
20185
+ ...paths.length > 0 ? ["--", ...paths] : []
20186
+ ]);
20187
+ const submoduleInit = (paths = []) => git([
20188
+ "submodule",
20189
+ "init",
20190
+ ...paths.length > 0 ? ["--", ...paths] : []
20191
+ ]);
20192
+ const submoduleDeinit = (paths, all = false, force = false) => git([
20193
+ "submodule",
20194
+ "deinit",
20195
+ ...force ? ["--force"] : [],
20196
+ ...all ? ["--all"] : ["--", ...paths]
20197
+ ]);
20198
+ const submoduleSync = (paths = [], recursive = false) => git([
20199
+ "submodule",
20200
+ "sync",
20201
+ ...recursive ? ["--recursive"] : [],
20202
+ ...paths.length > 0 ? ["--", ...paths] : []
20203
+ ]);
20204
+ const submoduleSetUrl = (path, url) => git([
20205
+ "submodule",
20206
+ "set-url",
20207
+ "--",
20208
+ path,
20209
+ secretUrl(url)
20210
+ ]);
20211
+ const submoduleSetBranch = (path, branch) => git([
20212
+ "submodule",
20213
+ "set-branch",
20214
+ ...branch === void 0 ? ["--default"] : ["--branch", branch],
20215
+ "--",
20216
+ path
20217
+ ]);
20218
+ const submoduleAbsorbgitdirs = (paths = []) => git([
20219
+ "submodule",
20220
+ "absorbgitdirs",
20221
+ ...paths.length > 0 ? ["--", ...paths] : []
20222
+ ]);
20223
+ const submoduleForeach = (command, recursive = false) => git([
20224
+ "submodule",
20225
+ "foreach",
20226
+ ...recursive ? ["--recursive"] : [],
20227
+ command
20228
+ ]);
20229
+ const lsRemote = (remote, heads = false, tags = false, patterns = []) => git([
20230
+ "ls-remote",
20231
+ ...heads ? ["--heads"] : [],
20232
+ ...tags ? ["--tags"] : [],
20233
+ secretUrl(remote),
20234
+ ...patterns
20235
+ ]);
20236
+ const remoteAdd = (name, url) => git([
20237
+ "remote",
20238
+ "add",
20239
+ name,
20240
+ secretUrl(url)
20241
+ ]);
20242
+ const remoteRemove = (name) => git([
20243
+ "remote",
20244
+ "remove",
20245
+ name
20246
+ ]);
20247
+ const remoteSetUrl = (name, url) => git([
20248
+ "remote",
20249
+ "set-url",
20250
+ name,
20251
+ secretUrl(url)
20252
+ ]);
20253
+ const stashRef = (index) => `stash@{${index}}`;
20254
+ const stashPush = (message, includeUntracked = false, paths = []) => git([
20255
+ "stash",
20256
+ "push",
20257
+ ...includeUntracked ? ["--include-untracked"] : [],
20258
+ ...message !== void 0 ? ["-m", message] : [],
20259
+ ...paths.length > 0 ? ["--", ...paths] : []
20260
+ ]);
20261
+ const stashPop = (index) => git([
20262
+ "stash",
20263
+ "pop",
20264
+ ...index !== void 0 ? [stashRef(index)] : []
20265
+ ]);
20266
+ const stashApply = (index) => git([
20267
+ "stash",
20268
+ "apply",
20269
+ ...index !== void 0 ? [stashRef(index)] : []
20270
+ ]);
20271
+ const stashDrop = (index) => git([
20272
+ "stash",
20273
+ "drop",
20274
+ ...index !== void 0 ? [stashRef(index)] : []
20275
+ ]);
20276
+ const stashList = () => git([
20277
+ "stash",
20278
+ "list",
20279
+ "-z",
20280
+ "--format=%gd%x1f%H%x1f%gs"
20281
+ ]);
20282
+ const branchList = (remotes = false, all = false) => git([
20283
+ "branch",
20284
+ "--list",
20285
+ ...all ? ["--all"] : remotes ? ["--remotes"] : [],
20286
+ "--format=%(HEAD)%00%(refname:short)%00%(objectname)"
20287
+ ]);
20288
+ const tagCreate = (name, ref, message, force = false) => git([
20289
+ "tag",
20290
+ ...force ? ["--force"] : [],
20291
+ ...message !== void 0 ? ["-m", message] : [],
20292
+ name,
20293
+ ...ref !== void 0 ? [ref] : []
20294
+ ]);
20295
+ const tagDelete = (name) => git([
20296
+ "tag",
20297
+ "--delete",
20298
+ name
20299
+ ]);
20300
+ const tagList = (pattern) => git([
20301
+ "tag",
20302
+ "--list",
20303
+ ...pattern !== void 0 ? [pattern] : []
20304
+ ]);
20305
+ const forEachRef = (patterns = []) => git([
20306
+ "for-each-ref",
20307
+ "--format=%(refname)%00%(objectname)%00%(objecttype)",
20308
+ ...patterns
20309
+ ]);
20310
+ const revList = (ref, limit, firstParent = false) => git([
20311
+ "rev-list",
20312
+ ...limit !== void 0 ? [`--max-count=${limit}`] : [],
20313
+ ...firstParent ? ["--first-parent"] : [],
20314
+ ref
20315
+ ]);
20316
+ const commit = (message, all = false, allowEmpty = false, amend = false, author) => git([
20317
+ "commit",
20318
+ ...all ? ["--all"] : [],
20319
+ ...allowEmpty ? ["--allow-empty"] : [],
20320
+ ...amend ? ["--amend"] : [],
20321
+ ...author !== void 0 ? [`--author=${author}`] : [],
20322
+ "-m",
20323
+ message
20324
+ ]);
20325
+ const push$1 = (remote, refspec, force = false, forceWithLease = false, tags = false, setUpstream = false) => git([
20326
+ "push",
20327
+ ...force ? ["--force"] : [],
20328
+ ...forceWithLease ? ["--force-with-lease"] : [],
20329
+ ...tags ? ["--tags"] : [],
20330
+ ...setUpstream ? ["--set-upstream"] : [],
20331
+ secretUrl(remote),
20332
+ ...refspec !== void 0 ? [refspec] : []
20333
+ ]);
20334
+ const pull = (remote, ref, rebase = false, ffOnly = false) => git([
20335
+ "pull",
20336
+ ...rebase ? ["--rebase"] : [],
20337
+ ...ffOnly ? ["--ff-only"] : [],
20338
+ secretUrl(remote),
20339
+ ...ref !== void 0 ? [ref] : []
20340
+ ]);
20341
+ const configList = (file) => git([
20342
+ "config",
20343
+ ...file !== void 0 ? ["-f", file] : [],
20344
+ "--list",
20345
+ "-z"
20346
+ ]);
20347
+ const configGetAll = (key, file) => git([
20348
+ "config",
20349
+ ...file !== void 0 ? ["-f", file] : [],
20350
+ "--get-all",
20351
+ "-z",
20352
+ key
20353
+ ]);
20354
+ const configUnset = (key, file, all = false) => git([
20355
+ "config",
20356
+ ...file !== void 0 ? ["-f", file] : [],
20357
+ all ? "--unset-all" : "--unset",
20358
+ key
20359
+ ]);
20360
+ const rm = (paths, cached = false, recursive = false, force = false) => git([
20361
+ "rm",
20362
+ ...cached ? ["--cached"] : [],
20363
+ ...recursive ? ["-r"] : [],
20364
+ ...force ? ["--force"] : [],
20365
+ "--",
20366
+ ...paths
20367
+ ]);
20368
+ const mv = (source, destination, force = false) => git([
20369
+ "mv",
20370
+ ...force ? ["--force"] : [],
20371
+ "--",
20372
+ source,
20373
+ destination
20374
+ ]);
20375
+ const checkIgnore = (paths) => git([
20376
+ "check-ignore",
20377
+ "-z",
20378
+ "--stdin"
20379
+ ], paths.map((path) => `${path}\0`).join(""));
20380
+ const worktreeAdd = (path, ref, detach = false, force = false) => git([
20381
+ "worktree",
20382
+ "add",
20383
+ ...force ? ["--force"] : [],
20384
+ ...detach ? ["--detach"] : [],
20385
+ path,
20386
+ ...ref !== void 0 ? [ref] : []
20387
+ ]);
20388
+ const worktreeList = () => git([
20389
+ "worktree",
20390
+ "list",
20391
+ "--porcelain",
20392
+ "-z"
20393
+ ]);
20394
+ const worktreeRemove = (path, force = false) => git([
20395
+ "worktree",
20396
+ "remove",
20397
+ ...force ? ["--force"] : [],
20398
+ path
20399
+ ]);
20400
+ const lsFiles = (pathspec = []) => git([
20401
+ "ls-files",
20402
+ "--stage",
20403
+ "-z",
20404
+ ...pathspec.length > 0 ? ["--", ...pathspec] : []
20405
+ ]);
20406
+ /**
20407
+ * Pure constructors for the `git` {@link GitInvocation} values this package
20408
+ * spawns.
20409
+ *
20410
+ * @remarks
20411
+ * Every constructor returns a cwd-less, argv-only {@link GitInvocation} — no
20412
+ * spawning, no working directory baked in. `Git` applies the working
20413
+ * directory per call with `ChildProcess.setCwd` on `invocation.command` and
20414
+ * owns the actual spawn, timeout, and error classification.
20415
+ *
20416
+ * **Redaction policy.** A constructor whose argv carries a sensitive
20417
+ * positional — a config value (`configSet`), or a URL that may embed
20418
+ * userinfo (the remote of `fetch`, `fetchUnshallow`, `lsRemote`, `push` and
20419
+ * `pull`, and the url of `submoduleAdd`, `submoduleSetUrl`, `remoteAdd` and
20420
+ * `remoteSetUrl`) —
20421
+ * masks it in {@link GitInvocation.redactedArgs}: a config value becomes
20422
+ * `<redacted>` wholesale, a URL keeps everything but its `userinfo@`
20423
+ * component. The `Git` service persists only the redacted argv in error
20424
+ * values, and its span annotations carry stable identifiers only (`cwd`,
20425
+ * keys, paths, remote/ref names) — never config values, never URLs.
20426
+ *
20427
+ * @public
20428
+ */
20429
+ var GitCommand = class {
20430
+ constructor() {}
20431
+ /**
20432
+ * `git show <ref>:<path>` — the contents of `path` as it existed at `ref`,
20433
+ * without checking anything out.
20434
+ */
20435
+ static show = show;
20436
+ /**
20437
+ * `git ls-tree -r -z <ref> [-- <pathspec>...]` — every path in the tree at
20438
+ * `ref`, recursively, NUL-terminated, optionally scoped to `pathspec`.
20439
+ *
20440
+ * @remarks
20441
+ * `-z` is load-bearing: git paths may themselves contain newlines, so the
20442
+ * caller must split on `"\0"`, never on `"\n"`. When `pathspec` is provided,
20443
+ * a literal `--` separator is inserted before the pathspec entries to prevent
20444
+ * git from interpreting pathspec values as options.
20445
+ */
20446
+ static lsTree = lsTree;
20447
+ /**
19448
20448
  * `git cat-file -e <ref>` — checks whether `ref` resolves to an existing
19449
20449
  * object, without printing it. A non-zero exit means the ref does not exist.
19450
20450
  */
@@ -19520,9 +20520,106 @@ var GitCommand = class {
19520
20520
  /**
19521
20521
  * Mutating: `git fetch [--depth <n>] <remote> [tag] <ref>` — fetches the given
19522
20522
  * ref from a remote, optionally with a depth limit and the `tag` keyword.
20523
+ *
20524
+ * @remarks
20525
+ * `remote` may be a URL as well as a remote name; an embedded
20526
+ * `userinfo@` credential is masked in {@link GitInvocation.redactedArgs}.
19523
20527
  */
19524
20528
  static fetch = fetch$1;
19525
20529
  /**
20530
+ * Mutating: `git fetch --unshallow <remote>` — converts a shallow clone
20531
+ * into a complete one by fetching the missing history.
20532
+ *
20533
+ * @remarks
20534
+ * `--unshallow` is a distinct MODE, not a depth value: git rejects it
20535
+ * outright in a repository that is not shallow, with
20536
+ * `--unshallow on a complete repository does not make sense`, so it
20537
+ * cannot be expressed as `fetch`'s `depth` option. The caller decides
20538
+ * whether to run it — probe with `Git.isShallow` first.
20539
+ *
20540
+ * `remote` may be a URL as well as a remote name; an embedded `userinfo@`
20541
+ * credential is masked in {@link GitInvocation.redactedArgs}.
20542
+ */
20543
+ static fetchUnshallow = fetchUnshallow;
20544
+ /**
20545
+ * `git rev-parse --is-shallow-repository` — prints `true` when the
20546
+ * repository is a shallow clone, `false` otherwise.
20547
+ *
20548
+ * @remarks
20549
+ * A dedicated probe constructor, deliberately separate from
20550
+ * {@link GitCommand.revParse}: `revParse` takes a REF and resolves it,
20551
+ * while this takes nothing and answers a repository-shape question.
20552
+ * Folding the flag into `revParse` would make that constructor
20553
+ * sometimes-takes-a-ref, sometimes-takes-a-flag.
20554
+ */
20555
+ static isShallow = isShallow;
20556
+ /**
20557
+ * Mutating: `git reset --soft|--mixed|--hard [<ref>]` — moves `HEAD` (and,
20558
+ * per mode, the index and working tree) to `ref`.
20559
+ *
20560
+ * @remarks
20561
+ * The mode flag is always explicit — `--mixed` is emitted for the default
20562
+ * rather than omitted — so the argv states what runs. `ref` may be any
20563
+ * commit-ish, including a gitlink sha.
20564
+ */
20565
+ static reset = reset;
20566
+ /**
20567
+ * Mutating: `git clean --force [-d] [-x] [-- <paths>...]` — deletes
20568
+ * untracked files from the working tree.
20569
+ *
20570
+ * @remarks
20571
+ * `--force` is unconditional: this constructor exists so a consumer can
20572
+ * restore a tree to a known state (e.g. before retrying a non-idempotent
20573
+ * operation), and without `--force` git refuses to clean at all under the
20574
+ * default `clean.requireForce` config — a clean that silently did nothing
20575
+ * would hand the retry the same dirty tree. `-d` removes untracked
20576
+ * directories too; `-x` removes ignored files as well. The literal `--`
20577
+ * separator makes the optional pathspec injection-safe by construction.
20578
+ */
20579
+ static clean = clean;
20580
+ /**
20581
+ * Mutating: `git restore [--source <ref>] [--staged] [--worktree] -- <paths...>`
20582
+ * — restores the given paths from the index (or from `source`), the
20583
+ * `checkout -- <paths>`-shaped operation.
20584
+ *
20585
+ * @remarks
20586
+ * This is a separate constructor precisely because {@link GitCommand.checkout}'s
20587
+ * service guard refuses `--` and option-like refs by design — `restore` is
20588
+ * git's own verb for pathspec restoration, and its paths always sit behind
20589
+ * a literal `--`, so they are injection-safe by construction. With neither
20590
+ * `staged` nor `worktree` set, git defaults to restoring the working tree.
20591
+ */
20592
+ static restore = restore;
20593
+ /**
20594
+ * Mutating: `git branch [-f] <name> [<start-point>]`, or
20595
+ * `git checkout (-b | -B) <name> [<start-point>]` when `checkout` is true —
20596
+ * creates a branch, optionally from an explicit start point, optionally
20597
+ * switching to it, optionally force-resetting an existing branch.
20598
+ *
20599
+ * @remarks
20600
+ * Branch creation is a branch-member concern, NOT a widening of
20601
+ * {@link GitCommand.checkout}: `checkout`'s contract stays "move to an
20602
+ * existing ref" and its option-like-ref refusal stays intact. The `-b` /
20603
+ * `-B` here is this constructor's own literal, never caller data.
20604
+ *
20605
+ * `force` with `checkout` exists because the delete-then-create longhand
20606
+ * (`branch -D` swallowed, then `checkout -b`) papers over a real edge:
20607
+ * `git branch -D` refuses to delete the currently checked-out branch,
20608
+ * while `checkout -B` resets it fine — one invocation handles both
20609
+ * states.
20610
+ */
20611
+ static branchCreate = branchCreate;
20612
+ /**
20613
+ * Mutating: `git branch -d <name>` (or `-D` when `force` is true) —
20614
+ * deletes a local branch.
20615
+ *
20616
+ * @remarks
20617
+ * The default `-d` refuses to delete a branch not fully merged — a typed
20618
+ * failure, which is usually the honest answer. `force: true` emits `-D`
20619
+ * and deletes regardless.
20620
+ */
20621
+ static branchDelete = branchDelete;
20622
+ /**
19526
20623
  * Mutating: `git submodule update [--init] [--depth <n>] [-- <paths>...]` — updates
19527
20624
  * registered submodules, optionally initializing them, with an optional depth limit,
19528
20625
  * and scoped to specific paths. The literal `--` separator makes the pathspec
@@ -19533,6 +20630,10 @@ var GitCommand = class {
19533
20630
  * Mutating: `git submodule add [--depth <n>] -- <url> <path>` — registers and
19534
20631
  * initializes a new submodule. The literal `--` separator makes the url and path
19535
20632
  * injection-safe by construction.
20633
+ *
20634
+ * @remarks
20635
+ * An embedded `userinfo@` credential in `url` is masked in
20636
+ * {@link GitInvocation.redactedArgs}.
19536
20637
  */
19537
20638
  static submoduleAdd = submoduleAdd;
19538
20639
  /**
@@ -19545,6 +20646,13 @@ var GitCommand = class {
19545
20646
  /**
19546
20647
  * Mutating: `git config [-f <file>] <key> <value>` — writes a configuration value,
19547
20648
  * optionally into an explicit configuration file (e.g., `.gitmodules`).
20649
+ *
20650
+ * @remarks
20651
+ * `value` may be a secret (a token, a credential-bearing URL), so it is
20652
+ * masked wholesale — as `<redacted>` — in
20653
+ * {@link GitInvocation.redactedArgs}. The key and file stay visible: they
20654
+ * are stable identifiers, and they are what a caller debugging a failed
20655
+ * write actually needs.
19548
20656
  */
19549
20657
  static configSet = configSet;
19550
20658
  /**
@@ -19627,10 +20735,305 @@ var GitCommand = class {
19627
20735
  * Each entry is a pair of status codes followed by a space and the path.
19628
20736
  */
19629
20737
  static status = status;
20738
+ /**
20739
+ * `git submodule status [--recursive] [-- <paths>...]` — one line per
20740
+ * registered submodule: a state prefix, the checked-out (or gitlink) sha,
20741
+ * the path, and — when the submodule is initialized — a `git describe`
20742
+ * suffix in parentheses.
20743
+ *
20744
+ * @remarks
20745
+ * `git submodule status` has no `-z` mode, so its output is line-based —
20746
+ * the one path-emitting constructor in this package that cannot follow
20747
+ * the `-z` rule. A submodule path containing a newline would corrupt the
20748
+ * parse; accepted as a git-imposed limitation.
20749
+ */
20750
+ static submoduleStatus = submoduleStatus;
20751
+ /**
20752
+ * Mutating: `git submodule init [-- <paths>...]` — registers the
20753
+ * submodules from `.gitmodules` into `.git/config` (all of them, or only
20754
+ * `paths`), without cloning or checking anything out.
20755
+ */
20756
+ static submoduleInit = submoduleInit;
20757
+ /**
20758
+ * Mutating: `git submodule deinit [--force] (--all | -- <paths>...)` —
20759
+ * unregisters submodules: clears their working trees and removes their
20760
+ * `.git/config` registration. The literal `--` separator makes the
20761
+ * pathspec injection-safe by construction.
20762
+ */
20763
+ static submoduleDeinit = submoduleDeinit;
20764
+ /**
20765
+ * Mutating: `git submodule sync [--recursive] [-- <paths>...]` —
20766
+ * re-copies each submodule's URL from `.gitmodules` into `.git/config`
20767
+ * (and into the submodule's own `remote.origin.url`), so a `.gitmodules`
20768
+ * URL change actually reaches git's live configuration.
20769
+ */
20770
+ static submoduleSync = submoduleSync;
20771
+ /**
20772
+ * Mutating: `git submodule set-url -- <path> <url>` — rewrites the
20773
+ * submodule's URL in `.gitmodules` and synchronizes it into
20774
+ * `.git/config`. The literal `--` separator makes the path and url
20775
+ * injection-safe by construction.
20776
+ *
20777
+ * @remarks
20778
+ * An embedded `userinfo@` credential in `url` is masked in
20779
+ * {@link GitInvocation.redactedArgs}.
20780
+ */
20781
+ static submoduleSetUrl = submoduleSetUrl;
20782
+ /**
20783
+ * Mutating: `git submodule set-branch (--branch <branch> | --default) -- <path>`
20784
+ * — records (or clears, when `branch` is omitted) the branch a submodule
20785
+ * tracks in `.gitmodules`. The literal `--` separator makes the path
20786
+ * injection-safe by construction.
20787
+ */
20788
+ static submoduleSetBranch = submoduleSetBranch;
20789
+ /**
20790
+ * Mutating: `git submodule absorbgitdirs [-- <paths>...]` — moves each
20791
+ * submodule's embedded `.git` directory into the superproject's
20792
+ * `.git/modules/` and leaves a gitfile pointer behind.
20793
+ */
20794
+ static submoduleAbsorbgitdirs = submoduleAbsorbgitdirs;
20795
+ /**
20796
+ * Mutating: `git submodule foreach [--recursive] <command>` — runs a shell
20797
+ * command in every checked-out submodule. `command` is a single shell
20798
+ * string, evaluated by git in each submodule's directory; it can mutate
20799
+ * anything, which is why the constructor is marked mutating regardless of
20800
+ * what the command does.
20801
+ *
20802
+ * @remarks
20803
+ * This is the ONE constructor whose argument cannot be made injection-safe
20804
+ * by construction: git evaluates `command` with `sh -c`, so every character
20805
+ * of it is shell code — a `--` separator or quoting cannot help. Callers
20806
+ * must treat `command` as a trusted literal and never interpolate untrusted
20807
+ * data into it.
20808
+ */
20809
+ static submoduleForeach = submoduleForeach;
20810
+ /**
20811
+ * `git ls-remote [--heads] [--tags] <remote> [<patterns>...]` — the refs a
20812
+ * remote advertises (sha + refname), optionally filtered to branch heads,
20813
+ * tags, and/or shell-glob patterns.
20814
+ *
20815
+ * @remarks
20816
+ * A read that talks to the NETWORK, not to the local repository — the one
20817
+ * non-mutating constructor in this package that does. An embedded
20818
+ * `userinfo@` credential in `remote` is masked in
20819
+ * {@link GitInvocation.redactedArgs}. An annotated tag advertises two
20820
+ * entries: `refs/tags/<name>` (the tag object) and `refs/tags/<name>^{}`
20821
+ * (the peeled commit).
20822
+ */
20823
+ static lsRemote = lsRemote;
20824
+ /**
20825
+ * Mutating: `git remote add <name> <url>` — registers a new remote.
20826
+ *
20827
+ * @remarks
20828
+ * An embedded `userinfo@` credential in `url` is masked in
20829
+ * {@link GitInvocation.redactedArgs}.
20830
+ */
20831
+ static remoteAdd = remoteAdd;
20832
+ /**
20833
+ * Mutating: `git remote remove <name>` — deletes a remote and its
20834
+ * remote-tracking refs and configuration.
20835
+ */
20836
+ static remoteRemove = remoteRemove;
20837
+ /**
20838
+ * Mutating: `git remote set-url <name> <url>` — rewrites a remote's fetch
20839
+ * URL.
20840
+ *
20841
+ * @remarks
20842
+ * An embedded `userinfo@` credential in `url` is masked in
20843
+ * {@link GitInvocation.redactedArgs}.
20844
+ */
20845
+ static remoteSetUrl = remoteSetUrl;
20846
+ /**
20847
+ * Mutating: `git stash push [--include-untracked] [-m <message>] [-- <paths>...]`
20848
+ * — saves the working tree (and index) state onto the stash stack. The
20849
+ * literal `--` separator makes the optional pathspec injection-safe by
20850
+ * construction; the message rides behind `-m`, which git consumes as a
20851
+ * value even when it begins with `-`.
20852
+ */
20853
+ static stashPush = stashPush;
20854
+ /**
20855
+ * Mutating: `git stash pop [stash@{n}]` — applies a stash entry and drops
20856
+ * it on success. The stash ref is rendered from an INTEGER index by this
20857
+ * package, never caller text.
20858
+ */
20859
+ static stashPop = stashPop;
20860
+ /**
20861
+ * Mutating: `git stash apply [stash@{n}]` — applies a stash entry and
20862
+ * keeps it on the stack. The stash ref is rendered from an INTEGER index
20863
+ * by this package, never caller text.
20864
+ */
20865
+ static stashApply = stashApply;
20866
+ /**
20867
+ * Mutating: `git stash drop [stash@{n}]` — deletes a stash entry without
20868
+ * applying it. The stash ref is rendered from an INTEGER index by this
20869
+ * package, never caller text.
20870
+ */
20871
+ static stashDrop = stashDrop;
20872
+ /**
20873
+ * `git stash list -z --format=%gd%x1f%H%x1f%gs` — every stash entry as a
20874
+ * NUL-terminated record of unit-separated fields: the reflog selector
20875
+ * (`stash@{0}`), the stash commit sha, and the reflog subject.
20876
+ *
20877
+ * @remarks
20878
+ * The `%x1f` (ASCII unit separator) field separator plus `-z` record
20879
+ * terminator keeps the parse split-safe: a stash message cannot contain
20880
+ * either byte (reflog subjects are single-line).
20881
+ */
20882
+ static stashList = stashList;
20883
+ /**
20884
+ * `git branch --list [--remotes | --all] --format=%(HEAD)%00%(refname:short)%00%(objectname)`
20885
+ * — every branch as a NUL-separated triple: the current-branch marker, the
20886
+ * short name, and the tip sha.
20887
+ *
20888
+ * @remarks
20889
+ * Records are newline-separated, which is split-safe here: git refnames
20890
+ * cannot contain a newline (or a space), so the only NUL bytes are the
20891
+ * format's own field separators. `all` wins over `remotes` when both are
20892
+ * set.
20893
+ */
20894
+ static branchList = branchList;
20895
+ /**
20896
+ * Mutating: `git tag [--force] [-m <message>] <name> [<ref>]` — creates a
20897
+ * lightweight tag, or an annotated one when `message` is given (`-m`
20898
+ * implies `-a`).
20899
+ */
20900
+ static tagCreate = tagCreate;
20901
+ /** Mutating: `git tag --delete <name>` — deletes a local tag. */
20902
+ static tagDelete = tagDelete;
20903
+ /**
20904
+ * `git tag --list [<pattern>]` — tag names, optionally filtered by a
20905
+ * shell-glob pattern, one per line (refnames cannot contain newlines).
20906
+ */
20907
+ static tagList = tagList;
20908
+ /**
20909
+ * `git for-each-ref --format=%(refname)%00%(objectname)%00%(objecttype) [<patterns>...]`
20910
+ * — every matching ref as a NUL-separated triple: full refname, sha, and
20911
+ * object type.
20912
+ *
20913
+ * @remarks
20914
+ * The format is this package's own fixed triple — the parse contract and
20915
+ * the argv are decided together, so the format string is a constructor
20916
+ * literal, never caller data. An annotated tag's `objecttype` is `tag`
20917
+ * (the tag object), not `commit`.
20918
+ */
20919
+ static forEachRef = forEachRef;
20920
+ /**
20921
+ * `git rev-list [--max-count=<n>] [--first-parent] <ref-or-range>` — commit
20922
+ * shas reachable from the ref (or range, e.g. `main..feat`), newest first.
20923
+ */
20924
+ static revList = revList;
20925
+ /**
20926
+ * Mutating: `git commit [--all] [--allow-empty] [--amend] [--author=<author>] -m <message>`
20927
+ * — records a commit. The message always rides argv behind `-m` (git
20928
+ * consumes it as a value even when it begins with `-`); committer identity
20929
+ * comes from the caller's environment — this constructor sets no
20930
+ * `GIT_AUTHOR_*`/`GIT_COMMITTER_*` variables, and the optional `author`
20931
+ * override is the fused `--author=` form.
20932
+ */
20933
+ static commit = commit;
20934
+ /**
20935
+ * Mutating: `git push [--force | --force-with-lease] [--tags] [--set-upstream] <remote> [<refspec>]`
20936
+ * — updates remote refs.
20937
+ *
20938
+ * @remarks
20939
+ * `remote` may be a URL as well as a remote name; an embedded `userinfo@`
20940
+ * credential is masked in {@link GitInvocation.redactedArgs}.
20941
+ */
20942
+ static push = push$1;
20943
+ /**
20944
+ * Mutating: `git pull [--rebase] [--ff-only] <remote> [<ref>]` — fetches
20945
+ * and integrates.
20946
+ *
20947
+ * @remarks
20948
+ * `remote` may be a URL as well as a remote name; an embedded `userinfo@`
20949
+ * credential is masked in {@link GitInvocation.redactedArgs}.
20950
+ */
20951
+ static pull = pull;
20952
+ /**
20953
+ * `git config [-f <file>] --list -z` — every configuration entry in scope
20954
+ * (or in the given file only), NUL-terminated, the key separated from the
20955
+ * value by a newline within each record.
20956
+ *
20957
+ * @remarks
20958
+ * `-z` is load-bearing: a config VALUE may contain newlines; only the NUL
20959
+ * record terminator plus first-newline field split parses it losslessly.
20960
+ * A valueless key (git's boolean-true shorthand) emits no newline at all.
20961
+ */
20962
+ static configList = configList;
20963
+ /**
20964
+ * `git config [-f <file>] --get-all -z <key>` — every value of a
20965
+ * (possibly multi-valued) key, NUL-terminated. An unset key exits 1 with
20966
+ * silent stderr.
20967
+ */
20968
+ static configGetAll = configGetAll;
20969
+ /**
20970
+ * Mutating: `git config [-f <file>] (--unset | --unset-all) <key>` —
20971
+ * removes a key (or, with `all`, every value of a multi-valued key).
20972
+ *
20973
+ * @remarks
20974
+ * git exits 5, silently, when the key was not set — a loud failure by
20975
+ * this package's classification, deliberately: an unset that silently did
20976
+ * nothing is indistinguishable from one that worked.
20977
+ */
20978
+ static configUnset = configUnset;
20979
+ /**
20980
+ * Mutating: `git rm [--cached] [-r] [--force] -- <paths...>` — removes
20981
+ * paths from the index (and, without `cached`, the working tree). The
20982
+ * literal `--` separator makes the pathspec injection-safe by
20983
+ * construction.
20984
+ */
20985
+ static rm = rm;
20986
+ /**
20987
+ * Mutating: `git mv [--force] -- <source> <destination>` — moves or
20988
+ * renames a tracked path. The literal `--` separator makes both positionals
20989
+ * injection-safe by construction.
20990
+ */
20991
+ static mv = mv;
20992
+ /**
20993
+ * `git check-ignore -z --stdin` — which of the given paths git would
20994
+ * ignore, paths fed NUL-separated via stdin and answers returned
20995
+ * NUL-separated.
20996
+ *
20997
+ * @remarks
20998
+ * The `--stdin -z` form is the only fully robust one: `-z` without
20999
+ * `--stdin` is rejected by git outright, and the non-`-z` output C-quotes
21000
+ * special-character paths. Feeding paths via stdin also makes them
21001
+ * injection-safe by construction — nothing caller-controlled enters the
21002
+ * argv. When NO path is ignored, git exits 1 with silent stderr.
21003
+ */
21004
+ static checkIgnore = checkIgnore;
21005
+ /**
21006
+ * Mutating: `git worktree add [--force] [--detach] <path> [<ref>]` —
21007
+ * creates a linked working tree at `path`, checked out at `ref` (or the
21008
+ * branch named after `path`'s basename).
21009
+ */
21010
+ static worktreeAdd = worktreeAdd;
21011
+ /**
21012
+ * `git worktree list --porcelain -z` — every working tree as a block of
21013
+ * NUL-terminated attributes (`worktree <path>`, `HEAD <sha>`,
21014
+ * `branch <ref>` / `detached`, `bare`, `locked [<reason>]`,
21015
+ * `prunable [<reason>]`), blocks separated by an empty attribute.
21016
+ */
21017
+ static worktreeList = worktreeList;
21018
+ /** Mutating: `git worktree remove [--force] <path>` — removes a linked working tree. */
21019
+ static worktreeRemove = worktreeRemove;
21020
+ /**
21021
+ * `git ls-files --stage -z [-- <pathspec>...]` — every INDEX entry (mode,
21022
+ * oid, stage number, path), NUL-terminated, optionally scoped to
21023
+ * `pathspec`.
21024
+ *
21025
+ * @remarks
21026
+ * The index-side sibling of {@link GitCommand.lsTree}: `lsTree` reads a
21027
+ * COMMITTED tree at a ref, while this reads the staging area — the only
21028
+ * place a staged-but-uncommitted gitlink (`160000 <oid> 0 <path>`) is
21029
+ * visible. `-z` is load-bearing twice over: paths may contain newlines,
21030
+ * and the non-`-z` output C-quotes special-character paths.
21031
+ */
21032
+ static lsFiles = lsFiles;
19630
21033
  };
19631
21034
 
19632
21035
  //#endregion
19633
- //#region ../../node_modules/.pnpm/@effected+git@0.5.2_effect@4.0.0-beta.101/node_modules/@effected/git/internal/run.js
21036
+ //#region ../../node_modules/.pnpm/@effected+git@0.6.0_effect@4.0.0-beta.101/node_modules/@effected/git/internal/run.js
19634
21037
  /**
19635
21038
  * Spawns `command` and collects its stdout, stderr, and exit code as a single
19636
21039
  * triple.
@@ -19658,7 +21061,7 @@ const runCollected = (command) => Effect.scoped(Effect.gen(function* () {
19658
21061
  }));
19659
21062
 
19660
21063
  //#endregion
19661
- //#region ../../node_modules/.pnpm/@effected+git@0.5.2_effect@4.0.0-beta.101/node_modules/@effected/git/Git.js
21064
+ //#region ../../node_modules/.pnpm/@effected+git@0.6.0_effect@4.0.0-beta.101/node_modules/@effected/git/Git.js
19662
21065
  /** git's own ceiling: a run that has not answered in 30s is not going to. */
19663
21066
  const GIT_TIMEOUT = Duration.seconds(30);
19664
21067
  /**
@@ -19686,7 +21089,16 @@ var GitCommandError = class extends Schema.TaggedErrorClass()("GitCommandError",
19686
21089
  * logic routes on this instead of matching `detail` prose.
19687
21090
  */
19688
21091
  kind: Schema.Literals(["refused", "failed"]),
19689
- /** The argument vector, without the leading `git`. */
21092
+ /**
21093
+ * The REDACTED argument vector, without the leading `git`.
21094
+ *
21095
+ * Sensitive positionals — config values, a URL's embedded userinfo — are
21096
+ * already masked by the constructor's redaction mask before this error is
21097
+ * constructed (`configSet`'s value reads `<redacted>`; a
21098
+ * `https://user:token@host/...` remote keeps everything but its
21099
+ * `userinfo@`). The raw argv is never persisted in an error value, and
21100
+ * `message` renders this redacted vector.
21101
+ */
19690
21102
  args: Schema.Array(Schema.String),
19691
21103
  /** The working directory the command ran in. */
19692
21104
  cwd: Schema.String,
@@ -19732,12 +21144,77 @@ var UnknownRefError = class extends Schema.TaggedErrorClass()("UnknownRefError",
19732
21144
  }
19733
21145
  };
19734
21146
  /**
19735
- * One entry of a `git ls-tree` listing.
21147
+ * A `git push` was rejected because the remote ref has moved: the classic
21148
+ * non-fast-forward rejection (`fetch first` / `non-fast-forward`), or a
21149
+ * `--force-with-lease` lease failure (`stale info`).
21150
+ *
21151
+ * @remarks
21152
+ * The typed signal a fetch-then-retry (or rebase-then-retry) fallback
21153
+ * branches on — every other push failure stays a {@link GitCommandError}.
21154
+ * Only `Git.push` can fail with this error.
19736
21155
  *
19737
21156
  * @public
19738
21157
  */
19739
- var LsTreeEntry = class extends Schema.Class("LsTreeEntry")({
19740
- /** The entry's file mode, e.g. `100644`. */
21158
+ var NonFastForwardError = class extends Schema.TaggedErrorClass()("NonFastForwardError", {
21159
+ /** The working directory the push ran in. */
21160
+ cwd: Schema.String,
21161
+ /** The refspec that was rejected, when the caller passed one. */
21162
+ refspec: Schema.optionalKey(Schema.String)
21163
+ }) {
21164
+ /** Renders the rejected push into a one-line message. */
21165
+ get message() {
21166
+ return this.refspec !== void 0 ? `push of '${this.refspec}' rejected as non-fast-forward in ${this.cwd}` : `push rejected as non-fast-forward in ${this.cwd}`;
21167
+ }
21168
+ };
21169
+ /**
21170
+ * A merge-shaped operation (`pull`, `stash pop`, `stash apply`) stopped with
21171
+ * conflict markers in the working tree.
21172
+ *
21173
+ * @remarks
21174
+ * The typed signal a resolve-or-abort recovery branches on. The conflicted
21175
+ * state is REAL: git has already written conflict markers, and (for `pull`)
21176
+ * `MERGE_HEAD` is set — the caller owns resolving or aborting. Detection
21177
+ * matches git's conflict report, which lands on STDOUT for a merge and on
21178
+ * stderr for a rebase-mode pull; both streams are inspected.
21179
+ *
21180
+ * @public
21181
+ */
21182
+ var MergeConflictError = class extends Schema.TaggedErrorClass()("MergeConflictError", {
21183
+ /** The working directory the merge ran in. */
21184
+ cwd: Schema.String }) {
21185
+ /** Renders the conflicted merge into a one-line message. */
21186
+ get message() {
21187
+ return `merge conflict in ${this.cwd}: fix conflicts (or abort) before continuing`;
21188
+ }
21189
+ };
21190
+ /**
21191
+ * A merge-shaped operation refused to start because local modifications would
21192
+ * be overwritten — git's refusal reads
21193
+ * `Your local changes ... would be overwritten by merge`.
21194
+ *
21195
+ * @remarks
21196
+ * The typed "commit or stash first" signal. Unlike {@link MergeConflictError}
21197
+ * the working tree is UNTOUCHED — git aborted before changing anything.
21198
+ * Only the merge-shaped methods (`pull`, `stashPop`, `stashApply`) can fail
21199
+ * with this error.
21200
+ *
21201
+ * @public
21202
+ */
21203
+ var DirtyWorktreeError = class extends Schema.TaggedErrorClass()("DirtyWorktreeError", {
21204
+ /** The working directory whose local changes blocked the operation. */
21205
+ cwd: Schema.String }) {
21206
+ /** Renders the blocked operation into a one-line message. */
21207
+ get message() {
21208
+ return `local changes would be overwritten in ${this.cwd}: commit or stash them first`;
21209
+ }
21210
+ };
21211
+ /**
21212
+ * One entry of a `git ls-tree` listing.
21213
+ *
21214
+ * @public
21215
+ */
21216
+ var LsTreeEntry = class extends Schema.Class("LsTreeEntry")({
21217
+ /** The entry's file mode, e.g. `100644`. */
19741
21218
  mode: Schema.String,
19742
21219
  /** The kind of object the entry points at. */
19743
21220
  type: Schema.Literals([
@@ -19792,11 +21269,26 @@ const UNKNOWN_REF_PATTERNS = [
19792
21269
  "couldn't find remote ref"
19793
21270
  ];
19794
21271
  const ABSENT_AT_REF_PATTERNS = ["does not exist in", "exists on disk, but not in"];
21272
+ const PUSH_REJECTED_PATTERNS = [
21273
+ "non-fast-forward",
21274
+ "fetch first",
21275
+ "stale info"
21276
+ ];
21277
+ const MERGE_CONFLICT_PATTERNS = [
21278
+ "CONFLICT (",
21279
+ "Automatic merge failed",
21280
+ "could not apply"
21281
+ ];
21282
+ const DIRTY_WORKTREE_PATTERN = "would be overwritten by";
19795
21283
  const matchesAny = (stderr, patterns) => patterns.some((pattern) => stderr.includes(pattern));
19796
21284
  /**
19797
21285
  * Classifies one completed run (or spawn-level `PlatformError`) against
19798
21286
  * git's stderr taxonomy. Written once — every `Git` method funnels through
19799
21287
  * this before deciding its own return value.
21288
+ *
21289
+ * `args` is the invocation's REDACTED argv: it is the only argv this
21290
+ * function may persist into a `GitCommandError`, per the #86 redaction
21291
+ * policy.
19800
21292
  */
19801
21293
  const classify = (cwd, args, outcome, kind) => {
19802
21294
  if (outcome instanceof PlatformError.PlatformError) {
@@ -19819,6 +21311,11 @@ const classify = (cwd, args, outcome, kind) => {
19819
21311
  };
19820
21312
  if (stderr.includes(NOT_A_REPOSITORY)) return { _tag: "notARepository" };
19821
21313
  if (matchesAny(stderr, UNKNOWN_REF_PATTERNS)) return { _tag: "unknownRef" };
21314
+ if (kind === "push" && stderr.includes("[rejected]") && matchesAny(stderr, PUSH_REJECTED_PATTERNS)) return { _tag: "nonFastForward" };
21315
+ if (kind === "merge") {
21316
+ if (stderr.includes(DIRTY_WORKTREE_PATTERN)) return { _tag: "dirtyWorktree" };
21317
+ if (matchesAny(stdout, MERGE_CONFLICT_PATTERNS) || matchesAny(stderr, MERGE_CONFLICT_PATTERNS)) return { _tag: "mergeConflict" };
21318
+ }
19822
21319
  if (kind === "quiet" && exitCode === 1 && stderr === "") return { _tag: "absent" };
19823
21320
  if (kind === "noSuchRemote" && stderr.includes("No such remote")) return { _tag: "absent" };
19824
21321
  if (kind === "show" && matchesAny(stderr, ABSENT_AT_REF_PATTERNS)) return { _tag: "absent" };
@@ -19835,13 +21332,19 @@ const classify = (cwd, args, outcome, kind) => {
19835
21332
  };
19836
21333
  };
19837
21334
  /**
19838
- * Runs `command`, classifies the outcome, and never fails: a spawn-level
19839
- * `PlatformError` and a per-run timeout are both absorbed into the
19840
- * `"failure"` classification rather than escaping the effect's error
19841
- * channel.
21335
+ * Runs an invocation's command in `cwd`, classifies the outcome, and never
21336
+ * fails: a spawn-level `PlatformError` and a per-run timeout are both
21337
+ * absorbed into the `"failure"` classification rather than escaping the
21338
+ * effect's error channel.
21339
+ *
21340
+ * The argv handed to `classify` — and therefore persisted into any
21341
+ * `GitCommandError` — is the invocation's REDACTED argv, never the raw one:
21342
+ * the redaction mask the pure constructor carries is applied here, at the
21343
+ * single classification choke point (the #86 redaction policy).
19842
21344
  */
19843
- const runClassified = (command, cwd, kind) => {
19844
- const args = ChildProcess.isStandardCommand(command) ? command.args : [];
21345
+ const runClassified = (invocation, cwd, kind) => {
21346
+ const args = invocation.redactedArgs;
21347
+ const command = ChildProcess.setCwd(invocation.command, cwd);
19845
21348
  return runCollected(command).pipe(Effect.map((collected) => classify(cwd, args, collected, kind)), Effect.catch((platformError) => Effect.succeed(classify(cwd, args, platformError, kind))), Effect.timeoutOrElse({
19846
21349
  duration: GIT_TIMEOUT,
19847
21350
  orElse: () => Effect.succeed({
@@ -19971,7 +21474,43 @@ var StatusEntry = class extends Schema.Class("StatusEntry")({
19971
21474
  path: Schema.String,
19972
21475
  /** The original path; present only on rename/copy entries. */
19973
21476
  origPath: Schema.optionalKey(Schema.String)
19974
- }) {};
21477
+ }) {
21478
+ /**
21479
+ * Renders this entry back to one porcelain-shaped line: `XY <path>`.
21480
+ *
21481
+ * @remarks
21482
+ * **The rename convention is decided here, once, for every consumer.** By
21483
+ * default a rename/copy entry renders its NEW path only — `path` IS the
21484
+ * entry's current path, the one a line-oriented downstream can actually
21485
+ * open — which is a deliberate divergence from git's own non-`-z`
21486
+ * rendering (`orig -> new`). The arrow form is ambiguous to naive
21487
+ * line/whitespace splitters (paths may contain spaces, or a literal
21488
+ * `" -> "`), so it is opt-in via `renames: "arrow"` for consumers that
21489
+ * want git parity.
21490
+ *
21491
+ * A second recorded divergence: git's non-`-z` porcelain C-quotes paths
21492
+ * containing special characters; this renderer emits paths raw. It exists
21493
+ * for whitespace-insensitive text consumers — a machine parser should
21494
+ * consume the decoded {@link StatusEntry} values (or `-z` output)
21495
+ * directly, never re-parse this rendering.
21496
+ */
21497
+ toLine(options) {
21498
+ const rendered = options?.renames === "arrow" && this.origPath !== void 0 ? `${this.origPath} -> ${this.path}` : this.path;
21499
+ return `${this.x}${this.y} ${rendered}`;
21500
+ }
21501
+ /**
21502
+ * Renders entries back to porcelain-shaped text: one {@link StatusEntry.toLine}
21503
+ * line per entry, newline-joined, no trailing newline.
21504
+ *
21505
+ * @remarks
21506
+ * The route back from `Git.status`'s parsed entries to line-oriented text,
21507
+ * so a consumer whose downstream contract is porcelain-shaped text does
21508
+ * not hand-roll its own renderer (and re-decide the rename convention —
21509
+ * see {@link StatusEntry.toLine} for that decision). An empty array
21510
+ * renders as the empty string.
21511
+ */
21512
+ static format = (entries, options) => entries.map((entry) => entry.toLine(options)).join("\n");
21513
+ };
19975
21514
  /**
19976
21515
  * Parses `git log -1 --format=%H%x00%G?%x00%B` output: exactly two NUL
19977
21516
  * separators, everything after the second is the raw message, untrimmed.
@@ -20025,6 +21564,360 @@ const parseStatus = (output) => {
20025
21564
  return entries;
20026
21565
  };
20027
21566
  /**
21567
+ * One line of a `git submodule status` listing.
21568
+ *
21569
+ * @remarks
21570
+ * The `state` decodes git's one-character prefix: `" "` → `"current"` (the
21571
+ * checked-out commit matches the index gitlink), `"-"` → `"uninitialized"`,
21572
+ * `"+"` → `"outOfSync"` (the checked-out commit differs from the gitlink),
21573
+ * `"U"` → `"conflict"` (merge conflicts). `describe` carries the
21574
+ * parenthesized `git describe` suffix git appends for initialized
21575
+ * submodules.
21576
+ *
21577
+ * @public
21578
+ */
21579
+ var SubmoduleStatusEntry = class extends Schema.Class("SubmoduleStatusEntry")({
21580
+ /** The decoded state prefix. */
21581
+ state: Schema.Literals([
21582
+ "current",
21583
+ "uninitialized",
21584
+ "outOfSync",
21585
+ "conflict"
21586
+ ]),
21587
+ /** The submodule's checked-out (or, uninitialized, gitlink) commit sha. */
21588
+ sha: Schema.String,
21589
+ /** The submodule's path relative to the superproject root. */
21590
+ path: Schema.String,
21591
+ /** The `git describe` suffix, present only for initialized submodules. */
21592
+ describe: Schema.optionalKey(Schema.String)
21593
+ }) {};
21594
+ /**
21595
+ * Parses `git submodule status` output. Line-based — the one parser in this
21596
+ * package without a `-z` mode to lean on, because git does not offer one for
21597
+ * `submodule status`; a submodule path containing a newline (or a literal
21598
+ * ` (` suffix mimicking the describe parenthesis) would corrupt the parse.
21599
+ * Accepted as a git-imposed limitation.
21600
+ */
21601
+ const parseSubmoduleStatus = (output) => {
21602
+ const entries = [];
21603
+ for (const line of output.split("\n")) {
21604
+ const trimmedEnd = line.endsWith("\r") ? line.slice(0, -1) : line;
21605
+ if (trimmedEnd === "") continue;
21606
+ const prefix = trimmedEnd.charAt(0);
21607
+ const state = prefix === "-" ? "uninitialized" : prefix === "+" ? "outOfSync" : prefix === "U" ? "conflict" : "current";
21608
+ const rest = prefix === " " || prefix === "-" || prefix === "+" || prefix === "U" ? trimmedEnd.slice(1) : trimmedEnd;
21609
+ const shaEnd = rest.indexOf(" ");
21610
+ const sha = shaEnd === -1 ? rest : rest.slice(0, shaEnd);
21611
+ const remainder = shaEnd === -1 ? "" : rest.slice(shaEnd + 1);
21612
+ const describeStart = remainder.endsWith(")") ? remainder.lastIndexOf(" (") : -1;
21613
+ if (describeStart === -1) entries.push(SubmoduleStatusEntry.make({
21614
+ state,
21615
+ sha,
21616
+ path: remainder
21617
+ }));
21618
+ else entries.push(SubmoduleStatusEntry.make({
21619
+ state,
21620
+ sha,
21621
+ path: remainder.slice(0, describeStart),
21622
+ describe: remainder.slice(describeStart + 2, -1)
21623
+ }));
21624
+ }
21625
+ return entries;
21626
+ };
21627
+ /**
21628
+ * One ref a remote advertises, from `git ls-remote`.
21629
+ *
21630
+ * @remarks
21631
+ * `ref` is the FULL refname as advertised (`refs/heads/main`,
21632
+ * `refs/tags/v1`), including the `^{}` suffix on an annotated tag's peeled
21633
+ * entry — an annotated tag appears twice, once as the tag object and once
21634
+ * peeled to its commit.
21635
+ *
21636
+ * @public
21637
+ */
21638
+ var LsRemoteEntry = class LsRemoteEntry extends Schema.Class("LsRemoteEntry")({
21639
+ /** The sha the advertised ref points at. */
21640
+ sha: Schema.String,
21641
+ /** The full advertised refname, `^{}` peel suffix included. */
21642
+ ref: Schema.String
21643
+ }) {
21644
+ /**
21645
+ * The human-facing short name of an advertised refname: the
21646
+ * `refs/heads/` / `refs/tags/` / `refs/remotes/` prefix and any `^{}`
21647
+ * peel suffix stripped (`refs/tags/v1^{}` → `v1`).
21648
+ */
21649
+ static shortName = (ref) => {
21650
+ const base = ref.endsWith("^{}") ? ref.slice(0, -3) : ref;
21651
+ for (const prefix of [
21652
+ "refs/heads/",
21653
+ "refs/tags/",
21654
+ "refs/remotes/"
21655
+ ]) if (base.startsWith(prefix)) return base.slice(prefix.length);
21656
+ return base;
21657
+ };
21658
+ /**
21659
+ * The entries whose short name is a NEAR MISS for `ref`: not an exact
21660
+ * match, but ending in `ref` right behind a separator (`@`, `/`, `-`,
21661
+ * `_`) — the monorepo-prefixed-tag case, where a caller asks for
21662
+ * `4.0.0-beta.101` and the remote advertises `effect@4.0.0-beta.101`.
21663
+ *
21664
+ * @remarks
21665
+ * A pure, decode-side helper for validate-before-mutate flows: run
21666
+ * `lsRemote`, look for the wanted ref, and when it is absent hand the
21667
+ * listing to this to compute a suggestion. Deliberately a helper on the
21668
+ * ENTRY value rather than behavior baked into the service — the service
21669
+ * returns the full listing and the caller owns the matching policy. An
21670
+ * annotated tag's peeled `^{}` entry shares its base short name, so a
21671
+ * near miss on such a tag can surface both of its entries.
21672
+ */
21673
+ static nearMatches = (entries, ref) => {
21674
+ const separators = [
21675
+ "@",
21676
+ "/",
21677
+ "-",
21678
+ "_"
21679
+ ];
21680
+ return entries.filter((entry) => {
21681
+ const short = LsRemoteEntry.shortName(entry.ref);
21682
+ if (short === ref || !short.endsWith(ref)) return false;
21683
+ return separators.includes(short.charAt(short.length - ref.length - 1));
21684
+ });
21685
+ };
21686
+ };
21687
+ /**
21688
+ * Parses `git ls-remote` output: one `<sha>\t<refname>` line per advertised
21689
+ * ref. Line-based deliberately — refnames cannot contain a newline (or a
21690
+ * tab), so the split is safe without a `-z` mode (which `ls-remote` does not
21691
+ * offer).
21692
+ */
21693
+ const parseLsRemote = (output) => output.split("\n").filter((line) => line.length > 0).map((line) => {
21694
+ const tabIndex = line.indexOf(" ");
21695
+ return LsRemoteEntry.make({
21696
+ sha: line.slice(0, tabIndex),
21697
+ ref: line.slice(tabIndex + 1)
21698
+ });
21699
+ });
21700
+ /**
21701
+ * One stash entry, from `git stash list`.
21702
+ *
21703
+ * @public
21704
+ */
21705
+ var StashEntry = class extends Schema.Class("StashEntry")({
21706
+ /** The reflog selector (`stash@{0}`) — the index other stash methods take. */
21707
+ ref: Schema.String,
21708
+ /** The stash commit's sha. */
21709
+ sha: Schema.String,
21710
+ /** The reflog subject: `WIP on <branch>: ...` or `On <branch>: <message>`. */
21711
+ message: Schema.String
21712
+ }) {};
21713
+ /**
21714
+ * Parses `git stash list -z --format=%gd%x1f%H%x1f%gs` output: NUL-terminated
21715
+ * records of unit-separated (`\x1f`) fields. Reflog subjects are single-line
21716
+ * and cannot contain either separator byte.
21717
+ */
21718
+ const parseStashList = (output) => parseNulSeparated(output).map((record) => {
21719
+ const [ref = "", sha = "", ...rest] = record.split("");
21720
+ return StashEntry.make({
21721
+ ref,
21722
+ sha,
21723
+ message: rest.join("")
21724
+ });
21725
+ });
21726
+ /**
21727
+ * One local (or remote-tracking) branch, from `git branch --list`.
21728
+ *
21729
+ * @public
21730
+ */
21731
+ var BranchEntry = class extends Schema.Class("BranchEntry")({
21732
+ /** The short branch name (`main`, or `origin/main` for a remote branch). */
21733
+ name: Schema.String,
21734
+ /** The branch tip's sha. */
21735
+ sha: Schema.String,
21736
+ /** Whether this branch is checked out in the current working tree. */
21737
+ current: Schema.Boolean
21738
+ }) {};
21739
+ /**
21740
+ * Parses `git branch --list --format=%(HEAD)%00%(refname:short)%00%(objectname)`
21741
+ * output: newline-separated records (refnames cannot contain newlines) of
21742
+ * NUL-separated fields. The `%(HEAD)` marker is `*` for the checked-out
21743
+ * branch; anything else (` `, or `+` for a branch checked out in a linked
21744
+ * worktree) is not-current.
21745
+ */
21746
+ const parseBranchList = (output) => output.split("\n").filter((line) => line.length > 0).map((line) => {
21747
+ const [marker = "", name = "", sha = ""] = line.split("\0");
21748
+ return BranchEntry.make({
21749
+ name,
21750
+ sha,
21751
+ current: marker === "*"
21752
+ });
21753
+ });
21754
+ /**
21755
+ * One ref, from `git for-each-ref`.
21756
+ *
21757
+ * @public
21758
+ */
21759
+ var RefEntry = class extends Schema.Class("RefEntry")({
21760
+ /** The full refname (`refs/tags/v1`). */
21761
+ ref: Schema.String,
21762
+ /** The sha of the object the ref points at. */
21763
+ sha: Schema.String,
21764
+ /**
21765
+ * The pointed-at object's type. An annotated tag is `tag` (the tag
21766
+ * object itself, not its target commit).
21767
+ */
21768
+ objectType: Schema.Literals([
21769
+ "commit",
21770
+ "tag",
21771
+ "tree",
21772
+ "blob"
21773
+ ])
21774
+ }) {};
21775
+ /**
21776
+ * Parses `git for-each-ref --format=%(refname)%00%(objectname)%00%(objecttype)`
21777
+ * output: newline-separated records (refnames cannot contain newlines) of
21778
+ * NUL-separated fields.
21779
+ */
21780
+ const parseForEachRef = (output) => output.split("\n").filter((line) => line.length > 0).map((line) => {
21781
+ const [ref = "", sha = "", objectType = "commit"] = line.split("\0");
21782
+ return RefEntry.make({
21783
+ ref,
21784
+ sha,
21785
+ objectType
21786
+ });
21787
+ });
21788
+ /**
21789
+ * One configuration entry, from `git config --list`.
21790
+ *
21791
+ * @public
21792
+ */
21793
+ var ConfigListEntry = class extends Schema.Class("ConfigListEntry")({
21794
+ /** The canonical dotted key (`section.subsection.key`). */
21795
+ key: Schema.String,
21796
+ /**
21797
+ * The raw value. A valueless key (git's boolean-true shorthand,
21798
+ * `[section]` + bare `key`) surfaces as the empty string — distinguish it
21799
+ * with `configGetAll` if the difference matters.
21800
+ */
21801
+ value: Schema.String
21802
+ }) {};
21803
+ /**
21804
+ * Parses `git config --list -z` output: NUL-terminated records, key separated
21805
+ * from value by the FIRST newline (a config value may itself contain
21806
+ * newlines — the reason `-z` is load-bearing). A record with no newline is a
21807
+ * valueless boolean-shorthand key.
21808
+ */
21809
+ const parseConfigList = (output) => parseNulSeparated(output).map((record) => {
21810
+ const newlineIndex = record.indexOf("\n");
21811
+ return newlineIndex === -1 ? ConfigListEntry.make({
21812
+ key: record,
21813
+ value: ""
21814
+ }) : ConfigListEntry.make({
21815
+ key: record.slice(0, newlineIndex),
21816
+ value: record.slice(newlineIndex + 1)
21817
+ });
21818
+ });
21819
+ /**
21820
+ * One working tree, from `git worktree list --porcelain`.
21821
+ *
21822
+ * @public
21823
+ */
21824
+ var WorktreeEntry = class extends Schema.Class("WorktreeEntry")({
21825
+ /** The working tree's absolute path. */
21826
+ path: Schema.String,
21827
+ /** The checked-out commit sha; absent for a bare repository entry. */
21828
+ head: Schema.optionalKey(Schema.String),
21829
+ /** The checked-out branch's full refname; absent when detached or bare. */
21830
+ branch: Schema.optionalKey(Schema.String),
21831
+ /** Whether the working tree is in detached-HEAD state. */
21832
+ detached: Schema.Boolean,
21833
+ /** Whether the entry is the bare repository itself. */
21834
+ bare: Schema.Boolean,
21835
+ /** Present when the worktree is locked; holds the lock reason (possibly empty). */
21836
+ locked: Schema.optionalKey(Schema.String),
21837
+ /** Present when the worktree is prunable; holds the reason (possibly empty). */
21838
+ prunable: Schema.optionalKey(Schema.String)
21839
+ }) {};
21840
+ /**
21841
+ * Parses `git worktree list --porcelain -z` output: NUL-terminated attribute
21842
+ * lines, one blank attribute terminating each entry. Attribute vocabulary:
21843
+ * `worktree <path>`, `HEAD <sha>`, `branch <ref>`, and the flag/annotation
21844
+ * attributes `detached`, `bare`, `locked [<reason>]`, `prunable [<reason>]`.
21845
+ */
21846
+ const parseWorktreeList = (output) => {
21847
+ const entries = [];
21848
+ let path;
21849
+ let head;
21850
+ let branch;
21851
+ let detached = false;
21852
+ let bare = false;
21853
+ let locked;
21854
+ let prunable;
21855
+ const flush = () => {
21856
+ if (path !== void 0) entries.push(WorktreeEntry.make({
21857
+ path,
21858
+ detached,
21859
+ bare,
21860
+ ...head !== void 0 ? { head } : {},
21861
+ ...branch !== void 0 ? { branch } : {},
21862
+ ...locked !== void 0 ? { locked } : {},
21863
+ ...prunable !== void 0 ? { prunable } : {}
21864
+ }));
21865
+ path = void 0;
21866
+ head = void 0;
21867
+ branch = void 0;
21868
+ detached = false;
21869
+ bare = false;
21870
+ locked = void 0;
21871
+ prunable = void 0;
21872
+ };
21873
+ for (const attribute of output.split("\0")) if (attribute === "") flush();
21874
+ else if (attribute.startsWith("worktree ")) path = attribute.slice(9);
21875
+ else if (attribute.startsWith("HEAD ")) head = attribute.slice(5);
21876
+ else if (attribute.startsWith("branch ")) branch = attribute.slice(7);
21877
+ else if (attribute === "detached") detached = true;
21878
+ else if (attribute === "bare") bare = true;
21879
+ else if (attribute === "locked" || attribute.startsWith("locked ")) locked = attribute === "locked" ? "" : attribute.slice(7);
21880
+ else if (attribute === "prunable" || attribute.startsWith("prunable ")) prunable = attribute === "prunable" ? "" : attribute.slice(9);
21881
+ flush();
21882
+ return entries;
21883
+ };
21884
+ /**
21885
+ * One index (staging area) entry, from `git ls-files --stage`.
21886
+ *
21887
+ * @remarks
21888
+ * The index-side sibling of {@link LsTreeEntry}: this is the ONLY place a
21889
+ * staged-but-uncommitted gitlink (`mode` `160000`) is visible — `lsTree`
21890
+ * reads the committed tree and misses exactly that window.
21891
+ *
21892
+ * @public
21893
+ */
21894
+ var LsFilesEntry = class extends Schema.Class("LsFilesEntry")({
21895
+ /** The entry's file mode, e.g. `100644` — `160000` for a gitlink. */
21896
+ mode: Schema.String,
21897
+ /** The staged object id. */
21898
+ oid: Schema.String,
21899
+ /** The merge stage: `0` normally; `1`/`2`/`3` during an unresolved merge. */
21900
+ stage: Schema.Number,
21901
+ /** The entry's path, relative to `cwd`. May contain spaces or newlines. */
21902
+ path: Schema.String
21903
+ }) {};
21904
+ /**
21905
+ * Parses `git ls-files --stage -z` output: each NUL-terminated entry is
21906
+ * `<mode> <oid> <stage>\t<path>`. `path` is everything after the first tab,
21907
+ * so a path containing spaces or newlines is preserved intact — the same
21908
+ * split rule as `parseLsTree`.
21909
+ */
21910
+ const parseLsFiles = (output) => parseNulSeparated(output).map((entry) => {
21911
+ const tabIndex = entry.indexOf(" ");
21912
+ const header = entry.slice(0, tabIndex).split(" ");
21913
+ return LsFilesEntry.make({
21914
+ mode: header[0] ?? "",
21915
+ oid: header[1] ?? "",
21916
+ stage: Number(header[2] ?? "0"),
21917
+ path: entry.slice(tabIndex + 1)
21918
+ });
21919
+ });
21920
+ /**
20028
21921
  * Refuse a caller-supplied ref or range that git would parse as an option.
20029
21922
  *
20030
21923
  * Refs are caller-controlled and land in git's argv as positional entries; a
@@ -20034,20 +21927,49 @@ const parseStatus = (output) => {
20034
21927
  * refused outright, before any spawn, as a typed {@link GitCommandError}.
20035
21928
  * `show`'s `path` needs no guard: it is fused after the ref into one
20036
21929
  * `ref:path` token, which cannot begin with `-` unless the ref does.
21930
+ *
21931
+ * `sensitive` values get the same check but a REDACTED report: a refused
21932
+ * sensitive positional (a `configSet` value) must not leak into
21933
+ * `GitCommandError.args`/`detail` any more than a spawned one may — the #86
21934
+ * redaction policy applies to guard rejections too.
20037
21935
  */
20038
- const rejectOptionLikeRefs = (cwd, refs) => {
21936
+ const rejectOptionLikeRefs = (cwd, refs, sensitive = []) => {
20039
21937
  const offending = refs.find((ref) => ref.startsWith("-"));
20040
- return offending === void 0 ? Effect.void : Effect.fail(new GitCommandError({
21938
+ if (offending !== void 0) return Effect.fail(new GitCommandError({
20041
21939
  kind: "refused",
20042
21940
  args: [offending],
20043
21941
  cwd,
20044
21942
  stderr: "",
20045
21943
  detail: `refused a ref argument git would parse as an option: ${JSON.stringify(offending)}`
20046
21944
  }));
21945
+ return sensitive.find((value) => value.startsWith("-")) === void 0 ? Effect.void : Effect.fail(new GitCommandError({
21946
+ kind: "refused",
21947
+ args: ["<redacted>"],
21948
+ cwd,
21949
+ stderr: "",
21950
+ detail: "refused a sensitive argument git would parse as an option (value redacted)"
21951
+ }));
20047
21952
  };
21953
+ /**
21954
+ * Refuse a caller-supplied numeric index/limit that is not a non-negative
21955
+ * integer.
21956
+ *
21957
+ * Every relational comparison against `NaN` is `false`, so a bare
21958
+ * `value < 0` guard admits `NaN` (and a fractional value truncates nothing —
21959
+ * it rides straight into the argv as `stash@{1.5}` / `--max-count=NaN`).
21960
+ * Integrality and range are therefore checked together, pre-spawn, as a
21961
+ * typed refusal.
21962
+ */
21963
+ const rejectNonNaturalNumber = (cwd, label, value) => value === void 0 || Number.isInteger(value) && value >= 0 ? Effect.void : Effect.fail(new GitCommandError({
21964
+ kind: "refused",
21965
+ args: [String(value)],
21966
+ cwd,
21967
+ stderr: "",
21968
+ detail: `refused ${label}: expected a non-negative integer, received ${value}`
21969
+ }));
20048
21970
  /** Builds the `Git.Service` shape over an already-resolved `ChildProcessSpawner`. */
20049
21971
  const make = (spawner) => {
20050
- const runFor = (command, cwd, kind) => runClassified(command, cwd, kind).pipe(Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner));
21972
+ const runFor = (invocation, cwd, kind) => runClassified(invocation, cwd, kind).pipe(Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner));
20051
21973
  const show = Effect.fn("Git.show")(function* (cwd, ref, path) {
20052
21974
  yield* Effect.annotateCurrentSpan({
20053
21975
  cwd,
@@ -20055,8 +21977,7 @@ const make = (spawner) => {
20055
21977
  path
20056
21978
  });
20057
21979
  yield* rejectOptionLikeRefs(cwd, [ref]);
20058
- const command = ChildProcess.setCwd(GitCommand.show(ref, path), cwd);
20059
- const classified = yield* runFor(command, cwd, "show");
21980
+ const classified = yield* runFor(GitCommand.show(ref, path), cwd, "show");
20060
21981
  switch (classified._tag) {
20061
21982
  case "success": return Option.some(classified.output);
20062
21983
  case "absent": return Option.none();
@@ -20075,8 +21996,7 @@ const make = (spawner) => {
20075
21996
  ref
20076
21997
  });
20077
21998
  yield* rejectOptionLikeRefs(cwd, [ref]);
20078
- const command = ChildProcess.setCwd(GitCommand.lsTree(ref, options?.pathspec ?? []), cwd);
20079
- const classified = yield* runFor(command, cwd, "generic");
21999
+ const classified = yield* runFor(GitCommand.lsTree(ref, options?.pathspec ?? []), cwd, "generic");
20080
22000
  switch (classified._tag) {
20081
22001
  case "success": return parseLsTree(classified.output);
20082
22002
  case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
@@ -20094,8 +22014,7 @@ const make = (spawner) => {
20094
22014
  ref
20095
22015
  });
20096
22016
  yield* rejectOptionLikeRefs(cwd, [ref]);
20097
- const command = ChildProcess.setCwd(GitCommand.refExists(ref), cwd);
20098
- const classified = yield* runFor(command, cwd, "refExists");
22017
+ const classified = yield* runFor(GitCommand.refExists(ref), cwd, "refExists");
20099
22018
  switch (classified._tag) {
20100
22019
  case "success": return true;
20101
22020
  case "refMissing": return false;
@@ -20112,8 +22031,7 @@ const make = (spawner) => {
20112
22031
  b
20113
22032
  });
20114
22033
  yield* rejectOptionLikeRefs(cwd, [a, b]);
20115
- const command = ChildProcess.setCwd(GitCommand.mergeBase(a, b), cwd);
20116
- const classified = yield* runFor(command, cwd, "generic");
22034
+ const classified = yield* runFor(GitCommand.mergeBase(a, b), cwd, "generic");
20117
22035
  switch (classified._tag) {
20118
22036
  case "success": return classified.output.trim();
20119
22037
  case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
@@ -20134,8 +22052,7 @@ const make = (spawner) => {
20134
22052
  relative
20135
22053
  });
20136
22054
  yield* rejectOptionLikeRefs(cwd, [options.base, options.head]);
20137
- const command = ChildProcess.setCwd(GitCommand.changedFiles(options.base, options.head, relative), cwd);
20138
- const classified = yield* runFor(command, cwd, "generic");
22055
+ const classified = yield* runFor(GitCommand.changedFiles(options.base, options.head, relative), cwd, "generic");
20139
22056
  switch (classified._tag) {
20140
22057
  case "success": return parseNulSeparated(classified.output);
20141
22058
  case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
@@ -20147,8 +22064,8 @@ const make = (spawner) => {
20147
22064
  default: return yield* Effect.die(`Git.changedFiles: unexpected classification "${classified._tag}"`);
20148
22065
  }
20149
22066
  });
20150
- const collectPaths = (method, command, cwd) => Effect.gen(function* () {
20151
- const classified = yield* runFor(command, cwd, "generic");
22067
+ const collectPaths = (method, invocation, cwd) => Effect.gen(function* () {
22068
+ const classified = yield* runFor(invocation, cwd, "generic");
20152
22069
  switch (classified._tag) {
20153
22070
  case "success": return parseNulSeparated(classified.output);
20154
22071
  case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
@@ -20166,7 +22083,7 @@ const make = (spawner) => {
20166
22083
  cwd,
20167
22084
  relative
20168
22085
  });
20169
- return yield* collectPaths("Git.unstagedChanges", ChildProcess.setCwd(GitCommand.unstagedChanges(relative), cwd), cwd);
22086
+ return yield* collectPaths("Git.unstagedChanges", GitCommand.unstagedChanges(relative), cwd);
20170
22087
  });
20171
22088
  const stagedChanges = Effect.fn("Git.stagedChanges")(function* (cwd, options) {
20172
22089
  const relative = options?.relative ?? false;
@@ -20174,7 +22091,7 @@ const make = (spawner) => {
20174
22091
  cwd,
20175
22092
  relative
20176
22093
  });
20177
- return yield* collectPaths("Git.stagedChanges", ChildProcess.setCwd(GitCommand.stagedChanges(relative), cwd), cwd);
22094
+ return yield* collectPaths("Git.stagedChanges", GitCommand.stagedChanges(relative), cwd);
20178
22095
  });
20179
22096
  const untrackedFiles = Effect.fn("Git.untrackedFiles")(function* (cwd, options) {
20180
22097
  const relative = options?.relative ?? false;
@@ -20182,7 +22099,7 @@ const make = (spawner) => {
20182
22099
  cwd,
20183
22100
  relative
20184
22101
  });
20185
- return yield* collectPaths("Git.untrackedFiles", ChildProcess.setCwd(GitCommand.untrackedFiles(relative), cwd), cwd);
22102
+ return yield* collectPaths("Git.untrackedFiles", GitCommand.untrackedFiles(relative), cwd);
20186
22103
  });
20187
22104
  const workingChanges = Effect.fn("Git.workingChanges")(function* (cwd, options) {
20188
22105
  yield* Effect.annotateCurrentSpan({
@@ -20207,80 +22124,669 @@ const make = (spawner) => {
20207
22124
  relative
20208
22125
  });
20209
22126
  yield* rejectOptionLikeRefs(cwd, options.head === void 0 ? [options.base] : [options.base, options.head]);
20210
- const command = ChildProcess.setCwd(GitCommand.nameStatus(options.base, options.head, relative), cwd);
20211
- const classified = yield* runFor(command, cwd, "generic");
22127
+ const classified = yield* runFor(GitCommand.nameStatus(options.base, options.head, relative), cwd, "generic");
22128
+ switch (classified._tag) {
22129
+ case "success": return parseNameStatus(classified.output);
22130
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22131
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22132
+ ref: options.head === void 0 ? options.base : `${options.base}...${options.head}`,
22133
+ cwd
22134
+ }));
22135
+ case "failure": return yield* Effect.fail(classified.error);
22136
+ default: return yield* Effect.die(`Git.nameStatus: unexpected classification "${classified._tag}"`);
22137
+ }
22138
+ });
22139
+ const revParse = Effect.fn("Git.revParse")(function* (cwd, ref) {
22140
+ yield* Effect.annotateCurrentSpan({
22141
+ cwd,
22142
+ ref
22143
+ });
22144
+ yield* rejectOptionLikeRefs(cwd, [ref]);
22145
+ const classified = yield* runFor(GitCommand.revParse(ref), cwd, "generic");
22146
+ switch (classified._tag) {
22147
+ case "success": return classified.output.trim();
22148
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22149
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22150
+ ref,
22151
+ cwd
22152
+ }));
22153
+ case "failure": return yield* Effect.fail(classified.error);
22154
+ default: return yield* Effect.die(`Git.revParse: unexpected classification "${classified._tag}"`);
22155
+ }
22156
+ });
22157
+ const checkout = Effect.fn("Git.checkout")(function* (cwd, ref, options) {
22158
+ const detach = options?.detach ?? false;
22159
+ yield* Effect.annotateCurrentSpan({
22160
+ cwd,
22161
+ ref,
22162
+ detach
22163
+ });
22164
+ yield* rejectOptionLikeRefs(cwd, [ref]);
22165
+ const classified = yield* runFor(GitCommand.checkout(ref, detach), cwd, "generic");
22166
+ switch (classified._tag) {
22167
+ case "success": return;
22168
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22169
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22170
+ ref,
22171
+ cwd
22172
+ }));
22173
+ case "failure": return yield* Effect.fail(classified.error);
22174
+ default: return yield* Effect.die(`Git.checkout: unexpected classification "${classified._tag}"`);
22175
+ }
22176
+ });
22177
+ const reset = Effect.fn("Git.reset")(function* (cwd, options) {
22178
+ const mode = options?.mode ?? "mixed";
22179
+ yield* Effect.annotateCurrentSpan({
22180
+ cwd,
22181
+ mode,
22182
+ ref: options?.ref ?? "HEAD"
22183
+ });
22184
+ if (options?.ref !== void 0) yield* rejectOptionLikeRefs(cwd, [options.ref]);
22185
+ const classified = yield* runFor(GitCommand.reset(mode, options?.ref), cwd, "generic");
22186
+ switch (classified._tag) {
22187
+ case "success": return;
22188
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22189
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22190
+ ref: options?.ref ?? "HEAD",
22191
+ cwd
22192
+ }));
22193
+ case "failure": return yield* Effect.fail(classified.error);
22194
+ default: return yield* Effect.die(`Git.reset: unexpected classification "${classified._tag}"`);
22195
+ }
22196
+ });
22197
+ const clean = Effect.fn("Git.clean")(function* (cwd, options) {
22198
+ const directories = options?.directories ?? false;
22199
+ const ignored = options?.ignored ?? false;
22200
+ yield* Effect.annotateCurrentSpan({
22201
+ cwd,
22202
+ directories,
22203
+ ignored
22204
+ });
22205
+ const classified = yield* runFor(GitCommand.clean(directories, ignored, options?.paths ?? []), cwd, "generic");
22206
+ switch (classified._tag) {
22207
+ case "success": return;
22208
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22209
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22210
+ ref: "working tree",
22211
+ cwd
22212
+ }));
22213
+ case "failure": return yield* Effect.fail(classified.error);
22214
+ default: return yield* Effect.die(`Git.clean: unexpected classification "${classified._tag}"`);
22215
+ }
22216
+ });
22217
+ const restore = Effect.fn("Git.restore")(function* (cwd, paths, options) {
22218
+ yield* Effect.annotateCurrentSpan({
22219
+ cwd,
22220
+ count: paths.length,
22221
+ source: options?.source ?? "(index)"
22222
+ });
22223
+ if (options?.source !== void 0) yield* rejectOptionLikeRefs(cwd, [options.source]);
22224
+ const classified = yield* runFor(GitCommand.restore(paths, options?.source, options?.staged ?? false, options?.worktree ?? false), cwd, "generic");
22225
+ switch (classified._tag) {
22226
+ case "success": return;
22227
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22228
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22229
+ ref: options?.source ?? "working tree",
22230
+ cwd
22231
+ }));
22232
+ case "failure": return yield* Effect.fail(classified.error);
22233
+ default: return yield* Effect.die(`Git.restore: unexpected classification "${classified._tag}"`);
22234
+ }
22235
+ });
22236
+ const branchCreate = Effect.fn("Git.branchCreate")(function* (cwd, name, options) {
22237
+ const checkoutBranch = options?.checkout ?? false;
22238
+ const force = options?.force ?? false;
22239
+ yield* Effect.annotateCurrentSpan({
22240
+ cwd,
22241
+ name,
22242
+ startPoint: options?.startPoint ?? "HEAD",
22243
+ checkout: checkoutBranch,
22244
+ force
22245
+ });
22246
+ yield* rejectOptionLikeRefs(cwd, [name, ...options?.startPoint !== void 0 ? [options.startPoint] : []]);
22247
+ const classified = yield* runFor(GitCommand.branchCreate(name, options?.startPoint, checkoutBranch, force), cwd, "generic");
22248
+ switch (classified._tag) {
22249
+ case "success": return;
22250
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22251
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22252
+ ref: options?.startPoint ?? name,
22253
+ cwd
22254
+ }));
22255
+ case "failure": return yield* Effect.fail(classified.error);
22256
+ default: return yield* Effect.die(`Git.branchCreate: unexpected classification "${classified._tag}"`);
22257
+ }
22258
+ });
22259
+ const branchDelete = Effect.fn("Git.branchDelete")(function* (cwd, name, options) {
22260
+ yield* Effect.annotateCurrentSpan({
22261
+ cwd,
22262
+ name,
22263
+ force: options?.force ?? false
22264
+ });
22265
+ yield* rejectOptionLikeRefs(cwd, [name]);
22266
+ const classified = yield* runFor(GitCommand.branchDelete(name, options?.force ?? false), cwd, "generic");
22267
+ switch (classified._tag) {
22268
+ case "success": return;
22269
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22270
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22271
+ ref: name,
22272
+ cwd
22273
+ }));
22274
+ case "failure": return yield* Effect.fail(classified.error);
22275
+ default: return yield* Effect.die(`Git.branchDelete: unexpected classification "${classified._tag}"`);
22276
+ }
22277
+ });
22278
+ const isShallow = Effect.fn("Git.isShallow")(function* (cwd) {
22279
+ yield* Effect.annotateCurrentSpan({ cwd });
22280
+ const classified = yield* runFor(GitCommand.isShallow(), cwd, "generic");
22281
+ switch (classified._tag) {
22282
+ case "success": return classified.output.trim() === "true";
22283
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22284
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22285
+ ref: "HEAD",
22286
+ cwd
22287
+ }));
22288
+ case "failure": return yield* Effect.fail(classified.error);
22289
+ default: return yield* Effect.die(`Git.isShallow: unexpected classification "${classified._tag}"`);
22290
+ }
22291
+ });
22292
+ const fetchUnshallow = Effect.fn("Git.fetchUnshallow")(function* (cwd, options) {
22293
+ const remote = options?.remote ?? "origin";
22294
+ yield* Effect.annotateCurrentSpan({ cwd });
22295
+ yield* rejectOptionLikeRefs(cwd, [remote]);
22296
+ const classified = yield* runFor(GitCommand.fetchUnshallow(remote), cwd, "generic");
22297
+ switch (classified._tag) {
22298
+ case "success": return;
22299
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22300
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22301
+ ref: "--unshallow",
22302
+ cwd
22303
+ }));
22304
+ case "failure": return yield* Effect.fail(classified.error);
22305
+ default: return yield* Effect.die(`Git.fetchUnshallow: unexpected classification "${classified._tag}"`);
22306
+ }
22307
+ });
22308
+ const fetch = Effect.fn("Git.fetch")(function* (cwd, options) {
22309
+ const remote = options.remote ?? "origin";
22310
+ const tag = options.tag ?? false;
22311
+ yield* Effect.annotateCurrentSpan({
22312
+ cwd,
22313
+ ref: options.ref,
22314
+ tag
22315
+ });
22316
+ yield* rejectOptionLikeRefs(cwd, [remote, options.ref]);
22317
+ yield* rejectNonNaturalNumber(cwd, "a fetch depth", options.depth);
22318
+ const classified = yield* runFor(GitCommand.fetch(remote, options.ref, options.depth, tag), cwd, "generic");
22319
+ switch (classified._tag) {
22320
+ case "success": return;
22321
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22322
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22323
+ ref: options.ref,
22324
+ cwd
22325
+ }));
22326
+ case "failure": return yield* Effect.fail(classified.error);
22327
+ default: return yield* Effect.die(`Git.fetch: unexpected classification "${classified._tag}"`);
22328
+ }
22329
+ });
22330
+ const fetchAny = Effect.fn("Git.fetchAny")(function* (cwd, options) {
22331
+ yield* Effect.annotateCurrentSpan({
22332
+ cwd,
22333
+ ref: options.ref
22334
+ });
22335
+ return yield* fetch(cwd, {
22336
+ ...options,
22337
+ tag: true
22338
+ }).pipe(Effect.catchTag(["UnknownRefError", "GitCommandError"], (error) => error._tag === "GitCommandError" && error.kind === "refused" ? Effect.fail(error) : fetch(cwd, options)));
22339
+ });
22340
+ const submoduleUpdate = Effect.fn("Git.submoduleUpdate")(function* (cwd, options) {
22341
+ const init = options?.init ?? false;
22342
+ yield* Effect.annotateCurrentSpan({
22343
+ cwd,
22344
+ init
22345
+ });
22346
+ yield* rejectNonNaturalNumber(cwd, "a submodule update depth", options?.depth);
22347
+ const classified = yield* runFor(GitCommand.submoduleUpdate(init, options?.depth, options?.paths ?? []), cwd, "generic");
22348
+ switch (classified._tag) {
22349
+ case "success": return;
22350
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22351
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22352
+ ref: "submodule update",
22353
+ cwd
22354
+ }));
22355
+ case "failure": return yield* Effect.fail(classified.error);
22356
+ default: return yield* Effect.die(`Git.submoduleUpdate: unexpected classification "${classified._tag}"`);
22357
+ }
22358
+ });
22359
+ const submoduleAdd = Effect.fn("Git.submoduleAdd")(function* (cwd, options) {
22360
+ yield* Effect.annotateCurrentSpan({
22361
+ cwd,
22362
+ path: options.path
22363
+ });
22364
+ yield* rejectNonNaturalNumber(cwd, "a submodule add depth", options.depth);
22365
+ const classified = yield* runFor(GitCommand.submoduleAdd(options.url, options.path, options.depth), cwd, "generic");
22366
+ switch (classified._tag) {
22367
+ case "success": return;
22368
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22369
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22370
+ ref: options.path,
22371
+ cwd
22372
+ }));
22373
+ case "failure": return yield* Effect.fail(classified.error);
22374
+ default: return yield* Effect.die(`Git.submoduleAdd: unexpected classification "${classified._tag}"`);
22375
+ }
22376
+ });
22377
+ const sparseCheckoutSet = Effect.fn("Git.sparseCheckoutSet")(function* (cwd, patterns, options) {
22378
+ yield* Effect.annotateCurrentSpan({
22379
+ cwd,
22380
+ cone: options.cone
22381
+ });
22382
+ yield* rejectOptionLikeRefs(cwd, patterns);
22383
+ const classified = yield* runFor(GitCommand.sparseCheckoutSet(patterns, options.cone), cwd, "generic");
22384
+ switch (classified._tag) {
22385
+ case "success": return;
22386
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22387
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22388
+ ref: "sparse-checkout",
22389
+ cwd
22390
+ }));
22391
+ case "failure": return yield* Effect.fail(classified.error);
22392
+ default: return yield* Effect.die(`Git.sparseCheckoutSet: unexpected classification "${classified._tag}"`);
22393
+ }
22394
+ });
22395
+ const configSet = Effect.fn("Git.configSet")(function* (cwd, key, value, options) {
22396
+ yield* Effect.annotateCurrentSpan({
22397
+ cwd,
22398
+ key,
22399
+ file: options?.file ?? "(repository config)"
22400
+ });
22401
+ yield* rejectOptionLikeRefs(cwd, [key, ...options?.file !== void 0 ? [options.file] : []], [value]);
22402
+ const classified = yield* runFor(GitCommand.configSet(key, value, options?.file), cwd, "generic");
22403
+ switch (classified._tag) {
22404
+ case "success": return;
22405
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22406
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22407
+ ref: key,
22408
+ cwd
22409
+ }));
22410
+ case "failure": return yield* Effect.fail(classified.error);
22411
+ default: return yield* Effect.die(`Git.configSet: unexpected classification "${classified._tag}"`);
22412
+ }
22413
+ });
22414
+ const add = Effect.fn("Git.add")(function* (cwd, paths) {
22415
+ yield* Effect.annotateCurrentSpan({
22416
+ cwd,
22417
+ count: paths.length
22418
+ });
22419
+ const classified = yield* runFor(GitCommand.add(paths), cwd, "generic");
22420
+ switch (classified._tag) {
22421
+ case "success": return;
22422
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22423
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22424
+ ref: "working tree",
22425
+ cwd
22426
+ }));
22427
+ case "failure": return yield* Effect.fail(classified.error);
22428
+ default: return yield* Effect.die(`Git.add: unexpected classification "${classified._tag}"`);
22429
+ }
22430
+ });
22431
+ const defaultBranch = Effect.fn("Git.defaultBranch")(function* (cwd, options) {
22432
+ const remote = options?.remote ?? "origin";
22433
+ yield* Effect.annotateCurrentSpan({
22434
+ cwd,
22435
+ remote
22436
+ });
22437
+ yield* rejectOptionLikeRefs(cwd, [remote]);
22438
+ const classified = yield* runFor(GitCommand.defaultBranch(remote), cwd, "quiet");
22439
+ switch (classified._tag) {
22440
+ case "success": {
22441
+ const short = classified.output.trim();
22442
+ const prefix = `${remote}/`;
22443
+ return Option.some(short.startsWith(prefix) ? short.slice(prefix.length) : short);
22444
+ }
22445
+ case "absent": return Option.none();
22446
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22447
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22448
+ ref: `refs/remotes/${remote}/HEAD`,
22449
+ cwd
22450
+ }));
22451
+ case "failure": return yield* Effect.fail(classified.error);
22452
+ default: return yield* Effect.die(`Git.defaultBranch: unexpected classification "${classified._tag}"`);
22453
+ }
22454
+ });
22455
+ const currentBranch = Effect.fn("Git.currentBranch")(function* (cwd) {
22456
+ yield* Effect.annotateCurrentSpan({ cwd });
22457
+ const classified = yield* runFor(GitCommand.currentBranch(), cwd, "generic");
22458
+ switch (classified._tag) {
22459
+ case "success": {
22460
+ const name = classified.output.trim();
22461
+ return name === "HEAD" ? Option.none() : Option.some(name);
22462
+ }
22463
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22464
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22465
+ ref: "HEAD",
22466
+ cwd
22467
+ }));
22468
+ case "failure": return yield* Effect.fail(classified.error);
22469
+ default: return yield* Effect.die(`Git.currentBranch: unexpected classification "${classified._tag}"`);
22470
+ }
22471
+ });
22472
+ const repoRoot = Effect.fn("Git.repoRoot")(function* (cwd) {
22473
+ yield* Effect.annotateCurrentSpan({ cwd });
22474
+ const classified = yield* runFor(GitCommand.repoRoot(), cwd, "generic");
22475
+ switch (classified._tag) {
22476
+ case "success": return classified.output.trim();
22477
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22478
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22479
+ ref: "working tree",
22480
+ cwd
22481
+ }));
22482
+ case "failure": return yield* Effect.fail(classified.error);
22483
+ default: return yield* Effect.die(`Git.repoRoot: unexpected classification "${classified._tag}"`);
22484
+ }
22485
+ });
22486
+ const configGet = Effect.fn("Git.configGet")(function* (cwd, key) {
22487
+ yield* Effect.annotateCurrentSpan({
22488
+ cwd,
22489
+ key
22490
+ });
22491
+ yield* rejectOptionLikeRefs(cwd, [key]);
22492
+ const classified = yield* runFor(GitCommand.configGet(key), cwd, "quiet");
22493
+ switch (classified._tag) {
22494
+ case "success": return Option.some(classified.output.trim());
22495
+ case "absent": return Option.none();
22496
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22497
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22498
+ ref: key,
22499
+ cwd
22500
+ }));
22501
+ case "failure": return yield* Effect.fail(classified.error);
22502
+ default: return yield* Effect.die(`Git.configGet: unexpected classification "${classified._tag}"`);
22503
+ }
22504
+ });
22505
+ const remoteUrl = Effect.fn("Git.remoteUrl")(function* (cwd, options) {
22506
+ const remote = options?.remote ?? "origin";
22507
+ yield* Effect.annotateCurrentSpan({
22508
+ cwd,
22509
+ remote
22510
+ });
22511
+ yield* rejectOptionLikeRefs(cwd, [remote]);
22512
+ const classified = yield* runFor(GitCommand.remoteUrl(remote), cwd, "noSuchRemote");
22513
+ switch (classified._tag) {
22514
+ case "success": return Option.some(classified.output.trim());
22515
+ case "absent": return Option.none();
22516
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22517
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22518
+ ref: remote,
22519
+ cwd
22520
+ }));
22521
+ case "failure": return yield* Effect.fail(classified.error);
22522
+ default: return yield* Effect.die(`Git.remoteUrl: unexpected classification "${classified._tag}"`);
22523
+ }
22524
+ });
22525
+ const commitInfo = Effect.fn("Git.commitInfo")(function* (cwd, ref) {
22526
+ const target = ref ?? "HEAD";
22527
+ yield* Effect.annotateCurrentSpan({
22528
+ cwd,
22529
+ ref: target
22530
+ });
22531
+ yield* rejectOptionLikeRefs(cwd, [target]);
22532
+ const classified = yield* runFor(GitCommand.commitInfo(target), cwd, "generic");
22533
+ switch (classified._tag) {
22534
+ case "success": return parseCommitInfo(classified.output);
22535
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22536
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22537
+ ref: target,
22538
+ cwd
22539
+ }));
22540
+ case "failure": return yield* Effect.fail(classified.error);
22541
+ default: return yield* Effect.die(`Git.commitInfo: unexpected classification "${classified._tag}"`);
22542
+ }
22543
+ });
22544
+ const status = Effect.fn("Git.status")(function* (cwd) {
22545
+ yield* Effect.annotateCurrentSpan({ cwd });
22546
+ const classified = yield* runFor(GitCommand.status(), cwd, "generic");
22547
+ switch (classified._tag) {
22548
+ case "success": return parseStatus(classified.output);
22549
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22550
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22551
+ ref: "working tree",
22552
+ cwd
22553
+ }));
22554
+ case "failure": return yield* Effect.fail(classified.error);
22555
+ default: return yield* Effect.die(`Git.status: unexpected classification "${classified._tag}"`);
22556
+ }
22557
+ });
22558
+ const submoduleStatus = Effect.fn("Git.submoduleStatus")(function* (cwd, options) {
22559
+ yield* Effect.annotateCurrentSpan({
22560
+ cwd,
22561
+ recursive: options?.recursive ?? false
22562
+ });
22563
+ const classified = yield* runFor(GitCommand.submoduleStatus(options?.paths ?? [], options?.recursive ?? false), cwd, "generic");
22564
+ switch (classified._tag) {
22565
+ case "success": return parseSubmoduleStatus(classified.output);
22566
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22567
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22568
+ ref: "submodule status",
22569
+ cwd
22570
+ }));
22571
+ case "failure": return yield* Effect.fail(classified.error);
22572
+ default: return yield* Effect.die(`Git.submoduleStatus: unexpected classification "${classified._tag}"`);
22573
+ }
22574
+ });
22575
+ const submoduleInit = Effect.fn("Git.submoduleInit")(function* (cwd, options) {
22576
+ yield* Effect.annotateCurrentSpan({ cwd });
22577
+ const classified = yield* runFor(GitCommand.submoduleInit(options?.paths ?? []), cwd, "generic");
22578
+ switch (classified._tag) {
22579
+ case "success": return;
22580
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22581
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22582
+ ref: "submodule init",
22583
+ cwd
22584
+ }));
22585
+ case "failure": return yield* Effect.fail(classified.error);
22586
+ default: return yield* Effect.die(`Git.submoduleInit: unexpected classification "${classified._tag}"`);
22587
+ }
22588
+ });
22589
+ const submoduleDeinit = Effect.fn("Git.submoduleDeinit")(function* (cwd, options) {
22590
+ const paths = options.paths ?? [];
22591
+ const all = options.all ?? false;
22592
+ yield* Effect.annotateCurrentSpan({
22593
+ cwd,
22594
+ all,
22595
+ count: paths.length
22596
+ });
22597
+ if (!all && paths.length === 0) return yield* Effect.fail(new GitCommandError({
22598
+ kind: "refused",
22599
+ args: ["submodule", "deinit"],
22600
+ cwd,
22601
+ stderr: "",
22602
+ detail: "refused: submoduleDeinit needs either paths or all: true"
22603
+ }));
22604
+ const classified = yield* runFor(GitCommand.submoduleDeinit(paths, all, options.force ?? false), cwd, "generic");
22605
+ switch (classified._tag) {
22606
+ case "success": return;
22607
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22608
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22609
+ ref: "submodule deinit",
22610
+ cwd
22611
+ }));
22612
+ case "failure": return yield* Effect.fail(classified.error);
22613
+ default: return yield* Effect.die(`Git.submoduleDeinit: unexpected classification "${classified._tag}"`);
22614
+ }
22615
+ });
22616
+ const submoduleSync = Effect.fn("Git.submoduleSync")(function* (cwd, options) {
22617
+ yield* Effect.annotateCurrentSpan({
22618
+ cwd,
22619
+ recursive: options?.recursive ?? false
22620
+ });
22621
+ const classified = yield* runFor(GitCommand.submoduleSync(options?.paths ?? [], options?.recursive ?? false), cwd, "generic");
22622
+ switch (classified._tag) {
22623
+ case "success": return;
22624
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22625
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22626
+ ref: "submodule sync",
22627
+ cwd
22628
+ }));
22629
+ case "failure": return yield* Effect.fail(classified.error);
22630
+ default: return yield* Effect.die(`Git.submoduleSync: unexpected classification "${classified._tag}"`);
22631
+ }
22632
+ });
22633
+ const submoduleSetUrl = Effect.fn("Git.submoduleSetUrl")(function* (cwd, path, url) {
22634
+ yield* Effect.annotateCurrentSpan({
22635
+ cwd,
22636
+ path
22637
+ });
22638
+ const classified = yield* runFor(GitCommand.submoduleSetUrl(path, url), cwd, "generic");
22639
+ switch (classified._tag) {
22640
+ case "success": return;
22641
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22642
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22643
+ ref: path,
22644
+ cwd
22645
+ }));
22646
+ case "failure": return yield* Effect.fail(classified.error);
22647
+ default: return yield* Effect.die(`Git.submoduleSetUrl: unexpected classification "${classified._tag}"`);
22648
+ }
22649
+ });
22650
+ const submoduleSetBranch = Effect.fn("Git.submoduleSetBranch")(function* (cwd, path, options) {
22651
+ const branch = options?.branch;
22652
+ yield* Effect.annotateCurrentSpan({
22653
+ cwd,
22654
+ path,
22655
+ branch: branch ?? "(default)"
22656
+ });
22657
+ if (branch !== void 0) yield* rejectOptionLikeRefs(cwd, [branch]);
22658
+ const classified = yield* runFor(GitCommand.submoduleSetBranch(path, branch), cwd, "generic");
22659
+ switch (classified._tag) {
22660
+ case "success": return;
22661
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22662
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22663
+ ref: branch ?? path,
22664
+ cwd
22665
+ }));
22666
+ case "failure": return yield* Effect.fail(classified.error);
22667
+ default: return yield* Effect.die(`Git.submoduleSetBranch: unexpected classification "${classified._tag}"`);
22668
+ }
22669
+ });
22670
+ const submoduleAbsorbgitdirs = Effect.fn("Git.submoduleAbsorbgitdirs")(function* (cwd, options) {
22671
+ yield* Effect.annotateCurrentSpan({ cwd });
22672
+ const classified = yield* runFor(GitCommand.submoduleAbsorbgitdirs(options?.paths ?? []), cwd, "generic");
20212
22673
  switch (classified._tag) {
20213
- case "success": return parseNameStatus(classified.output);
22674
+ case "success": return;
20214
22675
  case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
20215
22676
  case "unknownRef": return yield* Effect.fail(new UnknownRefError({
20216
- ref: options.head === void 0 ? options.base : `${options.base}...${options.head}`,
22677
+ ref: "submodule absorbgitdirs",
20217
22678
  cwd
20218
22679
  }));
20219
22680
  case "failure": return yield* Effect.fail(classified.error);
20220
- default: return yield* Effect.die(`Git.nameStatus: unexpected classification "${classified._tag}"`);
22681
+ default: return yield* Effect.die(`Git.submoduleAbsorbgitdirs: unexpected classification "${classified._tag}"`);
20221
22682
  }
20222
22683
  });
20223
- const revParse = Effect.fn("Git.revParse")(function* (cwd, ref) {
22684
+ const submoduleForeach = Effect.fn("Git.submoduleForeach")(function* (cwd, command, options) {
20224
22685
  yield* Effect.annotateCurrentSpan({
20225
22686
  cwd,
20226
- ref
22687
+ recursive: options?.recursive ?? false
20227
22688
  });
20228
- yield* rejectOptionLikeRefs(cwd, [ref]);
20229
- const command = ChildProcess.setCwd(GitCommand.revParse(ref), cwd);
20230
- const classified = yield* runFor(command, cwd, "generic");
22689
+ yield* rejectOptionLikeRefs(cwd, [command]);
22690
+ const classified = yield* runFor(GitCommand.submoduleForeach(command, options?.recursive ?? false), cwd, "generic");
20231
22691
  switch (classified._tag) {
20232
- case "success": return classified.output.trim();
22692
+ case "success": return classified.output;
20233
22693
  case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
20234
22694
  case "unknownRef": return yield* Effect.fail(new UnknownRefError({
20235
- ref,
22695
+ ref: "submodule foreach",
20236
22696
  cwd
20237
22697
  }));
20238
22698
  case "failure": return yield* Effect.fail(classified.error);
20239
- default: return yield* Effect.die(`Git.revParse: unexpected classification "${classified._tag}"`);
22699
+ default: return yield* Effect.die(`Git.submoduleForeach: unexpected classification "${classified._tag}"`);
20240
22700
  }
20241
22701
  });
20242
- const checkout = Effect.fn("Git.checkout")(function* (cwd, ref, options) {
20243
- const detach = options?.detach ?? false;
20244
- yield* Effect.annotateCurrentSpan({
20245
- cwd,
20246
- ref,
20247
- detach
20248
- });
20249
- yield* rejectOptionLikeRefs(cwd, [ref]);
20250
- const command = ChildProcess.setCwd(GitCommand.checkout(ref, detach), cwd);
20251
- const classified = yield* runFor(command, cwd, "generic");
22702
+ const runVoid = (method, invocation, cwd, refLabel) => Effect.gen(function* () {
22703
+ const classified = yield* runFor(invocation, cwd, "generic");
20252
22704
  switch (classified._tag) {
20253
22705
  case "success": return;
20254
22706
  case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
20255
22707
  case "unknownRef": return yield* Effect.fail(new UnknownRefError({
20256
- ref,
22708
+ ref: refLabel,
20257
22709
  cwd
20258
22710
  }));
20259
22711
  case "failure": return yield* Effect.fail(classified.error);
20260
- default: return yield* Effect.die(`Git.checkout: unexpected classification "${classified._tag}"`);
22712
+ default: return yield* Effect.die(`${method}: unexpected classification "${classified._tag}"`);
20261
22713
  }
20262
22714
  });
20263
- const fetch = Effect.fn("Git.fetch")(function* (cwd, options) {
20264
- const remote = options.remote ?? "origin";
20265
- const tag = options.tag ?? false;
22715
+ const runParsed = (method, invocation, cwd, refLabel, kind, parse, absent) => Effect.gen(function* () {
22716
+ const classified = yield* runFor(invocation, cwd, kind);
22717
+ switch (classified._tag) {
22718
+ case "success": return parse(classified.output);
22719
+ case "absent":
22720
+ if (absent !== void 0) return absent();
22721
+ return yield* Effect.die(`${method}: unexpected classification "absent"`);
22722
+ case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
22723
+ case "unknownRef": return yield* Effect.fail(new UnknownRefError({
22724
+ ref: refLabel,
22725
+ cwd
22726
+ }));
22727
+ case "failure": return yield* Effect.fail(classified.error);
22728
+ default: return yield* Effect.die(`${method}: unexpected classification "${classified._tag}"`);
22729
+ }
22730
+ });
22731
+ const lsRemote = Effect.fn("Git.lsRemote")(function* (cwd, remote, options) {
20266
22732
  yield* Effect.annotateCurrentSpan({
20267
22733
  cwd,
20268
- remote,
20269
- ref: options.ref,
20270
- tag
22734
+ heads: options?.heads ?? false,
22735
+ tags: options?.tags ?? false,
22736
+ patterns: (options?.patterns ?? []).length
20271
22737
  });
20272
- yield* rejectOptionLikeRefs(cwd, [remote, options.ref]);
20273
- const command = ChildProcess.setCwd(GitCommand.fetch(remote, options.ref, options.depth, tag), cwd);
20274
- const classified = yield* runFor(command, cwd, "generic");
22738
+ yield* rejectOptionLikeRefs(cwd, [remote, ...options?.patterns ?? []]);
22739
+ return yield* runParsed("Git.lsRemote", GitCommand.lsRemote(remote, options?.heads ?? false, options?.tags ?? false, options?.patterns ?? []), cwd, "ls-remote", "generic", parseLsRemote);
22740
+ });
22741
+ const remoteAdd = Effect.fn("Git.remoteAdd")(function* (cwd, name, url) {
22742
+ yield* Effect.annotateCurrentSpan({
22743
+ cwd,
22744
+ name
22745
+ });
22746
+ yield* rejectOptionLikeRefs(cwd, [name, url]);
22747
+ return yield* runVoid("Git.remoteAdd", GitCommand.remoteAdd(name, url), cwd, name);
22748
+ });
22749
+ const remoteRemove = Effect.fn("Git.remoteRemove")(function* (cwd, name) {
22750
+ yield* Effect.annotateCurrentSpan({
22751
+ cwd,
22752
+ name
22753
+ });
22754
+ yield* rejectOptionLikeRefs(cwd, [name]);
22755
+ return yield* runVoid("Git.remoteRemove", GitCommand.remoteRemove(name), cwd, name);
22756
+ });
22757
+ const remoteSetUrl = Effect.fn("Git.remoteSetUrl")(function* (cwd, name, url) {
22758
+ yield* Effect.annotateCurrentSpan({
22759
+ cwd,
22760
+ name
22761
+ });
22762
+ yield* rejectOptionLikeRefs(cwd, [name, url]);
22763
+ return yield* runVoid("Git.remoteSetUrl", GitCommand.remoteSetUrl(name, url), cwd, name);
22764
+ });
22765
+ const stashPush = Effect.fn("Git.stashPush")(function* (cwd, options) {
22766
+ yield* Effect.annotateCurrentSpan({
22767
+ cwd,
22768
+ includeUntracked: options?.includeUntracked ?? false
22769
+ });
22770
+ return yield* runVoid("Git.stashPush", GitCommand.stashPush(options?.message, options?.includeUntracked ?? false, options?.paths ?? []), cwd, "stash");
22771
+ });
22772
+ const stashRestore = (method, invocation) => Effect.fn(method)(function* (cwd, options) {
22773
+ yield* Effect.annotateCurrentSpan({
22774
+ cwd,
22775
+ index: options?.index ?? 0
22776
+ });
22777
+ yield* rejectNonNaturalNumber(cwd, "a stash index", options?.index);
22778
+ const classified = yield* runFor(invocation(options?.index), cwd, "merge");
20275
22779
  switch (classified._tag) {
20276
22780
  case "success": return;
22781
+ case "dirtyWorktree": return yield* Effect.fail(new DirtyWorktreeError({ cwd }));
22782
+ case "mergeConflict": return yield* Effect.fail(new MergeConflictError({ cwd }));
20277
22783
  case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
20278
22784
  case "unknownRef": return yield* Effect.fail(new UnknownRefError({
20279
- ref: options.ref,
22785
+ ref: "stash",
20280
22786
  cwd
20281
22787
  }));
20282
22788
  case "failure": return yield* Effect.fail(classified.error);
20283
- default: return yield* Effect.die(`Git.fetch: unexpected classification "${classified._tag}"`);
22789
+ default: return yield* Effect.die(`${method}: unexpected classification "${classified._tag}"`);
20284
22790
  }
20285
22791
  });
20286
22792
  return {
@@ -20293,254 +22799,235 @@ const make = (spawner) => {
20293
22799
  revParse,
20294
22800
  checkout,
20295
22801
  fetch,
20296
- fetchAny: Effect.fn("Git.fetchAny")(function* (cwd, options) {
20297
- const remote = options.remote ?? "origin";
22802
+ fetchAny,
22803
+ fetchUnshallow,
22804
+ isShallow,
22805
+ reset,
22806
+ clean,
22807
+ restore,
22808
+ branchCreate,
22809
+ branchDelete,
22810
+ submoduleUpdate,
22811
+ submoduleAdd,
22812
+ submoduleStatus,
22813
+ submoduleInit,
22814
+ submoduleDeinit,
22815
+ submoduleSync,
22816
+ submoduleSetUrl,
22817
+ submoduleSetBranch,
22818
+ submoduleAbsorbgitdirs,
22819
+ submoduleForeach,
22820
+ sparseCheckoutSet,
22821
+ configSet,
22822
+ add,
22823
+ nameStatus,
22824
+ unstagedChanges,
22825
+ stagedChanges,
22826
+ untrackedFiles,
22827
+ defaultBranch,
22828
+ currentBranch,
22829
+ repoRoot,
22830
+ configGet,
22831
+ remoteUrl,
22832
+ commitInfo,
22833
+ status,
22834
+ lsRemote,
22835
+ remoteAdd,
22836
+ remoteRemove,
22837
+ remoteSetUrl,
22838
+ stashPush,
22839
+ stashPop: stashRestore("Git.stashPop", GitCommand.stashPop),
22840
+ stashApply: stashRestore("Git.stashApply", GitCommand.stashApply),
22841
+ stashDrop: Effect.fn("Git.stashDrop")(function* (cwd, options) {
20298
22842
  yield* Effect.annotateCurrentSpan({
20299
22843
  cwd,
20300
- remote,
20301
- ref: options.ref
22844
+ index: options?.index ?? 0
20302
22845
  });
20303
- return yield* fetch(cwd, {
20304
- ...options,
20305
- tag: true
20306
- }).pipe(Effect.catchTag(["UnknownRefError", "GitCommandError"], (error) => error._tag === "GitCommandError" && error.kind === "refused" ? Effect.fail(error) : fetch(cwd, options)));
22846
+ yield* rejectNonNaturalNumber(cwd, "a stash index", options?.index);
22847
+ return yield* runVoid("Git.stashDrop", GitCommand.stashDrop(options?.index), cwd, "stash");
22848
+ }),
22849
+ stashList: Effect.fn("Git.stashList")(function* (cwd) {
22850
+ yield* Effect.annotateCurrentSpan({ cwd });
22851
+ return yield* runParsed("Git.stashList", GitCommand.stashList(), cwd, "stash", "generic", parseStashList);
20307
22852
  }),
20308
- submoduleUpdate: Effect.fn("Git.submoduleUpdate")(function* (cwd, options) {
20309
- const init = options?.init ?? false;
22853
+ branchList: Effect.fn("Git.branchList")(function* (cwd, options) {
20310
22854
  yield* Effect.annotateCurrentSpan({
20311
22855
  cwd,
20312
- init
22856
+ remotes: options?.remotes ?? false,
22857
+ all: options?.all ?? false
20313
22858
  });
20314
- const command = ChildProcess.setCwd(GitCommand.submoduleUpdate(init, options?.depth, options?.paths ?? []), cwd);
20315
- const classified = yield* runFor(command, cwd, "generic");
20316
- switch (classified._tag) {
20317
- case "success": return;
20318
- case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
20319
- case "unknownRef": return yield* Effect.fail(new UnknownRefError({
20320
- ref: "submodule update",
20321
- cwd
20322
- }));
20323
- case "failure": return yield* Effect.fail(classified.error);
20324
- default: return yield* Effect.die(`Git.submoduleUpdate: unexpected classification "${classified._tag}"`);
20325
- }
22859
+ return yield* runParsed("Git.branchList", GitCommand.branchList(options?.remotes ?? false, options?.all ?? false), cwd, "branches", "generic", parseBranchList);
20326
22860
  }),
20327
- submoduleAdd: Effect.fn("Git.submoduleAdd")(function* (cwd, options) {
22861
+ tagCreate: Effect.fn("Git.tagCreate")(function* (cwd, name, options) {
20328
22862
  yield* Effect.annotateCurrentSpan({
20329
22863
  cwd,
20330
- url: options.url,
20331
- path: options.path
22864
+ name,
22865
+ ref: options?.ref ?? "HEAD",
22866
+ force: options?.force ?? false
20332
22867
  });
20333
- const command = ChildProcess.setCwd(GitCommand.submoduleAdd(options.url, options.path, options.depth), cwd);
20334
- const classified = yield* runFor(command, cwd, "generic");
20335
- switch (classified._tag) {
20336
- case "success": return;
20337
- case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
20338
- case "unknownRef": return yield* Effect.fail(new UnknownRefError({
20339
- ref: options.url,
20340
- cwd
20341
- }));
20342
- case "failure": return yield* Effect.fail(classified.error);
20343
- default: return yield* Effect.die(`Git.submoduleAdd: unexpected classification "${classified._tag}"`);
20344
- }
22868
+ yield* rejectOptionLikeRefs(cwd, [name, ...options?.ref !== void 0 ? [options.ref] : []]);
22869
+ return yield* runVoid("Git.tagCreate", GitCommand.tagCreate(name, options?.ref, options?.message, options?.force ?? false), cwd, options?.ref ?? name);
20345
22870
  }),
20346
- sparseCheckoutSet: Effect.fn("Git.sparseCheckoutSet")(function* (cwd, patterns, options) {
22871
+ tagDelete: Effect.fn("Git.tagDelete")(function* (cwd, name) {
20347
22872
  yield* Effect.annotateCurrentSpan({
20348
22873
  cwd,
20349
- cone: options.cone
22874
+ name
20350
22875
  });
20351
- yield* rejectOptionLikeRefs(cwd, patterns);
20352
- const command = ChildProcess.setCwd(GitCommand.sparseCheckoutSet(patterns, options.cone), cwd);
20353
- const classified = yield* runFor(command, cwd, "generic");
20354
- switch (classified._tag) {
20355
- case "success": return;
20356
- case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
20357
- case "unknownRef": return yield* Effect.fail(new UnknownRefError({
20358
- ref: "sparse-checkout",
20359
- cwd
20360
- }));
20361
- case "failure": return yield* Effect.fail(classified.error);
20362
- default: return yield* Effect.die(`Git.sparseCheckoutSet: unexpected classification "${classified._tag}"`);
20363
- }
22876
+ yield* rejectOptionLikeRefs(cwd, [name]);
22877
+ return yield* runVoid("Git.tagDelete", GitCommand.tagDelete(name), cwd, name);
22878
+ }),
22879
+ tagList: Effect.fn("Git.tagList")(function* (cwd, options) {
22880
+ yield* Effect.annotateCurrentSpan({ cwd });
22881
+ yield* rejectOptionLikeRefs(cwd, options?.pattern !== void 0 ? [options.pattern] : []);
22882
+ return yield* runParsed("Git.tagList", GitCommand.tagList(options?.pattern), cwd, "tags", "generic", (output) => output.split("\n").filter((line) => line.length > 0));
20364
22883
  }),
20365
- configSet: Effect.fn("Git.configSet")(function* (cwd, key, value, options) {
22884
+ forEachRef: Effect.fn("Git.forEachRef")(function* (cwd, options) {
20366
22885
  yield* Effect.annotateCurrentSpan({
20367
22886
  cwd,
20368
- key,
20369
- file: options?.file ?? "(repository config)"
22887
+ patterns: (options?.patterns ?? []).length
20370
22888
  });
20371
- yield* rejectOptionLikeRefs(cwd, [
20372
- key,
20373
- value,
20374
- ...options?.file !== void 0 ? [options.file] : []
20375
- ]);
20376
- const command = ChildProcess.setCwd(GitCommand.configSet(key, value, options?.file), cwd);
20377
- const classified = yield* runFor(command, cwd, "generic");
20378
- switch (classified._tag) {
20379
- case "success": return;
20380
- case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
20381
- case "unknownRef": return yield* Effect.fail(new UnknownRefError({
20382
- ref: key,
20383
- cwd
20384
- }));
20385
- case "failure": return yield* Effect.fail(classified.error);
20386
- default: return yield* Effect.die(`Git.configSet: unexpected classification "${classified._tag}"`);
20387
- }
22889
+ yield* rejectOptionLikeRefs(cwd, options?.patterns ?? []);
22890
+ return yield* runParsed("Git.forEachRef", GitCommand.forEachRef(options?.patterns ?? []), cwd, "for-each-ref", "generic", parseForEachRef);
20388
22891
  }),
20389
- add: Effect.fn("Git.add")(function* (cwd, paths) {
22892
+ revList: Effect.fn("Git.revList")(function* (cwd, ref, options) {
20390
22893
  yield* Effect.annotateCurrentSpan({
20391
22894
  cwd,
20392
- count: paths.length
22895
+ ref,
22896
+ firstParent: options?.firstParent ?? false
22897
+ });
22898
+ yield* rejectOptionLikeRefs(cwd, [ref]);
22899
+ yield* rejectNonNaturalNumber(cwd, "a rev-list limit", options?.limit);
22900
+ return yield* runParsed("Git.revList", GitCommand.revList(ref, options?.limit, options?.firstParent ?? false), cwd, ref, "generic", (output) => output.split("\n").filter((line) => line.length > 0));
22901
+ }),
22902
+ commit: Effect.fn("Git.commit")(function* (cwd, message, options) {
22903
+ yield* Effect.annotateCurrentSpan({
22904
+ cwd,
22905
+ amend: options?.amend ?? false
22906
+ });
22907
+ return yield* runVoid("Git.commit", GitCommand.commit(message, options?.all ?? false, options?.allowEmpty ?? false, options?.amend ?? false, options?.author), cwd, "HEAD");
22908
+ }),
22909
+ push: Effect.fn("Git.push")(function* (cwd, options) {
22910
+ const remote = options?.remote ?? "origin";
22911
+ yield* Effect.annotateCurrentSpan({
22912
+ cwd,
22913
+ refspec: options?.refspec ?? "(current branch)",
22914
+ forceWithLease: options?.forceWithLease ?? false
20393
22915
  });
20394
- const command = ChildProcess.setCwd(GitCommand.add(paths), cwd);
20395
- const classified = yield* runFor(command, cwd, "generic");
22916
+ yield* rejectOptionLikeRefs(cwd, [remote, ...options?.refspec !== void 0 ? [options.refspec] : []]);
22917
+ const classified = yield* runFor(GitCommand.push(remote, options?.refspec, options?.force ?? false, options?.forceWithLease ?? false, options?.tags ?? false, options?.setUpstream ?? false), cwd, "push");
20396
22918
  switch (classified._tag) {
20397
22919
  case "success": return;
22920
+ case "nonFastForward": return yield* Effect.fail(new NonFastForwardError({
22921
+ cwd,
22922
+ ...options?.refspec !== void 0 ? { refspec: options.refspec } : {}
22923
+ }));
20398
22924
  case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
20399
22925
  case "unknownRef": return yield* Effect.fail(new UnknownRefError({
20400
- ref: "working tree",
22926
+ ref: options?.refspec ?? "HEAD",
20401
22927
  cwd
20402
22928
  }));
20403
22929
  case "failure": return yield* Effect.fail(classified.error);
20404
- default: return yield* Effect.die(`Git.add: unexpected classification "${classified._tag}"`);
22930
+ default: return yield* Effect.die(`Git.push: unexpected classification "${classified._tag}"`);
20405
22931
  }
20406
22932
  }),
20407
- nameStatus,
20408
- unstagedChanges,
20409
- stagedChanges,
20410
- untrackedFiles,
20411
- defaultBranch: Effect.fn("Git.defaultBranch")(function* (cwd, options) {
22933
+ pull: Effect.fn("Git.pull")(function* (cwd, options) {
20412
22934
  const remote = options?.remote ?? "origin";
20413
22935
  yield* Effect.annotateCurrentSpan({
20414
22936
  cwd,
20415
- remote
22937
+ ref: options?.ref ?? "(upstream)",
22938
+ rebase: options?.rebase ?? false
20416
22939
  });
20417
- yield* rejectOptionLikeRefs(cwd, [remote]);
20418
- const command = ChildProcess.setCwd(GitCommand.defaultBranch(remote), cwd);
20419
- const classified = yield* runFor(command, cwd, "quiet");
22940
+ yield* rejectOptionLikeRefs(cwd, [remote, ...options?.ref !== void 0 ? [options.ref] : []]);
22941
+ const classified = yield* runFor(GitCommand.pull(remote, options?.ref, options?.rebase ?? false, options?.ffOnly ?? false), cwd, "merge");
20420
22942
  switch (classified._tag) {
20421
- case "success": {
20422
- const short = classified.output.trim();
20423
- const prefix = `${remote}/`;
20424
- return Option.some(short.startsWith(prefix) ? short.slice(prefix.length) : short);
20425
- }
20426
- case "absent": return Option.none();
22943
+ case "success": return;
22944
+ case "dirtyWorktree": return yield* Effect.fail(new DirtyWorktreeError({ cwd }));
22945
+ case "mergeConflict": return yield* Effect.fail(new MergeConflictError({ cwd }));
20427
22946
  case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
20428
22947
  case "unknownRef": return yield* Effect.fail(new UnknownRefError({
20429
- ref: `refs/remotes/${remote}/HEAD`,
22948
+ ref: options?.ref ?? "(upstream)",
20430
22949
  cwd
20431
22950
  }));
20432
22951
  case "failure": return yield* Effect.fail(classified.error);
20433
- default: return yield* Effect.die(`Git.defaultBranch: unexpected classification "${classified._tag}"`);
22952
+ default: return yield* Effect.die(`Git.pull: unexpected classification "${classified._tag}"`);
20434
22953
  }
20435
22954
  }),
20436
- currentBranch: Effect.fn("Git.currentBranch")(function* (cwd) {
20437
- yield* Effect.annotateCurrentSpan({ cwd });
20438
- const command = ChildProcess.setCwd(GitCommand.currentBranch(), cwd);
20439
- const classified = yield* runFor(command, cwd, "generic");
20440
- switch (classified._tag) {
20441
- case "success": {
20442
- const name = classified.output.trim();
20443
- return name === "HEAD" ? Option.none() : Option.some(name);
20444
- }
20445
- case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
20446
- case "unknownRef": return yield* Effect.fail(new UnknownRefError({
20447
- ref: "HEAD",
20448
- cwd
20449
- }));
20450
- case "failure": return yield* Effect.fail(classified.error);
20451
- default: return yield* Effect.die(`Git.currentBranch: unexpected classification "${classified._tag}"`);
20452
- }
22955
+ configList: Effect.fn("Git.configList")(function* (cwd, options) {
22956
+ yield* Effect.annotateCurrentSpan({
22957
+ cwd,
22958
+ file: options?.file ?? "(repository config)"
22959
+ });
22960
+ yield* rejectOptionLikeRefs(cwd, options?.file !== void 0 ? [options.file] : []);
22961
+ return yield* runParsed("Git.configList", GitCommand.configList(options?.file), cwd, "config", "generic", parseConfigList);
20453
22962
  }),
20454
- repoRoot: Effect.fn("Git.repoRoot")(function* (cwd) {
20455
- yield* Effect.annotateCurrentSpan({ cwd });
20456
- const command = ChildProcess.setCwd(GitCommand.repoRoot(), cwd);
20457
- const classified = yield* runFor(command, cwd, "generic");
20458
- switch (classified._tag) {
20459
- case "success": return classified.output.trim();
20460
- case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
20461
- case "unknownRef": return yield* Effect.fail(new UnknownRefError({
20462
- ref: "working tree",
20463
- cwd
20464
- }));
20465
- case "failure": return yield* Effect.fail(classified.error);
20466
- default: return yield* Effect.die(`Git.repoRoot: unexpected classification "${classified._tag}"`);
20467
- }
22963
+ configGetAll: Effect.fn("Git.configGetAll")(function* (cwd, key, options) {
22964
+ yield* Effect.annotateCurrentSpan({
22965
+ cwd,
22966
+ key,
22967
+ file: options?.file ?? "(repository config)"
22968
+ });
22969
+ yield* rejectOptionLikeRefs(cwd, [key, ...options?.file !== void 0 ? [options.file] : []]);
22970
+ return yield* runParsed("Git.configGetAll", GitCommand.configGetAll(key, options?.file), cwd, key, "quiet", parseNulSeparated, () => []);
20468
22971
  }),
20469
- configGet: Effect.fn("Git.configGet")(function* (cwd, key) {
22972
+ configUnset: Effect.fn("Git.configUnset")(function* (cwd, key, options) {
20470
22973
  yield* Effect.annotateCurrentSpan({
20471
22974
  cwd,
20472
- key
22975
+ key,
22976
+ file: options?.file ?? "(repository config)"
20473
22977
  });
20474
- yield* rejectOptionLikeRefs(cwd, [key]);
20475
- const command = ChildProcess.setCwd(GitCommand.configGet(key), cwd);
20476
- const classified = yield* runFor(command, cwd, "quiet");
20477
- switch (classified._tag) {
20478
- case "success": return Option.some(classified.output.trim());
20479
- case "absent": return Option.none();
20480
- case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
20481
- case "unknownRef": return yield* Effect.fail(new UnknownRefError({
20482
- ref: key,
20483
- cwd
20484
- }));
20485
- case "failure": return yield* Effect.fail(classified.error);
20486
- default: return yield* Effect.die(`Git.configGet: unexpected classification "${classified._tag}"`);
20487
- }
22978
+ yield* rejectOptionLikeRefs(cwd, [key, ...options?.file !== void 0 ? [options.file] : []]);
22979
+ return yield* runVoid("Git.configUnset", GitCommand.configUnset(key, options?.file, options?.all ?? false), cwd, key);
20488
22980
  }),
20489
- remoteUrl: Effect.fn("Git.remoteUrl")(function* (cwd, options) {
20490
- const remote = options?.remote ?? "origin";
22981
+ rm: Effect.fn("Git.rm")(function* (cwd, paths, options) {
20491
22982
  yield* Effect.annotateCurrentSpan({
20492
22983
  cwd,
20493
- remote
22984
+ count: paths.length,
22985
+ cached: options?.cached ?? false
20494
22986
  });
20495
- yield* rejectOptionLikeRefs(cwd, [remote]);
20496
- const command = ChildProcess.setCwd(GitCommand.remoteUrl(remote), cwd);
20497
- const classified = yield* runFor(command, cwd, "noSuchRemote");
20498
- switch (classified._tag) {
20499
- case "success": return Option.some(classified.output.trim());
20500
- case "absent": return Option.none();
20501
- case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
20502
- case "unknownRef": return yield* Effect.fail(new UnknownRefError({
20503
- ref: remote,
20504
- cwd
20505
- }));
20506
- case "failure": return yield* Effect.fail(classified.error);
20507
- default: return yield* Effect.die(`Git.remoteUrl: unexpected classification "${classified._tag}"`);
20508
- }
22987
+ return yield* runVoid("Git.rm", GitCommand.rm(paths, options?.cached ?? false, options?.recursive ?? false, options?.force ?? false), cwd, "working tree");
20509
22988
  }),
20510
- commitInfo: Effect.fn("Git.commitInfo")(function* (cwd, ref) {
20511
- const target = ref ?? "HEAD";
22989
+ mv: Effect.fn("Git.mv")(function* (cwd, source, destination, options) {
20512
22990
  yield* Effect.annotateCurrentSpan({
20513
22991
  cwd,
20514
- ref: target
22992
+ source,
22993
+ destination
20515
22994
  });
20516
- yield* rejectOptionLikeRefs(cwd, [target]);
20517
- const command = ChildProcess.setCwd(GitCommand.commitInfo(target), cwd);
20518
- const classified = yield* runFor(command, cwd, "generic");
20519
- switch (classified._tag) {
20520
- case "success": return parseCommitInfo(classified.output);
20521
- case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
20522
- case "unknownRef": return yield* Effect.fail(new UnknownRefError({
20523
- ref: target,
20524
- cwd
20525
- }));
20526
- case "failure": return yield* Effect.fail(classified.error);
20527
- default: return yield* Effect.die(`Git.commitInfo: unexpected classification "${classified._tag}"`);
20528
- }
22995
+ return yield* runVoid("Git.mv", GitCommand.mv(source, destination, options?.force ?? false), cwd, "working tree");
22996
+ }),
22997
+ checkIgnore: Effect.fn("Git.checkIgnore")(function* (cwd, paths) {
22998
+ yield* Effect.annotateCurrentSpan({
22999
+ cwd,
23000
+ count: paths.length
23001
+ });
23002
+ return yield* runParsed("Git.checkIgnore", GitCommand.checkIgnore(paths), cwd, "check-ignore", "quiet", parseNulSeparated, () => []);
23003
+ }),
23004
+ worktreeAdd: Effect.fn("Git.worktreeAdd")(function* (cwd, path, options) {
23005
+ yield* Effect.annotateCurrentSpan({
23006
+ cwd,
23007
+ path,
23008
+ ref: options?.ref ?? "(default)"
23009
+ });
23010
+ yield* rejectOptionLikeRefs(cwd, [path, ...options?.ref !== void 0 ? [options.ref] : []]);
23011
+ return yield* runVoid("Git.worktreeAdd", GitCommand.worktreeAdd(path, options?.ref, options?.detach ?? false, options?.force ?? false), cwd, options?.ref ?? path);
20529
23012
  }),
20530
- status: Effect.fn("Git.status")(function* (cwd) {
23013
+ worktreeList: Effect.fn("Git.worktreeList")(function* (cwd) {
20531
23014
  yield* Effect.annotateCurrentSpan({ cwd });
20532
- const command = ChildProcess.setCwd(GitCommand.status(), cwd);
20533
- const classified = yield* runFor(command, cwd, "generic");
20534
- switch (classified._tag) {
20535
- case "success": return parseStatus(classified.output);
20536
- case "notARepository": return yield* Effect.fail(new NotARepositoryError({ cwd }));
20537
- case "unknownRef": return yield* Effect.fail(new UnknownRefError({
20538
- ref: "working tree",
20539
- cwd
20540
- }));
20541
- case "failure": return yield* Effect.fail(classified.error);
20542
- default: return yield* Effect.die(`Git.status: unexpected classification "${classified._tag}"`);
20543
- }
23015
+ return yield* runParsed("Git.worktreeList", GitCommand.worktreeList(), cwd, "worktrees", "generic", parseWorktreeList);
23016
+ }),
23017
+ worktreeRemove: Effect.fn("Git.worktreeRemove")(function* (cwd, path, options) {
23018
+ yield* Effect.annotateCurrentSpan({
23019
+ cwd,
23020
+ path
23021
+ });
23022
+ yield* rejectOptionLikeRefs(cwd, [path]);
23023
+ return yield* runVoid("Git.worktreeRemove", GitCommand.worktreeRemove(path, options?.force ?? false), cwd, path);
23024
+ }),
23025
+ lsFiles: Effect.fn("Git.lsFiles")(function* (cwd, options) {
23026
+ yield* Effect.annotateCurrentSpan({
23027
+ cwd,
23028
+ patterns: (options?.pathspec ?? []).length
23029
+ });
23030
+ return yield* runParsed("Git.lsFiles", GitCommand.lsFiles(options?.pathspec ?? []), cwd, "index", "generic", parseLsFiles);
20544
23031
  })
20545
23032
  };
20546
23033
  };
@@ -20552,17 +23039,23 @@ const make = (spawner) => {
20552
23039
  const notStubbed = (method) => () => Effect.die(/* @__PURE__ */ new Error(`Git.makeTest: ${method}() was called but not stubbed — no honest default exists for a test double; pass a \`${method}\` override.`));
20553
23040
  /**
20554
23041
  * Typed git introspection over core's `ChildProcessSpawner`: read a
20555
- * repository's state at any ref without checking it out, plus the mutating
20556
- * tier (`checkout`, `fetch`, `fetchAny`, `submoduleUpdate`, `submoduleAdd`,
20557
- * `sparseCheckoutSet`, `configSet`, `add`) that changes it.
23042
+ * repository's state at any ref without checking it out (including the
23043
+ * network read `lsRemote` and the index read `lsFiles`), plus the mutating
23044
+ * tier checkout/fetch, the working-tree restore trio and stash, branches
23045
+ * and tags, remotes, worktrees, commit/push/pull, submodules,
23046
+ * sparse-checkout, config writes and staging — that changes it. Every
23047
+ * mutating method's TSDoc opens with the literal word `Mutating:`.
20558
23048
  *
20559
23049
  * @remarks
20560
23050
  * Every method takes `cwd` explicitly and classifies git's stderr/exit-code
20561
23051
  * taxonomy exactly once, in this module's private `classify` step — a
20562
23052
  * spawn-level `PlatformError` and `Cause.TimeoutError` never escape a `Git`
20563
23053
  * method; every failure surfaces as {@link GitCommandError},
20564
- * {@link NotARepositoryError}, or {@link UnknownRefError}, or degrades to
20565
- * the documented non-error (`Option.none`, `false`).
23054
+ * {@link NotARepositoryError}, {@link UnknownRefError}, or one of the three
23055
+ * consumer-branchable classifications ({@link NonFastForwardError} from
23056
+ * `push`; {@link MergeConflictError} and {@link DirtyWorktreeError} from the
23057
+ * merge-shaped `pull` / `stashPop` / `stashApply`), or degrades to the
23058
+ * documented non-error (`Option.none`, `false`, the empty array).
20566
23059
  *
20567
23060
  * Every method whose TSDoc opens "Mutating:" changes the working tree,
20568
23061
  * `HEAD`, the index, the repository config, the object database and
@@ -20571,6 +23064,12 @@ const notStubbed = (method) => () => Effect.die(/* @__PURE__ */ new Error(`Git.m
20571
23064
  * that — a caller running two mutating calls (or a mutating call alongside a
20572
23065
  * read) against one `cwd` at once owns the race.
20573
23066
  *
23067
+ * **Redaction policy (documented, not just convention).** Error values
23068
+ * persist only the constructor's REDACTED argv (see `GitCommandError.args`),
23069
+ * and span annotations carry stable identifiers only — `cwd`, refs, keys,
23070
+ * paths, remote names — never config values and never URLs, which can embed
23071
+ * userinfo. A new method must follow both halves before it ships.
23072
+ *
20574
23073
  * @public
20575
23074
  */
20576
23075
  var Git = class Git extends Context.Service()("@effected/git/Git") {
@@ -20585,7 +23084,7 @@ var Git = class Git extends Context.Service()("@effected/git/Git") {
20585
23084
  *
20586
23085
  * @remarks
20587
23086
  * Unlike `WorkspaceDiscovery.makeTest`, **no method here has an honest
20588
- * default** — the shape is twenty-six unrelated git operations, and a
23087
+ * default** — the shape is unrelated git operations, and a
20589
23088
  * fabricated answer for any of them (an empty tree, a made-up sha, a silent
20590
23089
  * no-op `checkout`) would leak into consumer logic as fact. So every
20591
23090
  * unstubbed method fails loudly as a defect
@@ -20624,8 +23123,23 @@ var Git = class Git extends Context.Service()("@effected/git/Git") {
20624
23123
  checkout: notStubbed("checkout"),
20625
23124
  fetch: notStubbed("fetch"),
20626
23125
  fetchAny: notStubbed("fetchAny"),
23126
+ fetchUnshallow: notStubbed("fetchUnshallow"),
23127
+ isShallow: notStubbed("isShallow"),
23128
+ reset: notStubbed("reset"),
23129
+ clean: notStubbed("clean"),
23130
+ restore: notStubbed("restore"),
23131
+ branchCreate: notStubbed("branchCreate"),
23132
+ branchDelete: notStubbed("branchDelete"),
20627
23133
  submoduleUpdate: notStubbed("submoduleUpdate"),
20628
23134
  submoduleAdd: notStubbed("submoduleAdd"),
23135
+ submoduleStatus: notStubbed("submoduleStatus"),
23136
+ submoduleInit: notStubbed("submoduleInit"),
23137
+ submoduleDeinit: notStubbed("submoduleDeinit"),
23138
+ submoduleSync: notStubbed("submoduleSync"),
23139
+ submoduleSetUrl: notStubbed("submoduleSetUrl"),
23140
+ submoduleSetBranch: notStubbed("submoduleSetBranch"),
23141
+ submoduleAbsorbgitdirs: notStubbed("submoduleAbsorbgitdirs"),
23142
+ submoduleForeach: notStubbed("submoduleForeach"),
20629
23143
  sparseCheckoutSet: notStubbed("sparseCheckoutSet"),
20630
23144
  configSet: notStubbed("configSet"),
20631
23145
  add: notStubbed("add"),
@@ -20640,6 +23154,34 @@ var Git = class Git extends Context.Service()("@effected/git/Git") {
20640
23154
  remoteUrl: notStubbed("remoteUrl"),
20641
23155
  commitInfo: notStubbed("commitInfo"),
20642
23156
  status: notStubbed("status"),
23157
+ lsRemote: notStubbed("lsRemote"),
23158
+ remoteAdd: notStubbed("remoteAdd"),
23159
+ remoteRemove: notStubbed("remoteRemove"),
23160
+ remoteSetUrl: notStubbed("remoteSetUrl"),
23161
+ stashPush: notStubbed("stashPush"),
23162
+ stashPop: notStubbed("stashPop"),
23163
+ stashApply: notStubbed("stashApply"),
23164
+ stashDrop: notStubbed("stashDrop"),
23165
+ stashList: notStubbed("stashList"),
23166
+ branchList: notStubbed("branchList"),
23167
+ tagCreate: notStubbed("tagCreate"),
23168
+ tagDelete: notStubbed("tagDelete"),
23169
+ tagList: notStubbed("tagList"),
23170
+ forEachRef: notStubbed("forEachRef"),
23171
+ revList: notStubbed("revList"),
23172
+ commit: notStubbed("commit"),
23173
+ push: notStubbed("push"),
23174
+ pull: notStubbed("pull"),
23175
+ configList: notStubbed("configList"),
23176
+ configGetAll: notStubbed("configGetAll"),
23177
+ configUnset: notStubbed("configUnset"),
23178
+ rm: notStubbed("rm"),
23179
+ mv: notStubbed("mv"),
23180
+ checkIgnore: notStubbed("checkIgnore"),
23181
+ worktreeAdd: notStubbed("worktreeAdd"),
23182
+ worktreeList: notStubbed("worktreeList"),
23183
+ worktreeRemove: notStubbed("worktreeRemove"),
23184
+ lsFiles: notStubbed("lsFiles"),
20643
23185
  ...overrides
20644
23186
  });
20645
23187
  /**
@@ -20669,7 +23211,7 @@ var Git = class Git extends Context.Service()("@effected/git/Git") {
20669
23211
  };
20670
23212
 
20671
23213
  //#endregion
20672
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.9.5_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/ChangeDetector.js
23214
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.10.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+semv_feff9e309e6abeafa28f7ea259b8a9bf/node_modules/@effected/workspaces/ChangeDetector.js
20673
23215
  /**
20674
23216
  * Which git refs to compare, and whether to fold in the working tree.
20675
23217
  *
@@ -20969,7 +23511,7 @@ function resolveFromCatalog(catalogs, wantedDependency) {
20969
23511
  }
20970
23512
 
20971
23513
  //#endregion
20972
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.9.5_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/internal/catalogs.js
23514
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.10.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+semv_feff9e309e6abeafa28f7ea259b8a9bf/node_modules/@effected/workspaces/internal/catalogs.js
20973
23515
  /** Project a pnpm-workspace manifest's `catalog` / `catalogs` fields into a `Catalogs` map. */
20974
23516
  const inlineCatalogs = (manifest) => {
20975
23517
  if (manifest.catalog === void 0 && manifest.catalogs === void 0) return {};
@@ -21035,7 +23577,7 @@ const rangeOf = (catalogs, dependency, specifier) => {
21035
23577
  };
21036
23578
 
21037
23579
  //#endregion
21038
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.9.5_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/ConfigDependencyHooks.js
23580
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.10.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+semv_feff9e309e6abeafa28f7ea259b8a9bf/node_modules/@effected/workspaces/ConfigDependencyHooks.js
21039
23581
  /** Whether `value` is a non-null, non-array object. */
21040
23582
  const isObject$2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
21041
23583
  /**
@@ -21128,6 +23670,141 @@ const updateConfigOf = (mod) => {
21128
23670
  }
21129
23671
  };
21130
23672
  /**
23673
+ * The subprocess replay program {@link ConfigDependencyHooks.layerSubprocess}
23674
+ * hands to `node --input-type=module -e`.
23675
+ *
23676
+ * @remarks
23677
+ * A **static** string constant, deliberately: a bundler compiles a *computed*
23678
+ * dynamic `import()` into a context module that cannot resolve a runtime path
23679
+ * (`Cannot find module 'file:///…'`), so the computed import has to run in a
23680
+ * child process whose program text carries **no interpolated runtime value** —
23681
+ * the workspace root, the seed and the dependency names all arrive via argv
23682
+ * (`process.argv.slice(1)` under `-e`), never spliced into the script.
23683
+ *
23684
+ * The script mirrors this module's in-process semantics exactly so the two
23685
+ * layers are drop-in interchangeable: `pnpmfile.mjs` before `pnpmfile.cjs`
23686
+ * (pnpm 11's loader order), the `ERR_MODULE_NOT_FOUND`-for-the-candidate-itself
23687
+ * skip discrimination (`err.url` equality), the same hook-locator shapes, the
23688
+ * same tolerant threading of returned data (`configOf` / `finiteNumberOr` /
23689
+ * `stringArrayOr` clones below), and the same synchronous hook call. Only the
23690
+ * *mechanism* failures are reported: the script prints one final line of JSON —
23691
+ * `{ ok: true, config }` on success, `{ ok: false, name, message, stack? }`
23692
+ * naming the offending dependency on a load/replay failure — and exits through
23693
+ * the write callback so the payload is flushed even if a hook left the event
23694
+ * loop occupied. The final-line framing tolerates a hook's own `console.log`
23695
+ * noise on stdout.
23696
+ */
23697
+ const REPLAY_SCRIPT = `
23698
+ const [root, seedJson, ...names] = process.argv.slice(1);
23699
+ const { pathToFileURL } = await import("node:url");
23700
+ const { join } = await import("node:path");
23701
+ const isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
23702
+ const finiteNumberOr = (value, fallback) => (typeof value === "number" && Number.isFinite(value) ? value : fallback);
23703
+ const stringArrayOr = (value, fallback) =>
23704
+ Array.isArray(value) && value.every((entry) => typeof entry === "string") ? value : fallback;
23705
+ const configOf = (value, fallback) =>
23706
+ isObject(value)
23707
+ ? {
23708
+ catalog: isObject(value.catalog) ? value.catalog : fallback.catalog,
23709
+ catalogs: isObject(value.catalogs) ? value.catalogs : fallback.catalogs,
23710
+ minimumReleaseAge: finiteNumberOr(value.minimumReleaseAge, fallback.minimumReleaseAge),
23711
+ minimumReleaseAgeExclude: stringArrayOr(value.minimumReleaseAgeExclude, fallback.minimumReleaseAgeExclude),
23712
+ }
23713
+ : fallback;
23714
+ const failure = (name, cause) => ({
23715
+ ok: false,
23716
+ name,
23717
+ message: cause instanceof Error ? cause.message : String(cause),
23718
+ ...(cause instanceof Error && typeof cause.stack === "string" ? { stack: cause.stack } : {}),
23719
+ });
23720
+ const replay = async () => {
23721
+ let catalog = {};
23722
+ const catalogs = {};
23723
+ for (const [name, entries] of Object.entries(JSON.parse(seedJson))) {
23724
+ if (name === "default") catalog = { ...entries };
23725
+ else catalogs[name] = { ...entries };
23726
+ }
23727
+ let config = { catalog, catalogs, minimumReleaseAge: undefined, minimumReleaseAgeExclude: undefined };
23728
+ for (const name of names) {
23729
+ let loaded;
23730
+ let found = false;
23731
+ for (const filename of ["pnpmfile.mjs", "pnpmfile.cjs"]) {
23732
+ const candidate = pathToFileURL(join(root, "node_modules", ".pnpm-config", name, filename)).href;
23733
+ try {
23734
+ loaded = await import(candidate);
23735
+ found = true;
23736
+ break;
23737
+ } catch (cause) {
23738
+ const url =
23739
+ isObject(cause) && cause.code === "ERR_MODULE_NOT_FOUND" && typeof cause.url === "string"
23740
+ ? cause.url
23741
+ : undefined;
23742
+ if (url === candidate) continue;
23743
+ return failure(name, cause);
23744
+ }
23745
+ }
23746
+ if (!found) continue;
23747
+ let hook;
23748
+ for (const candidate of [loaded, isObject(loaded) ? loaded.default : undefined]) {
23749
+ if (!isObject(candidate)) continue;
23750
+ if (isObject(candidate.hooks) && typeof candidate.hooks.updateConfig === "function") {
23751
+ hook = candidate.hooks.updateConfig;
23752
+ break;
23753
+ }
23754
+ if (typeof candidate.updateConfig === "function") {
23755
+ hook = candidate.updateConfig;
23756
+ break;
23757
+ }
23758
+ }
23759
+ if (hook === undefined) continue;
23760
+ try {
23761
+ config = configOf(hook(config), config);
23762
+ } catch (cause) {
23763
+ return failure(name, cause);
23764
+ }
23765
+ }
23766
+ return { ok: true, config };
23767
+ };
23768
+ const payload = await replay();
23769
+ process.stdout.write("\\n" + JSON.stringify(payload) + "\\n", () => process.exit(0));
23770
+ `;
23771
+ /**
23772
+ * The ceiling on one subprocess replay. A config dependency's `updateConfig`
23773
+ * reads and rewrites a config object — no install work, no network — so thirty
23774
+ * seconds is generous. Without a ceiling a pnpmfile that loops or awaits a
23775
+ * promise that never settles hangs `inject`, and through it the one memoized
23776
+ * {@link WorkspaceCatalogs} assemble pass every catalog read blocks on. Expiry
23777
+ * kills the child (`Run` scopes it) and surfaces as a `CommandFailedError`
23778
+ * through the same typed transport-failure path as any other mechanism failure.
23779
+ */
23780
+ const REPLAY_TIMEOUT = Duration.seconds(30);
23781
+ /**
23782
+ * The subprocess protocol payload — a single JSON line near the end of the
23783
+ * child's stdout, framed and parsed by `Run.jsonLine`, which scans lines from
23784
+ * the end for the first that decodes (so a hook logging after the payload —
23785
+ * e.g. from `process.on("exit", ...)` — cannot displace it). The `ok`
23786
+ * discriminant is what keeps an accidental log line from satisfying the
23787
+ * envelope. The envelope is strict (a payload without a usable
23788
+ * `ok` discriminant is a mechanism failure, typed); the `config` slice inside a
23789
+ * success stays `Unknown` because a hook's returned *data* is tolerantly
23790
+ * threaded (`configOf`), never fatal.
23791
+ */
23792
+ const ReplayPayload = Schema.Union([Schema.Struct({
23793
+ ok: Schema.Literal(true),
23794
+ config: Schema.Unknown
23795
+ }), Schema.Struct({
23796
+ ok: Schema.Literal(false),
23797
+ name: Schema.optionalKey(Schema.String),
23798
+ message: Schema.optionalKey(Schema.String),
23799
+ stack: Schema.optionalKey(Schema.String)
23800
+ })]);
23801
+ /** Rebuild the subprocess's serialized failure as an `Error`, preserving the child-side stack when it carried one. */
23802
+ const replayFailureCause = (payload) => {
23803
+ const error = new Error(payload.message ?? "config dependency hook replay failed");
23804
+ if (payload.stack !== void 0) error.stack = payload.stack;
23805
+ return error;
23806
+ };
23807
+ /**
21131
23808
  * Replays a workspace's `configDependencies` `updateConfig` hooks over the inline
21132
23809
  * catalogs — the opt-in seam that lets hook-injected catalogs participate in
21133
23810
  * assembly.
@@ -21220,10 +23897,99 @@ var ConfigDependencyHooks = class ConfigDependencyHooks extends Context.Service(
21220
23897
  releaseAge: releaseAgeOf(config)
21221
23898
  };
21222
23899
  }) });
23900
+ /**
23901
+ * The subprocess layer: replays each config dependency's pnpmfile in a `node`
23902
+ * child process instead of an in-process dynamic `import()`, with identical
23903
+ * typed semantics to {@link ConfigDependencyHooks.layerLive} — the two are
23904
+ * drop-in interchangeable.
23905
+ *
23906
+ * @remarks
23907
+ * `layerLive` computes the `import()` path at runtime, and a bundler (rspack,
23908
+ * for one) compiles a *computed* dynamic import into a context module that
23909
+ * throws `Cannot find module 'file:///…'` at runtime — so in any bundled
23910
+ * consumer, a GitHub Action above all, the in-process replay is unreachable.
23911
+ * This layer keeps every computed load out of the bundle graph: the replay
23912
+ * program is a **static** string constant passed via argv
23913
+ * (`node --input-type=module -e <script> <root> <seed> <...names>`), and the
23914
+ * child process performs the computed imports where no bundler rewrote them.
23915
+ * A subprocess also keeps config-dependency code out of the consumer's own
23916
+ * process.
23917
+ *
23918
+ * The contract's semantics are unchanged, not the downstream fail-open shape:
23919
+ * an empty `configDependencies` returns the seed without spawning anything; a
23920
+ * `..` path segment in a dependency name fails typed **before** any spawn; a
23921
+ * missing pnpmfile (neither `.mjs` nor `.cjs`) is the one legitimate skip,
23922
+ * discriminated inside the child by `err.url` equality exactly as
23923
+ * `layerLive` discriminates in process; any other load failure — a syntax
23924
+ * error, a throwing top level, an `ERR_MODULE_NOT_FOUND` for a module the
23925
+ * pnpmfile itself imports — and a hook that throws when called are serialized
23926
+ * back per-name and surface typed as a `hooks`-source `CatalogAssemblyError`
23927
+ * naming that dependency. A hook's returned *data* stays tolerantly threaded
23928
+ * (last well-formed write wins), never fatal. Spawn and transport failures —
23929
+ * `node` absent, a non-zero exit without a result payload, unparseable
23930
+ * output — fail typed too, never a defect and never a silent skip.
23931
+ *
23932
+ * Two bounds this layer imposes that `layerLive` cannot: the replay is
23933
+ * given thirty seconds (a pnpmfile that loops or awaits forever fails typed
23934
+ * instead of hanging the memoized assemble pass — a subprocess is killable,
23935
+ * while `layerLive`'s in-process synchronous hook call is not interruptible
23936
+ * by any means, so the asymmetry is inherent, not a parity violation), and
23937
+ * the child's stdout is captured under `Run.jsonLine`'s 16 MiB default
23938
+ * ceiling (a hook that logs more than that fails typed as `tooLarge`, where
23939
+ * `layerLive` — which captures nothing — would succeed).
23940
+ *
23941
+ * Catalog folding and normalization stay in the **parent** (the same
23942
+ * `@pnpm/catalogs`-derived path `layerLive` uses); the child returns only the
23943
+ * raw threaded config slice, since the script cannot import kit code.
23944
+ *
23945
+ * Requires core's `ChildProcessSpawner`, resolved when the layer is built —
23946
+ * the consumer provides it once at the edge (`@effect/platform-node`'s
23947
+ * `NodeServices.layer`), the same discharge `@effected/git` uses. Wired by
23948
+ * `WorkspaceCatalogs.layerWithConfigDependenciesSubprocess` /
23949
+ * `Workspaces.layerWithConfigDependenciesSubprocess`.
23950
+ */
23951
+ static layerSubprocess = Layer.effect(ConfigDependencyHooks, Effect.gen(function* () {
23952
+ const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
23953
+ return { inject: (root, configDependencies, seed) => Effect.gen(function* () {
23954
+ const names = Object.keys(configDependencies);
23955
+ if (names.length === 0) return {
23956
+ catalogs: seed,
23957
+ releaseAge: {}
23958
+ };
23959
+ for (const name of names) if (hasTraversalSegment(name)) return yield* Effect.fail(new CatalogAssemblyError({
23960
+ source: "hooks",
23961
+ path: name,
23962
+ cause: /* @__PURE__ */ new Error(`config dependency name has a '..' path segment: ${name}`)
23963
+ }));
23964
+ const command = ChildProcess.make("node", [
23965
+ "--input-type=module",
23966
+ "-e",
23967
+ REPLAY_SCRIPT,
23968
+ root,
23969
+ JSON.stringify(seed),
23970
+ ...names
23971
+ ]);
23972
+ const payload = yield* Run.jsonLine(command, ReplayPayload, { timeout: REPLAY_TIMEOUT }).pipe(Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner), Effect.catch((cause) => Effect.fail(new CatalogAssemblyError({
23973
+ source: "hooks",
23974
+ path: root,
23975
+ cause
23976
+ }))));
23977
+ if (payload.ok === false) return yield* Effect.fail(new CatalogAssemblyError({
23978
+ source: "hooks",
23979
+ path: payload.name ?? root,
23980
+ cause: replayFailureCause(payload)
23981
+ }));
23982
+ const config = configOf(payload.config, seedToConfig(seed));
23983
+ return {
23984
+ catalogs: configToEntries(config),
23985
+ releaseAge: releaseAgeOf(config)
23986
+ };
23987
+ }) };
23988
+ }));
21223
23989
  };
21224
23990
 
21225
23991
  //#endregion
21226
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.9.5_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/PackageManagerName.js
23992
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.10.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+semv_feff9e309e6abeafa28f7ea259b8a9bf/node_modules/@effected/workspaces/PackageManagerName.js
21227
23993
  /**
21228
23994
  * The four package managers this package understands.
21229
23995
  *
@@ -21552,7 +24318,7 @@ var PackageManagerDetector = class PackageManagerDetector extends Context.Servic
21552
24318
  };
21553
24319
 
21554
24320
  //#endregion
21555
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.9.5_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/LockfileReader.js
24321
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.10.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+semv_feff9e309e6abeafa28f7ea259b8a9bf/node_modules/@effected/workspaces/LockfileReader.js
21556
24322
  /**
21557
24323
  * Raised when the workspace's lockfile cannot be read off disk.
21558
24324
  *
@@ -21733,7 +24499,7 @@ var LockfileReader = class LockfileReader extends Context.Service()("@effected/w
21733
24499
  };
21734
24500
 
21735
24501
  //#endregion
21736
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.9.5_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/Publishability.js
24502
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.10.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+semv_feff9e309e6abeafa28f7ea259b8a9bf/node_modules/@effected/workspaces/Publishability.js
21737
24503
  /** The public npm registry, used when `publishConfig.registry` says nothing. */
21738
24504
  const DEFAULT_REGISTRY = "https://registry.npmjs.org/";
21739
24505
  /**
@@ -21893,7 +24659,7 @@ var PublishabilityDetector = class extends Context.Service()("@effected/workspac
21893
24659
  };
21894
24660
 
21895
24661
  //#endregion
21896
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.9.5_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/internal/importerVersions.js
24662
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.10.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+semv_feff9e309e6abeafa28f7ea259b8a9bf/node_modules/@effected/workspaces/internal/importerVersions.js
21897
24663
  /**
21898
24664
  * Strip pnpm's peer-disambiguation suffix from a recorded importer version.
21899
24665
  *
@@ -21980,7 +24746,7 @@ const unanimousVersionOf = (index, dependency) => {
21980
24746
  };
21981
24747
 
21982
24748
  //#endregion
21983
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.9.5_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/WorkspaceCatalogs.js
24749
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.10.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+semv_feff9e309e6abeafa28f7ea259b8a9bf/node_modules/@effected/workspaces/WorkspaceCatalogs.js
21984
24750
  /**
21985
24751
  * An immutable, fully-normalized catalog collection — the one catalog
21986
24752
  * resolution semantic in the package.
@@ -22401,6 +25167,24 @@ var WorkspaceCatalogs = class WorkspaceCatalogs extends Context.Service()("@effe
22401
25167
  */
22402
25168
  static layerWithConfigDependencies = (options) => Layer.effect(WorkspaceCatalogs, WorkspaceCatalogs.make(options)).pipe(Layer.provide(ConfigDependencyHooks.layerLive));
22403
25169
  /**
25170
+ * The opt-in layer that replays config-dependency `pnpmfile` hooks in a
25171
+ * `node` **child process**: it wires
25172
+ * {@link ConfigDependencyHooks.layerSubprocess} in place of the in-process
25173
+ * `layerLive`.
25174
+ *
25175
+ * @remarks
25176
+ * Same typed semantics as {@link WorkspaceCatalogs.layerWithConfigDependencies}
25177
+ * — the two hook layers are drop-in interchangeable — but the replay's
25178
+ * computed dynamic `import()` runs in the subprocess, so it survives bundling
25179
+ * (a bundler compiles a computed in-process `import()` into a context module
25180
+ * that cannot resolve at runtime — every bundled GitHub Action hits this).
25181
+ * The cost is one extra requirement: core's `ChildProcessSpawner`, provided
25182
+ * once at the edge (`@effect/platform-node`'s `NodeServices.layer`) — the
25183
+ * same sanctioned R-widening as `Workspaces.layerWithGit`. Parameterized, so
25184
+ * bind it to a `const` and reuse it.
25185
+ */
25186
+ static layerWithConfigDependenciesSubprocess = (options) => Layer.effect(WorkspaceCatalogs, WorkspaceCatalogs.make(options)).pipe(Layer.provide(ConfigDependencyHooks.layerSubprocess));
25187
+ /**
22404
25188
  * A test double satisfying the full {@link WorkspaceCatalogsShape} with no
22405
25189
  * filesystem, lockfile read, or hook replay.
22406
25190
  *
@@ -22490,7 +25274,7 @@ var WorkspaceCatalogs = class WorkspaceCatalogs extends Context.Service()("@effe
22490
25274
  };
22491
25275
 
22492
25276
  //#endregion
22493
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.9.5_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/WorkspaceStateSnapshot.js
25277
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.10.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+semv_feff9e309e6abeafa28f7ea259b8a9bf/node_modules/@effected/workspaces/WorkspaceStateSnapshot.js
22494
25278
  const EMPTY = Object.freeze(Object.create(null));
22495
25279
  const DependencyMap = Schema.Record(Schema.String, Schema.String).pipe(Schema.withDecodingDefaultKey(Effect.succeed(EMPTY)), Schema.withConstructorDefault(Effect.succeed(EMPTY)));
22496
25280
  /**
@@ -22714,7 +25498,7 @@ var WorkspaceStateSnapshot = class extends Schema.Class("WorkspaceStateSnapshot"
22714
25498
  };
22715
25499
 
22716
25500
  //#endregion
22717
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.9.5_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/WorkspaceSnapshots.js
25501
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.10.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+semv_feff9e309e6abeafa28f7ea259b8a9bf/node_modules/@effected/workspaces/WorkspaceSnapshots.js
22718
25502
  /** Whether `value` is a non-null, non-array object. */
22719
25503
  const isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
22720
25504
  /** Whether every value in a record is a string — a usable dependency map. */
@@ -22992,7 +25776,7 @@ var WorkspaceSnapshots = class WorkspaceSnapshots extends Context.Service()("@ef
22992
25776
  };
22993
25777
 
22994
25778
  //#endregion
22995
- //#region ../../node_modules/.pnpm/@effected+workspaces@0.9.5_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__effect@4.0.0-beta.101/node_modules/@effected/workspaces/Workspaces.js
25779
+ //#region ../../node_modules/.pnpm/@effected+workspaces@0.10.2_@effected+jsonc@0.5.2_effect@4.0.0-beta.101__@effected+semv_feff9e309e6abeafa28f7ea259b8a9bf/node_modules/@effected/workspaces/Workspaces.js
22996
25780
  const compose = (options, catalogsFactory) => {
22997
25781
  const roots = WorkspaceRoot.layer;
22998
25782
  const detector = PackageManagerDetector.layer;
@@ -23009,6 +25793,7 @@ const layerWithGit = (options) => {
23009
25793
  };
23010
25794
  const resolvers = Layer.mergeAll(WorkspaceCatalogs.catalogResolver, WorkspaceDiscovery.workspaceResolver);
23011
25795
  const layerWithConfigDependencies = (options) => compose(options, WorkspaceCatalogs.layerWithConfigDependencies);
25796
+ const layerWithConfigDependenciesSubprocess = (options) => compose(options, WorkspaceCatalogs.layerWithConfigDependenciesSubprocess);
23012
25797
  const resolverLayer = (options) => resolvers.pipe(Layer.provide(layerWithConfigDependencies(options)));
23013
25798
  const resolveManifest = Effect.fn("Workspaces.resolveManifest")(function* (manifest, options) {
23014
25799
  return yield* manifest.resolve().pipe(Effect.provide(resolverLayer(options)));
@@ -23090,6 +25875,32 @@ var Workspaces = class {
23090
25875
  */
23091
25876
  static layerWithConfigDependencies = layerWithConfigDependencies;
23092
25877
  /**
25878
+ * The git-free composite with config-dependency hook replay in a `node`
25879
+ * **child process** —
25880
+ * {@link WorkspaceCatalogs.layerWithConfigDependenciesSubprocess} in place of
25881
+ * the in-process replay.
25882
+ *
25883
+ * @remarks
25884
+ * Same typed semantics as {@link Workspaces.layerWithConfigDependencies}; the
25885
+ * difference is mechanism, and it matters in exactly one environment class: a
25886
+ * **bundled** consumer. The in-process replay's computed dynamic `import()`
25887
+ * is compiled by bundlers (rspack among them) into a context module that
25888
+ * throws `Cannot find module 'file:///…'` at runtime, which makes
25889
+ * `WorkspaceCatalogs.releaseAgeGate()` unreachable from any bundled GitHub
25890
+ * Action. Here the computed import runs inside a `node` child process whose
25891
+ * program text is a static string handed over argv, so nothing computed
25892
+ * enters the bundle graph.
25893
+ *
25894
+ * The extra requirement is core's `ChildProcessSpawner`, provided once at
25895
+ * the edge (`@effect/platform-node`'s `NodeServices.layer`) — the same
25896
+ * sanctioned R-widening as {@link Workspaces.layerWithGit}, and the reason
25897
+ * this is a separate composite rather than a flag: a consumer that keeps the
25898
+ * in-process replay should not have to be able to spawn a subprocess.
25899
+ *
25900
+ * **Bind the result to a `const`.**
25901
+ */
25902
+ static layerWithConfigDependenciesSubprocess = layerWithConfigDependenciesSubprocess;
25903
+ /**
23093
25904
  * The git-free composite plus {@link ChangeDetector} and
23094
25905
  * {@link WorkspaceSnapshots}, over `@effected/git`'s `Git` service.
23095
25906
  *
@@ -23099,7 +25910,8 @@ var Workspaces = class {
23099
25910
  * never detects changes or reads at a ref should not have to be able to
23100
25911
  * spawn a subprocess. The consumer provides `ChildProcessSpawner` once at
23101
25912
  * the edge (`@effect/platform-node`'s `NodeServices.layer`); a test
23102
- * provides `Layer.succeed(Git, …)` and needs no repository on disk.
25913
+ * provides `Git.layerTest({ })` git's own shipped double, whose
25914
+ * unstubbed members die named — and needs no repository on disk.
23103
25915
  */
23104
25916
  static layerWithGit = layerWithGit;
23105
25917
  /**
@@ -23148,9 +25960,14 @@ var Workspaces = class {
23148
25960
  * import { Workspaces } from "@effected/workspaces";
23149
25961
  * import { Layer } from "effect";
23150
25962
  *
25963
+ * // Bound to consts per the warning above: each factory call mints a
25964
+ * // fresh layer reference, and layers memoize by reference.
25965
+ * const LocalExecLayer = Workspaces.localExecLayer();
25966
+ * const WorkspacesLayer = Workspaces.layer();
25967
+ *
23151
25968
  * const AppLayer = ToolDiscovery.layer.pipe(
23152
- * Layer.provide(Workspaces.localExecLayer()),
23153
- * Layer.provide(Workspaces.layer()),
25969
+ * Layer.provide(LocalExecLayer),
25970
+ * Layer.provide(WorkspacesLayer),
23154
25971
  * Layer.provide(NodeServices.layer),
23155
25972
  * );
23156
25973
  * ```