harnessbrew 0.4.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.
Files changed (60) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/LICENSE +21 -0
  3. package/README.md +266 -0
  4. package/dist/bin.d.ts +3 -0
  5. package/dist/bin.d.ts.map +1 -0
  6. package/dist/bin.js +4 -0
  7. package/dist/bin.js.map +1 -0
  8. package/dist/cli.d.ts +9 -0
  9. package/dist/cli.d.ts.map +1 -0
  10. package/dist/cli.js +242 -0
  11. package/dist/cli.js.map +1 -0
  12. package/dist/core/bundle.d.ts +43 -0
  13. package/dist/core/bundle.d.ts.map +1 -0
  14. package/dist/core/bundle.js +195 -0
  15. package/dist/core/bundle.js.map +1 -0
  16. package/dist/core/errors.d.ts +4 -0
  17. package/dist/core/errors.d.ts.map +1 -0
  18. package/dist/core/errors.js +7 -0
  19. package/dist/core/errors.js.map +1 -0
  20. package/dist/core/formulas.d.ts +29 -0
  21. package/dist/core/formulas.d.ts.map +1 -0
  22. package/dist/core/formulas.js +185 -0
  23. package/dist/core/formulas.js.map +1 -0
  24. package/dist/core/git.d.ts +3 -0
  25. package/dist/core/git.d.ts.map +1 -0
  26. package/dist/core/git.js +36 -0
  27. package/dist/core/git.js.map +1 -0
  28. package/dist/core/installations.d.ts +38 -0
  29. package/dist/core/installations.d.ts.map +1 -0
  30. package/dist/core/installations.js +250 -0
  31. package/dist/core/installations.js.map +1 -0
  32. package/dist/core/paths.d.ts +8 -0
  33. package/dist/core/paths.d.ts.map +1 -0
  34. package/dist/core/paths.js +39 -0
  35. package/dist/core/paths.js.map +1 -0
  36. package/dist/core/state.d.ts +16 -0
  37. package/dist/core/state.d.ts.map +1 -0
  38. package/dist/core/state.js +43 -0
  39. package/dist/core/state.js.map +1 -0
  40. package/dist/core/taps.d.ts +16 -0
  41. package/dist/core/taps.d.ts.map +1 -0
  42. package/dist/core/taps.js +102 -0
  43. package/dist/core/taps.js.map +1 -0
  44. package/dist/core/targets.d.ts +11 -0
  45. package/dist/core/targets.d.ts.map +1 -0
  46. package/dist/core/targets.js +150 -0
  47. package/dist/core/targets.js.map +1 -0
  48. package/dist/core/upgrades.d.ts +14 -0
  49. package/dist/core/upgrades.d.ts.map +1 -0
  50. package/dist/core/upgrades.js +127 -0
  51. package/dist/core/upgrades.js.map +1 -0
  52. package/dist/index.d.ts +15 -0
  53. package/dist/index.d.ts.map +1 -0
  54. package/dist/index.js +9 -0
  55. package/dist/index.js.map +1 -0
  56. package/dist/version.d.ts +2 -0
  57. package/dist/version.d.ts.map +1 -0
  58. package/dist/version.js +2 -0
  59. package/dist/version.js.map +1 -0
  60. package/package.json +63 -0
