@lannguyensi/harness 0.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.
Files changed (199) hide show
  1. package/CHANGELOG.md +552 -0
  2. package/LICENSE +21 -0
  3. package/README.md +154 -0
  4. package/dist/cli/add/index.d.ts +14 -0
  5. package/dist/cli/add/index.js +71 -0
  6. package/dist/cli/add/index.js.map +1 -0
  7. package/dist/cli/add/mutate.d.ts +39 -0
  8. package/dist/cli/add/mutate.js +36 -0
  9. package/dist/cli/add/mutate.js.map +1 -0
  10. package/dist/cli/adopt/derive.d.ts +38 -0
  11. package/dist/cli/adopt/derive.js +94 -0
  12. package/dist/cli/adopt/derive.js.map +1 -0
  13. package/dist/cli/adopt/index.d.ts +20 -0
  14. package/dist/cli/adopt/index.js +156 -0
  15. package/dist/cli/adopt/index.js.map +1 -0
  16. package/dist/cli/apply/apply.d.ts +49 -0
  17. package/dist/cli/apply/apply.js +333 -0
  18. package/dist/cli/apply/apply.js.map +1 -0
  19. package/dist/cli/apply/generate-memory-index.d.ts +17 -0
  20. package/dist/cli/apply/generate-memory-index.js +167 -0
  21. package/dist/cli/apply/generate-memory-index.js.map +1 -0
  22. package/dist/cli/apply/generate-settings.d.ts +15 -0
  23. package/dist/cli/apply/generate-settings.js +87 -0
  24. package/dist/cli/apply/generate-settings.js.map +1 -0
  25. package/dist/cli/apply/index.d.ts +1 -0
  26. package/dist/cli/apply/index.js +2 -0
  27. package/dist/cli/apply/index.js.map +1 -0
  28. package/dist/cli/audit.d.ts +36 -0
  29. package/dist/cli/audit.js +121 -0
  30. package/dist/cli/audit.js.map +1 -0
  31. package/dist/cli/describe.d.ts +13 -0
  32. package/dist/cli/describe.js +26 -0
  33. package/dist/cli/describe.js.map +1 -0
  34. package/dist/cli/diff/engine.d.ts +21 -0
  35. package/dist/cli/diff/engine.js +161 -0
  36. package/dist/cli/diff/engine.js.map +1 -0
  37. package/dist/cli/diff/git.d.ts +6 -0
  38. package/dist/cli/diff/git.js +32 -0
  39. package/dist/cli/diff/git.js.map +1 -0
  40. package/dist/cli/diff/index.d.ts +15 -0
  41. package/dist/cli/diff/index.js +39 -0
  42. package/dist/cli/diff/index.js.map +1 -0
  43. package/dist/cli/diff/since-apply.d.ts +57 -0
  44. package/dist/cli/diff/since-apply.js +255 -0
  45. package/dist/cli/diff/since-apply.js.map +1 -0
  46. package/dist/cli/doctor/format.d.ts +2 -0
  47. package/dist/cli/doctor/format.js +126 -0
  48. package/dist/cli/doctor/format.js.map +1 -0
  49. package/dist/cli/doctor/index.d.ts +14 -0
  50. package/dist/cli/doctor/index.js +281 -0
  51. package/dist/cli/doctor/index.js.map +1 -0
  52. package/dist/cli/doctor/types.d.ts +46 -0
  53. package/dist/cli/doctor/types.js +2 -0
  54. package/dist/cli/doctor/types.js.map +1 -0
  55. package/dist/cli/dry-run.d.ts +46 -0
  56. package/dist/cli/dry-run.js +168 -0
  57. package/dist/cli/dry-run.js.map +1 -0
  58. package/dist/cli/exit-codes.d.ts +10 -0
  59. package/dist/cli/exit-codes.js +15 -0
  60. package/dist/cli/exit-codes.js.map +1 -0
  61. package/dist/cli/explain.d.ts +14 -0
  62. package/dist/cli/explain.js +97 -0
  63. package/dist/cli/explain.js.map +1 -0
  64. package/dist/cli/export.d.ts +31 -0
  65. package/dist/cli/export.js +84 -0
  66. package/dist/cli/export.js.map +1 -0
  67. package/dist/cli/index.d.ts +8 -0
  68. package/dist/cli/index.js +549 -0
  69. package/dist/cli/index.js.map +1 -0
  70. package/dist/cli/init/index.d.ts +17 -0
  71. package/dist/cli/init/index.js +57 -0
  72. package/dist/cli/init/index.js.map +1 -0
  73. package/dist/cli/init/templates.d.ts +4 -0
  74. package/dist/cli/init/templates.js +175 -0
  75. package/dist/cli/init/templates.js.map +1 -0
  76. package/dist/cli/list.d.ts +12 -0
  77. package/dist/cli/list.js +118 -0
  78. package/dist/cli/list.js.map +1 -0
  79. package/dist/cli/loader.d.ts +24 -0
  80. package/dist/cli/loader.js +74 -0
  81. package/dist/cli/loader.js.map +1 -0
  82. package/dist/cli/main.d.ts +2 -0
  83. package/dist/cli/main.js +6 -0
  84. package/dist/cli/main.js.map +1 -0
  85. package/dist/cli/policy/intercept.d.ts +34 -0
  86. package/dist/cli/policy/intercept.js +172 -0
  87. package/dist/cli/policy/intercept.js.map +1 -0
  88. package/dist/cli/remove/index.d.ts +18 -0
  89. package/dist/cli/remove/index.js +95 -0
  90. package/dist/cli/remove/index.js.map +1 -0
  91. package/dist/cli/remove/mutate.d.ts +9 -0
  92. package/dist/cli/remove/mutate.js +68 -0
  93. package/dist/cli/remove/mutate.js.map +1 -0
  94. package/dist/cli/validate/checks.d.ts +23 -0
  95. package/dist/cli/validate/checks.js +253 -0
  96. package/dist/cli/validate/checks.js.map +1 -0
  97. package/dist/cli/validate/index.d.ts +18 -0
  98. package/dist/cli/validate/index.js +50 -0
  99. package/dist/cli/validate/index.js.map +1 -0
  100. package/dist/cli/validate/types.d.ts +7 -0
  101. package/dist/cli/validate/types.js +5 -0
  102. package/dist/cli/validate/types.js.map +1 -0
  103. package/dist/index.d.ts +15 -0
  104. package/dist/index.js +16 -0
  105. package/dist/index.js.map +1 -0
  106. package/dist/io/atomic-write.d.ts +8 -0
  107. package/dist/io/atomic-write.js +30 -0
  108. package/dist/io/atomic-write.js.map +1 -0
  109. package/dist/io/harness-lock.d.ts +33 -0
  110. package/dist/io/harness-lock.js +260 -0
  111. package/dist/io/harness-lock.js.map +1 -0
  112. package/dist/io/last-apply.d.ts +20 -0
  113. package/dist/io/last-apply.js +123 -0
  114. package/dist/io/last-apply.js.map +1 -0
  115. package/dist/io/lock.d.ts +11 -0
  116. package/dist/io/lock.js +33 -0
  117. package/dist/io/lock.js.map +1 -0
  118. package/dist/io/patch.d.ts +10 -0
  119. package/dist/io/patch.js +8 -0
  120. package/dist/io/patch.js.map +1 -0
  121. package/dist/io/restart-hints.d.ts +5 -0
  122. package/dist/io/restart-hints.js +59 -0
  123. package/dist/io/restart-hints.js.map +1 -0
  124. package/dist/io/three-state.d.ts +7 -0
  125. package/dist/io/three-state.js +20 -0
  126. package/dist/io/three-state.js.map +1 -0
  127. package/dist/io/validate-before-write.d.ts +12 -0
  128. package/dist/io/validate-before-write.js +23 -0
  129. package/dist/io/validate-before-write.js.map +1 -0
  130. package/dist/overrides/index.d.ts +2 -0
  131. package/dist/overrides/index.js +3 -0
  132. package/dist/overrides/index.js.map +1 -0
  133. package/dist/overrides/machines.d.ts +12 -0
  134. package/dist/overrides/machines.js +46 -0
  135. package/dist/overrides/machines.js.map +1 -0
  136. package/dist/overrides/merge.d.ts +6 -0
  137. package/dist/overrides/merge.js +173 -0
  138. package/dist/overrides/merge.js.map +1 -0
  139. package/dist/policies/duration.d.ts +5 -0
  140. package/dist/policies/duration.js +50 -0
  141. package/dist/policies/duration.js.map +1 -0
  142. package/dist/policies/extract.d.ts +50 -0
  143. package/dist/policies/extract.js +190 -0
  144. package/dist/policies/extract.js.map +1 -0
  145. package/dist/policies/index.d.ts +5 -0
  146. package/dist/policies/index.js +6 -0
  147. package/dist/policies/index.js.map +1 -0
  148. package/dist/policies/ledger-client.d.ts +39 -0
  149. package/dist/policies/ledger-client.js +378 -0
  150. package/dist/policies/ledger-client.js.map +1 -0
  151. package/dist/policies/requires.d.ts +44 -0
  152. package/dist/policies/requires.js +146 -0
  153. package/dist/policies/requires.js.map +1 -0
  154. package/dist/policies/timestamp.d.ts +14 -0
  155. package/dist/policies/timestamp.js +36 -0
  156. package/dist/policies/timestamp.js.map +1 -0
  157. package/dist/probes/mcp.d.ts +29 -0
  158. package/dist/probes/mcp.js +226 -0
  159. package/dist/probes/mcp.js.map +1 -0
  160. package/dist/probes/memory.d.ts +24 -0
  161. package/dist/probes/memory.js +89 -0
  162. package/dist/probes/memory.js.map +1 -0
  163. package/dist/runtime/index.d.ts +3 -0
  164. package/dist/runtime/index.js +4 -0
  165. package/dist/runtime/index.js.map +1 -0
  166. package/dist/runtime/intercept.d.ts +53 -0
  167. package/dist/runtime/intercept.js +181 -0
  168. package/dist/runtime/intercept.js.map +1 -0
  169. package/dist/runtime/ledger-record.d.ts +43 -0
  170. package/dist/runtime/ledger-record.js +239 -0
  171. package/dist/runtime/ledger-record.js.map +1 -0
  172. package/dist/runtime/session-id.d.ts +10 -0
  173. package/dist/runtime/session-id.js +37 -0
  174. package/dist/runtime/session-id.js.map +1 -0
  175. package/dist/schema/extract.d.ts +5 -0
  176. package/dist/schema/extract.js +23 -0
  177. package/dist/schema/extract.js.map +1 -0
  178. package/dist/schema/grounding.d.ts +65 -0
  179. package/dist/schema/grounding.js +21 -0
  180. package/dist/schema/grounding.js.map +1 -0
  181. package/dist/schema/hooks.d.ts +86 -0
  182. package/dist/schema/hooks.js +42 -0
  183. package/dist/schema/hooks.js.map +1 -0
  184. package/dist/schema/index.d.ts +961 -0
  185. package/dist/schema/index.js +55 -0
  186. package/dist/schema/index.js.map +1 -0
  187. package/dist/schema/memory.d.ts +131 -0
  188. package/dist/schema/memory.js +38 -0
  189. package/dist/schema/memory.js.map +1 -0
  190. package/dist/schema/policies.d.ts +412 -0
  191. package/dist/schema/policies.js +53 -0
  192. package/dist/schema/policies.js.map +1 -0
  193. package/dist/schema/requires.d.ts +115 -0
  194. package/dist/schema/requires.js +57 -0
  195. package/dist/schema/requires.js.map +1 -0
  196. package/dist/schema/tools.d.ts +283 -0
  197. package/dist/schema/tools.js +66 -0
  198. package/dist/schema/tools.js.map +1 -0
  199. package/package.json +63 -0
