@forwardimpact/libutil 0.1.91 → 0.1.93

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forwardimpact/libutil",
3
- "version": "0.1.91",
3
+ "version": "0.1.93",
4
4
  "description": "Cross-cutting utilities: retry, hashing, token counting, and project discovery.",
5
5
  "keywords": [
6
6
  "util",
package/src/calendar.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // Every `new Date(...)` here operates only on a value the caller passed (a ms
4
4
  // timestamp, a `Date`, or an ISO string) — never the ambient wall clock, which
5
5
  // lives behind `runtime.clock.now()`. That is why this module is allow-listed
6
- // in `scripts/check-ambient-deps.allow.yml` for the same reason `runtime.js`
6
+ // in `.coaligned/invariants/ambient-deps.allow.yml` for the same reason `runtime.js`
7
7
  // is: it produces deterministic time values from its arguments rather than
8
8
  // reaching for an ambient dependency. Consumers read "now" from
9
9
  // `runtime.clock.now()` and pass the result here when they need a formatted or
package/src/git-client.js CHANGED
@@ -56,14 +56,17 @@ export class GitClient {
56
56
  return this.#runRaw(args, { cwd });
57
57
  }
58
58
 
59
- /** Return `git status --porcelain` output. */
60
- async status({ cwd }) {
61
- return this.#runRaw(["status", "--porcelain"], { cwd });
59
+ /** Return `git status --porcelain` output, optionally limited to `paths`. */
60
+ async status({ cwd, paths } = {}) {
61
+ const args = ["status", "--porcelain"];
62
+ if (paths?.length) args.push("--", ...paths);
63
+ return this.#runRaw(args, { cwd });
62
64
  }
63
65
 
64
66
  /** Rebase the current branch onto `upstream`, optionally with a merge strategy. */
65
- async rebase(upstream, { cwd, strategy } = {}) {
67
+ async rebase(upstream, { cwd, strategy, autostash = false } = {}) {
66
68
  const args = ["rebase"];
69
+ if (autostash) args.push("--autostash");
67
70
  if (strategy) args.push("-X", strategy);
68
71
  args.push(upstream);
69
72
  return this.#runRaw(args, { cwd, allowFailure: true });
@@ -75,8 +78,11 @@ export class GitClient {
75
78
  }
76
79
 
77
80
  /** Merge `ref` into the current branch resolving conflicts with `-X ours`. */
78
- async mergeOursStrategy({ cwd, ref }) {
79
- return this.#runRaw(["merge", "-X", "ours", "--no-edit", ref], { cwd });
81
+ async mergeOursStrategy({ cwd, ref, autostash = false }) {
82
+ const args = ["merge"];
83
+ if (autostash) args.push("--autostash");
84
+ args.push("-X", "ours", "--no-edit", ref);
85
+ return this.#runRaw(args, { cwd });
80
86
  }
81
87
 
82
88
  /** Stage all changes and commit with `message`. */
@@ -87,6 +93,19 @@ export class GitClient {
87
93
  return this.#runRaw(args, { cwd });
88
94
  }
89
95
 
96
+ /**
97
+ * Stage and commit only `paths`, leaving the rest of the working tree
98
+ * untouched. The commit carries the same pathspec so content staged by
99
+ * other writers is never swept in.
100
+ */
101
+ async commitPaths(message, paths, { cwd, author } = {}) {
102
+ await this.#runRaw(["add", "--", ...paths], { cwd });
103
+ const args = ["commit", "-m", message];
104
+ if (author) args.push("--author", author);
105
+ args.push("--", ...paths);
106
+ return this.#runRaw(args, { cwd });
107
+ }
108
+
90
109
  /** Push `branch` to `remote`. */
91
110
  async push(remote = "origin", branch, { cwd, force = false } = {}) {
92
111
  const args = ["push", remote];
package/src/models.js CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Canonical Claude model identifiers, named by role. One home for every
3
3
  * model default in the monorepo — a model upgrade edits the values here
4
- * (plus any docs flagged by `scripts/check-model-defaults.mjs`) and
5
- * nothing else.
4
+ * (plus any docs flagged by `.coaligned/invariants/model-defaults.rules.mjs`)
5
+ * and nothing else.
6
6
  *
7
7
  * Markdown docs cannot import these constants, so the invariant script
8
8
  * cross-checks every model ID mentioned in docs and skills against the