@a2f0/agent-tool 0.1.39 → 0.1.40

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": "@a2f0/agent-tool",
3
- "version": "0.1.39",
3
+ "version": "0.1.40",
4
4
  "packageManager": "bun@1.4.4",
5
5
  "type": "module",
6
6
  "description": "Portable cross-agent review, PR workflows, and shared skills",
@@ -143,10 +143,32 @@ function runBun(bun: BunExecutable, directory: string, args: string[]) {
143
143
 
144
144
  function resolvedPlan(root: string, version: string, requested: Requested[], workspaceNames: Set<string>) {
145
145
  assert(Bun.semver.satisfies(version, ">=1.4.4"), `Resolved-only updates require the owning Bun 1.4.4 or newer (found ${version}); older Bun can add a direct declaration. Upgrade the project's pin through its normal approval workflow first.`);
146
+ const object = (value: unknown): value is Record<string, unknown> => value !== null && typeof value === "object" && !Array.isArray(value);
147
+ const strings = (value: unknown) => object(value) && Object.values(value).every(item => typeof item === "string");
148
+ const info = (value: unknown) => object(value) && SECTIONS.every(section => value[section] === undefined || strings(value[section]));
149
+ const overrides = (value: unknown): boolean => object(value) && Object.values(value).every(item => typeof item === "string" || overrides(item));
150
+ const tuple = (value: unknown): boolean => {
151
+ if (!Array.isArray(value) || typeof value[0] !== "string") return false;
152
+ const at = value[0].indexOf("@", value[0].startsWith("@") ? 1 : 0);
153
+ // Bun explicitly accepts @root: for an anonymous root referenced by file:.
154
+ if (at < 1 && !value[0].startsWith("@root:")) return false;
155
+ const resolution = value[0].slice(at + 1);
156
+ // v1/v2/v3 share package tuples. v2 tightens Bun's semantic checks; v3
157
+ // adds scoped override objects, not a new npm tuple layout.
158
+ if (EXACT.test(resolution)) return value.length === 4 && typeof value[1] === "string" && info(value[2]) && typeof value[3] === "string";
159
+ if (resolution.startsWith("workspace:")) return value.length === 1;
160
+ // Non-registry entries can coexist, but cannot be selected for refresh.
161
+ return (value.length === 2 || value.length === 3) && info(value[1]) && (value.length === 2 || typeof value[2] === "string");
162
+ };
146
163
  const readLock = () => {
147
- const lock = Bun.JSONC.parse(readFileSync(path.join(root, "bun.lock"), "utf8")) as Record<string, unknown> & { packages: Record<string, unknown[]> };
148
- assert(lock && (lock.lockfileVersion === 1 || lock.lockfileVersion === 2) && lock.packages && typeof lock.packages === "object" && !Array.isArray(lock.packages), "Resolved-only updates need a supported text bun.lock with packages.");
149
- return lock;
164
+ const lock = Bun.JSONC.parse(readFileSync(path.join(root, "bun.lock"), "utf8"));
165
+ assert(object(lock) && [1, 2, 3].includes(lock.lockfileVersion as number)
166
+ && object(lock.workspaces) && info(lock.workspaces[""]) && Object.values(lock.workspaces).every(info)
167
+ && object(lock.packages) && Object.values(lock.packages).every(tuple)
168
+ && (lock.overrides === undefined || overrides(lock.overrides)), "Resolved-only updates need a supported text bun.lock (versions 1, 2, or 3) with valid workspaces, packages, and overrides.");
169
+ // Bun's frozen preflight remains the authority for resolution, integrity,
170
+ // and configuration semantics after this fail-closed structural check.
171
+ return lock as Record<string, unknown> & { packages: Record<string, unknown[]> };
150
172
  };
151
173
  const keyName = (key: string) => { const parts = key.split("/"); return parts.at(-2)?.startsWith("@") ? parts.slice(-2).join("/") : parts.at(-1)!; };
152
174
  const registry = (tuple: unknown, name: string) => Array.isArray(tuple) && typeof tuple[0] === "string" && tuple[0].startsWith(`${name}@`) && EXACT.test(tuple[0].slice(name.length + 1));