@@ -0,0 +1,123 @@
1
+ // `.last-apply` tracker — records what harness wrote on the previous `apply`,
2
+ // so the three-state comparator (see `three-state.ts`) can tell drift apart
3
+ // from "no changes needed".
4
+ //
5
+ // Lives at `<generatedDir>/.last-apply`. Format is JSON:
6
+ // { files: { <relPath>: { sha256, content } } }
7
+ // Atomic writes via `atomic-write.ts` (Phase 2 #1 contract).
8
+ import * as crypto from "node:crypto";
9
+ import * as fs from "node:fs";
10
+ import * as path from "node:path";
11
+ import { atomicWriteFile } from "./atomic-write.js";
12
+ export const LAST_APPLY_BASENAME = ".last-apply";
13
+ export function lastApplyPath(generatedDir) {
14
+ return path.join(generatedDir, LAST_APPLY_BASENAME);
15
+ }
16
+ export function sha256Hex(content) {
17
+ return crypto.createHash("sha256").update(content, "utf8").digest("hex");
18
+ }
19
+ export function buildLastApply(files) {
20
+ const out = { files: {} };
21
+ for (const [relPath, content] of Object.entries(files)) {
22
+ out.files[relPath] = { sha256: sha256Hex(content), content };
23
+ }
24
+ return out;
25
+ }
26
+ export function writeLastApply(generatedDir, record) {
27
+ const target = lastApplyPath(generatedDir);
28
+ // Stable key order so re-applying produces byte-identical .last-apply when
29
+ // nothing changed (helps `diff --since-apply` and code-review noise).
30
+ const sorted = { files: {} };
31
+ for (const key of Object.keys(record.files).sort()) {
32
+ const entry = record.files[key];
33
+ if (entry !== undefined)
34
+ sorted.files[key] = entry;
35
+ }
36
+ if (record.manifest !== undefined)
37
+ sorted.manifest = record.manifest;
38
+ if (record.memoryDirs !== undefined) {
39
+ const sortedDirs = {};
40
+ for (const dirKey of Object.keys(record.memoryDirs).sort()) {
41
+ const snap = record.memoryDirs[dirKey];
42
+ if (snap === undefined)
43
+ continue;
44
+ const sortedHashes = {};
45
+ for (const fileKey of Object.keys(snap.fileHashes).sort()) {
46
+ const h = snap.fileHashes[fileKey];
47
+ if (h !== undefined)
48
+ sortedHashes[fileKey] = h;
49
+ }
50
+ sortedDirs[dirKey] = { sha256: snap.sha256, fileHashes: sortedHashes };
51
+ }
52
+ sorted.memoryDirs = sortedDirs;
53
+ }
54
+ atomicWriteFile(target, `${JSON.stringify(sorted, null, 2)}\n`);
55
+ }
56
+ export function readLastApply(generatedDir) {
57
+ const target = lastApplyPath(generatedDir);
58
+ if (!fs.existsSync(target))
59
+ return null;
60
+ const raw = fs.readFileSync(target, "utf8");
61
+ const parsed = JSON.parse(raw);
62
+ if (!isLastApplyRecord(parsed)) {
63
+ throw new Error(`malformed ${LAST_APPLY_BASENAME}: missing or invalid "files" map`);
64
+ }
65
+ return parsed;
66
+ }
67
+ // Recomputes content sha256 for each file in a record, returning the list of
68
+ // relPaths whose stored sha disagrees. An empty list means the record is
69
+ // internally consistent. Used by callers that want to defend against on-disk
70
+ // corruption of the .last-apply file before treating it as authoritative.
71
+ export function verifyLastApplyIntegrity(record) {
72
+ const mismatched = [];
73
+ for (const [relPath, entry] of Object.entries(record.files)) {
74
+ if (sha256Hex(entry.content) !== entry.sha256) {
75
+ mismatched.push(relPath);
76
+ }
77
+ }
78
+ return mismatched;
79
+ }
80
+ function isFileEntry(v) {
81
+ if (!v || typeof v !== "object")
82
+ return false;
83
+ const e = v;
84
+ return typeof e.sha256 === "string" && typeof e.content === "string";
85
+ }
86
+ function isMemoryDirSnapshot(v) {
87
+ if (!v || typeof v !== "object")
88
+ return false;
89
+ const s = v;
90
+ if (typeof s.sha256 !== "string")
91
+ return false;
92
+ if (!s.fileHashes || typeof s.fileHashes !== "object")
93
+ return false;
94
+ for (const h of Object.values(s.fileHashes)) {
95
+ if (typeof h !== "string")
96
+ return false;
97
+ }
98
+ return true;
99
+ }
100
+ function isLastApplyRecord(x) {
101
+ if (!x || typeof x !== "object")
102
+ return false;
103
+ const obj = x;
104
+ if (!obj.files || typeof obj.files !== "object")
105
+ return false;
106
+ for (const v of Object.values(obj.files)) {
107
+ if (!isFileEntry(v))
108
+ return false;
109
+ }
110
+ // Optional manifest snapshot: tolerate omission; reject malformed shape.
111
+ if (obj.manifest !== undefined && !isFileEntry(obj.manifest))
112
+ return false;
113
+ if (obj.memoryDirs !== undefined) {
114
+ if (typeof obj.memoryDirs !== "object" || obj.memoryDirs === null)
115
+ return false;
116
+ for (const v of Object.values(obj.memoryDirs)) {
117
+ if (!isMemoryDirSnapshot(v))
118
+ return false;
119
+ }
120
+ }
121
+ return true;
122
+ }
123
+ //# sourceMappingURL=last-apply.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"last-apply.js","sourceRoot":"","sources":["../../src/io/last-apply.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export interface LockOptions {
2
+ retries?: number;
3
+ minTimeoutMs?: number;
4
+ maxTimeoutMs?: number;
5
+ staleMs?: number;
6
+ }
7
+ export declare const DEFAULT_LOCK_RETRIES = 50;
8
+ export declare const DEFAULT_LOCK_MIN_TIMEOUT_MS = 50;
9
+ export declare const DEFAULT_LOCK_MAX_TIMEOUT_MS = 500;
10
+ export declare const DEFAULT_LOCK_STALE_MS = 10000;
11
+ export declare function withFileLock<T>(lockPath: string, fn: () => Promise<T> | T, options?: LockOptions): Promise<T>;
@@ -0,0 +1,33 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import lockfile from "proper-lockfile";
4
+ export const DEFAULT_LOCK_RETRIES = 50;
5
+ export const DEFAULT_LOCK_MIN_TIMEOUT_MS = 50;
6
+ export const DEFAULT_LOCK_MAX_TIMEOUT_MS = 500;
7
+ export const DEFAULT_LOCK_STALE_MS = 10_000;
8
+ export async function withFileLock(lockPath, fn, options = {}) {
9
+ ensureLockTarget(lockPath);
10
+ const release = await lockfile.lock(lockPath, {
11
+ retries: {
12
+ retries: options.retries ?? DEFAULT_LOCK_RETRIES,
13
+ minTimeout: options.minTimeoutMs ?? DEFAULT_LOCK_MIN_TIMEOUT_MS,
14
+ maxTimeout: options.maxTimeoutMs ?? DEFAULT_LOCK_MAX_TIMEOUT_MS,
15
+ },
16
+ stale: options.staleMs ?? DEFAULT_LOCK_STALE_MS,
17
+ realpath: false,
18
+ });
19
+ try {
20
+ return await fn();
21
+ }
22
+ finally {
23
+ await release();
24
+ }
25
+ }
26
+ function ensureLockTarget(lockPath) {
27
+ const dir = path.dirname(lockPath);
28
+ fs.mkdirSync(dir, { recursive: true });
29
+ if (!fs.existsSync(lockPath)) {
30
+ fs.writeFileSync(lockPath, "");
31
+ }
32
+ }
33
+ //# sourceMappingURL=lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock.js","sourceRoot":"","sources":["../../src/io/lock.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,QAAQ,MAAM,iBAAiB,CAAC;AASvC,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,CAAC;AACvC,MAAM,CAAC,MAAM,2BAA2B,GAAG,EAAE,CAAC;AAC9C,MAAM,CAAC,MAAM,2BAA2B,GAAG,GAAG,CAAC;AAC/C,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAE5C,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,QAAgB,EAChB,EAAwB,EACxB,UAAuB,EAAE;IAEzB,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAC3B,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE;QAC5C,OAAO,EAAE;YACP,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,oBAAoB;YAChD,UAAU,EAAE,OAAO,CAAC,YAAY,IAAI,2BAA2B;YAC/D,UAAU,EAAE,OAAO,CAAC,YAAY,IAAI,2BAA2B;SAChE;QACD,KAAK,EAAE,OAAO,CAAC,OAAO,IAAI,qBAAqB;QAC/C,QAAQ,EAAE,KAAK;KAChB,CAAC,CAAC;IACH,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,EAAE,CAAC;IACpB,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,EAAE,CAAC;IAClB,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,QAAgB;IACxC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnC,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACjC,CAAC;AACH,CAAC"}
@@ -0,0 +1,10 @@
1
+ export interface UnifiedDiffOptions {
2
+ fileName: string;
3
+ oldText: string;
4
+ newText: string;
5
+ oldHeader?: string;
6
+ newHeader?: string;
7
+ context?: number;
8
+ }
9
+ export declare function unifiedDiff(opts: UnifiedDiffOptions): string;
10
+ export declare function isNoop(diff: string): boolean;
@@ -0,0 +1,8 @@
1
+ import { createPatch } from "diff";
2
+ export function unifiedDiff(opts) {
3
+ return createPatch(opts.fileName, opts.oldText, opts.newText, opts.oldHeader ?? "before", opts.newHeader ?? "after", { context: opts.context ?? 3 });
4
+ }
5
+ export function isNoop(diff) {
6
+ return !/^[+-](?!\+\+ |-- )/m.test(diff);
7
+ }
8
+ //# sourceMappingURL=patch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patch.js","sourceRoot":"","sources":["../../src/io/patch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,MAAM,CAAC;AAWnC,MAAM,UAAU,WAAW,CAAC,IAAwB;IAClD,OAAO,WAAW,CAChB,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,SAAS,IAAI,QAAQ,EAC1B,IAAI,CAAC,SAAS,IAAI,OAAO,EACzB,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,CAAC,EAAE,CAC/B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,IAAY;IACjC,OAAO,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { Manifest } from "../schema/index.js";
2
+ export declare const RESTART_HINT_MCP = "mcp servers changed; /mcp reconnect required";
3
+ export declare const RESTART_HINT_MEMORY_ROUTER = "memory router command changed; restart session for new hooks";
4
+ export declare const RESTART_HINT_HOOKS = "hooks changed; restart session to reload settings.json";
5
+ export declare function emitRestartHints(prev: Manifest, next: Manifest): string[];
@@ -0,0 +1,59 @@
1
+ // Restart hints emitter — pure function over a manifest delta.
2
+ //
3
+ // After `harness apply` mutates `harness.generated/`, the user (or AI agent)
4
+ // usually has to perform a separate runtime action: reconnect MCP servers,
5
+ // restart the session to pick up new hooks, etc. This module computes which
6
+ // hints to print based on which manifest sections actually changed.
7
+ //
8
+ // Per ARCHITECTURE.md / ROADMAP Phase 3 acceptance:
9
+ // - mcp[] changed → MCP-restart hint
10
+ // - memory.router.command changed → session-restart hint
11
+ // - hooks structure changed → settings.json reload hint
12
+ // - description-only changes → no hints (description is metadata)
13
+ export const RESTART_HINT_MCP = "mcp servers changed; /mcp reconnect required";
14
+ export const RESTART_HINT_MEMORY_ROUTER = "memory router command changed; restart session for new hooks";
15
+ export const RESTART_HINT_HOOKS = "hooks changed; restart session to reload settings.json";
16
+ function deepEqual(a, b) {
17
+ return JSON.stringify(canonicalize(a)) === JSON.stringify(canonicalize(b));
18
+ }
19
+ // Stable JSON canonicalisation: sort object keys recursively. Arrays keep
20
+ // their order — for hooks/mcp the array order is meaningful.
21
+ function canonicalize(value) {
22
+ if (Array.isArray(value))
23
+ return value.map(canonicalize);
24
+ if (value && typeof value === "object") {
25
+ const out = {};
26
+ for (const k of Object.keys(value).sort()) {
27
+ out[k] = canonicalize(value[k]);
28
+ }
29
+ return out;
30
+ }
31
+ return value;
32
+ }
33
+ function stripDescription(x) {
34
+ const { description: _ignored, ...rest } = x;
35
+ return rest;
36
+ }
37
+ function hooksMaterial(hooks) {
38
+ return hooks.map(stripDescription);
39
+ }
40
+ function policiesMaterial(policies) {
41
+ return policies.map(stripDescription);
42
+ }
43
+ export function emitRestartHints(prev, next) {
44
+ const hints = [];
45
+ if (!deepEqual(prev.tools.mcp, next.tools.mcp)) {
46
+ hints.push(RESTART_HINT_MCP);
47
+ }
48
+ const prevRouterCmd = prev.memory.router?.command ?? null;
49
+ const nextRouterCmd = next.memory.router?.command ?? null;
50
+ if (!deepEqual(prevRouterCmd, nextRouterCmd)) {
51
+ hints.push(RESTART_HINT_MEMORY_ROUTER);
52
+ }
53
+ if (!deepEqual(hooksMaterial(prev.hooks), hooksMaterial(next.hooks)) ||
54
+ !deepEqual(policiesMaterial(prev.policies), policiesMaterial(next.policies))) {
55
+ hints.push(RESTART_HINT_HOOKS);
56
+ }
57
+ return hints;
58
+ }
59
+ //# sourceMappingURL=restart-hints.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restart-hints.js","sourceRoot":"","sources":["../../src/io/restart-hints.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,EAAE;AACF,6EAA6E;AAC7E,2EAA2E;AAC3E,4EAA4E;AAC5E,oEAAoE;AACpE,EAAE;AACF,oDAAoD;AACpD,sDAAsD;AACtD,2DAA2D;AAC3D,gEAAgE;AAChE,yEAAyE;AAIzE,MAAM,CAAC,MAAM,gBAAgB,GAC3B,8CAA8C,CAAC;AACjD,MAAM,CAAC,MAAM,0BAA0B,GACrC,8DAA8D,CAAC;AACjE,MAAM,CAAC,MAAM,kBAAkB,GAC7B,wDAAwD,CAAC;AAE3D,SAAS,SAAS,CAAC,CAAU,EAAE,CAAU;IACvC,OAAO,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7E,CAAC;AAED,0EAA0E;AAC1E,6DAA6D;AAC7D,SAAS,YAAY,CAAC,KAAc;IAClC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACzD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvC,MAAM,GAAG,GAA4B,EAAE,CAAC;QACxC,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,KAAgC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;YACrE,GAAG,CAAC,CAAC,CAAC,GAAG,YAAY,CAAE,KAAiC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/D,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,gBAAgB,CAAsC,CAAI;IACjE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,CAAC,CAAC;IAC7C,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,aAAa,CAAC,KAAa;IAClC,OAAO,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,gBAAgB,CAAC,QAAkB;IAC1C,OAAO,QAAQ,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAc,EAAE,IAAc;IAC7D,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/C,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAC/B,CAAC;IAED,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,IAAI,IAAI,CAAC;IAC1D,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,IAAI,IAAI,CAAC;IAC1D,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,aAAa,CAAC,EAAE,CAAC;QAC7C,KAAK,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;IACzC,CAAC;IAED,IACE,CAAC,SAAS,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChE,CAAC,SAAS,CAAC,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAC5E,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,7 @@
1
+ export type ThreeStateVerdict = "safe-overwrite" | "no-drift" | "drift-refuse";
2
+ export interface ThreeStateInput {
3
+ manifestExpected: string;
4
+ lastApplied: string | null;
5
+ onDiskCurrent: string | null;
6
+ }
7
+ export declare function compare(input: ThreeStateInput): ThreeStateVerdict;
@@ -0,0 +1,20 @@
1
+ // Three-state comparator for `harness apply` per ARCHITECTURE.md §7.
2
+ //
3
+ // Given:
4
+ // - manifestExpected: what the file should look like, derived from the manifest
5
+ // - lastApplied: what harness wrote on the previous apply (null on first run)
6
+ // - onDiskCurrent: what the file currently contains on disk (null if absent)
7
+ //
8
+ // returns one of:
9
+ // - "safe-overwrite": no last-apply record, no on-disk file → write fresh
10
+ // - "no-drift": last-apply present and matches on-disk → overwrite is safe
11
+ // - "drift-refuse": either (a) on-disk exists but no last-apply, or
12
+ // (b) last-apply present but on-disk differs (or is gone)
13
+ export function compare(input) {
14
+ const { lastApplied, onDiskCurrent } = input;
15
+ if (lastApplied === null) {
16
+ return onDiskCurrent === null ? "safe-overwrite" : "drift-refuse";
17
+ }
18
+ return onDiskCurrent === lastApplied ? "no-drift" : "drift-refuse";
19
+ }
20
+ //# sourceMappingURL=three-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"three-state.js","sourceRoot":"","sources":["../../src/io/three-state.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,EAAE;AACF,SAAS;AACT,kFAAkF;AAClF,qFAAqF;AACrF,kFAAkF;AAClF,EAAE;AACF,kBAAkB;AAClB,4EAA4E;AAC5E,mFAAmF;AACnF,wEAAwE;AACxE,uFAAuF;AAUvF,MAAM,UAAU,OAAO,CAAC,KAAsB;IAC5C,MAAM,EAAE,WAAW,EAAE,aAAa,EAAE,GAAG,KAAK,CAAC;IAE7C,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;QACzB,OAAO,aAAa,KAAK,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,cAAc,CAAC;IACpE,CAAC;IAED,OAAO,aAAa,KAAK,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,cAAc,CAAC;AACrE,CAAC"}
@@ -0,0 +1,12 @@
1
+ export type ValidationResult = {
2
+ ok: true;
3
+ } | {
4
+ ok: false;
5
+ errors: ValidationError[];
6
+ };
7
+ export interface ValidationError {
8
+ path: string;
9
+ message: string;
10
+ }
11
+ export declare function validateBeforeWrite(proposedRaw: unknown): ValidationResult;
12
+ export declare function formatValidationErrors(errors: ValidationError[]): string;
@@ -0,0 +1,23 @@
1
+ import { ManifestParseError, parseManifest } from "../schema/index.js";
2
+ export function validateBeforeWrite(proposedRaw) {
3
+ try {
4
+ parseManifest(proposedRaw);
5
+ return { ok: true };
6
+ }
7
+ catch (e) {
8
+ if (e instanceof ManifestParseError) {
9
+ return {
10
+ ok: false,
11
+ errors: e.issues.map((i) => ({
12
+ path: i.path.length > 0 ? i.path.join(".") : "<root>",
13
+ message: i.message,
14
+ })),
15
+ };
16
+ }
17
+ throw e;
18
+ }
19
+ }
20
+ export function formatValidationErrors(errors) {
21
+ return errors.map((e) => ` ${e.path}: ${e.message}`).join("\n");
22
+ }
23
+ //# sourceMappingURL=validate-before-write.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-before-write.js","sourceRoot":"","sources":["../../src/io/validate-before-write.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAWvE,MAAM,UAAU,mBAAmB,CAAC,WAAoB;IACtD,IAAI,CAAC;QACH,aAAa,CAAC,WAAW,CAAC,CAAC;QAC3B,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,YAAY,kBAAkB,EAAE,CAAC;YACpC,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBAC3B,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ;oBACrD,OAAO,EAAE,CAAC,CAAC,OAAO;iBACnB,CAAC,CAAC;aACJ,CAAC;QACJ,CAAC;QACD,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,MAAyB;IAC9D,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACnE,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from "./merge.js";
2
+ export * from "./machines.js";
@@ -0,0 +1,3 @@
1
+ export * from "./merge.js";
2
+ export * from "./machines.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/overrides/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC"}
@@ -0,0 +1,12 @@
1
+ export type MachineOs = "linux" | "darwin" | "wsl2" | "win32" | "default";
2
+ export interface MachineDiscriminators {
3
+ hostname: string;
4
+ os: MachineOs;
5
+ }
6
+ export interface DiscriminatorOptions {
7
+ hostname?: string;
8
+ platform?: NodeJS.Platform;
9
+ procVersionPath?: string;
10
+ }
11
+ export declare function resolveMachineDiscriminators(opts?: DiscriminatorOptions): MachineDiscriminators;
12
+ export declare function machineOverrideCandidates(discriminators: MachineDiscriminators): string[];
@@ -0,0 +1,46 @@
1
+ import * as fs from "node:fs";
2
+ import * as os from "node:os";
3
+ function detectWsl2(procVersionPath) {
4
+ try {
5
+ const contents = fs.readFileSync(procVersionPath, "utf8");
6
+ return /microsoft/i.test(contents);
7
+ }
8
+ catch {
9
+ return false;
10
+ }
11
+ }
12
+ export function resolveMachineDiscriminators(opts = {}) {
13
+ const platform = opts.platform ?? process.platform;
14
+ const procVersionPath = opts.procVersionPath ?? "/proc/version";
15
+ const hostname = (opts.hostname ?? os.hostname() ?? "").toLowerCase();
16
+ let osLabel;
17
+ if (platform === "linux" && detectWsl2(procVersionPath)) {
18
+ osLabel = "wsl2";
19
+ }
20
+ else if (platform === "linux") {
21
+ osLabel = "linux";
22
+ }
23
+ else if (platform === "darwin") {
24
+ osLabel = "darwin";
25
+ }
26
+ else if (platform === "win32") {
27
+ osLabel = "win32";
28
+ }
29
+ else {
30
+ osLabel = "default";
31
+ }
32
+ return { hostname, os: osLabel };
33
+ }
34
+ export function machineOverrideCandidates(discriminators) {
35
+ const candidates = ["default", discriminators.os];
36
+ if (discriminators.hostname)
37
+ candidates.push(discriminators.hostname);
38
+ const seen = new Set();
39
+ return candidates.filter((c) => {
40
+ if (seen.has(c))
41
+ return false;
42
+ seen.add(c);
43
+ return true;
44
+ });
45
+ }
46
+ //# sourceMappingURL=machines.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"machines.js","sourceRoot":"","sources":["../../src/overrides/machines.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAe9B,SAAS,UAAU,CAAC,eAAuB;IACzC,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,EAAE,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;QAC1D,OAAO,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,UAAU,4BAA4B,CAC1C,OAA6B,EAAE;IAE/B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC;IACnD,MAAM,eAAe,GAAG,IAAI,CAAC,eAAe,IAAI,eAAe,CAAC;IAChE,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IAEtE,IAAI,OAAkB,CAAC;IACvB,IAAI,QAAQ,KAAK,OAAO,IAAI,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;QACxD,OAAO,GAAG,MAAM,CAAC;IACnB,CAAC;SAAM,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QAChC,OAAO,GAAG,OAAO,CAAC;IACpB,CAAC;SAAM,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,OAAO,GAAG,QAAQ,CAAC;IACrB,CAAC;SAAM,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QAChC,OAAO,GAAG,OAAO,CAAC;IACpB,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,SAAS,CAAC;IACtB,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,cAAqC;IAErC,MAAM,UAAU,GAAa,CAAC,SAAS,EAAE,cAAc,CAAC,EAAE,CAAC,CAAC;IAC5D,IAAI,cAAc,CAAC,QAAQ;QAAE,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;IACtE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QAC7B,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;QAC9B,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACZ,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,6 @@
1
+ export declare class OverrideMergeError extends Error {
2
+ readonly path: string[];
3
+ constructor(message: string, path: string[]);
4
+ }
5
+ export declare function mergeManifest(base: unknown, override: unknown): unknown;
6
+ export declare function applyLayers(base: unknown, ...layers: Array<unknown | undefined>): unknown;
@@ -0,0 +1,173 @@
1
+ export class OverrideMergeError extends Error {
2
+ path;
3
+ constructor(message, path) {
4
+ super(`override merge failed at ${formatPath(path)}: ${message}`);
5
+ this.path = path;
6
+ this.name = "OverrideMergeError";
7
+ }
8
+ }
9
+ function formatPath(path) {
10
+ return path.length === 0 ? "<root>" : path.join(".");
11
+ }
12
+ const TOMBSTONE = Symbol("override-tombstone");
13
+ function isPlainObject(v) {
14
+ if (v === null || typeof v !== "object")
15
+ return false;
16
+ if (Array.isArray(v))
17
+ return false;
18
+ const proto = Object.getPrototypeOf(v);
19
+ return proto === Object.prototype || proto === null;
20
+ }
21
+ function isNameKeyedEntry(v) {
22
+ return isPlainObject(v) && typeof v.name === "string" && v.name.length > 0;
23
+ }
24
+ function classifyList(list, pathLabel, path) {
25
+ if (list.length === 0)
26
+ return "empty";
27
+ let named = 0;
28
+ let plain = 0;
29
+ for (const item of list) {
30
+ if (isNameKeyedEntry(item))
31
+ named++;
32
+ else
33
+ plain++;
34
+ }
35
+ if (named > 0 && plain > 0) {
36
+ throw new OverrideMergeError(`${pathLabel} list mixes entries that have a "name" field with entries that do not; lists must be uniformly name-keyed or not`, path);
37
+ }
38
+ return named > 0 ? "named" : "plain";
39
+ }
40
+ function deepClone(value) {
41
+ if (value === null || typeof value !== "object")
42
+ return value;
43
+ if (Array.isArray(value))
44
+ return value.map(deepClone);
45
+ if (isPlainObject(value)) {
46
+ const out = {};
47
+ for (const [k, v] of Object.entries(value))
48
+ out[k] = deepClone(v);
49
+ return out;
50
+ }
51
+ return value;
52
+ }
53
+ function mergeNamedList(base, override, path) {
54
+ const baseShape = classifyList(base, "base", path);
55
+ const overrideShape = classifyList(override, "override", path);
56
+ if (baseShape !== "empty" && overrideShape !== "empty" && baseShape !== overrideShape) {
57
+ throw new OverrideMergeError(`cannot merge override ${overrideShape}-list onto base ${baseShape}-list; declare the override as the same shape or omit it`, path);
58
+ }
59
+ if (overrideShape !== "named") {
60
+ if (overrideShape === "empty")
61
+ return [];
62
+ return override.map(deepClone);
63
+ }
64
+ const result = [];
65
+ const seenNames = new Set();
66
+ if (baseShape === "named") {
67
+ for (const baseEntry of base) {
68
+ const matching = override.find((o) => o.name === baseEntry.name);
69
+ if (!matching) {
70
+ result.push(deepClone(baseEntry));
71
+ seenNames.add(baseEntry.name);
72
+ continue;
73
+ }
74
+ seenNames.add(baseEntry.name);
75
+ if (matching._delete === true)
76
+ continue;
77
+ const merged = mergeValue(baseEntry, matching, [...path, baseEntry.name]);
78
+ if (merged === TOMBSTONE)
79
+ continue;
80
+ result.push(merged);
81
+ }
82
+ }
83
+ for (const overrideEntry of override) {
84
+ if (seenNames.has(overrideEntry.name))
85
+ continue;
86
+ if (overrideEntry._delete === true)
87
+ continue;
88
+ const cleaned = stripTombstones(overrideEntry, [...path, overrideEntry.name]);
89
+ if (cleaned === TOMBSTONE)
90
+ continue;
91
+ result.push(cleaned);
92
+ }
93
+ return result;
94
+ }
95
+ function stripTombstones(value, path) {
96
+ if (value === null)
97
+ return TOMBSTONE;
98
+ if (Array.isArray(value)) {
99
+ const result = [];
100
+ for (let i = 0; i < value.length; i++) {
101
+ const v = value[i];
102
+ const child = stripTombstones(v, [...path, String(i)]);
103
+ if (child === TOMBSTONE)
104
+ continue;
105
+ result.push(child);
106
+ }
107
+ return result;
108
+ }
109
+ if (isPlainObject(value)) {
110
+ const out = {};
111
+ for (const [k, v] of Object.entries(value)) {
112
+ if (k === "_delete")
113
+ continue;
114
+ const child = stripTombstones(v, [...path, k]);
115
+ if (child === TOMBSTONE)
116
+ continue;
117
+ out[k] = child;
118
+ }
119
+ return out;
120
+ }
121
+ return value;
122
+ }
123
+ function mergeValue(base, override, path) {
124
+ if (override === null)
125
+ return TOMBSTONE;
126
+ if (Array.isArray(override)) {
127
+ if (Array.isArray(base)) {
128
+ return mergeNamedList(base, override, path);
129
+ }
130
+ return stripTombstones(override, path);
131
+ }
132
+ if (isPlainObject(override)) {
133
+ if (!isPlainObject(base)) {
134
+ const cleaned = stripTombstones(override, path);
135
+ return cleaned === TOMBSTONE ? TOMBSTONE : cleaned;
136
+ }
137
+ const out = {};
138
+ for (const [k, v] of Object.entries(base))
139
+ out[k] = deepClone(v);
140
+ for (const [key, overrideChild] of Object.entries(override)) {
141
+ if (key === "_delete")
142
+ continue;
143
+ const baseChild = out[key];
144
+ const merged = mergeValue(baseChild, overrideChild, [...path, key]);
145
+ if (merged === TOMBSTONE) {
146
+ delete out[key];
147
+ }
148
+ else {
149
+ out[key] = merged;
150
+ }
151
+ }
152
+ return out;
153
+ }
154
+ return override;
155
+ }
156
+ export function mergeManifest(base, override) {
157
+ if (base === undefined)
158
+ return override;
159
+ if (override === undefined)
160
+ return base;
161
+ const result = mergeValue(base, override, []);
162
+ return result === TOMBSTONE ? undefined : result;
163
+ }
164
+ export function applyLayers(base, ...layers) {
165
+ let acc = base;
166
+ for (const layer of layers) {
167
+ if (layer === undefined)
168
+ continue;
169
+ acc = mergeManifest(acc, layer);
170
+ }
171
+ return acc;
172
+ }
173
+ //# sourceMappingURL=merge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge.js","sourceRoot":"","sources":["../../src/overrides/merge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare class InvalidDurationError extends Error {
2
+ readonly value: string;
3
+ constructor(value: string);
4
+ }
5
+ export declare function parseDurationSeconds(value: string): number;