@@ -0,0 +1,43 @@
1
+ import { type BuiltinTarget } from "./targets.js";
2
+ export interface HarnessTapDeclaration {
3
+ name: string;
4
+ git: string;
5
+ ref?: string;
6
+ }
7
+ export interface HarnessAssetDeclaration {
8
+ formula: string;
9
+ targets: BuiltinTarget[];
10
+ }
11
+ export interface Harnessfile {
12
+ schemaVersion: 1;
13
+ taps: HarnessTapDeclaration[];
14
+ assets: HarnessAssetDeclaration[];
15
+ }
16
+ export interface HarnessLock {
17
+ schemaVersion: 1;
18
+ taps: Array<{
19
+ name: string;
20
+ git: string;
21
+ commit: string;
22
+ ref?: string;
23
+ }>;
24
+ assets: Array<{
25
+ formula: string;
26
+ commit: string;
27
+ dependencies: string[];
28
+ targets: string[];
29
+ }>;
30
+ }
31
+ export interface BundleOptions {
32
+ targetRoots?: Partial<Record<BuiltinTarget, string>>;
33
+ }
34
+ export interface BundleCleanupResult {
35
+ removed: string[];
36
+ retained: string[];
37
+ }
38
+ export declare function readHarnessfile(filePath: string): Promise<Harnessfile>;
39
+ export declare function lockfilePath(harnessfilePath: string): string;
40
+ export declare function bundleInstall(home: string, harnessfilePath: string, options?: BundleOptions): Promise<HarnessLock>;
41
+ export declare function bundleCleanup(home: string, harnessfilePath: string): Promise<BundleCleanupResult>;
42
+ export declare function removeLock(harnessfilePath: string): Promise<void>;
43
+ //# sourceMappingURL=bundle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundle.d.ts","sourceRoot":"","sources":["../../src/core/bundle.ts"],"names":[],"mappings":"AAOA,OAAO,EAAiD,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAGjG,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,aAAa,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,WAAW;IAC1B,aAAa,EAAE,CAAC,CAAC;IACjB,IAAI,EAAE,qBAAqB,EAAE,CAAC;IAC9B,MAAM,EAAE,uBAAuB,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,WAAW;IAC1B,aAAa,EAAE,CAAC,CAAC;IACjB,IAAI,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACzE,MAAM,EAAE,KAAK,CAAC;QACZ,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,YAAY,EAAE,MAAM,EAAE,CAAC;QACvB,OAAO,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAMD,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAuC5E;AAED,wBAAgB,YAAY,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,CAE5D;AAiDD,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,eAAe,EAAE,MAAM,EACvB,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,WAAW,CAAC,CAiDtB;AA4BD,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAWvG;AAED,wBAAsB,UAAU,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEvE"}
@@ -0,0 +1,195 @@
1
+ import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { parse } from "yaml";
4
+ import { HarnessBrewError } from "./errors.js";
5
+ import { getFormula } from "./formulas.js";
6
+ import { installFormula, listInstalled, resolveDependencies, uninstallFormula } from "./installations.js";
7
+ import { addTap, checkoutTap, listTaps, updateTaps } from "./taps.js";
8
+ import { builtinTargets, installForTarget, linkFormula } from "./targets.js";
9
+ import { upgradeFormulas } from "./upgrades.js";
10
+ function isRecord(value) {
11
+ return typeof value === "object" && value !== null && !Array.isArray(value);
12
+ }
13
+ export async function readHarnessfile(filePath) {
14
+ let raw;
15
+ try {
16
+ raw = parse(await readFile(filePath, "utf8"), { maxAliasCount: 20 });
17
+ }
18
+ catch (error) {
19
+ throw new HarnessBrewError(`Invalid Harnessfile ${filePath}: ${error.message}`);
20
+ }
21
+ if (!isRecord(raw) || (raw.schemaVersion ?? 1) !== 1) {
22
+ throw new HarnessBrewError(`Unsupported Harnessfile schema: ${filePath}`);
23
+ }
24
+ if (!Array.isArray(raw.taps) || !Array.isArray(raw.assets)) {
25
+ throw new HarnessBrewError(`Harnessfile must contain taps and assets arrays: ${filePath}`);
26
+ }
27
+ const taps = raw.taps.map((item) => {
28
+ if (!isRecord(item) || typeof item.name !== "string" || typeof item.git !== "string") {
29
+ throw new HarnessBrewError(`Invalid tap declaration in ${filePath}`);
30
+ }
31
+ if (item.ref !== undefined && typeof item.ref !== "string") {
32
+ throw new HarnessBrewError(`Invalid tap ref in ${filePath}`);
33
+ }
34
+ return { name: item.name, git: item.git, ...(item.ref === undefined ? {} : { ref: item.ref }) };
35
+ });
36
+ const assets = raw.assets.map((item) => {
37
+ if (!isRecord(item) || typeof item.formula !== "string") {
38
+ throw new HarnessBrewError(`Invalid asset declaration in ${filePath}`);
39
+ }
40
+ const targets = item.targets ?? [];
41
+ if (!Array.isArray(targets) || targets.some((target) => !builtinTargets.includes(target))) {
42
+ throw new HarnessBrewError(`Invalid asset targets for ${item.formula}`);
43
+ }
44
+ return { formula: item.formula, targets: [...new Set(targets)] };
45
+ });
46
+ if (new Set(taps.map((tap) => tap.name)).size !== taps.length) {
47
+ throw new HarnessBrewError("Harnessfile contains duplicate taps.");
48
+ }
49
+ if (new Set(assets.map((asset) => asset.formula)).size !== assets.length) {
50
+ throw new HarnessBrewError("Harnessfile contains duplicate assets.");
51
+ }
52
+ return { schemaVersion: 1, taps, assets };
53
+ }
54
+ export function lockfilePath(harnessfilePath) {
55
+ return `${harnessfilePath}.lock`;
56
+ }
57
+ async function readLock(filePath) {
58
+ try {
59
+ const parsed = JSON.parse(await readFile(filePath, "utf8"));
60
+ if (parsed.schemaVersion !== 1 || !Array.isArray(parsed.taps) || !Array.isArray(parsed.assets))
61
+ throw new Error("shape");
62
+ return parsed;
63
+ }
64
+ catch (error) {
65
+ if (error.code === "ENOENT")
66
+ return undefined;
67
+ throw new HarnessBrewError(`Invalid Harnessfile lock: ${filePath}`);
68
+ }
69
+ }
70
+ async function writeLock(filePath, lock) {
71
+ await mkdir(path.dirname(filePath), { recursive: true });
72
+ const temporaryPath = `${filePath}.${process.pid}.tmp`;
73
+ await writeFile(temporaryPath, `${JSON.stringify(lock, null, 2)}\n`, "utf8");
74
+ await rename(temporaryPath, filePath);
75
+ }
76
+ async function syncTaps(home, manifest, lock) {
77
+ const registered = new Map((await listTaps(home)).map((tap) => [tap.name, tap]));
78
+ for (const declaration of manifest.taps) {
79
+ const existing = registered.get(declaration.name);
80
+ if (existing !== undefined && existing.url !== declaration.git) {
81
+ throw new HarnessBrewError(`Tap URL mismatch for ${declaration.name}: ${existing.url} != ${declaration.git}`);
82
+ }
83
+ const locked = lock?.taps.find((tap) => tap.name === declaration.name);
84
+ if (locked !== undefined && locked.git !== declaration.git) {
85
+ throw new HarnessBrewError(`Lockfile Tap URL mismatch for ${declaration.name}`);
86
+ }
87
+ if (existing === undefined) {
88
+ const ref = locked?.commit ?? declaration.ref;
89
+ await addTap(home, declaration.name, declaration.git, ref === undefined ? {} : { ref });
90
+ }
91
+ else if (locked === undefined) {
92
+ if (existing.ref !== declaration.ref) {
93
+ throw new HarnessBrewError(`Tap ref mismatch for ${declaration.name}; remove and re-add the tap.`);
94
+ }
95
+ await updateTaps(home, declaration.name);
96
+ }
97
+ if (locked !== undefined)
98
+ await checkoutTap(home, declaration.name, locked.commit);
99
+ }
100
+ }
101
+ function rootOptions(target, options) {
102
+ const root = options.targetRoots?.[target];
103
+ return root === undefined ? {} : { root };
104
+ }
105
+ export async function bundleInstall(home, harnessfilePath, options = {}) {
106
+ const manifest = await readHarnessfile(harnessfilePath);
107
+ const targetLockPath = lockfilePath(harnessfilePath);
108
+ const existingLock = await readLock(targetLockPath);
109
+ await syncTaps(home, manifest, existingLock);
110
+ const resolved = new Map();
111
+ for (const asset of manifest.assets) {
112
+ await upgradeFormulas(home, asset.formula);
113
+ const receipts = asset.targets.length === 0
114
+ ? await installFormula(home, asset.formula)
115
+ : await installForTarget(home, asset.formula, asset.targets[0], rootOptions(asset.targets[0], options));
116
+ for (const target of asset.targets.slice(1)) {
117
+ for (const receipt of receipts)
118
+ await linkFormula(home, receipt.coordinate, target, rootOptions(target, options));
119
+ }
120
+ receipts.forEach((receipt) => resolved.set(receipt.coordinate, receipt));
121
+ }
122
+ if (existingLock !== undefined) {
123
+ for (const asset of existingLock.assets) {
124
+ const receipt = resolved.get(asset.formula);
125
+ if (receipt !== undefined && receipt.commit !== asset.commit) {
126
+ throw new HarnessBrewError(`Locked commit mismatch for ${asset.formula}`);
127
+ }
128
+ }
129
+ }
130
+ const taps = await listTaps(home);
131
+ const lock = {
132
+ schemaVersion: 1,
133
+ taps: manifest.taps.map((declaration) => {
134
+ const tap = taps.find((candidate) => candidate.name === declaration.name);
135
+ if (tap === undefined)
136
+ throw new HarnessBrewError(`Tap was not synchronized: ${declaration.name}`);
137
+ return {
138
+ name: tap.name,
139
+ git: tap.url,
140
+ commit: tap.commit,
141
+ ...(declaration.ref === undefined ? {} : { ref: declaration.ref })
142
+ };
143
+ }),
144
+ assets: [...resolved.values()].sort((left, right) => left.coordinate.localeCompare(right.coordinate)).map((receipt) => ({
145
+ formula: receipt.coordinate,
146
+ commit: receipt.commit,
147
+ dependencies: receipt.dependencies,
148
+ targets: receipt.targets
149
+ }))
150
+ };
151
+ await writeLock(targetLockPath, lock);
152
+ return lock;
153
+ }
154
+ async function desiredCoordinates(home, manifest) {
155
+ const desired = new Set();
156
+ for (const asset of manifest.assets) {
157
+ const root = await getFormula(home, asset.formula);
158
+ (await resolveDependencies(home, root)).forEach((formula) => desired.add(formula.coordinate));
159
+ }
160
+ return desired;
161
+ }
162
+ function removalOrder(receipts) {
163
+ const byCoordinate = new Map(receipts.map((receipt) => [receipt.coordinate, receipt]));
164
+ const ordered = [];
165
+ const visited = new Set();
166
+ function visit(receipt) {
167
+ if (visited.has(receipt.coordinate))
168
+ return;
169
+ visited.add(receipt.coordinate);
170
+ ordered.push(receipt);
171
+ receipt.dependencies.forEach((dependency) => {
172
+ const item = byCoordinate.get(dependency);
173
+ if (item !== undefined)
174
+ visit(item);
175
+ });
176
+ }
177
+ receipts.forEach(visit);
178
+ return ordered;
179
+ }
180
+ export async function bundleCleanup(home, harnessfilePath) {
181
+ const manifest = await readHarnessfile(harnessfilePath);
182
+ const desired = await desiredCoordinates(home, manifest);
183
+ const installed = await listInstalled(home);
184
+ const candidates = installed.filter((receipt) => !desired.has(receipt.coordinate));
185
+ const removed = [];
186
+ for (const receipt of removalOrder(candidates)) {
187
+ await uninstallFormula(home, receipt.coordinate);
188
+ removed.push(receipt.coordinate);
189
+ }
190
+ return { removed, retained: installed.filter((receipt) => desired.has(receipt.coordinate)).map((receipt) => receipt.coordinate) };
191
+ }
192
+ export async function removeLock(harnessfilePath) {
193
+ await rm(lockfilePath(harnessfilePath), { force: true });
194
+ }
195
+ //# sourceMappingURL=bundle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundle.js","sourceRoot":"","sources":["../../src/core/bundle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,mBAAmB,EAAE,gBAAgB,EAAuB,MAAM,oBAAoB,CAAC;AAC/H,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACtE,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,WAAW,EAAsB,MAAM,cAAc,CAAC;AACjG,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAuChD,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,QAAgB;IACpD,IAAI,GAAY,CAAC;IACjB,IAAI,CAAC;QACH,GAAG,GAAG,KAAK,CAAC,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC,CAAC;IACvE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,gBAAgB,CAAC,uBAAuB,QAAQ,KAAM,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;IAC7F,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;QACrD,MAAM,IAAI,gBAAgB,CAAC,mCAAmC,QAAQ,EAAE,CAAC,CAAC;IAC5E,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3D,MAAM,IAAI,gBAAgB,CAAC,oDAAoD,QAAQ,EAAE,CAAC,CAAC;IAC7F,CAAC;IACD,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAyB,EAAE;QACxD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,IAAI,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;YACrF,MAAM,IAAI,gBAAgB,CAAC,8BAA8B,QAAQ,EAAE,CAAC,CAAC;QACvE,CAAC;QACD,IAAI,IAAI,CAAC,GAAG,KAAK,SAAS,IAAI,OAAO,IAAI,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;YAC3D,MAAM,IAAI,gBAAgB,CAAC,sBAAsB,QAAQ,EAAE,CAAC,CAAC;QAC/D,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC;IAClG,CAAC,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAA2B,EAAE;QAC9D,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;YACxD,MAAM,IAAI,gBAAgB,CAAC,gCAAgC,QAAQ,EAAE,CAAC,CAAC;QACzE,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;QACnC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,cAAc,CAAC,QAAQ,CAAC,MAAuB,CAAC,CAAC,EAAE,CAAC;YAC3G,MAAM,IAAI,gBAAgB,CAAC,6BAA6B,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QAC1E,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,OAA0B,CAAC,CAAC,EAAE,CAAC;IACtF,CAAC,CAAC,CAAC;IACH,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;QAC9D,MAAM,IAAI,gBAAgB,CAAC,sCAAsC,CAAC,CAAC;IACrE,CAAC;IACD,IAAI,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC;QACzE,MAAM,IAAI,gBAAgB,CAAC,wCAAwC,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,EAAE,aAAa,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,eAAuB;IAClD,OAAO,GAAG,eAAe,OAAO,CAAC;AACnC,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,QAAgB;IACtC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAgB,CAAC;QAC3E,IAAI,MAAM,CAAC,aAAa,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;QACzH,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,SAAS,CAAC;QACzE,MAAM,IAAI,gBAAgB,CAAC,6BAA6B,QAAQ,EAAE,CAAC,CAAC;IACtE,CAAC;AACH,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,QAAgB,EAAE,IAAiB;IAC1D,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzD,MAAM,aAAa,GAAG,GAAG,QAAQ,IAAI,OAAO,CAAC,GAAG,MAAM,CAAC;IACvD,MAAM,SAAS,CAAC,aAAa,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC7E,MAAM,MAAM,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;AACxC,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,IAAY,EAAE,QAAqB,EAAE,IAA6B;IACxF,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;IACjF,KAAK,MAAM,WAAW,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;QACxC,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAClD,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,GAAG,KAAK,WAAW,CAAC,GAAG,EAAE,CAAC;YAC/D,MAAM,IAAI,gBAAgB,CAAC,wBAAwB,WAAW,CAAC,IAAI,KAAK,QAAQ,CAAC,GAAG,OAAO,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC;QAChH,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,WAAW,CAAC,IAAI,CAAC,CAAC;QACvE,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,GAAG,KAAK,WAAW,CAAC,GAAG,EAAE,CAAC;YAC3D,MAAM,IAAI,gBAAgB,CAAC,iCAAiC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;QAClF,CAAC;QACD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,MAAM,GAAG,GAAG,MAAM,EAAE,MAAM,IAAI,WAAW,CAAC,GAAG,CAAC;YAC9C,MAAM,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAC1F,CAAC;aAAM,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YAChC,IAAI,QAAQ,CAAC,GAAG,KAAK,WAAW,CAAC,GAAG,EAAE,CAAC;gBACrC,MAAM,IAAI,gBAAgB,CAAC,wBAAwB,WAAW,CAAC,IAAI,8BAA8B,CAAC,CAAC;YACrG,CAAC;YACD,MAAM,UAAU,CAAC,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;QAC3C,CAAC;QACD,IAAI,MAAM,KAAK,SAAS;YAAE,MAAM,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACrF,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,MAAqB,EAAE,OAAsB;IAChE,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,MAAM,CAAC,CAAC;IAC3C,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;AAC5C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,IAAY,EACZ,eAAuB,EACvB,OAAO,GAAkB,EAAE;IAE3B,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,eAAe,CAAC,CAAC;IACxD,MAAM,cAAc,GAAG,YAAY,CAAC,eAAe,CAAC,CAAC;IACrD,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,cAAc,CAAC,CAAC;IACpD,MAAM,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC;IAE7C,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA0B,CAAC;IACnD,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;QACpC,MAAM,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QAC3C,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC;YACzC,CAAC,CAAC,MAAM,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC;YAC3C,CAAC,CAAC,MAAM,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAkB,EAAE,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAkB,EAAE,OAAO,CAAC,CAAC,CAAC;QAC5I,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5C,KAAK,MAAM,OAAO,IAAI,QAAQ;gBAAE,MAAM,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;QACpH,CAAC;QACD,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;IAC3E,CAAC;IAED,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QAC/B,KAAK,MAAM,KAAK,IAAI,YAAY,CAAC,MAAM,EAAE,CAAC;YACxC,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC5C,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,EAAE,CAAC;gBAC7D,MAAM,IAAI,gBAAgB,CAAC,8BAA8B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YAC5E,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,IAAI,GAAgB;QACxB,aAAa,EAAE,CAAC;QAChB,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE;YACtC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,WAAW,CAAC,IAAI,CAAC,CAAC;YAC1E,IAAI,GAAG,KAAK,SAAS;gBAAE,MAAM,IAAI,gBAAgB,CAAC,6BAA6B,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;YACnG,OAAO;gBACL,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,GAAG,EAAE,GAAG,CAAC,GAAG;gBACZ,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,GAAG,CAAC,WAAW,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,WAAW,CAAC,GAAG,EAAE,CAAC;aACnE,CAAC;QACJ,CAAC,CAAC;QACF,MAAM,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACtH,OAAO,EAAE,OAAO,CAAC,UAAU;YAC3B,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,OAAO,EAAE,OAAO,CAAC,OAAO;SACzB,CAAC,CAAC;KACJ,CAAC;IACF,MAAM,SAAS,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;IACtC,OAAO,IAAI,CAAC;AACd,CAAC;AAED,KAAK,UAAU,kBAAkB,CAAC,IAAY,EAAE,QAAqB;IACnE,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;QACpC,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QACnD,CAAC,MAAM,mBAAmB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;IAChG,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,YAAY,CAAC,QAA0B;IAC9C,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACvF,MAAM,OAAO,GAAqB,EAAE,CAAC;IACrC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,SAAS,KAAK,CAAC,OAAuB;QACpC,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC;YAAE,OAAO;QAC5C,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAChC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACtB,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,EAAE;YAC1C,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YAC1C,IAAI,IAAI,KAAK,SAAS;gBAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;IACL,CAAC;IACD,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACxB,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAY,EAAE,eAAuB;IACvE,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,eAAe,CAAC,CAAC;IACxD,MAAM,OAAO,GAAG,MAAM,kBAAkB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACzD,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,UAAU,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;IACnF,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,OAAO,IAAI,YAAY,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/C,MAAM,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;AACpI,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,eAAuB;IACtD,MAAM,EAAE,CAAC,YAAY,CAAC,eAAe,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare class HarnessBrewError extends Error {
2
+ constructor(message: string);
3
+ }
4
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF"}
@@ -0,0 +1,7 @@
1
+ export class HarnessBrewError extends Error {
2
+ constructor(message) {
3
+ super(message);
4
+ this.name = "HarnessBrewError";
5
+ }
6
+ }
7
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IACzC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF"}
@@ -0,0 +1,29 @@
1
+ export declare const formulaKinds: readonly ["skill", "agent", "workflow", "instruction", "prompt", "mcp", "adapter"];
2
+ export type FormulaKind = (typeof formulaKinds)[number];
3
+ export interface Formula {
4
+ schemaVersion: 1;
5
+ name: string;
6
+ kind: FormulaKind;
7
+ description: string;
8
+ entry: string;
9
+ targets: string[];
10
+ dependencies: string[];
11
+ tags: string[];
12
+ conflicts: string[];
13
+ deprecated?: string;
14
+ }
15
+ export interface CatalogFormula extends Formula {
16
+ tap: string;
17
+ coordinate: string;
18
+ directory: string;
19
+ commit: string;
20
+ }
21
+ export interface FormulaSearchOptions {
22
+ kind?: FormulaKind;
23
+ target?: string;
24
+ }
25
+ export declare function validateTapRepository(repositoryPath: string): Promise<void>;
26
+ export declare function loadCatalog(home: string): Promise<CatalogFormula[]>;
27
+ export declare function searchFormulas(home: string, query?: string, options?: FormulaSearchOptions): Promise<CatalogFormula[]>;
28
+ export declare function getFormula(home: string, nameOrCoordinate: string): Promise<CatalogFormula>;
29
+ //# sourceMappingURL=formulas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formulas.d.ts","sourceRoot":"","sources":["../../src/core/formulas.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,YAAY,YAAI,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,CAAU,CAAC;AAC/G,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAexD,MAAM,WAAW,OAAO;IACtB,aAAa,EAAE,CAAC,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,WAAW,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAe,SAAQ,OAAO;IAC7C,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AA8BD,wBAAsB,qBAAqB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOjF;AAuGD,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAOzE;AAED,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,KAAK,SAAK,EACV,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,cAAc,EAAE,CAAC,CAS3B;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAUhG"}
@@ -0,0 +1,185 @@
1
+ import { readFile, readdir, stat } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { HarnessBrewError } from "./errors.js";
4
+ import { resolveTapPath } from "./paths.js";
5
+ import { readState } from "./state.js";
6
+ export const formulaKinds = ["skill", "agent", "workflow", "instruction", "prompt", "mcp", "adapter"];
7
+ const kindDirectories = {
8
+ skill: "skills",
9
+ agent: "agents",
10
+ workflow: "workflows",
11
+ instruction: "instructions",
12
+ prompt: "prompts",
13
+ mcp: "mcp",
14
+ adapter: "adapters"
15
+ };
16
+ const formulaNamePattern = /^[a-z0-9][a-z0-9-]*$/;
17
+ const coordinatePattern = /^[a-z0-9][a-z0-9-]*\/[a-z0-9][a-z0-9-]*\/[a-z0-9][a-z0-9-]*$/;
18
+ function isStringArray(value) {
19
+ return Array.isArray(value) && value.every((item) => typeof item === "string" && item.trim() !== "");
20
+ }
21
+ function requireString(value, field, formulaPath) {
22
+ if (typeof value !== "string" || value.trim() === "") {
23
+ throw new HarnessBrewError(`Invalid formula ${field}: ${formulaPath}`);
24
+ }
25
+ return value;
26
+ }
27
+ async function readJson(filePath) {
28
+ let content;
29
+ try {
30
+ content = await readFile(filePath, "utf8");
31
+ }
32
+ catch (error) {
33
+ if (error.code === "ENOENT") {
34
+ throw new HarnessBrewError(`Required file not found: ${filePath}`);
35
+ }
36
+ throw error;
37
+ }
38
+ try {
39
+ return JSON.parse(content);
40
+ }
41
+ catch {
42
+ throw new HarnessBrewError(`Invalid JSON: ${filePath}`);
43
+ }
44
+ }
45
+ export async function validateTapRepository(repositoryPath) {
46
+ const manifestPath = path.join(repositoryPath, "tap.json");
47
+ const manifest = await readJson(manifestPath);
48
+ if (typeof manifest !== "object" || manifest === null || manifest.schemaVersion !== 1) {
49
+ throw new HarnessBrewError(`Unsupported tap manifest: ${manifestPath}`);
50
+ }
51
+ await scanTap(repositoryPath, { name: "validation/tap", commit: "validation" });
52
+ }
53
+ function validateFormula(raw, formulaPath, expectedName, expectedKind) {
54
+ if (typeof raw !== "object" || raw === null) {
55
+ throw new HarnessBrewError(`Invalid formula object: ${formulaPath}`);
56
+ }
57
+ const value = raw;
58
+ if (value.schemaVersion !== 1) {
59
+ throw new HarnessBrewError(`Unsupported formula schema: ${formulaPath}`);
60
+ }
61
+ const name = requireString(value.name, "name", formulaPath);
62
+ if (!formulaNamePattern.test(name) || name !== expectedName) {
63
+ throw new HarnessBrewError(`Formula name must match its directory (${expectedName}): ${formulaPath}`);
64
+ }
65
+ const kind = requireString(value.kind, "kind", formulaPath);
66
+ if (kind !== expectedKind) {
67
+ throw new HarnessBrewError(`Formula kind must match ${expectedKind}: ${formulaPath}`);
68
+ }
69
+ const description = requireString(value.description, "description", formulaPath);
70
+ const entry = requireString(value.entry, "entry", formulaPath);
71
+ if (path.isAbsolute(entry) || entry.split(/[\\/]/u).includes("..")) {
72
+ throw new HarnessBrewError(`Formula entry must stay inside its directory: ${formulaPath}`);
73
+ }
74
+ if (!isStringArray(value.targets) || value.targets.length === 0) {
75
+ throw new HarnessBrewError(`Formula targets must be a non-empty string array: ${formulaPath}`);
76
+ }
77
+ const dependencies = value.dependencies === undefined ? [] : value.dependencies;
78
+ if (!isStringArray(dependencies) || dependencies.some((item) => !coordinatePattern.test(item))) {
79
+ throw new HarnessBrewError(`Formula dependencies must use <owner>/<tap>/<formula>: ${formulaPath}`);
80
+ }
81
+ const tags = value.tags === undefined ? [] : value.tags;
82
+ if (!isStringArray(tags)) {
83
+ throw new HarnessBrewError(`Formula tags must be a string array: ${formulaPath}`);
84
+ }
85
+ const conflicts = value.conflicts === undefined ? [] : value.conflicts;
86
+ if (!isStringArray(conflicts) || conflicts.some((item) => !coordinatePattern.test(item))) {
87
+ throw new HarnessBrewError(`Formula conflicts must use <owner>/<tap>/<formula>: ${formulaPath}`);
88
+ }
89
+ const deprecated = value.deprecated;
90
+ if (deprecated !== undefined && (typeof deprecated !== "string" || deprecated.trim() === "")) {
91
+ throw new HarnessBrewError(`Formula deprecated must be a non-empty string: ${formulaPath}`);
92
+ }
93
+ return {
94
+ schemaVersion: 1,
95
+ name,
96
+ kind: expectedKind,
97
+ description,
98
+ entry,
99
+ targets: [...new Set(value.targets)],
100
+ dependencies: [...new Set(dependencies)],
101
+ tags: [...new Set(tags)],
102
+ conflicts: [...new Set(conflicts)],
103
+ ...(deprecated === undefined ? {} : { deprecated })
104
+ };
105
+ }
106
+ async function directoryNames(directory) {
107
+ try {
108
+ const entries = await readdir(directory, { withFileTypes: true });
109
+ return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
110
+ }
111
+ catch (error) {
112
+ if (error.code === "ENOENT")
113
+ return [];
114
+ throw error;
115
+ }
116
+ }
117
+ async function scanTap(repositoryPath, tap) {
118
+ const formulas = [];
119
+ const names = new Set();
120
+ for (const kind of formulaKinds) {
121
+ const kindDirectory = path.join(repositoryPath, kindDirectories[kind]);
122
+ for (const name of await directoryNames(kindDirectory)) {
123
+ const formulaDirectory = path.join(kindDirectory, name);
124
+ const formulaPath = path.join(formulaDirectory, "formula.json");
125
+ const formula = validateFormula(await readJson(formulaPath), formulaPath, name, kind);
126
+ if (names.has(name)) {
127
+ throw new HarnessBrewError(`Duplicate formula name in ${tap.name}: ${name}`);
128
+ }
129
+ names.add(name);
130
+ const entryPath = path.resolve(formulaDirectory, formula.entry);
131
+ if (!entryPath.startsWith(`${path.resolve(formulaDirectory)}${path.sep}`)) {
132
+ throw new HarnessBrewError(`Formula entry escapes its directory: ${formulaPath}`);
133
+ }
134
+ try {
135
+ if (!(await stat(entryPath)).isFile())
136
+ throw new Error("not a file");
137
+ }
138
+ catch {
139
+ throw new HarnessBrewError(`Formula entry not found: ${entryPath}`);
140
+ }
141
+ formulas.push({
142
+ ...formula,
143
+ tap: tap.name,
144
+ coordinate: `${tap.name}/${formula.name}`,
145
+ directory: formulaDirectory,
146
+ commit: tap.commit
147
+ });
148
+ }
149
+ }
150
+ return formulas;
151
+ }
152
+ export async function loadCatalog(home) {
153
+ const state = await readState(home);
154
+ const formulas = [];
155
+ for (const tap of Object.values(state.taps).sort((left, right) => left.name.localeCompare(right.name))) {
156
+ formulas.push(...await scanTap(resolveTapPath(home, tap.name), tap));
157
+ }
158
+ return formulas.sort((left, right) => left.coordinate.localeCompare(right.coordinate));
159
+ }
160
+ export async function searchFormulas(home, query = "", options = {}) {
161
+ const normalized = query.toLocaleLowerCase();
162
+ return (await loadCatalog(home)).filter((formula) => {
163
+ if (options.kind !== undefined && formula.kind !== options.kind)
164
+ return false;
165
+ if (options.target !== undefined && !formula.targets.includes(options.target))
166
+ return false;
167
+ if (normalized === "")
168
+ return true;
169
+ return [formula.coordinate, formula.description, formula.kind, ...formula.tags]
170
+ .some((value) => value.toLocaleLowerCase().includes(normalized));
171
+ });
172
+ }
173
+ export async function getFormula(home, nameOrCoordinate) {
174
+ const catalog = await loadCatalog(home);
175
+ const matches = nameOrCoordinate.split("/").length === 3
176
+ ? catalog.filter((formula) => formula.coordinate === nameOrCoordinate)
177
+ : catalog.filter((formula) => formula.name === nameOrCoordinate);
178
+ if (matches.length === 0)
179
+ throw new HarnessBrewError(`Formula not found: ${nameOrCoordinate}`);
180
+ if (matches.length > 1) {
181
+ throw new HarnessBrewError(`Formula name is ambiguous: ${nameOrCoordinate}. Use a full tap coordinate.`);
182
+ }
183
+ return matches[0];
184
+ }
185
+ //# sourceMappingURL=formulas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formulas.js","sourceRoot":"","sources":["../../src/core/formulas.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function runGit(args: readonly string[], cwd?: string): Promise<string>;
2
+ export declare function resolveGitCommit(repositoryPath: string, ref?: string): Promise<string>;
3
+ //# sourceMappingURL=git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/core/git.ts"],"names":[],"mappings":"AAMA,wBAAsB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAanF;AAED,wBAAsB,gBAAgB,CAAC,cAAc,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAgB5F"}
@@ -0,0 +1,36 @@
1
+ import { execFile } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ import { HarnessBrewError } from "./errors.js";
4
+ const execFileAsync = promisify(execFile);
5
+ export async function runGit(args, cwd) {
6
+ try {
7
+ const result = await execFileAsync("git", [...args], {
8
+ cwd,
9
+ encoding: "utf8",
10
+ maxBuffer: 10 * 1024 * 1024
11
+ });
12
+ return result.stdout.trim();
13
+ }
14
+ catch (error) {
15
+ const failure = error;
16
+ const detail = failure.stderr?.trim() || failure.message;
17
+ throw new HarnessBrewError(`Git command failed: ${detail}`);
18
+ }
19
+ }
20
+ export async function resolveGitCommit(repositoryPath, ref) {
21
+ if (ref === undefined) {
22
+ const symbolic = await runGit(["symbolic-ref", "refs/remotes/origin/HEAD"], repositoryPath);
23
+ return runGit(["rev-parse", "--verify", `${symbolic}^{commit}`], repositoryPath);
24
+ }
25
+ const candidates = [`refs/remotes/origin/${ref}`, `refs/tags/${ref}`, ref];
26
+ for (const candidate of candidates) {
27
+ try {
28
+ return await runGit(["rev-parse", "--verify", `${candidate}^{commit}`], repositoryPath);
29
+ }
30
+ catch {
31
+ // Try the next unambiguous Git ref form.
32
+ }
33
+ }
34
+ throw new HarnessBrewError(`Git ref not found: ${ref}`);
35
+ }
36
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/core/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAuB,EAAE,GAAY;IAChE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE;YACnD,GAAG;YACH,QAAQ,EAAE,MAAM;YAChB,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI;SAC5B,CAAC,CAAC;QACH,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IAC9B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAoC,CAAC;QACrD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC,OAAO,CAAC;QACzD,MAAM,IAAI,gBAAgB,CAAC,uBAAuB,MAAM,EAAE,CAAC,CAAC;IAC9D,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,cAAsB,EAAE,GAAY;IACzE,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,CAAC,cAAc,EAAE,0BAA0B,CAAC,EAAE,cAAc,CAAC,CAAC;QAC5F,OAAO,MAAM,CAAC,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,QAAQ,WAAW,CAAC,EAAE,cAAc,CAAC,CAAC;IACnF,CAAC;IAED,MAAM,UAAU,GAAG,CAAC,uBAAuB,GAAG,EAAE,EAAE,aAAa,GAAG,EAAE,EAAE,GAAG,CAAC,CAAC;IAC3E,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,CAAC;YACH,OAAO,MAAM,MAAM,CAAC,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,SAAS,WAAW,CAAC,EAAE,cAAc,CAAC,CAAC;QAC1F,CAAC;QAAC,MAAM,CAAC;YACP,yCAAyC;QAC3C,CAAC;IACH,CAAC;IAED,MAAM,IAAI,gBAAgB,CAAC,sBAAsB,GAAG,EAAE,CAAC,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { type CatalogFormula } from "./formulas.js";
2
+ export interface InstalledFile {
3
+ path: string;
4
+ sha256: string;
5
+ }
6
+ export interface InstalledLink extends InstalledFile {
7
+ source: string;
8
+ target: string;
9
+ }
10
+ export interface InstallReceipt {
11
+ schemaVersion: 1;
12
+ coordinate: string;
13
+ kind: string;
14
+ tap: string;
15
+ commit: string;
16
+ cellarPath: string;
17
+ entry: string;
18
+ dependencies: string[];
19
+ conflicts: string[];
20
+ requested: boolean;
21
+ files: InstalledFile[];
22
+ supportedTargets: string[];
23
+ targets: string[];
24
+ links: InstalledLink[];
25
+ installedAt: string;
26
+ }
27
+ export interface UninstallOptions {
28
+ force?: boolean;
29
+ }
30
+ export declare function readReceipt(home: string, coordinate: string): Promise<InstallReceipt | undefined>;
31
+ export declare function writeReceipt(home: string, receipt: InstallReceipt): Promise<void>;
32
+ export declare function listInstalled(home: string): Promise<InstallReceipt[]>;
33
+ export declare function resolveDependencies(home: string, root: CatalogFormula): Promise<CatalogFormula[]>;
34
+ export declare function installCatalogFormula(home: string, formula: CatalogFormula, requested: boolean): Promise<InstallReceipt>;
35
+ export declare function installFormula(home: string, nameOrCoordinate: string): Promise<InstallReceipt[]>;
36
+ export declare function verifyReceiptIntegrity(receipt: InstallReceipt): Promise<void>;
37
+ export declare function uninstallFormula(home: string, nameOrCoordinate: string, options?: UninstallOptions): Promise<InstallReceipt>;
38
+ //# sourceMappingURL=installations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installations.d.ts","sourceRoot":"","sources":["../../src/core/installations.ts"],"names":[],"mappings":"AAIA,OAAO,EAA2B,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAG7E,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAc,SAAQ,aAAa;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,aAAa,EAAE,CAAC,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAoCD,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAgBvG;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAMvF;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAc3E;AAED,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CA2BvG;AAkBD,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,OAAO,GACjB,OAAO,CAAC,cAAc,CAAC,CA0CzB;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAyBtG;AAyBD,wBAAsB,sBAAsB,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAGnF;AAED,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,gBAAgB,EAAE,MAAM,EACxB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,cAAc,CAAC,CAuBzB"}