@moldea.ai/core 5.0.1 → 7.0.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 (136) hide show
  1. package/README.md +12 -11
  2. package/dist/analysis-worker.js +180 -0
  3. package/dist/analysis-worker.js.map +1 -0
  4. package/dist/binding-coverage/index.d.ts +26 -0
  5. package/dist/binding-coverage/index.d.ts.map +1 -0
  6. package/dist/chunks/core-Cdeiu6xG.js +3364 -0
  7. package/dist/chunks/core-Cdeiu6xG.js.map +1 -0
  8. package/dist/chunks/errors-BE4DS3Ak.js +435 -0
  9. package/dist/chunks/errors-BE4DS3Ak.js.map +1 -0
  10. package/dist/chunks/{exceptions-HS9ofVy2.js → exceptions-IXsorE8t.js} +27 -28
  11. package/dist/chunks/exceptions-IXsorE8t.js.map +1 -0
  12. package/dist/chunks/lifecycle-D_RvxhDC.js +67 -0
  13. package/dist/chunks/lifecycle-D_RvxhDC.js.map +1 -0
  14. package/dist/chunks/options-5x9gu2Qb.js +604 -0
  15. package/dist/chunks/options-5x9gu2Qb.js.map +1 -0
  16. package/dist/chunks/repository-rpc-B_y0Kspf.js +124 -0
  17. package/dist/chunks/repository-rpc-B_y0Kspf.js.map +1 -0
  18. package/dist/chunks/scope-AGMcHUE_.js +1827 -0
  19. package/dist/chunks/scope-AGMcHUE_.js.map +1 -0
  20. package/dist/chunks/syntax-CVvExx4R.js +137 -0
  21. package/dist/chunks/syntax-CVvExx4R.js.map +1 -0
  22. package/dist/constants/index.d.ts +2 -1
  23. package/dist/constants/index.d.ts.map +1 -1
  24. package/dist/contracts/index.d.ts +37 -27
  25. package/dist/contracts/index.d.ts.map +1 -1
  26. package/dist/core/index.d.ts +1 -4
  27. package/dist/core/index.d.ts.map +1 -1
  28. package/dist/decision/index.d.ts +1 -1
  29. package/dist/decision-graph/index.d.ts +9 -7
  30. package/dist/decision-graph/index.d.ts.map +1 -1
  31. package/dist/diagnostic-utilities/index.d.ts +6 -2
  32. package/dist/diagnostic-utilities/index.d.ts.map +1 -1
  33. package/dist/diagnostics/index.d.ts +21 -33
  34. package/dist/diagnostics/index.d.ts.map +1 -1
  35. package/dist/exceptions/index.d.ts +25 -10
  36. package/dist/exceptions/index.d.ts.map +1 -1
  37. package/dist/export-inventory/index.d.ts +3 -0
  38. package/dist/export-inventory/index.d.ts.map +1 -0
  39. package/dist/export-inventory/inventory.d.ts +22 -0
  40. package/dist/export-inventory/inventory.d.ts.map +1 -0
  41. package/dist/export-inventory/syntax.d.ts +4 -0
  42. package/dist/export-inventory/syntax.d.ts.map +1 -0
  43. package/dist/export-inventory/types.d.ts +9 -0
  44. package/dist/export-inventory/types.d.ts.map +1 -0
  45. package/dist/format/index.d.ts +8 -0
  46. package/dist/format/index.d.ts.map +1 -1
  47. package/dist/impact-pattern-validation/index.d.ts +2 -0
  48. package/dist/impact-pattern-validation/index.d.ts.map +1 -0
  49. package/dist/impact-pattern-validation/inspection.d.ts +24 -0
  50. package/dist/impact-pattern-validation/inspection.d.ts.map +1 -0
  51. package/dist/index.d.ts +5 -3
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +4 -5776
  54. package/dist/integration-validation/index.d.ts +4 -0
  55. package/dist/integration-validation/index.d.ts.map +1 -0
  56. package/dist/integration-validation/inspection.d.ts +18 -0
  57. package/dist/integration-validation/inspection.d.ts.map +1 -0
  58. package/dist/integration-validation/parser.d.ts +9 -0
  59. package/dist/integration-validation/parser.d.ts.map +1 -0
  60. package/dist/integration-validation/types.d.ts +13 -0
  61. package/dist/integration-validation/types.d.ts.map +1 -0
  62. package/dist/manifest/index.d.ts +2 -4
  63. package/dist/manifest/index.d.ts.map +1 -1
  64. package/dist/manifest-validation/index.d.ts +7 -10
  65. package/dist/manifest-validation/index.d.ts.map +1 -1
  66. package/dist/node/index.d.ts +4 -0
  67. package/dist/node/index.d.ts.map +1 -0
  68. package/dist/node-inspection/analysis-worker.d.ts +2 -0
  69. package/dist/node-inspection/analysis-worker.d.ts.map +1 -0
  70. package/dist/node-inspection/client.d.ts +28 -0
  71. package/dist/node-inspection/client.d.ts.map +1 -0
  72. package/dist/node-inspection/constants.d.ts +21 -0
  73. package/dist/node-inspection/constants.d.ts.map +1 -0
  74. package/dist/node-inspection/errors.d.ts +11 -0
  75. package/dist/node-inspection/errors.d.ts.map +1 -0
  76. package/dist/node-inspection/lifecycle.d.ts +15 -0
  77. package/dist/node-inspection/lifecycle.d.ts.map +1 -0
  78. package/dist/node-inspection/protocol.d.ts +20 -0
  79. package/dist/node-inspection/protocol.d.ts.map +1 -0
  80. package/dist/node-inspection/repository-rpc.d.ts +28 -0
  81. package/dist/node-inspection/repository-rpc.d.ts.map +1 -0
  82. package/dist/node-inspection/runner.d.ts +2 -0
  83. package/dist/node-inspection/runner.d.ts.map +1 -0
  84. package/dist/node-inspection/types.d.ts +95 -0
  85. package/dist/node-inspection/types.d.ts.map +1 -0
  86. package/dist/node-runner.js +149 -0
  87. package/dist/node-runner.js.map +1 -0
  88. package/dist/node.js +335 -0
  89. package/dist/node.js.map +1 -0
  90. package/dist/options/index.d.ts +2 -14
  91. package/dist/options/index.d.ts.map +1 -1
  92. package/dist/project-inspection/index.d.ts +21 -1
  93. package/dist/project-inspection/index.d.ts.map +1 -1
  94. package/dist/project-validation/index.d.ts +33 -11
  95. package/dist/project-validation/index.d.ts.map +1 -1
  96. package/dist/repository-inspection-session/index.d.ts +2 -4
  97. package/dist/repository-inspection-session/index.d.ts.map +1 -1
  98. package/dist/repository-reference-validation/index.d.ts +12 -6
  99. package/dist/repository-reference-validation/index.d.ts.map +1 -1
  100. package/dist/retained-memory/index.d.ts +18 -0
  101. package/dist/retained-memory/index.d.ts.map +1 -0
  102. package/dist/scope/index.d.ts +3 -0
  103. package/dist/scope/index.d.ts.map +1 -0
  104. package/dist/scope/scope.d.ts +13 -0
  105. package/dist/scope/scope.d.ts.map +1 -0
  106. package/dist/scope-matching/index.d.ts +2 -1
  107. package/dist/scope-matching/index.d.ts.map +1 -1
  108. package/dist/scope-matching/matching.d.ts +11 -2
  109. package/dist/scope-matching/matching.d.ts.map +1 -1
  110. package/dist/scope-matching/patterns.d.ts +4 -0
  111. package/dist/scope-matching/patterns.d.ts.map +1 -0
  112. package/dist/scope.js +17 -0
  113. package/dist/scope.js.map +1 -0
  114. package/dist/universal-project-inspection/index.d.ts +13 -11
  115. package/dist/universal-project-inspection/index.d.ts.map +1 -1
  116. package/dist/warning-acceptance/acceptance.d.ts +11 -0
  117. package/dist/warning-acceptance/acceptance.d.ts.map +1 -0
  118. package/dist/warning-acceptance/index.d.ts +2 -0
  119. package/dist/warning-acceptance/index.d.ts.map +1 -0
  120. package/package.json +14 -6
  121. package/dist/adapter/index.d.ts +0 -131
  122. package/dist/adapter/index.d.ts.map +0 -1
  123. package/dist/adapter-availability/index.d.ts +0 -15
  124. package/dist/adapter-availability/index.d.ts.map +0 -1
  125. package/dist/adapter-execution/index.d.ts +0 -31
  126. package/dist/adapter-execution/index.d.ts.map +0 -1
  127. package/dist/adapter-repository/index.d.ts +0 -27
  128. package/dist/adapter-repository/index.d.ts.map +0 -1
  129. package/dist/adapter-retained-memory/index.d.ts +0 -8
  130. package/dist/adapter-retained-memory/index.d.ts.map +0 -1
  131. package/dist/adapter-validation/index.d.ts +0 -43
  132. package/dist/adapter-validation/index.d.ts.map +0 -1
  133. package/dist/adapter.js +0 -115
  134. package/dist/adapter.js.map +0 -1
  135. package/dist/chunks/exceptions-HS9ofVy2.js.map +0 -1
  136. package/dist/index.js.map +0 -1
@@ -0,0 +1,3364 @@
1
+ import { E as parseDecisionIdFromPath, S as isRuntimeGuidancePath, T as isVariableId, a as escapeJsonPointerSegment, c as freezeRecursively, d as hasNonWhitespace, g as isContextPath, i as createCoreDiagnosticCollector, k as trimRepositoryFormatWhitespace, l as compareExactStrings, n as normalizeCoreOptions, o as normalizeDiagnostics, r as countDiagnosticsBySeverity, s as createNullPrototypeRecord, t as createCoreOperationOptionsSnapshot, u as countUnicodeScalars } from "./options-5x9gu2Qb.js";
2
+ import { n as CoreOperationException } from "./exceptions-IXsorE8t.js";
3
+ import { a as createSourceLocator, c as calculateContentDigest, i as parseStrictYaml, l as calculateNormalizedTextDigest, n as inspectManifestDocument, o as collectManifestScopeDeclarations, r as parseManifestDocument, s as matchesRepositoryGlob, t as matchManifestScope, u as normalizeTextDocument } from "./scope-AGMcHUE_.js";
4
+ import { REPOSITORY_ROOT, RepositorySourceException, compareRepositoryPaths, createRepositoryIdentity, isRepositoryPath, parseRepositoryPath } from "@moldea.ai/repository";
5
+ //#region \0rolldown/runtime.js
6
+ var __defProp = Object.defineProperty;
7
+ var __exportAll = (all, no_symbols) => {
8
+ let target = {};
9
+ for (var name in all) __defProp(target, name, {
10
+ get: all[name],
11
+ enumerable: true
12
+ });
13
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
14
+ return target;
15
+ };
16
+ //#endregion
17
+ //#region src/canonical-content-page/index.ts
18
+ var decoder = new TextDecoder("utf-8", {
19
+ fatal: true,
20
+ ignoreBOM: true
21
+ });
22
+ var invalidArgument$2 = () => {
23
+ throw new CoreOperationException({
24
+ code: "INVALID_ARGUMENT",
25
+ operation: "read-canonical-content-page"
26
+ });
27
+ };
28
+ var invalidContent = () => {
29
+ throw new CoreOperationException({
30
+ code: "CONTENT_INVALID",
31
+ operation: "read-canonical-content-page"
32
+ });
33
+ };
34
+ var isRepositoryReader$1 = (candidate) => typeof candidate === "object" && candidate !== null && typeof candidate.getEntry === "function" && typeof candidate.readFilePage === "function";
35
+ var readBytes = async (repository, path, offset, maxBytes, signal) => {
36
+ const chunks = [];
37
+ let byteLength = 0;
38
+ let nextOffset = offset;
39
+ let lastPage = null;
40
+ let totalBytes = null;
41
+ while (byteLength < maxBytes) {
42
+ const page = await repository.readFilePage(path, {
43
+ maxBytes: maxBytes - byteLength,
44
+ offset: nextOffset,
45
+ ...signal === void 0 ? {} : { signal }
46
+ });
47
+ if (page.snapshot.id !== repository.snapshot.id || page.offset !== nextOffset || page.bytes.byteLength > maxBytes - byteLength || page.totalBytes < page.offset + page.bytes.byteLength || totalBytes !== null && page.totalBytes !== totalBytes || page.bytes.byteLength === 0 && !page.isComplete) throw new RepositorySourceException({
48
+ code: "INVALID_SOURCE_DATA",
49
+ operation: "read-file-page",
50
+ path,
51
+ retryable: false
52
+ });
53
+ chunks.push(page.bytes);
54
+ byteLength += page.bytes.byteLength;
55
+ totalBytes = page.totalBytes;
56
+ lastPage = page;
57
+ if (page.isComplete || byteLength === maxBytes) break;
58
+ if (page.nextOffset !== page.offset + page.bytes.byteLength) throw new RepositorySourceException({
59
+ code: "INVALID_SOURCE_DATA",
60
+ operation: "read-file-page",
61
+ path,
62
+ retryable: false
63
+ });
64
+ nextOffset = page.nextOffset;
65
+ }
66
+ if (lastPage === null) return invalidArgument$2();
67
+ const bytes = new Uint8Array(byteLength);
68
+ let writeOffset = 0;
69
+ for (const chunk of chunks) {
70
+ bytes.set(chunk, writeOffset);
71
+ writeOffset += chunk.byteLength;
72
+ }
73
+ return {
74
+ bytes,
75
+ lastPage
76
+ };
77
+ };
78
+ var decodeSafePrefix = (bytes, maximumBytes) => {
79
+ const minimumCandidate = Math.max(0, maximumBytes - 3);
80
+ for (let end = maximumBytes; end >= minimumCandidate; end -= 1) try {
81
+ const content = decoder.decode(bytes.subarray(0, end));
82
+ if (end === 0 && bytes.byteLength > 0) continue;
83
+ return [content, end];
84
+ } catch {}
85
+ return invalidContent();
86
+ };
87
+ /** Reads one explicit canonical file range without materializing the complete file. */
88
+ var readCanonicalContentPage = async (input, options) => {
89
+ if (typeof input !== "object" || input === null || Reflect.ownKeys(input).some((key) => key !== "maxBytes" && key !== "offset" && key !== "path" && key !== "repository" && key !== "signal") || !isRepositoryReader$1(input.repository) || !Number.isSafeInteger(input.maxBytes) || input.maxBytes < 1 || input.maxBytes > options.limits.maxFileBytes || !Number.isSafeInteger(input.offset) || input.offset < 0) return invalidArgument$2();
90
+ const path = parseRepositoryPath(input.path);
91
+ if (!path.startsWith("/moldea/")) return invalidArgument$2();
92
+ const operationOptions = input.signal === void 0 ? void 0 : { signal: input.signal };
93
+ const entry = await input.repository.getEntry(path, operationOptions);
94
+ if (entry === null) throw new RepositorySourceException({
95
+ code: "ENTRY_NOT_FOUND",
96
+ operation: "read-file-page",
97
+ path,
98
+ retryable: false
99
+ });
100
+ if (entry.type !== "file" || entry.byteLength === null) throw new RepositorySourceException({
101
+ code: "ENTRY_NOT_FILE",
102
+ operation: "read-file-page",
103
+ path,
104
+ retryable: false
105
+ });
106
+ if (entry.byteLength > options.limits.maxFileBytes) throw new CoreOperationException({
107
+ code: "RESOURCE_LIMIT_EXCEEDED",
108
+ limit: "maxFileBytes",
109
+ limitMaximum: options.limits.maxFileBytes,
110
+ nextAction: "reduce-input-or-increase-limit",
111
+ observedUsage: entry.byteLength,
112
+ operation: "read-canonical-content-page"
113
+ });
114
+ if (input.offset > entry.byteLength) return invalidArgument$2();
115
+ if (input.offset === entry.byteLength) return freezeRecursively({
116
+ byteEnd: input.offset,
117
+ byteStart: input.offset,
118
+ content: "",
119
+ contentIdentity: entry.contentIdentity,
120
+ isComplete: true,
121
+ nextOffset: null,
122
+ path,
123
+ source: input.repository.snapshot,
124
+ totalBytes: entry.byteLength
125
+ });
126
+ const lookaheadBytes = Math.min(entry.byteLength - input.offset, input.maxBytes + 3);
127
+ const { bytes, lastPage } = await readBytes(input.repository, path, input.offset, lookaheadBytes, input.signal);
128
+ if (lastPage.totalBytes !== entry.byteLength || (bytes[0] & 192) === 128) return invalidArgument$2();
129
+ const [content, consumedBytes] = decodeSafePrefix(bytes, Math.min(input.maxBytes, bytes.byteLength));
130
+ const byteEnd = input.offset + consumedBytes;
131
+ const isComplete = byteEnd === entry.byteLength;
132
+ return freezeRecursively({
133
+ byteEnd,
134
+ byteStart: input.offset,
135
+ content,
136
+ contentIdentity: entry.contentIdentity,
137
+ isComplete,
138
+ nextOffset: isComplete ? null : byteEnd,
139
+ path,
140
+ source: input.repository.snapshot,
141
+ totalBytes: entry.byteLength
142
+ });
143
+ };
144
+ //#endregion
145
+ //#region src/decision-validation/index.ts
146
+ var DECISION_STATUSES = /* @__PURE__ */ new Set([
147
+ "accepted",
148
+ "proposed",
149
+ "rejected",
150
+ "superseded"
151
+ ]);
152
+ var DECISION_ID_PATTERN = /^\d{13}$/u;
153
+ var CREATED_AT_PATTERN = /^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])T(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d\.\d{3}Z$/u;
154
+ var getEntity = (decisionId) => {
155
+ return decisionId === null ? null : { decisionId };
156
+ };
157
+ var addInvalidFrontmatter = (context, range, reason, pointer = null) => {
158
+ context.diagnostics.add({
159
+ code: "MOLDEA_DECISION_FRONTMATTER_INVALID",
160
+ details: { reason },
161
+ entity: getEntity(context.decisionId),
162
+ path: context.path,
163
+ pointer,
164
+ range
165
+ });
166
+ };
167
+ var isCanonicalCreatedAt = (value) => {
168
+ if (!CREATED_AT_PATTERN.test(value)) return false;
169
+ const timestamp = Date.parse(value);
170
+ return Number.isFinite(timestamp) && new Date(timestamp).toISOString() === value;
171
+ };
172
+ var readMapping = (node, context) => {
173
+ if (node.kind !== "mapping") {
174
+ addInvalidFrontmatter(context, node.range, "mapping-required");
175
+ return null;
176
+ }
177
+ const entries = /* @__PURE__ */ new Map();
178
+ for (const entry of node.entries) {
179
+ if (entry.key.kind !== "scalar" || typeof entry.key.value !== "string") {
180
+ addInvalidFrontmatter(context, entry.key.range, "string-key-required");
181
+ continue;
182
+ }
183
+ const key = entry.key.value;
184
+ if (key !== "status" && key !== "createdAt" && key !== "supersedes") {
185
+ context.diagnostics.add({
186
+ code: "MOLDEA_DECISION_PROPERTY_UNKNOWN",
187
+ entity: getEntity(context.decisionId),
188
+ path: context.path,
189
+ pointer: `/${escapeJsonPointerSegment(key)}`,
190
+ range: entry.key.range
191
+ });
192
+ continue;
193
+ }
194
+ entries.set(key, entry.value);
195
+ }
196
+ return entries;
197
+ };
198
+ var readStatus = (node, context) => {
199
+ if (node?.kind !== "scalar" || typeof node.value !== "string" || !DECISION_STATUSES.has(node.value)) {
200
+ context.diagnostics.add({
201
+ code: "MOLDEA_DECISION_STATUS_INVALID",
202
+ entity: getEntity(context.decisionId),
203
+ path: context.path,
204
+ pointer: "/status",
205
+ range: node?.range ?? null
206
+ });
207
+ return null;
208
+ }
209
+ return node.value;
210
+ };
211
+ var readCreatedAt = (node, context) => {
212
+ if (node?.kind !== "scalar" || typeof node.value !== "string" || !isCanonicalCreatedAt(node.value)) {
213
+ context.diagnostics.add({
214
+ code: "MOLDEA_DECISION_CREATED_AT_INVALID",
215
+ entity: getEntity(context.decisionId),
216
+ path: context.path,
217
+ pointer: "/createdAt",
218
+ range: node?.range ?? null
219
+ });
220
+ return null;
221
+ }
222
+ if (context.decisionId !== null && Date.parse(node.value) !== Number(context.decisionId)) context.diagnostics.add({
223
+ code: "MOLDEA_DECISION_TIMESTAMP_MISMATCH",
224
+ entity: getEntity(context.decisionId),
225
+ path: context.path,
226
+ pointer: "/createdAt",
227
+ range: node.range
228
+ });
229
+ return node.value;
230
+ };
231
+ var readSupersedes = (node, context) => {
232
+ if (node === void 0) return [];
233
+ if (node.kind !== "sequence" || node.items.length === 0) {
234
+ addInvalidFrontmatter(context, node.range, "non-empty-supersedes-sequence-required", "/supersedes");
235
+ return null;
236
+ }
237
+ const supersedes = [];
238
+ const seen = /* @__PURE__ */ new Set();
239
+ node.items.forEach((item, index) => {
240
+ const pointer = `/supersedes/${index}`;
241
+ if (item.kind !== "scalar" || typeof item.value !== "string" || !DECISION_ID_PATTERN.test(item.value)) {
242
+ addInvalidFrontmatter(context, item.range, "decision-id-string-required", pointer);
243
+ return;
244
+ }
245
+ if (seen.has(item.value)) {
246
+ context.diagnostics.add({
247
+ code: "MOLDEA_ID_DUPLICATE",
248
+ entity: getEntity(context.decisionId),
249
+ path: context.path,
250
+ pointer,
251
+ range: item.range
252
+ });
253
+ return;
254
+ }
255
+ seen.add(item.value);
256
+ supersedes.push(item.value);
257
+ if (item.value === context.decisionId) context.diagnostics.add({
258
+ code: "MOLDEA_DECISION_SELF_SUPERSESSION",
259
+ entity: getEntity(context.decisionId),
260
+ path: context.path,
261
+ pointer,
262
+ range: item.range
263
+ });
264
+ });
265
+ return supersedes.sort(compareExactStrings);
266
+ };
267
+ /**
268
+ * Locates exact decision frontmatter delimiters and preserves the complete Markdown body.
269
+ * @param value The complete normalized decision document.
270
+ * @param locator The full-document scalar-aware source locator.
271
+ * @param context The decision diagnostic context.
272
+ * @returns The YAML prefix and exact body, or `null` when delimiters are unavailable.
273
+ */
274
+ var extractDecisionSections = (value, locator, context) => {
275
+ const firstLineEnd = value.indexOf("\n");
276
+ const openingLineEnd = firstLineEnd === -1 ? value.length : firstLineEnd;
277
+ if (value.slice(0, openingLineEnd) !== "---") {
278
+ context.diagnostics.add({
279
+ code: "MOLDEA_DECISION_FRONTMATTER_MISSING",
280
+ entity: getEntity(context.decisionId),
281
+ path: context.path,
282
+ range: locator.locateRange(0, openingLineEnd)
283
+ });
284
+ return null;
285
+ }
286
+ let lineStart = firstLineEnd === -1 ? value.length : firstLineEnd + 1;
287
+ while (lineStart <= value.length) {
288
+ const nextLineBreak = value.indexOf("\n", lineStart);
289
+ const lineEnd = nextLineBreak === -1 ? value.length : nextLineBreak;
290
+ if (value.slice(lineStart, lineEnd) === "---") {
291
+ const bodyStart = nextLineBreak === -1 ? lineEnd : nextLineBreak + 1;
292
+ return {
293
+ body: value.slice(bodyStart),
294
+ bodyRange: locator.locateRange(bodyStart, value.length),
295
+ yaml: value.slice(0, lineStart)
296
+ };
297
+ }
298
+ if (nextLineBreak === -1) break;
299
+ lineStart = nextLineBreak + 1;
300
+ }
301
+ context.diagnostics.add({
302
+ code: "MOLDEA_DECISION_FRONTMATTER_MISSING",
303
+ entity: getEntity(context.decisionId),
304
+ path: context.path,
305
+ range: locator.locateRange(value.length, value.length)
306
+ });
307
+ return null;
308
+ };
309
+ /**
310
+ * Validates one parsed decision-frontmatter mapping without resolving other files.
311
+ * @param node The strict parser-neutral YAML root.
312
+ * @param context The decision diagnostic context.
313
+ * @returns Canonical decision metadata when every document-level rule is valid.
314
+ */
315
+ var validateDecisionFrontmatter = (node, context) => {
316
+ const initialDiagnosticCount = context.diagnostics.size;
317
+ const entries = readMapping(node, context);
318
+ if (entries === null) return null;
319
+ const status = readStatus(entries.get("status"), context);
320
+ const createdAt = readCreatedAt(entries.get("createdAt"), context);
321
+ const supersedes = readSupersedes(entries.get("supersedes"), context);
322
+ if (status === null || createdAt === null || supersedes === null || context.diagnostics.size > initialDiagnosticCount) return null;
323
+ return {
324
+ createdAt,
325
+ status,
326
+ supersedes
327
+ };
328
+ };
329
+ /** Adds the decision-body diagnostic when the preserved Markdown has no content. */
330
+ var validateDecisionBody = (body, range, context) => {
331
+ if (hasNonWhitespace(body)) return true;
332
+ context.diagnostics.add({
333
+ code: "MOLDEA_DECISION_BODY_EMPTY",
334
+ entity: getEntity(context.decisionId),
335
+ path: context.path,
336
+ range
337
+ });
338
+ return false;
339
+ };
340
+ //#endregion
341
+ //#region src/decision/index.ts
342
+ /**
343
+ * Parses and validates one complete decision document without resolving cross-file relationships.
344
+ * @param input The canonical logical path and exact decision text or bytes.
345
+ * @param options The immutable Core limit snapshot.
346
+ * @param operation The owning public or repository-level operation for typed failures.
347
+ * @returns A frozen all-or-nothing decision parse result.
348
+ * @throws
349
+ * - INVALID_REPOSITORY_PATH: The repository path is invalid.
350
+ * - INVALID_ARGUMENT: The Core operation received an invalid argument.
351
+ * - RESOURCE_LIMIT_EXCEEDED: A Core resource limit was exceeded.
352
+ */
353
+ var parseDecisionDocument = async (input, options, operation = "parse-decision") => {
354
+ options = createCoreOperationOptionsSnapshot(options);
355
+ const normalized = normalizeTextDocument(input, options.limits, operation);
356
+ const path = parseRepositoryPath(input.path);
357
+ const diagnostics = createCoreDiagnosticCollector(options.limits, operation);
358
+ const decisionId = parseDecisionIdFromPath(path);
359
+ if (decisionId === null) diagnostics.add({
360
+ code: "MOLDEA_DECISION_FILENAME_INVALID",
361
+ path
362
+ });
363
+ for (const diagnostic of normalized.diagnostics) diagnostics.merge(diagnostic);
364
+ if (!normalized.valid || normalized.text === null) return freezeRecursively({
365
+ decision: null,
366
+ diagnostics: diagnostics.finalize(),
367
+ valid: false
368
+ });
369
+ const context = {
370
+ decisionId,
371
+ diagnostics,
372
+ path
373
+ };
374
+ const locator = createSourceLocator(normalized.text.value);
375
+ const sections = extractDecisionSections(normalized.text.value, locator, context);
376
+ let metadata = null;
377
+ if (sections !== null) {
378
+ validateDecisionBody(sections.body, sections.bodyRange, context);
379
+ const parsed = parseStrictYaml(sections.yaml, path, locator, diagnostics);
380
+ if (parsed.valid && parsed.value !== null) metadata = validateDecisionFrontmatter(parsed.value, context);
381
+ }
382
+ if (decisionId === null || sections === null || metadata === null || diagnostics.size > 0) return freezeRecursively({
383
+ decision: null,
384
+ diagnostics: diagnostics.finalize(),
385
+ valid: false
386
+ });
387
+ const digest = await calculateNormalizedTextDigest(normalized.text);
388
+ const asset = {
389
+ content: normalized.text.value,
390
+ digest,
391
+ path,
392
+ scalarLength: normalized.text.scalarLength,
393
+ utf8ByteLength: normalized.text.utf8ByteLength
394
+ };
395
+ return freezeRecursively({
396
+ decision: {
397
+ asset,
398
+ body: sections.body,
399
+ createdAt: metadata.createdAt,
400
+ id: decisionId,
401
+ path,
402
+ status: metadata.status,
403
+ supersedes: metadata.supersedes
404
+ },
405
+ diagnostics: diagnostics.finalize(),
406
+ valid: true
407
+ });
408
+ };
409
+ //#endregion
410
+ //#region src/project-agent-assignments/index.ts
411
+ /** Iterates content-free agent-to-runtime assignments without retaining an intermediate array. */
412
+ var iterateProjectAgentAssignments = function* (project) {
413
+ for (const agent of project.agents) yield {
414
+ agentId: agent.id,
415
+ runtimeId: agent.declaration.runtime.id
416
+ };
417
+ };
418
+ //#endregion
419
+ //#region src/project-metadata/index.ts
420
+ var createAssetItem = (asset, kind, agentId = null, decisionId = null) => ({
421
+ agentId,
422
+ byteLength: asset.utf8ByteLength,
423
+ canonicalDigest: null,
424
+ decisionId,
425
+ digest: asset.digest,
426
+ kind,
427
+ path: asset.path,
428
+ scalarLength: asset.scalarLength
429
+ });
430
+ /** Iterates content-free asset metadata without retaining a second project-sized collection. */
431
+ var iterateProjectMetadata = function* (project) {
432
+ yield createAssetItem(project.manifest.asset, "manifest");
433
+ yield createAssetItem(project.project, "project");
434
+ for (const context of project.context) yield createAssetItem(context.asset, "context");
435
+ for (const { decision } of project.decisions) yield createAssetItem(decision.asset, "decision", null, decision.id);
436
+ for (const runtime of project.runtimes) yield createAssetItem(runtime.asset, "runtime-guidance");
437
+ for (const agent of project.agents) {
438
+ yield createAssetItem(agent.description.asset, "agent-description", agent.id);
439
+ yield createAssetItem(agent.instruction, "agent-instruction", agent.id);
440
+ if (agent.handoffDescription !== null) yield createAssetItem(agent.handoffDescription.asset, "agent-handoff-description", agent.id);
441
+ for (const mirror of agent.mirrors) yield {
442
+ agentId: agent.id,
443
+ byteLength: mirror.byteLength,
444
+ canonicalDigest: mirror.canonicalDigest,
445
+ decisionId: null,
446
+ digest: mirror.digest,
447
+ kind: "mirror",
448
+ path: mirror.path,
449
+ scalarLength: mirror.scalarLength
450
+ };
451
+ }
452
+ };
453
+ /** Creates the content-free summary for one validated project snapshot. */
454
+ var createProjectSummary = (project) => ({
455
+ counts: {
456
+ agents: project.agents.length,
457
+ context: project.context.length,
458
+ decisions: project.decisions.length,
459
+ mirrors: project.agents.reduce((count, agent) => count + agent.mirrors.length, 0),
460
+ runtimes: project.runtimes.length,
461
+ unresolved: project.agents.reduce((count, agent) => count + Object.keys(agent.declaration.unresolved ?? {}).length, Object.keys(project.unresolved).length)
462
+ },
463
+ manifestDigest: project.manifest.asset.digest,
464
+ manifestPath: project.manifest.asset.path,
465
+ projectDigest: project.project.digest,
466
+ projectPath: project.project.path
467
+ });
468
+ //#endregion
469
+ //#region src/binding-coverage/index.ts
470
+ /** Counts every declared, existing binding by its actual export-check outcome. */
471
+ var countBindingCoverage = (coverage) => ({
472
+ bindings: coverage.length,
473
+ exportsPassed: coverage.filter((record) => record.exportCheck === "passed").length,
474
+ exportsFailed: coverage.filter((record) => record.exportCheck === "failed").length,
475
+ exportsNotChecked: coverage.filter((record) => record.exportCheck === "not-checked").length
476
+ });
477
+ //#endregion
478
+ //#region src/retained-memory/index.ts
479
+ var ledgers = /* @__PURE__ */ new WeakMap();
480
+ /** Registers the sole memory owner for one internal reader. */
481
+ var registerRetainedMemory = (reader, ledger) => {
482
+ if (ledgers.has(reader)) throw new TypeError("The inspection reader is already registered.");
483
+ ledgers.set(reader, ledger);
484
+ };
485
+ /** Returns the ledger shared by all phases of a repository inspection. */
486
+ var getRetainedMemory = (reader) => {
487
+ const ledger = ledgers.get(reader);
488
+ if (ledger === void 0) throw new TypeError("The inspection reader has no retained-memory ledger.");
489
+ return ledger;
490
+ };
491
+ /** Reserves retained coverage in production sessions and leaves standalone file-check readers untracked. */
492
+ var reserveRetainedBytesIfTracked = (reader, bytes) => {
493
+ ledgers.get(reader)?.reserve(bytes);
494
+ };
495
+ //#endregion
496
+ //#region src/repository-inspection-session/index.ts
497
+ var MANIFEST_PATH$3 = parseRepositoryPath("/moldea/moldea.yaml");
498
+ var SOURCE_PAGE_ENTRIES = 256;
499
+ var SOURCE_PAGE_BYTES = 65536;
500
+ var CANONICAL_BYTE_RETENTION_MULTIPLIER = 4;
501
+ var RETAINED_PATH_FIXED_BYTES = 64;
502
+ var RETAINED_PATH_BYTE_MULTIPLIER = 2;
503
+ var encoder$1 = new TextEncoder();
504
+ var invalidSourceData$3 = (operation, path) => {
505
+ throw new RepositorySourceException({
506
+ code: "INVALID_SOURCE_DATA",
507
+ operation,
508
+ path,
509
+ retryable: false
510
+ });
511
+ };
512
+ var copyReaderEntry$1 = (candidate, operation, fallbackPath, expectedPath) => {
513
+ if (typeof candidate !== "object" || candidate === null) return invalidSourceData$3(operation, fallbackPath);
514
+ const record = candidate;
515
+ const pathCandidate = record["path"];
516
+ const typeCandidate = record["type"];
517
+ const byteLength = record["byteLength"];
518
+ const contentIdentity = record["contentIdentity"];
519
+ if (typeof pathCandidate !== "string" || !isRepositoryPath(pathCandidate)) return invalidSourceData$3(operation, fallbackPath);
520
+ const path = parseRepositoryPath(pathCandidate);
521
+ if (expectedPath !== void 0 && path !== expectedPath) return invalidSourceData$3(operation, path);
522
+ if (typeCandidate !== "file" && typeCandidate !== "directory" && typeCandidate !== "symlink") return invalidSourceData$3(operation, path);
523
+ if (typeCandidate === "file" ? !Number.isSafeInteger(byteLength) || byteLength < 0 || contentIdentity !== null && typeof contentIdentity !== "string" : byteLength !== null || contentIdentity !== null) return invalidSourceData$3(operation, path);
524
+ return {
525
+ byteLength,
526
+ contentIdentity,
527
+ path,
528
+ type: typeCandidate
529
+ };
530
+ };
531
+ var isStrictDescendant = (path, prefix) => {
532
+ if (path === prefix) return false;
533
+ const descendantPrefix = prefix === REPOSITORY_ROOT ? REPOSITORY_ROOT : `${prefix}/`;
534
+ return path.startsWith(descendantPrefix);
535
+ };
536
+ var throwResourceLimitExceeded = (limit, limitMaximum, observedUsage) => {
537
+ throw new CoreOperationException({
538
+ code: "RESOURCE_LIMIT_EXCEEDED",
539
+ limit,
540
+ limitMaximum,
541
+ nextAction: "reduce-input-or-increase-limit",
542
+ observedUsage,
543
+ operation: "validate-project"
544
+ });
545
+ };
546
+ var createSourceOptions = (sessionSignal, operationSignal) => {
547
+ const signal = sessionSignal === void 0 ? operationSignal : operationSignal === void 0 || operationSignal === sessionSignal ? sessionSignal : AbortSignal.any([sessionSignal, operationSignal]);
548
+ return signal === void 0 ? void 0 : { signal };
549
+ };
550
+ /**
551
+ * Creates the isolated reader state for one repository inspection.
552
+ * @param repository The source-neutral reader bound to one coherent snapshot.
553
+ * @param limits The immutable resource limits for the inspection.
554
+ * @param signal Optional cancellation shared by every inspection operation.
555
+ * @returns A session that pages source metadata and range-reads bounded canonical files.
556
+ * @throws
557
+ * - ABORTED: The Core operation was aborted.
558
+ */
559
+ var createRepositoryInspectionSession = (repository, limits, signal) => {
560
+ const seenPaths = /* @__PURE__ */ new Set();
561
+ let canonicalBytes = 0;
562
+ let peakRetainedBytes = 0;
563
+ let retainedBytes = 0;
564
+ let totalBytesRead = 0;
565
+ const createAbortedException = (abortedSignal) => {
566
+ return new CoreOperationException({
567
+ cause: abortedSignal.reason,
568
+ code: "ABORTED",
569
+ operation: "validate-project"
570
+ });
571
+ };
572
+ const reserveRetainedBytes = (byteLength) => {
573
+ if (!Number.isSafeInteger(byteLength) || byteLength < 0 || byteLength > limits.maxRetainedBytes - retainedBytes) return throwResourceLimitExceeded("maxRetainedBytes", limits.maxRetainedBytes, retainedBytes + byteLength);
574
+ retainedBytes += byteLength;
575
+ peakRetainedBytes = Math.max(peakRetainedBytes, retainedBytes);
576
+ };
577
+ const observeTransientBytes = (byteLength) => {
578
+ if (!Number.isSafeInteger(byteLength) || byteLength < 0 || byteLength > limits.maxRetainedBytes - retainedBytes) return throwResourceLimitExceeded("maxRetainedBytes", limits.maxRetainedBytes, retainedBytes + byteLength);
579
+ peakRetainedBytes = Math.max(peakRetainedBytes, retainedBytes + byteLength);
580
+ };
581
+ const registerPath = (path) => {
582
+ if (path === REPOSITORY_ROOT || seenPaths.has(path)) return;
583
+ if (seenPaths.size >= limits.maxEntries) return throwResourceLimitExceeded("maxEntries", limits.maxEntries, seenPaths.size + 1);
584
+ reserveRetainedBytes(RETAINED_PATH_FIXED_BYTES + encoder$1.encode(path).byteLength * RETAINED_PATH_BYTE_MULTIPLIER);
585
+ seenPaths.add(path);
586
+ };
587
+ const throwIfSignalAborted = (operationSignal) => {
588
+ const abortedSignal = signal?.aborted ? signal : operationSignal?.aborted ? operationSignal : null;
589
+ if (abortedSignal !== null) throw createAbortedException(abortedSignal);
590
+ };
591
+ throwIfSignalAborted();
592
+ const reserveReadBytes = (byteLength) => {
593
+ if (byteLength > limits.maxTotalBytesRead - totalBytesRead) return throwResourceLimitExceeded("maxTotalBytesRead", limits.maxTotalBytesRead, totalBytesRead + byteLength);
594
+ totalBytesRead += byteLength;
595
+ };
596
+ const getEntry = async (path, options) => {
597
+ const parsedPath = parseRepositoryPath(path);
598
+ throwIfSignalAborted(options?.signal);
599
+ registerPath(parsedPath);
600
+ const candidate = await repository.getEntry(parsedPath, createSourceOptions(signal, options?.signal));
601
+ throwIfSignalAborted(options?.signal);
602
+ return candidate === null ? null : copyReaderEntry$1(candidate, "get-entry", parsedPath, parsedPath);
603
+ };
604
+ const iterateEntries = (options) => {
605
+ const prefix = options?.prefix === void 0 ? REPOSITORY_ROOT : parseRepositoryPath(options.prefix);
606
+ return { async *[Symbol.asyncIterator]() {
607
+ registerPath(prefix);
608
+ const yieldedPaths = /* @__PURE__ */ new Set();
609
+ let cursor;
610
+ let previousPath = null;
611
+ do {
612
+ throwIfSignalAborted(options?.signal);
613
+ const page = await repository.listEntriesPage({
614
+ ...cursor === void 0 ? {} : { cursor },
615
+ maxEntries: Math.min(SOURCE_PAGE_ENTRIES, limits.maxEntries),
616
+ prefix,
617
+ ...createSourceOptions(signal, options?.signal) ?? {}
618
+ });
619
+ if (page.snapshot.id !== repository.snapshot.id || page.entries.length === 0 && !page.isComplete) return invalidSourceData$3("list-entries-page", prefix);
620
+ for (const candidate of page.entries) {
621
+ throwIfSignalAborted(options?.signal);
622
+ const entry = copyReaderEntry$1(candidate, "list-entries-page", prefix);
623
+ if (!isStrictDescendant(entry.path, prefix) || yieldedPaths.has(entry.path) || previousPath !== null && compareRepositoryPaths(previousPath, entry.path) >= 0) return invalidSourceData$3("list-entries-page", entry.path);
624
+ yieldedPaths.add(entry.path);
625
+ previousPath = entry.path;
626
+ registerPath(entry.path);
627
+ yield entry;
628
+ }
629
+ if (page.isComplete) {
630
+ if (page.nextCursor !== null) return invalidSourceData$3("list-entries-page", prefix);
631
+ return;
632
+ }
633
+ if (page.nextCursor === null || page.nextCursor === cursor) return invalidSourceData$3("list-entries-page", prefix);
634
+ cursor = page.nextCursor;
635
+ } while (true);
636
+ } };
637
+ };
638
+ const loadFile = async (path, operationSignal, isSource = false) => {
639
+ const multiplier = isSource ? 1 : CANONICAL_BYTE_RETENTION_MULTIPLIER;
640
+ const fileLimit = path === MANIFEST_PATH$3 ? "maxManifestBytes" : "maxFileBytes";
641
+ const availableRetainedBytes = limits.maxRetainedBytes - retainedBytes;
642
+ if (availableRetainedBytes < 1) return throwResourceLimitExceeded("maxRetainedBytes", limits.maxRetainedBytes, retainedBytes + 1);
643
+ const firstPageMaximumBytes = Math.min(SOURCE_PAGE_BYTES, Math.max(1, limits[fileLimit]), availableRetainedBytes);
644
+ observeTransientBytes(firstPageMaximumBytes);
645
+ const firstPage = await repository.readFilePage(path, {
646
+ maxBytes: firstPageMaximumBytes,
647
+ offset: 0,
648
+ ...createSourceOptions(signal, operationSignal) ?? {}
649
+ });
650
+ throwIfSignalAborted(operationSignal);
651
+ if (firstPage.snapshot.id !== repository.snapshot.id || firstPage.offset !== 0 || !(firstPage.bytes instanceof Uint8Array) || !Number.isSafeInteger(firstPage.totalBytes) || firstPage.totalBytes < 0 || firstPage.bytes.byteLength > SOURCE_PAGE_BYTES || firstPage.bytes.byteLength > firstPage.totalBytes || firstPage.bytes.byteLength === 0 && !firstPage.isComplete) return invalidSourceData$3("read-file-page", path);
652
+ if (firstPage.totalBytes > limits[fileLimit]) return throwResourceLimitExceeded(fileLimit, limits[fileLimit], firstPage.totalBytes);
653
+ const firstPageBytes = firstPage.bytes.byteLength;
654
+ const retainedBytesAvailableForCanonicalContent = limits.maxRetainedBytes - retainedBytes - firstPageBytes;
655
+ if (retainedBytesAvailableForCanonicalContent < 0 || firstPage.totalBytes > Math.floor(retainedBytesAvailableForCanonicalContent / multiplier)) {
656
+ const projectedUsage = retainedBytes + firstPageBytes + firstPage.totalBytes * multiplier;
657
+ return throwResourceLimitExceeded("maxRetainedBytes", limits.maxRetainedBytes, Number.isSafeInteger(projectedUsage) ? projectedUsage : Number.MAX_SAFE_INTEGER);
658
+ }
659
+ reserveReadBytes(firstPage.totalBytes);
660
+ const canonicalRetainedBytes = firstPage.totalBytes * multiplier;
661
+ observeTransientBytes(canonicalRetainedBytes + firstPageBytes);
662
+ reserveRetainedBytes(canonicalRetainedBytes);
663
+ if (!isSource) canonicalBytes += firstPage.totalBytes;
664
+ const content = new Uint8Array(firstPage.totalBytes);
665
+ let offset = 0;
666
+ let page = firstPage;
667
+ let isFirstPage = true;
668
+ while (isFirstPage || offset < content.byteLength) {
669
+ isFirstPage = false;
670
+ if (page.snapshot.id !== repository.snapshot.id || page.offset !== offset || page.totalBytes !== content.byteLength || !(page.bytes instanceof Uint8Array) || page.bytes.byteLength > SOURCE_PAGE_BYTES || page.bytes.byteLength > content.byteLength - offset || page.bytes.byteLength === 0 && !page.isComplete) return invalidSourceData$3("read-file-page", path);
671
+ content.set(page.bytes, offset);
672
+ offset += page.bytes.byteLength;
673
+ if (page.isComplete) {
674
+ if (page.nextOffset !== null || offset !== content.byteLength) return invalidSourceData$3("read-file-page", path);
675
+ break;
676
+ }
677
+ if (page.nextOffset !== offset) return invalidSourceData$3("read-file-page", path);
678
+ page = await repository.readFilePage(path, {
679
+ maxBytes: Math.min(SOURCE_PAGE_BYTES, Math.max(1, content.byteLength - offset)),
680
+ offset,
681
+ ...createSourceOptions(signal, operationSignal) ?? {}
682
+ });
683
+ throwIfSignalAborted(operationSignal);
684
+ }
685
+ return content;
686
+ };
687
+ const awaitWithCancellation = async (promise, operationSignal) => {
688
+ const callerSignal = createSourceOptions(signal, operationSignal)?.signal;
689
+ if (callerSignal === void 0) return promise;
690
+ return new Promise((resolve, reject) => {
691
+ const cleanup = () => callerSignal.removeEventListener("abort", abort);
692
+ const abort = () => {
693
+ cleanup();
694
+ reject(createAbortedException(callerSignal));
695
+ };
696
+ if (callerSignal.aborted) abort();
697
+ else callerSignal.addEventListener("abort", abort, { once: true });
698
+ promise.then((result) => {
699
+ cleanup();
700
+ resolve(result);
701
+ }, (error) => {
702
+ cleanup();
703
+ reject(error instanceof Error ? error : new RepositorySourceException({
704
+ cause: error,
705
+ code: "INVALID_SOURCE_DATA",
706
+ operation: "read-file-page",
707
+ path: null,
708
+ retryable: false
709
+ }));
710
+ });
711
+ });
712
+ };
713
+ const readCompleteFile = async (path, options) => {
714
+ const parsedPath = parseRepositoryPath(path);
715
+ throwIfSignalAborted(options?.signal);
716
+ registerPath(parsedPath);
717
+ const content = await awaitWithCancellation(loadFile(parsedPath, options?.signal), options?.signal);
718
+ throwIfSignalAborted(options?.signal);
719
+ return content.slice();
720
+ };
721
+ const reader = Object.freeze({
722
+ getEntry,
723
+ iterateEntries,
724
+ readCompleteFile
725
+ });
726
+ registerRetainedMemory(reader, {
727
+ reserve: reserveRetainedBytes,
728
+ tryReserve: (bytes) => {
729
+ if (!Number.isSafeInteger(bytes) || bytes < 0 || bytes > limits.maxRetainedBytes - retainedBytes) return false;
730
+ reserveRetainedBytes(bytes);
731
+ return true;
732
+ },
733
+ release: (bytes) => {
734
+ if (!Number.isSafeInteger(bytes) || bytes < 0 || bytes > retainedBytes) throw new TypeError("The retained-memory release is invalid.");
735
+ retainedBytes -= bytes;
736
+ },
737
+ readSourceFile: async (path) => {
738
+ throwIfSignalAborted();
739
+ registerPath(path);
740
+ const bytes = await awaitWithCancellation(loadFile(path, void 0, true));
741
+ throwIfSignalAborted();
742
+ let isReleased = false;
743
+ return {
744
+ bytes,
745
+ release: () => {
746
+ if (!isReleased) retainedBytes -= bytes.byteLength;
747
+ isReleased = true;
748
+ }
749
+ };
750
+ }
751
+ });
752
+ return Object.freeze({
753
+ getResourceUsage: () => Object.freeze({
754
+ canonicalBytes,
755
+ peakRetainedBytes,
756
+ retainedBytes,
757
+ totalBytesRead
758
+ }),
759
+ reader,
760
+ throwIfAborted: throwIfSignalAborted
761
+ });
762
+ };
763
+ //#endregion
764
+ //#region src/agent-asset-validation/index.ts
765
+ var OPENING_HEADING_PATTERN = /^#{1,6} /u;
766
+ /** Finds the first nonblank line at or after one normalized line index. */
767
+ var findNonblankLine = (lines, startIndex) => {
768
+ for (let index = startIndex; index < lines.length; index += 1) {
769
+ const line = lines[index];
770
+ if (line !== void 0 && hasNonWhitespace(line)) return index;
771
+ }
772
+ return null;
773
+ };
774
+ /**
775
+ * Validates the effective value of one agent description asset.
776
+ * @param asset The normalized complete description or handoff-description asset.
777
+ * @param agentId The owning registered agent ID.
778
+ * @param kind The description role determining its diagnostic code.
779
+ * @param limits The Core diagnostic budget.
780
+ * @returns The frozen effective description when every version 1 rule passes.
781
+ * @throws
782
+ * - RESOURCE_LIMIT_EXCEEDED: The repository-level diagnostic budget was exceeded.
783
+ */
784
+ var validateAgentDescription = (asset, agentId, kind, limits) => {
785
+ const diagnostics = createCoreDiagnosticCollector(limits, "validate-project");
786
+ const value = trimRepositoryFormatWhitespace(asset.content);
787
+ const scalarLength = countUnicodeScalars(value);
788
+ const code = kind === "description" ? "MOLDEA_AGENT_DESCRIPTION_INVALID" : "MOLDEA_AGENT_HANDOFF_DESCRIPTION_INVALID";
789
+ if (scalarLength === 0) diagnostics.add({
790
+ code,
791
+ details: { reason: "empty" },
792
+ entity: { agentId },
793
+ path: asset.path
794
+ });
795
+ if (scalarLength > 1e3) diagnostics.add({
796
+ code,
797
+ details: { reason: "too-long" },
798
+ entity: { agentId },
799
+ path: asset.path
800
+ });
801
+ if (value.includes("{{") || value.includes("}}")) diagnostics.add({
802
+ code,
803
+ details: { reason: "runtime-variable-delimiter" },
804
+ entity: { agentId },
805
+ path: asset.path
806
+ });
807
+ const finalizedDiagnostics = diagnostics.finalize();
808
+ return freezeRecursively({
809
+ description: finalizedDiagnostics.length === 0 ? {
810
+ asset,
811
+ scalarLength,
812
+ value
813
+ } : null,
814
+ diagnostics: finalizedDiagnostics,
815
+ valid: finalizedDiagnostics.length === 0
816
+ });
817
+ };
818
+ /**
819
+ * Validates one canonical instruction's non-empty content and opening identity.
820
+ * @param asset The normalized complete instruction asset.
821
+ * @param agentId The owning registered agent ID.
822
+ * @param limits The Core diagnostic budget.
823
+ * @returns The frozen instruction result, retaining non-empty content for later validation.
824
+ * @throws
825
+ * - RESOURCE_LIMIT_EXCEEDED: The repository-level diagnostic budget was exceeded.
826
+ */
827
+ var validateAgentInstruction = (asset, agentId, limits) => {
828
+ const diagnostics = createCoreDiagnosticCollector(limits, "validate-project");
829
+ if (!hasNonWhitespace(asset.content)) {
830
+ diagnostics.add({
831
+ code: "MOLDEA_AGENT_INSTRUCTION_EMPTY",
832
+ entity: { agentId },
833
+ path: asset.path
834
+ });
835
+ return freezeRecursively({
836
+ diagnostics: diagnostics.finalize(),
837
+ instruction: null,
838
+ valid: false
839
+ });
840
+ }
841
+ const identityToken = `\`${agentId}\``;
842
+ const lines = asset.content.split("\n");
843
+ const openingIndex = findNonblankLine(lines, 0);
844
+ let identityIndex = openingIndex;
845
+ if (openingIndex !== null && OPENING_HEADING_PATTERN.test(lines[openingIndex] ?? "")) identityIndex = findNonblankLine(lines, openingIndex + 1);
846
+ if (identityIndex === null || !(lines[identityIndex] ?? "").includes(identityToken)) diagnostics.add({
847
+ code: "MOLDEA_AGENT_IDENTITY_INVALID",
848
+ details: { reason: asset.content.includes(identityToken) ? "misplaced" : "missing" },
849
+ entity: { agentId },
850
+ path: asset.path
851
+ });
852
+ const finalizedDiagnostics = diagnostics.finalize();
853
+ return freezeRecursively({
854
+ diagnostics: finalizedDiagnostics,
855
+ instruction: asset,
856
+ valid: finalizedDiagnostics.length === 0
857
+ });
858
+ };
859
+ //#endregion
860
+ //#region src/repository-text/index.ts
861
+ var invalidSourceData$2 = (path) => {
862
+ throw new RepositorySourceException({
863
+ code: "INVALID_SOURCE_DATA",
864
+ operation: "read-file-page",
865
+ path,
866
+ retryable: false
867
+ });
868
+ };
869
+ /**
870
+ * Reads and normalizes one canonical Markdown asset through a repository reader.
871
+ * @param repository The coherent source-neutral repository reader.
872
+ * @param path The discovered regular-file path to read exactly once.
873
+ * @param limits The Core limits applied to the source bytes and diagnostics.
874
+ * @param signal Optional cancellation forwarded to the repository read.
875
+ * @returns A deeply immutable indexed asset or its deterministic text diagnostics.
876
+ * @throws
877
+ * - ENTRY_NOT_FOUND: The discovered file disappeared from the reader snapshot.
878
+ * - ENTRY_NOT_FILE: The discovered entry is no longer a regular file.
879
+ * - ACCESS_DENIED: Access to the repository source was denied.
880
+ * - SOURCE_UNAVAILABLE: The repository source is unavailable.
881
+ * - SNAPSHOT_CHANGED: The repository snapshot changed during the read.
882
+ * - INVALID_SOURCE_DATA: The repository reader returned invalid contract data.
883
+ * - RESOURCE_LIMIT_EXCEEDED: A Core or repository resource limit was exceeded.
884
+ * - ABORTED: Repository inspection or the repository read was aborted.
885
+ */
886
+ var readRepositoryTextAsset = async (repository, path, limits, signal) => {
887
+ const content = await repository.readCompleteFile(path, signal === void 0 ? void 0 : { signal });
888
+ if (!(content instanceof Uint8Array)) return invalidSourceData$2(path);
889
+ const normalized = normalizeTextDocument({
890
+ content,
891
+ path
892
+ }, limits, "validate-project");
893
+ if (!normalized.valid || normalized.text === null) return freezeRecursively({
894
+ asset: null,
895
+ diagnostics: normalized.diagnostics,
896
+ valid: false
897
+ });
898
+ const asset = {
899
+ content: normalized.text.value,
900
+ digest: await calculateNormalizedTextDigest(normalized.text),
901
+ path,
902
+ scalarLength: normalized.text.scalarLength,
903
+ utf8ByteLength: normalized.text.utf8ByteLength
904
+ };
905
+ return freezeRecursively({
906
+ asset,
907
+ diagnostics: [],
908
+ valid: true
909
+ });
910
+ };
911
+ //#endregion
912
+ //#region src/runtime-placeholder-validation/index.ts
913
+ var readBraceRunEnd = (content, startOffset, brace) => {
914
+ let endOffset = startOffset + 1;
915
+ while (content[endOffset] === brace) endOffset += 1;
916
+ return endOffset;
917
+ };
918
+ /** Finds the end of the next closing-delimiter run without rescanning prior content. */
919
+ var findClosingRunEnd = (content, startOffset) => {
920
+ let cursor = startOffset;
921
+ while (cursor < content.length) {
922
+ if (content[cursor] !== "}") {
923
+ cursor += 1;
924
+ continue;
925
+ }
926
+ const runEnd = readBraceRunEnd(content, cursor, "}");
927
+ if (runEnd - cursor >= 2) return runEnd;
928
+ cursor = runEnd;
929
+ }
930
+ return content.length;
931
+ };
932
+ /** Adds one malformed-placeholder diagnostic for an exact normalized source span. */
933
+ var addMalformedDiagnostic = (collector, instruction, agentId, reason, range) => {
934
+ collector.add({
935
+ code: "MOLDEA_VARIABLE_PLACEHOLDER_MALFORMED",
936
+ details: { reason },
937
+ entity: { agentId },
938
+ path: instruction.path,
939
+ range
940
+ });
941
+ };
942
+ /** Records a valid placeholder occurrence and its first normalized source range. */
943
+ var recordOccurrence = (occurrences, variableId, range) => {
944
+ const occurrence = occurrences.get(variableId);
945
+ if (occurrence === void 0) {
946
+ occurrences.set(variableId, {
947
+ count: 1,
948
+ firstRange: range
949
+ });
950
+ return;
951
+ }
952
+ occurrence.count += 1;
953
+ };
954
+ /**
955
+ * Validates runtime-variable placeholders in one normalized canonical agent instruction.
956
+ * @param manifestPath The canonical manifest path containing variable declarations.
957
+ * @param agentId The owning agent ID.
958
+ * @param instruction The normalized non-empty canonical instruction asset.
959
+ * @param declaredVariables The owning agent's normalized variable declarations.
960
+ * @param limits The resource limits applied to emitted diagnostics.
961
+ * @returns Frozen deterministic placeholder diagnostics.
962
+ * @throws
963
+ * - RESOURCE_LIMIT_EXCEEDED: The repository-level diagnostic budget was exceeded.
964
+ */
965
+ var validateRuntimePlaceholders = (manifestPath, agentId, instruction, declaredVariables, limits) => {
966
+ const collector = createCoreDiagnosticCollector(limits, "validate-project");
967
+ const locator = createSourceLocator(instruction.content);
968
+ const occurrences = /* @__PURE__ */ new Map();
969
+ let cursor = 0;
970
+ while (cursor < instruction.content.length) {
971
+ const character = instruction.content[cursor];
972
+ if (character === "}") {
973
+ const runEnd = readBraceRunEnd(instruction.content, cursor, "}");
974
+ const runLength = runEnd - cursor;
975
+ if (runLength >= 2) addMalformedDiagnostic(collector, instruction, agentId, runLength === 2 ? "unmatched-closing" : "invalid-closing-delimiter", locator.locateRange(cursor, runEnd));
976
+ cursor = runEnd;
977
+ continue;
978
+ }
979
+ if (character !== "{") {
980
+ cursor += 1;
981
+ continue;
982
+ }
983
+ const openingEnd = readBraceRunEnd(instruction.content, cursor, "{");
984
+ const openingLength = openingEnd - cursor;
985
+ if (openingLength === 1) {
986
+ cursor = openingEnd;
987
+ continue;
988
+ }
989
+ if (openingLength > 2) {
990
+ addMalformedDiagnostic(collector, instruction, agentId, "invalid-opening-delimiter", locator.locateRange(cursor, openingEnd));
991
+ cursor = openingEnd;
992
+ continue;
993
+ }
994
+ let candidateCursor = openingEnd;
995
+ let isCandidateComplete = false;
996
+ while (candidateCursor < instruction.content.length) {
997
+ const candidateCharacter = instruction.content[candidateCursor];
998
+ if (candidateCharacter === "{") {
999
+ const nestedOpeningEnd = readBraceRunEnd(instruction.content, candidateCursor, "{");
1000
+ if (nestedOpeningEnd - candidateCursor >= 2) {
1001
+ const malformedEnd = findClosingRunEnd(instruction.content, nestedOpeningEnd);
1002
+ addMalformedDiagnostic(collector, instruction, agentId, "nested-opening", locator.locateRange(cursor, malformedEnd));
1003
+ cursor = malformedEnd;
1004
+ isCandidateComplete = true;
1005
+ break;
1006
+ }
1007
+ candidateCursor = nestedOpeningEnd;
1008
+ continue;
1009
+ }
1010
+ if (candidateCharacter !== "}") {
1011
+ candidateCursor += 1;
1012
+ continue;
1013
+ }
1014
+ const closingEnd = readBraceRunEnd(instruction.content, candidateCursor, "}");
1015
+ const closingLength = closingEnd - candidateCursor;
1016
+ if (closingLength === 1) {
1017
+ candidateCursor = closingEnd;
1018
+ continue;
1019
+ }
1020
+ if (closingLength > 2) {
1021
+ addMalformedDiagnostic(collector, instruction, agentId, "invalid-closing-delimiter", locator.locateRange(cursor, closingEnd));
1022
+ cursor = closingEnd;
1023
+ isCandidateComplete = true;
1024
+ break;
1025
+ }
1026
+ const variableId = instruction.content.slice(openingEnd, candidateCursor);
1027
+ const placeholderRange = locator.locateRange(cursor, closingEnd);
1028
+ if (isVariableId(variableId)) recordOccurrence(occurrences, variableId, placeholderRange);
1029
+ else addMalformedDiagnostic(collector, instruction, agentId, "invalid-variable-id", placeholderRange);
1030
+ cursor = closingEnd;
1031
+ isCandidateComplete = true;
1032
+ break;
1033
+ }
1034
+ if (!isCandidateComplete) {
1035
+ addMalformedDiagnostic(collector, instruction, agentId, "unmatched-opening", locator.locateRange(cursor, instruction.content.length));
1036
+ cursor = instruction.content.length;
1037
+ }
1038
+ }
1039
+ for (const variableId of [...occurrences.keys()].sort(compareExactStrings)) {
1040
+ if (declaredVariables[variableId] !== void 0) continue;
1041
+ const occurrence = occurrences.get(variableId);
1042
+ if (occurrence === void 0) continue;
1043
+ collector.add({
1044
+ code: "MOLDEA_VARIABLE_UNDECLARED",
1045
+ details: { occurrences: occurrence.count },
1046
+ entity: {
1047
+ agentId,
1048
+ variableId
1049
+ },
1050
+ path: instruction.path,
1051
+ range: occurrence.firstRange
1052
+ });
1053
+ }
1054
+ for (const variableId of Object.keys(declaredVariables).sort(compareExactStrings)) {
1055
+ if (occurrences.has(variableId)) continue;
1056
+ collector.add({
1057
+ code: "MOLDEA_VARIABLE_UNUSED",
1058
+ entity: {
1059
+ agentId,
1060
+ variableId
1061
+ },
1062
+ path: manifestPath,
1063
+ pointer: `/agents/${escapeJsonPointerSegment(agentId)}/variables/${escapeJsonPointerSegment(variableId)}`
1064
+ });
1065
+ }
1066
+ return collector.finalize();
1067
+ };
1068
+ //#endregion
1069
+ //#region src/agent-assets/index.ts
1070
+ var MANIFEST_PATH$2 = parseRepositoryPath("/moldea/moldea.yaml");
1071
+ var addDiagnostics$4 = (collector, diagnostics) => {
1072
+ for (const diagnostic of diagnostics) collector.merge(diagnostic);
1073
+ };
1074
+ var isBlockedPath$2 = (path, blockedPaths) => {
1075
+ let candidate = path;
1076
+ while (candidate.length > 0) {
1077
+ if (blockedPaths.has(candidate)) return true;
1078
+ const separatorIndex = candidate.lastIndexOf("/");
1079
+ if (separatorIndex <= 0) return false;
1080
+ candidate = candidate.slice(0, separatorIndex);
1081
+ }
1082
+ return false;
1083
+ };
1084
+ /** Reads and validates a required or optional description asset. */
1085
+ var readDescription = async (repository, path, agentId, kind, options, collector, signal) => {
1086
+ const readResult = await readRepositoryTextAsset(repository, path, options.limits, signal);
1087
+ addDiagnostics$4(collector, readResult.diagnostics);
1088
+ if (readResult.asset === null) return null;
1089
+ const validation = validateAgentDescription(readResult.asset, agentId, kind, options.limits);
1090
+ addDiagnostics$4(collector, validation.diagnostics);
1091
+ return validation.description;
1092
+ };
1093
+ /** Reads and validates a mandatory instruction asset. */
1094
+ var readInstruction = async (repository, path, agentId, declaration, options, collector, signal) => {
1095
+ const readResult = await readRepositoryTextAsset(repository, path, options.limits, signal);
1096
+ addDiagnostics$4(collector, readResult.diagnostics);
1097
+ if (readResult.asset === null) return null;
1098
+ const validation = validateAgentInstruction(readResult.asset, agentId, options.limits);
1099
+ addDiagnostics$4(collector, validation.diagnostics);
1100
+ if (validation.instruction !== null) addDiagnostics$4(collector, validateRuntimePlaceholders(MANIFEST_PATH$2, agentId, validation.instruction, declaration.variables ?? {}, options.limits));
1101
+ return validation.instruction;
1102
+ };
1103
+ /**
1104
+ * Reconciles registered agents with their convention-owned directories and Markdown assets.
1105
+ * @param repository The coherent source-neutral repository reader.
1106
+ * @param manifest The normalized manifest containing registered agents.
1107
+ * @param discovery The canonical inventory and path-owned structural diagnostics.
1108
+ * @param options The immutable Core configuration snapshot.
1109
+ * @param signal Optional cancellation forwarded to every repository read.
1110
+ * @returns Deeply immutable registered-agent assets and deterministic diagnostics.
1111
+ * @throws
1112
+ * - ENTRY_NOT_FOUND: A discovered agent asset disappeared from the reader snapshot.
1113
+ * - ENTRY_NOT_FILE: A discovered agent asset is no longer a regular file.
1114
+ * - ACCESS_DENIED: Access to the repository source was denied.
1115
+ * - SOURCE_UNAVAILABLE: The repository source is unavailable.
1116
+ * - SNAPSHOT_CHANGED: The repository snapshot changed during agent reads.
1117
+ * - INVALID_SOURCE_DATA: The repository reader returned invalid contract data.
1118
+ * - RESOURCE_LIMIT_EXCEEDED: A Core or repository resource limit was exceeded.
1119
+ * - ABORTED: Agent inspection or a repository operation was aborted.
1120
+ */
1121
+ var inspectAgentAssets = async (repository, manifest, discovery, options, signal) => {
1122
+ options = createCoreOperationOptionsSnapshot(options);
1123
+ const collector = createCoreDiagnosticCollector(options.limits, "validate-project");
1124
+ const agents = [];
1125
+ const registeredAgents = manifest.agents ?? {};
1126
+ const registeredIds = new Set(Object.keys(registeredAgents));
1127
+ const discoveredById = new Map(discovery.inventory.agents.map((agent) => [agent.id, agent]));
1128
+ const blockedPaths = new Set(discovery.diagnostics.flatMap((diagnostic) => diagnostic.path === null ? [] : [diagnostic.path]));
1129
+ for (const discovered of discovery.inventory.agents) if (!registeredIds.has(discovered.id)) collector.add({
1130
+ code: "MOLDEA_AGENT_DIRECTORY_UNREGISTERED",
1131
+ entity: { agentId: discovered.id },
1132
+ path: discovered.path
1133
+ });
1134
+ for (const agentId of [...registeredIds].sort(compareExactStrings)) {
1135
+ const declaration = registeredAgents[agentId];
1136
+ if (declaration === void 0) continue;
1137
+ const discovered = discoveredById.get(agentId);
1138
+ if (discovered === void 0) {
1139
+ const directoryPath = parseRepositoryPath(`/moldea/agents/${agentId}`);
1140
+ if (!isBlockedPath$2(directoryPath, blockedPaths)) collector.add({
1141
+ code: "MOLDEA_AGENT_DIRECTORY_MISSING",
1142
+ entity: { agentId },
1143
+ path: directoryPath
1144
+ });
1145
+ agents.push({
1146
+ declaration,
1147
+ description: null,
1148
+ handoffDescription: null,
1149
+ id: agentId,
1150
+ instruction: null
1151
+ });
1152
+ continue;
1153
+ }
1154
+ let description = null;
1155
+ let instruction = null;
1156
+ let handoffDescription = null;
1157
+ if (discovered.description === null) {
1158
+ const path = parseRepositoryPath(`${discovered.path}/description.md`);
1159
+ if (!isBlockedPath$2(path, blockedPaths)) collector.add({
1160
+ code: "MOLDEA_AGENT_DESCRIPTION_MISSING",
1161
+ entity: { agentId },
1162
+ path
1163
+ });
1164
+ } else description = await readDescription(repository, discovered.description, agentId, "description", options, collector, signal);
1165
+ if (discovered.instruction === null) {
1166
+ const path = parseRepositoryPath(`${discovered.path}/instruction.md`);
1167
+ if (!isBlockedPath$2(path, blockedPaths)) collector.add({
1168
+ code: "MOLDEA_AGENT_INSTRUCTION_MISSING",
1169
+ entity: { agentId },
1170
+ path
1171
+ });
1172
+ } else instruction = await readInstruction(repository, discovered.instruction, agentId, declaration, options, collector, signal);
1173
+ if (discovered.handoffDescription !== null) handoffDescription = await readDescription(repository, discovered.handoffDescription, agentId, "handoff-description", options, collector, signal);
1174
+ agents.push({
1175
+ declaration,
1176
+ description,
1177
+ handoffDescription,
1178
+ id: agentId,
1179
+ instruction
1180
+ });
1181
+ }
1182
+ const diagnostics = collector.finalize();
1183
+ return freezeRecursively({
1184
+ agents,
1185
+ diagnostics,
1186
+ valid: diagnostics.length === 0
1187
+ });
1188
+ };
1189
+ //#endregion
1190
+ //#region src/canonical-discovery-validation/index.ts
1191
+ var AGENT_ASSET_PATTERN = /^\/moldea\/agents\/([^/]+)\/(description|instruction|handoff-description)\.md$/u;
1192
+ var AGENT_DIRECTORY_PATTERN = /^\/moldea\/agents\/([^/]+)$/u;
1193
+ var DECISION_CANDIDATE_PATTERN = /^\/moldea\/decisions\/[^/]+\.md$/u;
1194
+ var readCanonicalFile = (path) => {
1195
+ if (path === "/moldea/moldea.yaml") return {
1196
+ agentId: null,
1197
+ fileKind: "manifest",
1198
+ kind: "canonical-file"
1199
+ };
1200
+ if (path === "/moldea/project.md") return {
1201
+ agentId: null,
1202
+ fileKind: "project",
1203
+ kind: "canonical-file"
1204
+ };
1205
+ if (isContextPath(path, false)) return {
1206
+ agentId: null,
1207
+ fileKind: "context",
1208
+ kind: "canonical-file"
1209
+ };
1210
+ if (DECISION_CANDIDATE_PATTERN.test(path)) return {
1211
+ agentId: null,
1212
+ fileKind: "decision",
1213
+ kind: "canonical-file"
1214
+ };
1215
+ if (isRuntimeGuidancePath(path)) return {
1216
+ agentId: null,
1217
+ fileKind: "runtime-guidance",
1218
+ kind: "canonical-file"
1219
+ };
1220
+ const agentAsset = AGENT_ASSET_PATTERN.exec(path);
1221
+ if (agentAsset === null) return null;
1222
+ const agentId = agentAsset[1];
1223
+ const fileName = agentAsset[2];
1224
+ if (agentId === void 0 || fileName === void 0) return null;
1225
+ return {
1226
+ agentId,
1227
+ fileKind: fileName === "description" ? "agent-description" : fileName === "instruction" ? "agent-instruction" : "agent-handoff-description",
1228
+ kind: "canonical-file"
1229
+ };
1230
+ };
1231
+ var readAgentDirectoryId = (path) => {
1232
+ return AGENT_DIRECTORY_PATTERN.exec(path)?.[1] ?? null;
1233
+ };
1234
+ var isRequiredDirectoryPath = (path) => {
1235
+ return path === "/moldea" || path === "/moldea/context" || path === "/moldea/decisions" || path === "/moldea/runtimes" || path === "/moldea/agents";
1236
+ };
1237
+ var isPermittedStructuralDirectoryPath = (path) => {
1238
+ return isRequiredDirectoryPath(path) || path.startsWith("/moldea/context/") || path.startsWith("/moldea/runtimes/");
1239
+ };
1240
+ /**
1241
+ * Classifies one reader entry against the version 1 canonical layout.
1242
+ * @param entry The detached entry beneath the canonical moldea root.
1243
+ * @returns Its canonical category or the precise structural failure category.
1244
+ */
1245
+ var classifyCanonicalEntry = (entry) => {
1246
+ const canonicalFile = readCanonicalFile(entry.path);
1247
+ if (canonicalFile !== null) {
1248
+ if (entry.type === "file") return canonicalFile;
1249
+ return entry.type === "symlink" ? { kind: "canonical-asset-symlink" } : {
1250
+ expectedType: "file",
1251
+ kind: "entry-type-invalid"
1252
+ };
1253
+ }
1254
+ const agentId = readAgentDirectoryId(entry.path);
1255
+ if (agentId !== null) return entry.type === "directory" ? {
1256
+ agentId,
1257
+ kind: "agent-directory"
1258
+ } : {
1259
+ expectedType: "directory",
1260
+ kind: "entry-type-invalid"
1261
+ };
1262
+ if (isRequiredDirectoryPath(entry.path)) return entry.type === "directory" ? { kind: "structural-directory" } : {
1263
+ expectedType: "directory",
1264
+ kind: "entry-type-invalid"
1265
+ };
1266
+ if (entry.type === "directory") return isPermittedStructuralDirectoryPath(entry.path) ? { kind: "structural-directory" } : { kind: "ignored-directory" };
1267
+ return { kind: "unrecognized" };
1268
+ };
1269
+ //#endregion
1270
+ //#region src/canonical-discovery/index.ts
1271
+ var MOLDEA_ROOT$1 = parseRepositoryPath("/moldea");
1272
+ var MANIFEST_PATH$1 = parseRepositoryPath("/moldea/moldea.yaml");
1273
+ var PROJECT_PATH$1 = parseRepositoryPath("/moldea/project.md");
1274
+ var createWorkingInventory = () => ({
1275
+ agents: /* @__PURE__ */ new Map(),
1276
+ context: /* @__PURE__ */ new Set(),
1277
+ decisions: /* @__PURE__ */ new Set(),
1278
+ manifest: null,
1279
+ project: null,
1280
+ runtimeGuidance: /* @__PURE__ */ new Set()
1281
+ });
1282
+ var invalidSourceData$1 = (operation, path) => {
1283
+ throw new RepositorySourceException({
1284
+ code: "INVALID_SOURCE_DATA",
1285
+ operation,
1286
+ path,
1287
+ retryable: false
1288
+ });
1289
+ };
1290
+ var copyReaderEntry = (candidate, operation, expectedPath) => {
1291
+ if (typeof candidate !== "object" || candidate === null) return invalidSourceData$1(operation, expectedPath ?? null);
1292
+ const record = candidate;
1293
+ const pathCandidate = record["path"];
1294
+ const typeCandidate = record["type"];
1295
+ const byteLength = record["byteLength"];
1296
+ const contentIdentity = record["contentIdentity"];
1297
+ if (typeof pathCandidate !== "string" || !isRepositoryPath(pathCandidate)) return invalidSourceData$1(operation, expectedPath ?? null);
1298
+ const path = parseRepositoryPath(pathCandidate);
1299
+ if (expectedPath !== void 0 && path !== expectedPath) return invalidSourceData$1(operation, path);
1300
+ if (typeCandidate !== "file" && typeCandidate !== "directory" && typeCandidate !== "symlink") return invalidSourceData$1(operation, path);
1301
+ if (typeCandidate === "file" ? !Number.isSafeInteger(byteLength) || byteLength < 0 || contentIdentity !== null && typeof contentIdentity !== "string" : byteLength !== null || contentIdentity !== null) return invalidSourceData$1(operation, path);
1302
+ return {
1303
+ byteLength,
1304
+ contentIdentity,
1305
+ path,
1306
+ type: typeCandidate
1307
+ };
1308
+ };
1309
+ var readExactEntry = async (repository, path, signal) => {
1310
+ const candidate = await repository.getEntry(path, signal === void 0 ? void 0 : { signal });
1311
+ return candidate === null ? null : copyReaderEntry(candidate, "get-entry", path);
1312
+ };
1313
+ var addEntryTypeDiagnostic = (diagnostics, entry, expectedType) => {
1314
+ diagnostics.add({
1315
+ code: "MOLDEA_ENTRY_TYPE_INVALID",
1316
+ details: {
1317
+ actualType: entry.type,
1318
+ expectedType
1319
+ },
1320
+ path: entry.path
1321
+ });
1322
+ };
1323
+ var getAgent = (agents, agentId) => {
1324
+ const existing = agents.get(agentId);
1325
+ if (existing !== void 0) return existing;
1326
+ const created = {
1327
+ description: null,
1328
+ handoffDescription: null,
1329
+ id: agentId,
1330
+ instruction: null,
1331
+ path: parseRepositoryPath(`/moldea/agents/${agentId}`)
1332
+ };
1333
+ agents.set(agentId, created);
1334
+ return created;
1335
+ };
1336
+ var retainCanonicalFile = (inventory, path, fileKind, agentId) => {
1337
+ switch (fileKind) {
1338
+ case "manifest":
1339
+ inventory.manifest = path;
1340
+ return;
1341
+ case "project":
1342
+ inventory.project = path;
1343
+ return;
1344
+ case "context":
1345
+ inventory.context.add(path);
1346
+ return;
1347
+ case "decision":
1348
+ inventory.decisions.add(path);
1349
+ return;
1350
+ case "runtime-guidance":
1351
+ inventory.runtimeGuidance.add(path);
1352
+ return;
1353
+ }
1354
+ if (agentId === null) return invalidSourceData$1("list-entries-page", path);
1355
+ const agent = getAgent(inventory.agents, agentId);
1356
+ if (fileKind === "agent-description") agent.description = path;
1357
+ else if (fileKind === "agent-instruction") agent.instruction = path;
1358
+ else agent.handoffDescription = path;
1359
+ };
1360
+ var finalizeInventory = (working) => {
1361
+ const sortPaths = (paths) => {
1362
+ return [...paths].sort(compareExactStrings);
1363
+ };
1364
+ const agents = [...working.agents.values()].sort((left, right) => compareExactStrings(left.id, right.id)).map((agent) => freezeRecursively({ ...agent }));
1365
+ return freezeRecursively({
1366
+ agents,
1367
+ context: sortPaths(working.context),
1368
+ decisions: sortPaths(working.decisions),
1369
+ manifest: working.manifest,
1370
+ project: working.project,
1371
+ runtimeGuidance: sortPaths(working.runtimeGuidance)
1372
+ });
1373
+ };
1374
+ var finalizeResult = (working, diagnostics) => {
1375
+ const finalizedDiagnostics = diagnostics.finalize();
1376
+ return freezeRecursively({
1377
+ diagnostics: finalizedDiagnostics,
1378
+ inventory: finalizeInventory(working),
1379
+ valid: finalizedDiagnostics.length === 0
1380
+ });
1381
+ };
1382
+ var retainFoundationEntry = (entry, expectedPath, missingCode, working, diagnostics) => {
1383
+ if (entry === null) {
1384
+ diagnostics.add({
1385
+ code: missingCode,
1386
+ path: expectedPath
1387
+ });
1388
+ return;
1389
+ }
1390
+ if (entry.type === "file") {
1391
+ if (expectedPath === MANIFEST_PATH$1) working.manifest = expectedPath;
1392
+ else working.project = expectedPath;
1393
+ return;
1394
+ }
1395
+ if (entry.type === "symlink") {
1396
+ diagnostics.add({
1397
+ code: "MOLDEA_CANONICAL_ASSET_SYMLINK",
1398
+ path: expectedPath
1399
+ });
1400
+ return;
1401
+ }
1402
+ addEntryTypeDiagnostic(diagnostics, entry, "file");
1403
+ };
1404
+ var checkFoundationListing = (listedEntry, exactEntry) => {
1405
+ if (exactEntry === null || exactEntry.type !== listedEntry.type) return invalidSourceData$1("list-entries-page", listedEntry.path);
1406
+ };
1407
+ /**
1408
+ * Discovers and classifies version 1 canonical assets through one repository snapshot.
1409
+ * @param repository The coherent source-neutral repository reader.
1410
+ * @param limits The immutable Core limits governing diagnostic collection.
1411
+ * @param signal Optional cancellation forwarded to every repository operation.
1412
+ * @param foundations Optional exact foundation entries already observed by this inspection.
1413
+ * @returns A deeply immutable inventory and its deterministic structural diagnostics.
1414
+ * @throws
1415
+ * - ENTRY_NOT_FOUND: The reader snapshot became inconsistent during discovery.
1416
+ * - ENTRY_NOT_DIRECTORY: The reader snapshot became inconsistent during discovery.
1417
+ * - ACCESS_DENIED: Access to the repository source was denied.
1418
+ * - SOURCE_UNAVAILABLE: The repository source was unavailable.
1419
+ * - SNAPSHOT_CHANGED: The repository snapshot changed during discovery.
1420
+ * - INVALID_SOURCE_DATA: The repository reader returned invalid contract data.
1421
+ * - RESOURCE_LIMIT_EXCEEDED: A Core or repository resource limit was exceeded.
1422
+ * - ABORTED: Discovery or a repository operation was aborted.
1423
+ */
1424
+ var discoverCanonicalAssets = async (repository, limits, signal, foundations) => {
1425
+ const diagnostics = createCoreDiagnosticCollector(limits, "validate-project");
1426
+ const working = createWorkingInventory();
1427
+ const moldeaEntry = foundations === void 0 ? await readExactEntry(repository, MOLDEA_ROOT$1, signal) : foundations.moldeaRoot;
1428
+ if (moldeaEntry === null) {
1429
+ diagnostics.add({
1430
+ code: "MOLDEA_MANIFEST_MISSING",
1431
+ path: MANIFEST_PATH$1
1432
+ });
1433
+ diagnostics.add({
1434
+ code: "MOLDEA_PROJECT_FILE_MISSING",
1435
+ path: PROJECT_PATH$1
1436
+ });
1437
+ return finalizeResult(working, diagnostics);
1438
+ }
1439
+ if (moldeaEntry.type !== "directory") {
1440
+ addEntryTypeDiagnostic(diagnostics, moldeaEntry, "directory");
1441
+ return finalizeResult(working, diagnostics);
1442
+ }
1443
+ const manifestEntry = foundations === void 0 ? await readExactEntry(repository, MANIFEST_PATH$1, signal) : foundations.manifest;
1444
+ const projectEntry = foundations === void 0 ? await readExactEntry(repository, PROJECT_PATH$1, signal) : foundations.project;
1445
+ retainFoundationEntry(manifestEntry, MANIFEST_PATH$1, "MOLDEA_MANIFEST_MISSING", working, diagnostics);
1446
+ retainFoundationEntry(projectEntry, PROJECT_PATH$1, "MOLDEA_PROJECT_FILE_MISSING", working, diagnostics);
1447
+ const seenPaths = /* @__PURE__ */ new Set();
1448
+ let listedManifest = false;
1449
+ let listedProject = false;
1450
+ const listOptions = signal === void 0 ? { prefix: MOLDEA_ROOT$1 } : {
1451
+ prefix: MOLDEA_ROOT$1,
1452
+ signal
1453
+ };
1454
+ for await (const candidate of repository.iterateEntries(listOptions)) {
1455
+ const entry = copyReaderEntry(candidate, "list-entries-page");
1456
+ if (!entry.path.startsWith("/moldea/")) return invalidSourceData$1("list-entries-page", entry.path);
1457
+ if (seenPaths.has(entry.path)) return invalidSourceData$1("list-entries-page", entry.path);
1458
+ seenPaths.add(entry.path);
1459
+ if (entry.path === MANIFEST_PATH$1) {
1460
+ checkFoundationListing(entry, manifestEntry);
1461
+ listedManifest = true;
1462
+ continue;
1463
+ }
1464
+ if (entry.path === PROJECT_PATH$1) {
1465
+ checkFoundationListing(entry, projectEntry);
1466
+ listedProject = true;
1467
+ continue;
1468
+ }
1469
+ const classification = classifyCanonicalEntry(entry);
1470
+ switch (classification.kind) {
1471
+ case "canonical-file":
1472
+ retainCanonicalFile(working, entry.path, classification.fileKind, classification.agentId);
1473
+ break;
1474
+ case "agent-directory":
1475
+ getAgent(working.agents, classification.agentId);
1476
+ break;
1477
+ case "canonical-asset-symlink":
1478
+ diagnostics.add({
1479
+ code: "MOLDEA_CANONICAL_ASSET_SYMLINK",
1480
+ path: entry.path
1481
+ });
1482
+ break;
1483
+ case "entry-type-invalid":
1484
+ addEntryTypeDiagnostic(diagnostics, entry, classification.expectedType);
1485
+ break;
1486
+ case "unrecognized": diagnostics.add({
1487
+ code: "MOLDEA_CANONICAL_PATH_UNRECOGNIZED",
1488
+ details: { entryType: entry.type },
1489
+ path: entry.path
1490
+ });
1491
+ }
1492
+ }
1493
+ if (manifestEntry !== null !== listedManifest) return invalidSourceData$1("list-entries-page", MANIFEST_PATH$1);
1494
+ if (projectEntry !== null !== listedProject) return invalidSourceData$1("list-entries-page", PROJECT_PATH$1);
1495
+ return finalizeResult(working, diagnostics);
1496
+ };
1497
+ //#endregion
1498
+ //#region src/decision-graph-validation/index.ts
1499
+ var sortCandidates = (candidates) => {
1500
+ return [...candidates].sort((left, right) => compareExactStrings(left.path, right.path));
1501
+ };
1502
+ var buildGraphIndex = (candidates) => {
1503
+ const mutableGroups = /* @__PURE__ */ new Map();
1504
+ for (const candidate of sortCandidates(candidates)) {
1505
+ if (candidate.id === null) continue;
1506
+ const group = mutableGroups.get(candidate.id) ?? [];
1507
+ group.push(candidate);
1508
+ mutableGroups.set(candidate.id, group);
1509
+ }
1510
+ const candidateGroups = /* @__PURE__ */ new Map();
1511
+ const nodes = /* @__PURE__ */ new Map();
1512
+ for (const id of [...mutableGroups.keys()].sort(compareExactStrings)) {
1513
+ const group = mutableGroups.get(id) ?? [];
1514
+ candidateGroups.set(id, group);
1515
+ if (group.length === 1 && group[0]?.decision !== null) {
1516
+ const decision = group[0]?.decision;
1517
+ if (decision !== void 0) nodes.set(id, decision);
1518
+ }
1519
+ }
1520
+ const edges = /* @__PURE__ */ new Map();
1521
+ for (const [id, decision] of nodes) {
1522
+ const resolvedTargets = decision.supersedes.filter((targetId) => {
1523
+ const group = candidateGroups.get(targetId);
1524
+ return group?.length === 1 && group[0]?.decision !== null;
1525
+ });
1526
+ edges.set(id, resolvedTargets);
1527
+ }
1528
+ return {
1529
+ candidateGroups,
1530
+ edges,
1531
+ nodes
1532
+ };
1533
+ };
1534
+ var collectDuplicateDiagnostics = (index, diagnostics) => {
1535
+ for (const [id, candidates] of index.candidateGroups) {
1536
+ if (candidates.length < 2) continue;
1537
+ for (const candidate of candidates) diagnostics.add({
1538
+ code: "MOLDEA_DECISION_ID_DUPLICATE",
1539
+ details: { occurrences: candidates.length },
1540
+ entity: { decisionId: id },
1541
+ path: candidate.path
1542
+ });
1543
+ }
1544
+ };
1545
+ var collectReferenceDiagnostics = (index, diagnostics) => {
1546
+ for (const decision of index.nodes.values()) for (const targetId of decision.supersedes) {
1547
+ if (index.candidateGroups.has(targetId)) continue;
1548
+ diagnostics.add({
1549
+ code: "MOLDEA_DECISION_REFERENCE_MISSING",
1550
+ details: { referencedDecisionId: targetId },
1551
+ entity: { decisionId: decision.id },
1552
+ path: decision.path,
1553
+ pointer: "/supersedes"
1554
+ });
1555
+ }
1556
+ };
1557
+ var collectStatusDiagnostics = (index, diagnostics) => {
1558
+ const activelySupersededIds = /* @__PURE__ */ new Set();
1559
+ for (const decision of index.nodes.values()) {
1560
+ if (decision.status !== "accepted" && decision.status !== "superseded") continue;
1561
+ for (const targetId of index.edges.get(decision.id) ?? []) {
1562
+ const target = index.nodes.get(targetId);
1563
+ if (target === void 0) continue;
1564
+ if (target.status === "superseded") {
1565
+ activelySupersededIds.add(targetId);
1566
+ continue;
1567
+ }
1568
+ diagnostics.add({
1569
+ code: "MOLDEA_DECISION_SUPERSESSION_STATUS_INVALID",
1570
+ details: {
1571
+ referencedDecisionId: targetId,
1572
+ sourceStatus: decision.status,
1573
+ targetStatus: target.status
1574
+ },
1575
+ entity: { decisionId: decision.id },
1576
+ path: decision.path,
1577
+ pointer: "/supersedes"
1578
+ });
1579
+ }
1580
+ }
1581
+ return activelySupersededIds;
1582
+ };
1583
+ var collectOrphanDiagnostics = (index, activelySupersededIds, diagnostics) => {
1584
+ for (const decision of index.nodes.values()) if (decision.status === "superseded" && !activelySupersededIds.has(decision.id)) diagnostics.add({
1585
+ code: "MOLDEA_DECISION_SUPERSEDED_ORPHAN",
1586
+ entity: { decisionId: decision.id },
1587
+ path: decision.path
1588
+ });
1589
+ };
1590
+ var calculateFinishOrder = (index) => {
1591
+ const visited = /* @__PURE__ */ new Set();
1592
+ const finished = [];
1593
+ for (const startId of index.nodes.keys()) {
1594
+ if (visited.has(startId)) continue;
1595
+ const stack = [{
1596
+ id: startId,
1597
+ nextNeighbor: 0
1598
+ }];
1599
+ visited.add(startId);
1600
+ while (stack.length > 0) {
1601
+ const current = stack.at(-1);
1602
+ if (current === void 0) break;
1603
+ const neighbor = (index.edges.get(current.id) ?? [])[current.nextNeighbor];
1604
+ if (neighbor === void 0) {
1605
+ finished.push(current.id);
1606
+ stack.pop();
1607
+ continue;
1608
+ }
1609
+ current.nextNeighbor += 1;
1610
+ if (!visited.has(neighbor)) {
1611
+ visited.add(neighbor);
1612
+ stack.push({
1613
+ id: neighbor,
1614
+ nextNeighbor: 0
1615
+ });
1616
+ }
1617
+ }
1618
+ }
1619
+ return finished;
1620
+ };
1621
+ var buildReverseEdges = (index) => {
1622
+ const reverseEdges = /* @__PURE__ */ new Map();
1623
+ for (const id of index.nodes.keys()) reverseEdges.set(id, []);
1624
+ for (const [sourceId, targets] of index.edges) for (const targetId of targets) reverseEdges.get(targetId)?.push(sourceId);
1625
+ for (const sources of reverseEdges.values()) sources.sort(compareExactStrings);
1626
+ return reverseEdges;
1627
+ };
1628
+ var findStronglyConnectedComponents = (index) => {
1629
+ const reverseEdges = buildReverseEdges(index);
1630
+ const visited = /* @__PURE__ */ new Set();
1631
+ const components = [];
1632
+ for (const startId of [...calculateFinishOrder(index)].reverse()) {
1633
+ if (visited.has(startId)) continue;
1634
+ const component = [];
1635
+ const stack = [startId];
1636
+ visited.add(startId);
1637
+ while (stack.length > 0) {
1638
+ const currentId = stack.pop();
1639
+ if (currentId === void 0) break;
1640
+ component.push(currentId);
1641
+ for (const sourceId of [...reverseEdges.get(currentId) ?? []].reverse()) if (!visited.has(sourceId)) {
1642
+ visited.add(sourceId);
1643
+ stack.push(sourceId);
1644
+ }
1645
+ }
1646
+ components.push(component.sort(compareExactStrings));
1647
+ }
1648
+ return components.sort((left, right) => compareExactStrings(left[0] ?? "", right[0] ?? ""));
1649
+ };
1650
+ var collectCycleDiagnostics = (index, diagnostics) => {
1651
+ for (const component of findStronglyConnectedComponents(index)) {
1652
+ if (component.length < 2) continue;
1653
+ const cycleRepresentativeDecisionId = component[0];
1654
+ if (cycleRepresentativeDecisionId === void 0) continue;
1655
+ for (const decisionId of component) {
1656
+ const decision = index.nodes.get(decisionId);
1657
+ if (decision !== void 0) diagnostics.add({
1658
+ code: "MOLDEA_DECISION_SUPERSESSION_CYCLE",
1659
+ details: {
1660
+ cycleRepresentativeDecisionId,
1661
+ cycleSize: component.length
1662
+ },
1663
+ entity: { decisionId },
1664
+ path: decision.path,
1665
+ pointer: "/supersedes"
1666
+ });
1667
+ }
1668
+ }
1669
+ };
1670
+ /**
1671
+ * Validates every trustworthy cross-file relationship in one decision candidate set.
1672
+ * @param candidates Discovered candidates with valid parsed decisions where available.
1673
+ * @param limits The immutable Core limits governing repository-level diagnostics.
1674
+ * @returns Deterministically sorted, deeply immutable graph diagnostics.
1675
+ * @throws
1676
+ * - RESOURCE_LIMIT_EXCEEDED: The repository-level diagnostic budget was exceeded.
1677
+ */
1678
+ var validateDecisionGraph = (candidates, limits) => {
1679
+ const diagnostics = createCoreDiagnosticCollector(limits, "validate-project");
1680
+ const index = buildGraphIndex(candidates);
1681
+ collectDuplicateDiagnostics(index, diagnostics);
1682
+ collectReferenceDiagnostics(index, diagnostics);
1683
+ collectCycleDiagnostics(index, diagnostics);
1684
+ collectOrphanDiagnostics(index, collectStatusDiagnostics(index, diagnostics), diagnostics);
1685
+ return diagnostics.finalize();
1686
+ };
1687
+ //#endregion
1688
+ //#region src/decision-graph/index.ts
1689
+ var invalidSourceData = (path) => {
1690
+ throw new RepositorySourceException({
1691
+ code: "INVALID_SOURCE_DATA",
1692
+ operation: "read-file-page",
1693
+ path,
1694
+ retryable: false
1695
+ });
1696
+ };
1697
+ var sortDecisions = (decisions) => {
1698
+ return [...decisions].sort((left, right) => {
1699
+ return compareExactStrings(left.id, right.id) || compareExactStrings(left.path, right.path);
1700
+ });
1701
+ };
1702
+ /**
1703
+ * Reads, parses, and validates every discovered decision through one repository snapshot.
1704
+ * @param repository The coherent source-neutral repository reader.
1705
+ * @param paths The decision candidates retained by canonical discovery.
1706
+ * @param options The immutable Core limit snapshot.
1707
+ * @param signal Optional cancellation forwarded to every repository read.
1708
+ * @returns A deeply immutable internal decision set and its deterministic diagnostics.
1709
+ * @throws
1710
+ * - ENTRY_NOT_FOUND: The requested repository entry was not found.
1711
+ * - ENTRY_NOT_FILE: The requested repository entry is not a file.
1712
+ * - ACCESS_DENIED: Access to the repository source was denied.
1713
+ * - SOURCE_UNAVAILABLE: The repository source is unavailable.
1714
+ * - SNAPSHOT_CHANGED: The repository snapshot changed during the operation.
1715
+ * - INVALID_SOURCE_DATA: The repository source returned invalid data.
1716
+ * - RESOURCE_LIMIT_EXCEEDED: A Core resource limit was exceeded.
1717
+ * - RESOURCE_LIMIT_EXCEEDED: A named repository resource limit was exceeded.
1718
+ * - ABORTED: The Core operation was aborted.
1719
+ * - ABORTED: The repository operation was aborted.
1720
+ */
1721
+ var readDecisionGraph = async (repository, paths, options, signal) => {
1722
+ options = createCoreOperationOptionsSnapshot(options);
1723
+ const diagnostics = createCoreDiagnosticCollector(options.limits, "validate-project");
1724
+ const candidates = [];
1725
+ const decisions = [];
1726
+ const readOptions = signal === void 0 ? void 0 : { signal };
1727
+ for (const path of [...paths].sort(compareExactStrings)) {
1728
+ const content = await repository.readCompleteFile(path, readOptions);
1729
+ if (!(content instanceof Uint8Array)) return invalidSourceData(path);
1730
+ const parsed = await parseDecisionDocument({
1731
+ content: content.slice(),
1732
+ path
1733
+ }, options, "validate-project");
1734
+ for (const diagnostic of parsed.diagnostics) diagnostics.merge(diagnostic);
1735
+ candidates.push({
1736
+ decision: parsed.decision,
1737
+ id: parseDecisionIdFromPath(path),
1738
+ path
1739
+ });
1740
+ if (parsed.decision !== null) decisions.push(parsed.decision);
1741
+ }
1742
+ for (const diagnostic of validateDecisionGraph(candidates, options.limits)) diagnostics.merge(diagnostic);
1743
+ const finalizedDiagnostics = diagnostics.finalize();
1744
+ return freezeRecursively({
1745
+ decisions: sortDecisions(decisions),
1746
+ diagnostics: finalizedDiagnostics,
1747
+ valid: finalizedDiagnostics.length === 0
1748
+ });
1749
+ };
1750
+ //#endregion
1751
+ //#region src/manifest-relationship-validation/index.ts
1752
+ /** Creates diagnostic entity metadata for a decision relationship. */
1753
+ var createDecisionEntity = (decisionPath, agentId) => {
1754
+ const decisionId = parseDecisionIdFromPath(decisionPath);
1755
+ return {
1756
+ ...agentId === void 0 ? {} : { agentId },
1757
+ ...decisionId === null ? {} : { decisionId }
1758
+ };
1759
+ };
1760
+ /** Adds a missing-context diagnostic unless discovery owns the target-path failure. */
1761
+ var validateContextRelationship = (referencedPath, pointer, validContextPaths, context, agentId) => {
1762
+ if (validContextPaths.has(referencedPath) || context.blockedPaths.has(referencedPath)) return;
1763
+ context.collector.add({
1764
+ code: "MOLDEA_REFERENCE_MISSING",
1765
+ details: { referencedPath },
1766
+ entity: agentId === void 0 ? null : { agentId },
1767
+ path: context.manifestPath,
1768
+ pointer
1769
+ });
1770
+ };
1771
+ /** Adds missing or inactive diagnostics for a decision relationship. */
1772
+ var validateDecisionRelationship = (referencedPath, pointer, context, agentId) => {
1773
+ if (!context.discoveredDecisionPaths.has(referencedPath)) {
1774
+ if (context.blockedPaths.has(referencedPath)) return;
1775
+ context.collector.add({
1776
+ code: "MOLDEA_DECISION_REFERENCE_MISSING",
1777
+ details: { referencedPath },
1778
+ entity: createDecisionEntity(referencedPath, agentId),
1779
+ path: context.manifestPath,
1780
+ pointer
1781
+ });
1782
+ return;
1783
+ }
1784
+ const parsedDecision = context.parsedDecisionsByPath.get(referencedPath);
1785
+ if (parsedDecision === void 0 || parsedDecision.status === "accepted") return;
1786
+ context.collector.add({
1787
+ code: "MOLDEA_DECISION_RELATIONSHIP_INACTIVE",
1788
+ details: {
1789
+ referencedPath,
1790
+ targetStatus: parsedDecision.status
1791
+ },
1792
+ entity: createDecisionEntity(referencedPath, agentId),
1793
+ path: context.manifestPath,
1794
+ pointer
1795
+ });
1796
+ };
1797
+ /**
1798
+ * Validates manifest and agent relationships against canonical discovery and parsed decisions.
1799
+ * @param manifestPath The canonical manifest path used for relationship diagnostics.
1800
+ * @param manifest The normalized manifest contract to validate.
1801
+ * @param discovery The canonical repository discovery result.
1802
+ * @param decisions The successfully parsed canonical decisions.
1803
+ * @param limits The resource limits applied to emitted diagnostics.
1804
+ * @returns The frozen deterministic relationship diagnostics.
1805
+ * @throws
1806
+ * - RESOURCE_LIMIT_EXCEEDED: The repository-level diagnostic budget was exceeded.
1807
+ */
1808
+ var validateManifestRelationships = (manifestPath, manifest, discovery, decisions, limits) => {
1809
+ const collector = createCoreDiagnosticCollector(limits, "validate-project");
1810
+ const validAgentContextPaths = new Set(discovery.inventory.context);
1811
+ const validTopLevelContextPaths = new Set(validAgentContextPaths);
1812
+ if (discovery.inventory.project !== null) validTopLevelContextPaths.add(discovery.inventory.project);
1813
+ const validationContext = {
1814
+ blockedPaths: new Set(discovery.diagnostics.flatMap((diagnostic) => diagnostic.path === null ? [] : [diagnostic.path])),
1815
+ collector,
1816
+ discoveredDecisionPaths: new Set(discovery.inventory.decisions),
1817
+ manifestPath,
1818
+ parsedDecisionsByPath: new Map(decisions.map((decision) => [decision.path, decision])),
1819
+ validAgentContextPaths,
1820
+ validTopLevelContextPaths
1821
+ };
1822
+ for (const referencedPathValue of Object.keys(manifest.context ?? {}).sort(compareExactStrings)) validateContextRelationship(parseRepositoryPath(referencedPathValue), `/context/${escapeJsonPointerSegment(referencedPathValue)}`, validationContext.validTopLevelContextPaths, validationContext);
1823
+ for (const referencedPathValue of Object.keys(manifest.decisions ?? {}).sort(compareExactStrings)) validateDecisionRelationship(parseRepositoryPath(referencedPathValue), `/decisions/${escapeJsonPointerSegment(referencedPathValue)}`, validationContext);
1824
+ for (const agentId of Object.keys(manifest.agents ?? {}).sort(compareExactStrings)) {
1825
+ const agent = manifest.agents?.[agentId];
1826
+ if (agent === void 0) continue;
1827
+ const escapedAgentId = escapeJsonPointerSegment(agentId);
1828
+ for (const referencedPath of [...agent.context ?? []].sort(compareExactStrings)) validateContextRelationship(referencedPath, `/agents/${escapedAgentId}/context`, validationContext.validAgentContextPaths, validationContext, agentId);
1829
+ for (const referencedPath of [...agent.decisions ?? []].sort(compareExactStrings)) validateDecisionRelationship(referencedPath, `/agents/${escapedAgentId}/decisions`, validationContext, agentId);
1830
+ }
1831
+ return collector.finalize();
1832
+ };
1833
+ //#endregion
1834
+ //#region src/integration-validation/parser.ts
1835
+ var START = "<!-- moldea:start -->";
1836
+ var END = "<!-- moldea:end -->";
1837
+ /** Finds one ordered marker pair on complete lines, matching the skill writer's region semantics. */
1838
+ var parseManagedIntegrationRegion = (text) => {
1839
+ const start = text.indexOf(START);
1840
+ const end = text.indexOf(END);
1841
+ if (start < 0 || end < start || text.indexOf(START, start + 21) >= 0 || text.indexOf(END, end + 19) >= 0) return null;
1842
+ const startsLine = (offset) => offset === 0 || offset === 1 && text[0] === "" || text[offset - 1] === "\n";
1843
+ if (!startsLine(start) || !startsLine(end)) return null;
1844
+ const afterStart = start + 21;
1845
+ const lineEnding = text.startsWith("\r\n", afterStart) ? "\r\n" : text[afterStart] === "\n" ? "\n" : null;
1846
+ if (lineEnding === null) return null;
1847
+ const afterEnd = end + 19;
1848
+ const endLength = text.startsWith("\r\n", afterEnd) ? 2 : text[afterEnd] === "\n" ? 1 : 0;
1849
+ if (endLength === 0 && afterEnd !== text.length) return null;
1850
+ return {
1851
+ start,
1852
+ end: afterEnd + endLength,
1853
+ lineEnding
1854
+ };
1855
+ };
1856
+ /**
1857
+ * Extracts the relative installation path from the fixed relevance-gate command without executing it.
1858
+ * @returns The safe installation path or the reason it could not be obtained.
1859
+ */
1860
+ var parseIntegrationBlock = (text) => {
1861
+ const region = parseManagedIntegrationRegion(text);
1862
+ if (region === null) return {
1863
+ kind: "missing",
1864
+ reason: text.includes(START) || text.includes(END) ? "block-invalid" : "block-missing"
1865
+ };
1866
+ const matches = text.slice(region.start, region.end).matchAll(/^node "<repo-root>\/([^"\r\n]+)\/scripts\/relevance-gate\.mjs"(?:[ \t\r]|$)/gm);
1867
+ const first = matches.next().value;
1868
+ if (first === void 0 || !matches.next().done) return {
1869
+ kind: "missing",
1870
+ reason: "skill-path-missing"
1871
+ };
1872
+ const skillPath = first[1];
1873
+ if (skillPath === void 0 || !/^[A-Za-z0-9._/-]+$/.test(skillPath) || skillPath.startsWith("/") || skillPath.endsWith("/") || skillPath.includes("//") || /(?:^|\/)\.{1,2}(?:\/|$)/.test(skillPath)) return {
1874
+ kind: "missing",
1875
+ reason: "skill-path-invalid"
1876
+ };
1877
+ return {
1878
+ kind: "found",
1879
+ skillPath
1880
+ };
1881
+ };
1882
+ //#endregion
1883
+ //#region src/integration-validation/inspection.ts
1884
+ var AGENTS_PATH = parseRepositoryPath("/AGENTS.md");
1885
+ /**
1886
+ * Reads bounded untrusted text with a reservation for decoding and temporary string copies.
1887
+ * @returns Decoded text or null for invalid UTF-8, with its reservation-release operation.
1888
+ * @throws
1889
+ * - ENTRY_NOT_FOUND: The requested repository entry was not found.
1890
+ * - ENTRY_NOT_FILE: The requested repository entry is not a file.
1891
+ * - RESOURCE_LIMIT_EXCEEDED: A Core resource limit was exceeded.
1892
+ * - RESOURCE_LIMIT_EXCEEDED: A named repository resource limit was exceeded.
1893
+ * - ABORTED: The Core operation was aborted.
1894
+ * - ABORTED: The repository operation was aborted.
1895
+ * - ACCESS_DENIED: Access to the repository source was denied.
1896
+ * - SOURCE_UNAVAILABLE: The repository source is unavailable.
1897
+ * - SNAPSHOT_CHANGED: The repository snapshot changed during the operation.
1898
+ * - INVALID_SOURCE_DATA: The repository source returned invalid data.
1899
+ */
1900
+ var readText = async (ledger, path) => {
1901
+ const source = await ledger.readSourceFile(path);
1902
+ const reservation = source.bytes.byteLength * 8;
1903
+ let isReserved = false;
1904
+ try {
1905
+ ledger.reserve(reservation);
1906
+ isReserved = true;
1907
+ let text;
1908
+ try {
1909
+ text = new TextDecoder("utf-8", { fatal: true }).decode(source.bytes);
1910
+ } catch {
1911
+ text = null;
1912
+ }
1913
+ return {
1914
+ text,
1915
+ release: () => ledger.release(reservation)
1916
+ };
1917
+ } catch (error) {
1918
+ if (isReserved) ledger.release(reservation);
1919
+ throw error;
1920
+ } finally {
1921
+ source.release();
1922
+ }
1923
+ };
1924
+ /** Distinguishes missing and non-regular files without an extra entry lookup or following symlinks. */
1925
+ var getAbsentKind = (error) => error instanceof RepositorySourceException ? error.code === "ENTRY_NOT_FOUND" ? "missing" : error.code === "ENTRY_NOT_FILE" ? "non-regular" : null : null;
1926
+ /**
1927
+ * Checks the root integration against its installed asset with at most two reads and two lookups.
1928
+ * @returns Completed content-free integration warnings, never an execution or runtime-wiring claim.
1929
+ * @throws
1930
+ * - RESOURCE_LIMIT_EXCEEDED: A Core resource limit was exceeded.
1931
+ * - RESOURCE_LIMIT_EXCEEDED: A named repository resource limit was exceeded.
1932
+ * - ABORTED: The Core operation was aborted.
1933
+ * - ABORTED: The repository operation was aborted.
1934
+ * - ACCESS_DENIED: Access to the repository source was denied.
1935
+ * - SOURCE_UNAVAILABLE: The repository source is unavailable.
1936
+ * - SNAPSHOT_CHANGED: The repository snapshot changed during the operation.
1937
+ * - INVALID_SOURCE_DATA: The repository source returned invalid data.
1938
+ */
1939
+ var inspectCodingAgentIntegration = async (reader, limits, signal) => {
1940
+ const ledger = getRetainedMemory(reader);
1941
+ const collector = createCoreDiagnosticCollector(limits, "validate-project");
1942
+ const report = (code, details) => {
1943
+ collector.add({
1944
+ code,
1945
+ path: AGENTS_PATH,
1946
+ subject: AGENTS_PATH,
1947
+ qualifier: null,
1948
+ entity: { integrationPath: AGENTS_PATH },
1949
+ details
1950
+ });
1951
+ return collector.finalize();
1952
+ };
1953
+ let document;
1954
+ try {
1955
+ document = await readText(ledger, AGENTS_PATH);
1956
+ } catch (error) {
1957
+ const entryKind = getAbsentKind(error);
1958
+ if (entryKind !== null) return report("MOLDEA_INTEGRATION_BLOCK_MISSING", { entryKind });
1959
+ throw error;
1960
+ }
1961
+ try {
1962
+ if (document.text === null) return report("MOLDEA_INTEGRATION_BLOCK_MISSING", {
1963
+ entryKind: "file",
1964
+ reason: "invalid-utf8"
1965
+ });
1966
+ const parsed = parseIntegrationBlock(document.text);
1967
+ if (parsed.kind === "missing") return report(parsed.reason.startsWith("block-") ? "MOLDEA_INTEGRATION_BLOCK_MISSING" : "MOLDEA_INTEGRATION_SKILL_MISSING", {
1968
+ entryKind: "file",
1969
+ reason: parsed.reason
1970
+ });
1971
+ const { skillPath } = parsed;
1972
+ for (const file of ["SKILL.md", "scripts/relevance-gate.mjs"]) {
1973
+ const path = parseRepositoryPath(`/${skillPath}/${file}`);
1974
+ const entry = await reader.getEntry(path, signal === void 0 ? void 0 : { signal });
1975
+ if (entry?.type !== "file") return report("MOLDEA_INTEGRATION_SKILL_MISSING", {
1976
+ referencedPath: `/${skillPath}`,
1977
+ missingFile: path,
1978
+ entryKind: entry?.type ?? "missing"
1979
+ });
1980
+ }
1981
+ const assetPath = parseRepositoryPath(`/${skillPath}/assets/managed-agents-block.md`);
1982
+ let asset;
1983
+ try {
1984
+ asset = await readText(ledger, assetPath);
1985
+ } catch (error) {
1986
+ const entryKind = getAbsentKind(error);
1987
+ if (entryKind !== null) return report("MOLDEA_INTEGRATION_SKILL_MISSING", {
1988
+ referencedPath: `/${skillPath}`,
1989
+ missingFile: assetPath,
1990
+ entryKind
1991
+ });
1992
+ throw error;
1993
+ }
1994
+ try {
1995
+ if (asset.text === null) return report("MOLDEA_INTEGRATION_BLOCK_STALE", {
1996
+ referencedPath: `/${skillPath}`,
1997
+ reason: "invalid-utf8-asset"
1998
+ });
1999
+ const region = parseManagedIntegrationRegion(document.text);
2000
+ let occurrences = 0;
2001
+ let offset = 0;
2002
+ while ((offset = asset.text.indexOf("{{skill-path}}", offset)) !== -1) {
2003
+ occurrences++;
2004
+ offset += 14;
2005
+ }
2006
+ const renderedReservation = (asset.text.length + occurrences * skillPath.length) * 8;
2007
+ ledger.reserve(renderedReservation);
2008
+ try {
2009
+ const expected = asset.text.replaceAll("{{skill-path}}", skillPath).replace(/\r\n?/g, "\n").replaceAll("\n", region.lineEnding);
2010
+ if (document.text.slice(region.start, region.end) !== expected) return report("MOLDEA_INTEGRATION_BLOCK_STALE", { referencedPath: `/${skillPath}` });
2011
+ } finally {
2012
+ ledger.release(renderedReservation);
2013
+ }
2014
+ return collector.finalize();
2015
+ } finally {
2016
+ asset.release();
2017
+ }
2018
+ } finally {
2019
+ document.release();
2020
+ }
2021
+ };
2022
+ //#endregion
2023
+ //#region src/impact-pattern-validation/inspection.ts
2024
+ /** Identifies the canonical document owning an impact relationship. */
2025
+ var getOwner = (owner) => {
2026
+ if (owner.kind === "context") return {
2027
+ subject: parseRepositoryPath(owner.id),
2028
+ entity: { contextPath: parseRepositoryPath(owner.id) }
2029
+ };
2030
+ if (owner.kind === "decision") return {
2031
+ subject: parseRepositoryPath(owner.id),
2032
+ entity: { decisionId: parseDecisionIdFromPath(parseRepositoryPath(owner.id)) ?? owner.id }
2033
+ };
2034
+ const agentId = owner.agentId ?? owner.id;
2035
+ return {
2036
+ subject: parseRepositoryPath(`/moldea/agents/${agentId}/instruction.md`),
2037
+ entity: {
2038
+ agentId,
2039
+ ...owner.kind === "tool" || owner.kind === "skill" ? {
2040
+ capabilityId: owner.id,
2041
+ capabilityKind: owner.kind
2042
+ } : {}
2043
+ }
2044
+ };
2045
+ };
2046
+ /** Groups patterns by their complete fixed directory prefix to share source traversal. */
2047
+ var groupPatterns = (manifest) => {
2048
+ const groups = /* @__PURE__ */ new Map();
2049
+ for (const declaration of collectManifestScopeDeclarations(manifest)) {
2050
+ if (declaration.field !== "affectedBy" || declaration.declaration.kind !== "glob") continue;
2051
+ const pattern = declaration.declaration.pattern;
2052
+ const segments = pattern.slice(1).split("/");
2053
+ const wildcard = segments.findIndex((segment) => segment.includes("*"));
2054
+ const prefix = parseRepositoryPath("/" + segments.slice(0, wildcard).join("/"));
2055
+ const group = groups.get(prefix) ?? [];
2056
+ group.push({
2057
+ declaration,
2058
+ pattern,
2059
+ segments
2060
+ });
2061
+ groups.set(prefix, group);
2062
+ }
2063
+ return groups;
2064
+ };
2065
+ /**
2066
+ * Checks globs only after required inspection, sharing bounded traversals and stopping on matches.
2067
+ * @returns Completed warnings, or no warnings when any traversal exhausts its resource budget.
2068
+ * @throws
2069
+ * - ABORTED: The Core operation was aborted.
2070
+ * - ABORTED: The repository operation was aborted.
2071
+ * - ENTRY_NOT_FOUND: The requested repository entry was not found.
2072
+ * - ENTRY_NOT_DIRECTORY: The requested repository entry is not a directory.
2073
+ * - PROVIDER_INCOMPLETE: The repository provider cannot expose a complete result.
2074
+ * - ACCESS_DENIED: Access to the repository source was denied.
2075
+ * - SOURCE_UNAVAILABLE: The repository source is unavailable.
2076
+ * - SNAPSHOT_CHANGED: The repository snapshot changed during the operation.
2077
+ * - INVALID_SOURCE_DATA: The repository source returned invalid data.
2078
+ * - RESOURCE_LIMIT_EXCEEDED: A Core resource limit was exceeded.
2079
+ */
2080
+ var inspectImpactPatterns = async (reader, manifest, limits, signal) => {
2081
+ const unmatched = [];
2082
+ try {
2083
+ for (const [prefix, patterns] of groupPatterns(manifest)) {
2084
+ const pending = new Set(patterns);
2085
+ if ((await reader.getEntry(prefix, signal === void 0 ? void 0 : { signal }))?.type === "directory") for await (const candidate of reader.iterateEntries({
2086
+ prefix,
2087
+ ...signal === void 0 ? {} : { signal }
2088
+ })) {
2089
+ if (candidate.type !== "file") continue;
2090
+ for (const pattern of pending) if (matchesRepositoryGlob(pattern.segments, candidate.path)) pending.delete(pattern);
2091
+ if (pending.size === 0) break;
2092
+ }
2093
+ unmatched.push(...pending);
2094
+ }
2095
+ } catch (error) {
2096
+ if (error instanceof CoreOperationException && error.code === "RESOURCE_LIMIT_EXCEEDED" && error.limit === "maxEntries" || error instanceof RepositorySourceException && error.code === "RESOURCE_LIMIT_EXCEEDED") return {
2097
+ completed: false,
2098
+ diagnostics: []
2099
+ };
2100
+ throw error;
2101
+ }
2102
+ const collector = createCoreDiagnosticCollector(limits, "validate-project");
2103
+ for (const { declaration, pattern } of unmatched) {
2104
+ const { subject, entity } = getOwner(declaration.owner);
2105
+ collector.add({
2106
+ code: "MOLDEA_IMPACT_PATTERN_UNMATCHED",
2107
+ path: parseRepositoryPath("/moldea/moldea.yaml"),
2108
+ pointer: declaration.pointer,
2109
+ subject,
2110
+ qualifier: pattern,
2111
+ entity,
2112
+ details: {
2113
+ pattern,
2114
+ owner: subject
2115
+ }
2116
+ });
2117
+ }
2118
+ return {
2119
+ completed: true,
2120
+ diagnostics: collector.finalize()
2121
+ };
2122
+ };
2123
+ //#endregion
2124
+ //#region src/warning-acceptance/acceptance.ts
2125
+ var identity = (entry) => JSON.stringify([
2126
+ entry.code,
2127
+ entry.subject,
2128
+ entry.qualifier ?? null
2129
+ ]);
2130
+ /**
2131
+ * Applies explicit manifest acceptances only to checks that completed, retaining all findings.
2132
+ * @returns Normalized diagnostics with acceptance flags, reasons, and obsolete-acceptance warnings.
2133
+ * @throws
2134
+ * - RESOURCE_LIMIT_EXCEEDED: A Core resource limit was exceeded.
2135
+ */
2136
+ var applyWarningAcceptances = (diagnostics, entries, completed, limits) => {
2137
+ const acceptances = new Map(entries.map((entry, index) => [identity(entry), {
2138
+ entry,
2139
+ index
2140
+ }]));
2141
+ const matched = /* @__PURE__ */ new Set();
2142
+ const results = diagnostics.map((diagnostic) => {
2143
+ if (diagnostic.severity !== "warning" || !diagnostic.acceptable || !completed.has(diagnostic.code)) return diagnostic;
2144
+ const key = identity(diagnostic);
2145
+ const acceptance = acceptances.get(key);
2146
+ if (acceptance === void 0) return diagnostic;
2147
+ matched.add(key);
2148
+ return freezeRecursively({
2149
+ ...diagnostic,
2150
+ accepted: true,
2151
+ reason: acceptance.entry.reason
2152
+ });
2153
+ });
2154
+ const collector = createCoreDiagnosticCollector(limits, "validate-project");
2155
+ for (const [key, { entry, index }] of acceptances) {
2156
+ if (matched.has(key) || !completed.has(entry.code)) continue;
2157
+ const pointer = `/acceptedWarnings/${index}`;
2158
+ collector.add({
2159
+ code: "MOLDEA_ACCEPTANCE_UNMATCHED",
2160
+ path: parseRepositoryPath("/moldea/moldea.yaml"),
2161
+ pointer,
2162
+ subject: parseRepositoryPath("/moldea/moldea.yaml"),
2163
+ qualifier: pointer,
2164
+ details: {
2165
+ code: entry.code,
2166
+ subject: entry.subject,
2167
+ qualifier: entry.qualifier ?? null
2168
+ }
2169
+ });
2170
+ }
2171
+ return normalizeDiagnostics([...results, ...collector.finalize()]);
2172
+ };
2173
+ //#endregion
2174
+ //#region src/mirrors/index.ts
2175
+ var addDiagnostics$3 = (collector, diagnostics) => {
2176
+ for (const diagnostic of diagnostics) collector.merge(diagnostic);
2177
+ };
2178
+ /** Adds one declaration-owned mirror diagnostic with safe target metadata. */
2179
+ var addMirrorDiagnostic = (collector, code, manifestPath, mirrorPath, pointer, agentId, entry) => {
2180
+ collector.add({
2181
+ code,
2182
+ details: {
2183
+ ...entry === void 0 ? {} : { actualType: entry.type },
2184
+ mirrorPath
2185
+ },
2186
+ entity: { agentId },
2187
+ path: manifestPath,
2188
+ pointer
2189
+ });
2190
+ };
2191
+ /** Resolves, normalizes, and compares one declared mirror. */
2192
+ var inspectMirror = async (repository, manifestPath, canonicalInstruction, mirrorPath, pointer, agentId, options, collector, operationOptions, signal) => {
2193
+ const entry = await repository.getEntry(mirrorPath, operationOptions);
2194
+ if (entry === null) {
2195
+ addMirrorDiagnostic(collector, "MOLDEA_MIRROR_MISSING", manifestPath, mirrorPath, pointer, agentId);
2196
+ return null;
2197
+ }
2198
+ if (entry.type === "symlink") {
2199
+ addMirrorDiagnostic(collector, "MOLDEA_MIRROR_SYMLINK", manifestPath, mirrorPath, pointer, agentId, entry);
2200
+ return null;
2201
+ }
2202
+ if (entry.type !== "file") {
2203
+ addMirrorDiagnostic(collector, "MOLDEA_MIRROR_NOT_FILE", manifestPath, mirrorPath, pointer, agentId, entry);
2204
+ return null;
2205
+ }
2206
+ const mirrorResult = await readRepositoryTextAsset(repository, mirrorPath, options.limits, signal);
2207
+ addDiagnostics$3(collector, mirrorResult.diagnostics);
2208
+ if (mirrorResult.asset === null) return null;
2209
+ if (mirrorResult.asset.content !== canonicalInstruction.content) {
2210
+ addMirrorDiagnostic(collector, "MOLDEA_MIRROR_STALE", manifestPath, mirrorPath, pointer, agentId);
2211
+ return null;
2212
+ }
2213
+ return {
2214
+ byteLength: mirrorResult.asset.utf8ByteLength,
2215
+ canonicalDigest: canonicalInstruction.digest,
2216
+ digest: mirrorResult.asset.digest,
2217
+ path: mirrorPath,
2218
+ scalarLength: mirrorResult.asset.scalarLength
2219
+ };
2220
+ };
2221
+ /**
2222
+ * Compares every declared mirror with its available normalized canonical instruction.
2223
+ * @param repository The budget-aware reader for the active inspection session.
2224
+ * @param manifestPath The canonical manifest path used for declaration diagnostics.
2225
+ * @param agents The registered agent assets and normalized instruction prerequisites.
2226
+ * @param options The immutable Core configuration snapshot.
2227
+ * @param signal Optional cancellation forwarded to every mirror lookup and read.
2228
+ * @returns Deeply immutable index-ready mirrors and deterministic diagnostics.
2229
+ * @throws
2230
+ * - INVALID_REPOSITORY_PATH: A repository path is invalid.
2231
+ * - ENTRY_NOT_FOUND: A confirmed mirror file disappeared from the reader snapshot.
2232
+ * - ENTRY_NOT_FILE: A confirmed mirror file changed type during inspection.
2233
+ * - ACCESS_DENIED: Access to the repository source was denied.
2234
+ * - SOURCE_UNAVAILABLE: The repository source is unavailable.
2235
+ * - SNAPSHOT_CHANGED: The repository snapshot changed during mirror inspection.
2236
+ * - INVALID_SOURCE_DATA: The repository reader returned invalid contract data.
2237
+ * - RESOURCE_LIMIT_EXCEEDED: A Core or repository resource limit was exceeded.
2238
+ * - ABORTED: Mirror inspection or a repository operation was aborted.
2239
+ */
2240
+ var inspectMirrors = async (repository, manifestPath, agents, options, signal) => {
2241
+ options = createCoreOperationOptionsSnapshot(options);
2242
+ const collector = createCoreDiagnosticCollector(options.limits, "validate-project");
2243
+ const agentMirrors = [];
2244
+ const operationOptions = signal === void 0 ? void 0 : { signal };
2245
+ for (const agent of [...agents].sort((left, right) => compareExactStrings(left.id, right.id))) {
2246
+ const mirrors = [];
2247
+ if (agent.instruction !== null) {
2248
+ const declaredMirrors = [...agent.declaration.mirrors ?? []].sort(compareExactStrings);
2249
+ for (const [index, mirrorPath] of declaredMirrors.entries()) {
2250
+ const mirror = await inspectMirror(repository, manifestPath, agent.instruction, mirrorPath, `/agents/${escapeJsonPointerSegment(agent.id)}/mirrors/${index}`, agent.id, options, collector, operationOptions, signal);
2251
+ if (mirror !== null) mirrors.push(mirror);
2252
+ }
2253
+ }
2254
+ agentMirrors.push({
2255
+ id: agent.id,
2256
+ mirrors
2257
+ });
2258
+ }
2259
+ const diagnostics = collector.finalize();
2260
+ return freezeRecursively({
2261
+ agentMirrors,
2262
+ diagnostics,
2263
+ valid: diagnostics.length === 0
2264
+ });
2265
+ };
2266
+ //#endregion
2267
+ //#region src/project-assets/index.ts
2268
+ var addDiagnostics$2 = (collector, diagnostics) => {
2269
+ for (const diagnostic of diagnostics) collector.merge(diagnostic);
2270
+ };
2271
+ /**
2272
+ * Reads and validates the project foundation before canonical enumeration.
2273
+ * @param repository The coherent source-neutral reader for the active inspection session.
2274
+ * @param path The canonical project path when its exact entry is a regular file.
2275
+ * @param options The immutable Core configuration snapshot.
2276
+ * @param signal Optional cancellation forwarded to the repository read.
2277
+ * @returns The deeply immutable project asset or deterministic content diagnostics.
2278
+ * @throws
2279
+ * - ENTRY_NOT_FOUND: The located project file disappeared from the snapshot.
2280
+ * - ENTRY_NOT_FILE: The located project entry changed type during inspection.
2281
+ * - ACCESS_DENIED: Access to the repository source was denied.
2282
+ * - SOURCE_UNAVAILABLE: The repository source is unavailable.
2283
+ * - SNAPSHOT_CHANGED: The repository snapshot changed during the project read.
2284
+ * - INVALID_SOURCE_DATA: The repository reader returned invalid contract data.
2285
+ * - RESOURCE_LIMIT_EXCEEDED: A Core or repository resource limit was exceeded.
2286
+ * - ABORTED: Project inspection or the repository read was aborted.
2287
+ */
2288
+ var readProjectFile = async (repository, path, options, signal) => {
2289
+ options = createCoreOperationOptionsSnapshot(options);
2290
+ const collector = createCoreDiagnosticCollector(options.limits, "validate-project");
2291
+ let project = null;
2292
+ if (path !== null) {
2293
+ const result = await readRepositoryTextAsset(repository, path, options.limits, signal);
2294
+ addDiagnostics$2(collector, result.diagnostics);
2295
+ if (result.asset !== null) {
2296
+ if (hasNonWhitespace(result.asset.content)) project = result.asset;
2297
+ else collector.add({
2298
+ code: "MOLDEA_PROJECT_FILE_EMPTY",
2299
+ path: result.asset.path
2300
+ });
2301
+ }
2302
+ }
2303
+ const diagnostics = collector.finalize();
2304
+ return freezeRecursively({
2305
+ diagnostics,
2306
+ project,
2307
+ valid: diagnostics.length === 0
2308
+ });
2309
+ };
2310
+ /**
2311
+ * Reads the project foundation and every discovered focused-context asset.
2312
+ * @param repository The coherent source-neutral reader for the active inspection session.
2313
+ * @param manifest The normalized manifest used to attach context relationships, when valid.
2314
+ * @param discovery The canonical inventory and path-owned structural diagnostics.
2315
+ * @param options The immutable Core configuration snapshot.
2316
+ * @param signal Optional cancellation forwarded to every repository read.
2317
+ * @param projectFile Optional project foundation already read before canonical enumeration.
2318
+ * @returns Deeply immutable valid assets and deterministic content diagnostics.
2319
+ * @throws
2320
+ * - ENTRY_NOT_FOUND: A discovered project or context file disappeared from the snapshot.
2321
+ * - ENTRY_NOT_FILE: A discovered project or context entry changed type during inspection.
2322
+ * - ACCESS_DENIED: Access to the repository source was denied.
2323
+ * - SOURCE_UNAVAILABLE: The repository source is unavailable.
2324
+ * - SNAPSHOT_CHANGED: The repository snapshot changed during asset reads.
2325
+ * - INVALID_SOURCE_DATA: The repository reader returned invalid contract data.
2326
+ * - RESOURCE_LIMIT_EXCEEDED: A Core or repository resource limit was exceeded.
2327
+ * - ABORTED: Project asset inspection or a repository operation was aborted.
2328
+ */
2329
+ var readProjectAssets = async (repository, manifest, discovery, options, signal, projectFile) => {
2330
+ options = createCoreOperationOptionsSnapshot(options);
2331
+ const collector = createCoreDiagnosticCollector(options.limits, "validate-project");
2332
+ const context = [];
2333
+ const inspectedProject = projectFile ?? await readProjectFile(repository, discovery.inventory.project, options, signal);
2334
+ addDiagnostics$2(collector, inspectedProject.diagnostics);
2335
+ for (const path of [...discovery.inventory.context].sort(compareExactStrings)) {
2336
+ const result = await readRepositoryTextAsset(repository, path, options.limits, signal);
2337
+ addDiagnostics$2(collector, result.diagnostics);
2338
+ if (result.asset === null) continue;
2339
+ if (!hasNonWhitespace(result.asset.content)) {
2340
+ collector.add({
2341
+ code: "MOLDEA_CONTEXT_FILE_EMPTY",
2342
+ path
2343
+ });
2344
+ continue;
2345
+ }
2346
+ context.push({
2347
+ asset: result.asset,
2348
+ relationships: manifest?.context?.[path] ?? null
2349
+ });
2350
+ }
2351
+ const diagnostics = collector.finalize();
2352
+ return freezeRecursively({
2353
+ context,
2354
+ diagnostics,
2355
+ project: inspectedProject.project,
2356
+ valid: diagnostics.length === 0
2357
+ });
2358
+ };
2359
+ //#endregion
2360
+ //#region src/project-index/index.ts
2361
+ var createIndexedDecisions = (decisions, manifest) => {
2362
+ return [...decisions].sort((left, right) => compareExactStrings(left.id, right.id) || compareExactStrings(left.path, right.path)).map((decision) => ({
2363
+ decision,
2364
+ relationships: manifest.value.decisions?.[decision.path] ?? null
2365
+ }));
2366
+ };
2367
+ var createIndexedAgents = (agents, agentMirrors) => {
2368
+ const mirrorsByAgent = new Map(agentMirrors.map((entry) => [entry.id, entry.mirrors]));
2369
+ const indexedAgents = [];
2370
+ if (mirrorsByAgent.size !== agents.length) return null;
2371
+ for (const agent of [...agents].sort((left, right) => compareExactStrings(left.id, right.id))) {
2372
+ const mirrors = mirrorsByAgent.get(agent.id);
2373
+ if (agent.description === null || agent.instruction === null || mirrors === void 0) return null;
2374
+ indexedAgents.push({
2375
+ context: [...agent.declaration.context ?? []].sort(compareExactStrings),
2376
+ decisions: [...agent.declaration.decisions ?? []].sort(compareExactStrings),
2377
+ declaration: agent.declaration,
2378
+ description: agent.description,
2379
+ handoffDescription: agent.handoffDescription,
2380
+ id: agent.id,
2381
+ instruction: agent.instruction,
2382
+ mirrors: [...mirrors].sort((left, right) => compareExactStrings(left.path, right.path))
2383
+ });
2384
+ }
2385
+ return indexedAgents;
2386
+ };
2387
+ /**
2388
+ * Constructs one deterministic provisional index from complete universal validation outputs.
2389
+ * @param input The normalized assets and relationships retained by universal inspection.
2390
+ * @returns The deeply immutable project index, or null when a required asset is unavailable.
2391
+ */
2392
+ var createProjectIndex = (input) => {
2393
+ const agents = createIndexedAgents(input.agents, input.agentMirrors);
2394
+ if (agents === null) return null;
2395
+ const unresolved = input.manifest.value.unresolved ?? createNullPrototypeRecord([]);
2396
+ return freezeRecursively({
2397
+ agents,
2398
+ context: [...input.context].sort((left, right) => compareExactStrings(left.asset.path, right.asset.path)),
2399
+ decisions: createIndexedDecisions(input.decisions, input.manifest),
2400
+ formatVersion: 1,
2401
+ manifest: input.manifest,
2402
+ project: input.project,
2403
+ runtimes: [...input.runtimes].sort((left, right) => compareExactStrings(left.asset.path, right.asset.path)),
2404
+ unresolved
2405
+ });
2406
+ };
2407
+ //#endregion
2408
+ //#region src/export-inventory/inventory.ts
2409
+ /** Identifies syntax-only source formats with explicit runtime export semantics. */
2410
+ var isSupportedExportSource = (path) => !/\.d\.(?:ts|tsx|mts|cts)$/.test(path) && /\.(?:ts|tsx|mts|cts|js|mjs|jsx)$/.test(path);
2411
+ /**
2412
+ * Reads and parses a declared source once, retaining only its export-name set.
2413
+ * @returns A conclusive inventory or the precise reason analysis could not run.
2414
+ * @throws
2415
+ * - RESOURCE_LIMIT_EXCEEDED: A Core resource limit was exceeded.
2416
+ * - RESOURCE_LIMIT_EXCEEDED: A named repository resource limit was exceeded.
2417
+ * - ABORTED: The Core operation was aborted.
2418
+ * - ABORTED: The repository operation was aborted.
2419
+ * - ACCESS_DENIED: Access to the repository source was denied.
2420
+ * - SOURCE_UNAVAILABLE: The repository source is unavailable.
2421
+ * - SNAPSHOT_CHANGED: The repository snapshot changed during the operation.
2422
+ * - INVALID_SOURCE_DATA: The repository source returned invalid data.
2423
+ * - ENTRY_NOT_FOUND: The requested repository entry was not found.
2424
+ * - ENTRY_NOT_FILE: The requested repository entry is not a file.
2425
+ */
2426
+ var readExportInventory = async (reader, path) => {
2427
+ if (!isSupportedExportSource(path)) return {
2428
+ kind: "not-checked",
2429
+ reason: "unsupported-file-type"
2430
+ };
2431
+ const ledger = getRetainedMemory(reader);
2432
+ const source = await ledger.readSourceFile(path);
2433
+ const reservation = 65536 + source.bytes.byteLength * 520;
2434
+ try {
2435
+ if (!ledger.tryReserve(reservation)) return {
2436
+ kind: "not-checked",
2437
+ reason: "resource-limit"
2438
+ };
2439
+ try {
2440
+ const { inventoryExports } = await import("./syntax-CVvExx4R.js");
2441
+ const result = inventoryExports(path, source.bytes);
2442
+ if (result.kind === "parsed") {
2443
+ let bytes = 64;
2444
+ for (const name of result.names) bytes += 64 + name.length * 2;
2445
+ ledger.reserve(bytes);
2446
+ }
2447
+ return result;
2448
+ } finally {
2449
+ ledger.release(reservation);
2450
+ }
2451
+ } finally {
2452
+ source.release();
2453
+ }
2454
+ };
2455
+ //#endregion
2456
+ //#region src/repository-reference-validation/index.ts
2457
+ var childPointer = (pointer, segment) => {
2458
+ return `${pointer}/${escapeJsonPointerSegment(segment)}`;
2459
+ };
2460
+ var compareNullableStrings = (left, right) => {
2461
+ if (left === void 0) return right === void 0 ? 0 : -1;
2462
+ return right === void 0 ? 1 : compareExactStrings(left, right);
2463
+ };
2464
+ var compareReferences = (left, right) => {
2465
+ return compareExactStrings(left.path, right.path) || compareNullableStrings(left.symbol, right.symbol);
2466
+ };
2467
+ /** Adds sorted repository-reference array entries with their normalized indexes. */
2468
+ var addReferenceCandidates = (candidates, references, pointer, entity, relationship) => {
2469
+ for (const [index, reference] of [...references ?? []].sort(compareReferences).entries()) candidates.push({
2470
+ entity,
2471
+ kind: "reference",
2472
+ path: reference.path,
2473
+ pointer: childPointer(pointer, String(index)),
2474
+ ...relationship === void 0 ? {} : { relationship },
2475
+ ...reference.symbol === void 0 ? {} : { symbol: reference.symbol }
2476
+ });
2477
+ };
2478
+ /** Adds sorted exact impact paths while retaining skipped glob indexes. */
2479
+ var addImpactCandidates = (candidates, affectedBy, pointer, entity) => {
2480
+ for (const [index, pattern] of [...affectedBy ?? []].sort(compareExactStrings).entries()) {
2481
+ if (pattern.includes("*")) continue;
2482
+ candidates.push({
2483
+ entity,
2484
+ kind: "impact",
2485
+ path: parseRepositoryPath(pattern),
2486
+ pointer: childPointer(pointer, String(index))
2487
+ });
2488
+ }
2489
+ };
2490
+ /** Adds repository-backed declarations owned by one context or decision relationship. */
2491
+ var addRelationshipCandidates = (candidates, relationship, pointer, entity) => {
2492
+ addReferenceCandidates(candidates, relationship.bindings, childPointer(pointer, "bindings"), entity, pointer.startsWith("/context/") ? "context-binding" : "decision-binding");
2493
+ addImpactCandidates(candidates, relationship.affectedBy, childPointer(pointer, "affectedBy"), entity);
2494
+ };
2495
+ /** Adds related repository references from sorted unresolved requirements. */
2496
+ var addUnresolvedCandidates = (candidates, requirements, pointer, entity) => {
2497
+ for (const requirementId of Object.keys(requirements ?? {}).sort(compareExactStrings)) {
2498
+ const requirement = requirements?.[requirementId];
2499
+ if (requirement === void 0) continue;
2500
+ addReferenceCandidates(candidates, requirement.related, childPointer(childPointer(pointer, requirementId), "related"), entity);
2501
+ }
2502
+ };
2503
+ /** Adds one capability's implementation, optional bindings, and exact impact paths. */
2504
+ var addCapabilityCandidates = (candidates, capability, capabilityKind, capabilityId, agentId, collectionPointer, additionalReferences = []) => {
2505
+ const capabilityPointer = childPointer(collectionPointer, capabilityId);
2506
+ const capabilityEntity = {
2507
+ agentId,
2508
+ capabilityId,
2509
+ capabilityKind
2510
+ };
2511
+ candidates.push({
2512
+ entity: capabilityEntity,
2513
+ kind: `${capabilityKind}-implementation`,
2514
+ relationship: `${capabilityKind}-implementation`,
2515
+ ...capability.implementation.symbol === void 0 ? {} : { symbol: capability.implementation.symbol },
2516
+ path: capability.implementation.path,
2517
+ pointer: childPointer(capabilityPointer, "implementation")
2518
+ });
2519
+ for (const [property, reference] of [["registration", capability.registration], ...additionalReferences]) if (reference !== void 0) candidates.push({
2520
+ entity: capabilityEntity,
2521
+ kind: "reference",
2522
+ path: reference.path,
2523
+ pointer: childPointer(capabilityPointer, property),
2524
+ relationship: `${capabilityKind}-${property === "inputSchema" ? "input-schema" : property === "outputSchema" ? "output-schema" : "registration"}`,
2525
+ ...reference.symbol === void 0 ? {} : { symbol: reference.symbol }
2526
+ });
2527
+ addImpactCandidates(candidates, capability.affectedBy, childPointer(capabilityPointer, "affectedBy"), capabilityEntity);
2528
+ };
2529
+ /** Adds all repository-backed declarations owned by one normalized agent. */
2530
+ var addAgentCandidates = (candidates, agentId, agent) => {
2531
+ const pointer = `/agents/${escapeJsonPointerSegment(agentId)}`;
2532
+ const entity = { agentId };
2533
+ const bindingsPointer = childPointer(pointer, "bindings");
2534
+ const bindings = agent.bindings;
2535
+ for (const property of [
2536
+ "runtimeAgent",
2537
+ "inputSchema",
2538
+ "outputSchema",
2539
+ "instructionLoader"
2540
+ ]) {
2541
+ const reference = bindings?.[property];
2542
+ if (reference !== void 0) candidates.push({
2543
+ entity,
2544
+ kind: "reference",
2545
+ path: reference.path,
2546
+ pointer: childPointer(bindingsPointer, property),
2547
+ relationship: {
2548
+ runtimeAgent: "runtime-agent",
2549
+ inputSchema: "agent-input-schema",
2550
+ outputSchema: "agent-output-schema",
2551
+ instructionLoader: "instruction-loader"
2552
+ }[property],
2553
+ ...reference.symbol === void 0 ? {} : { symbol: reference.symbol }
2554
+ });
2555
+ }
2556
+ for (const variableId of Object.keys(bindings?.variableProviders ?? {}).sort(compareExactStrings)) {
2557
+ const reference = bindings?.variableProviders?.[variableId];
2558
+ if (reference !== void 0) candidates.push({
2559
+ entity: {
2560
+ agentId,
2561
+ variableId
2562
+ },
2563
+ relationship: "variable-provider",
2564
+ ...reference.symbol === void 0 ? {} : { symbol: reference.symbol },
2565
+ kind: "reference",
2566
+ path: reference.path,
2567
+ pointer: childPointer(childPointer(bindingsPointer, "variableProviders"), variableId)
2568
+ });
2569
+ }
2570
+ addImpactCandidates(candidates, agent.affectedBy, childPointer(pointer, "affectedBy"), entity);
2571
+ const toolsPointer = childPointer(pointer, "tools");
2572
+ for (const capabilityId of Object.keys(agent.tools ?? {}).sort(compareExactStrings)) {
2573
+ const capability = agent.tools?.[capabilityId];
2574
+ if (capability !== void 0) addCapabilityCandidates(candidates, capability, "tool", capabilityId, agentId, toolsPointer, [["inputSchema", capability.inputSchema], ["outputSchema", capability.outputSchema]]);
2575
+ }
2576
+ const skillsPointer = childPointer(pointer, "skills");
2577
+ for (const capabilityId of Object.keys(agent.skills ?? {}).sort(compareExactStrings)) {
2578
+ const capability = agent.skills?.[capabilityId];
2579
+ if (capability !== void 0) addCapabilityCandidates(candidates, capability, "skill", capabilityId, agentId, skillsPointer);
2580
+ }
2581
+ addUnresolvedCandidates(candidates, agent.unresolved, childPointer(pointer, "unresolved"), entity);
2582
+ };
2583
+ /** Collects every repository-backed manifest declaration in deterministic pointer order. */
2584
+ var collectCandidates = (manifest) => {
2585
+ const candidates = [];
2586
+ for (const property of ["context", "decisions"]) {
2587
+ const relationships = manifest[property];
2588
+ for (const referencedPath of Object.keys(relationships ?? {}).sort(compareExactStrings)) {
2589
+ const relationship = relationships?.[referencedPath];
2590
+ if (relationship === void 0) continue;
2591
+ const pointer = childPointer(`/${property}`, referencedPath);
2592
+ const decisionId = property === "decisions" ? parseDecisionIdFromPath(parseRepositoryPath(referencedPath)) : null;
2593
+ addRelationshipCandidates(candidates, relationship, pointer, decisionId === null ? { contextPath: parseRepositoryPath(referencedPath) } : { decisionId });
2594
+ }
2595
+ }
2596
+ addUnresolvedCandidates(candidates, manifest.unresolved, "/unresolved", null);
2597
+ for (const agentId of Object.keys(manifest.agents ?? {}).sort(compareExactStrings)) {
2598
+ const agent = manifest.agents?.[agentId];
2599
+ if (agent !== void 0) addAgentCandidates(candidates, agentId, agent);
2600
+ }
2601
+ return candidates.sort((left, right) => compareExactStrings(left.pointer, right.pointer));
2602
+ };
2603
+ /** Tests whether discovery already owns a diagnostic for a path or one of its ancestors. */
2604
+ var isBlockedPath$1 = (path, blockedPaths) => {
2605
+ let candidate = path;
2606
+ while (candidate.length > 0) {
2607
+ if (blockedPaths.has(candidate)) return true;
2608
+ const separatorIndex = candidate.lastIndexOf("/");
2609
+ if (separatorIndex <= 0) return false;
2610
+ candidate = candidate.slice(0, separatorIndex);
2611
+ }
2612
+ return false;
2613
+ };
2614
+ /** Creates normalized diagnostic details for one failed exact lookup. */
2615
+ var createCandidateDetails = (candidate, entry) => {
2616
+ const details = { [candidate.kind === "impact" ? "impactPath" : "referencedPath"]: candidate.path };
2617
+ if (entry !== null) details["actualType"] = entry.type;
2618
+ if (candidate.kind === "tool-implementation" || candidate.kind === "skill-implementation") details["reason"] = entry === null ? "missing" : entry.type === "symlink" ? "symlink" : "not-file";
2619
+ return details;
2620
+ };
2621
+ /** Selects the most-specific diagnostic code for one failed exact lookup. */
2622
+ var getCandidateCode = (candidate, entry) => {
2623
+ if (entry?.type === "file") return null;
2624
+ if (candidate.kind === "tool-implementation") return "MOLDEA_TOOL_IMPLEMENTATION_MISSING";
2625
+ if (candidate.kind === "skill-implementation") return "MOLDEA_SKILL_IMPLEMENTATION_MISSING";
2626
+ if (candidate.kind === "impact") return entry === null ? "MOLDEA_IMPACT_PATH_MISSING" : "MOLDEA_IMPACT_PATH_NOT_FILE";
2627
+ if (entry === null) return "MOLDEA_REFERENCE_MISSING";
2628
+ return entry.type === "symlink" ? "MOLDEA_REFERENCE_SYMLINK" : "MOLDEA_REFERENCE_NOT_FILE";
2629
+ };
2630
+ /** Adds the one most-specific diagnostic for a resolved repository candidate. */
2631
+ var validateCandidate = (candidate, entry, manifestPath, collector) => {
2632
+ const code = getCandidateCode(candidate, entry);
2633
+ if (code === null) return;
2634
+ collector.add({
2635
+ code,
2636
+ details: createCandidateDetails(candidate, entry),
2637
+ entity: candidate.entity,
2638
+ path: manifestPath,
2639
+ pointer: candidate.pointer
2640
+ });
2641
+ };
2642
+ /**
2643
+ * Validates every manifest repository reference, binding, and exact impact path.
2644
+ * @param repository The budget-aware reader for the active inspection session.
2645
+ * @param manifestPath The canonical manifest path used for diagnostics.
2646
+ * @param manifest The normalized valid manifest contract to inspect.
2647
+ * @param discovery Canonical discovery state used to suppress dependent path diagnostics.
2648
+ * @param limits The resource limits applied to emitted diagnostics.
2649
+ * @param signal Optional cancellation forwarded to exact repository lookups.
2650
+ * @param coverage Operation-owned binding coverage populated only for regular files.
2651
+ * @returns Deeply immutable deterministic repository-reference diagnostics.
2652
+ * @throws
2653
+ * - INVALID_REPOSITORY_PATH: The repository path is invalid.
2654
+ * - ENTRY_NOT_FOUND: The requested repository entry was not found.
2655
+ * - ENTRY_NOT_FILE: The requested repository entry is not a file.
2656
+ * - ACCESS_DENIED: Access to the repository source was denied.
2657
+ * - SOURCE_UNAVAILABLE: The repository source is unavailable.
2658
+ * - SNAPSHOT_CHANGED: The repository snapshot changed during the operation.
2659
+ * - INVALID_SOURCE_DATA: The repository source returned invalid data.
2660
+ * - RESOURCE_LIMIT_EXCEEDED: A Core resource limit was exceeded.
2661
+ * - RESOURCE_LIMIT_EXCEEDED: A named repository resource limit was exceeded.
2662
+ * - ABORTED: The Core operation was aborted.
2663
+ * - ABORTED: The repository operation was aborted.
2664
+ */
2665
+ var validateRepositoryReferences = async (repository, manifestPath, manifest, discovery, limits, signal, coverage = []) => {
2666
+ const collector = createCoreDiagnosticCollector(limits, "validate-project");
2667
+ const blockedPaths = new Set(discovery.diagnostics.flatMap((diagnostic) => diagnostic.path === null ? [] : [diagnostic.path]));
2668
+ const inventories = /* @__PURE__ */ new Map();
2669
+ const entryCache = /* @__PURE__ */ new Map();
2670
+ const operationOptions = signal === void 0 ? void 0 : { signal };
2671
+ for (const candidate of collectCandidates(manifest)) {
2672
+ if (isBlockedPath$1(candidate.path, blockedPaths)) continue;
2673
+ let entryPromise = entryCache.get(candidate.path);
2674
+ if (entryPromise === void 0) {
2675
+ entryPromise = repository.getEntry(candidate.path, operationOptions);
2676
+ entryCache.set(candidate.path, entryPromise);
2677
+ }
2678
+ const entry = await entryPromise;
2679
+ validateCandidate(candidate, entry, manifestPath, collector);
2680
+ if (entry?.type !== "file" || candidate.relationship === void 0) continue;
2681
+ if (coverage.length >= limits.maxCoverage) throw new CoreOperationException({
2682
+ code: "RESOURCE_LIMIT_EXCEEDED",
2683
+ operation: "validate-project",
2684
+ limit: "maxCoverage",
2685
+ limitMaximum: limits.maxCoverage,
2686
+ observedUsage: coverage.length + 1,
2687
+ nextAction: "reduce-input-or-increase-limit"
2688
+ });
2689
+ const base = {
2690
+ entity: candidate.entity ?? {},
2691
+ relationship: candidate.relationship,
2692
+ path: candidate.path,
2693
+ symbol: candidate.symbol ?? null,
2694
+ fileCheck: "passed"
2695
+ };
2696
+ let record;
2697
+ if (candidate.symbol === void 0) record = {
2698
+ ...base,
2699
+ exportCheck: "not-checked",
2700
+ exportNotCheckedReason: "no-symbol"
2701
+ };
2702
+ else {
2703
+ let inventory = inventories.get(candidate.path);
2704
+ if (inventory === void 0) {
2705
+ inventory = await readExportInventory(repository, candidate.path);
2706
+ inventories.set(candidate.path, inventory);
2707
+ }
2708
+ if (inventory.kind === "not-checked") record = {
2709
+ ...base,
2710
+ exportCheck: "not-checked",
2711
+ exportNotCheckedReason: inventory.reason
2712
+ };
2713
+ else if (!inventory.complete) record = {
2714
+ ...base,
2715
+ exportCheck: "not-checked",
2716
+ exportNotCheckedReason: "unresolved-exports"
2717
+ };
2718
+ else if (inventory.names.has(candidate.symbol)) record = {
2719
+ ...base,
2720
+ exportCheck: "passed"
2721
+ };
2722
+ else {
2723
+ record = {
2724
+ ...base,
2725
+ exportCheck: "failed"
2726
+ };
2727
+ collector.add({
2728
+ code: "MOLDEA_REFERENCE_EXPORT_MISSING",
2729
+ entity: candidate.entity,
2730
+ path: manifestPath,
2731
+ pointer: candidate.pointer,
2732
+ details: {
2733
+ referencedPath: candidate.path,
2734
+ symbol: candidate.symbol,
2735
+ relationship: candidate.relationship
2736
+ }
2737
+ });
2738
+ }
2739
+ }
2740
+ reserveRetainedBytesIfTracked(repository, 512 + JSON.stringify(record).length * 2);
2741
+ coverage.push(record);
2742
+ }
2743
+ return collector.finalize();
2744
+ };
2745
+ //#endregion
2746
+ //#region src/runtime-guidance/index.ts
2747
+ var addDiagnostics$1 = (collector, diagnostics) => {
2748
+ for (const diagnostic of diagnostics) collector.merge(diagnostic);
2749
+ };
2750
+ var isBlockedPath = (path, blockedPaths) => {
2751
+ let candidate = path;
2752
+ while (candidate.length > 0) {
2753
+ if (blockedPaths.has(candidate)) return true;
2754
+ const separatorIndex = candidate.lastIndexOf("/");
2755
+ if (separatorIndex <= 0) return false;
2756
+ candidate = candidate.slice(0, separatorIndex);
2757
+ }
2758
+ return false;
2759
+ };
2760
+ /**
2761
+ * Reads all discovered runtime guidance and validates every manifest guidance relationship.
2762
+ * @param repository The coherent source-neutral repository reader.
2763
+ * @param manifestPath The canonical manifest path used for relationship diagnostics.
2764
+ * @param manifest The normalized manifest declaring optional agent guidance paths, when valid.
2765
+ * @param discovery The canonical inventory and path-owned structural diagnostics.
2766
+ * @param options The immutable Core configuration snapshot.
2767
+ * @param signal Optional cancellation forwarded to every repository read.
2768
+ * @returns Deeply immutable valid guidance assets and deterministic diagnostics.
2769
+ * @throws
2770
+ * - ENTRY_NOT_FOUND: A discovered guidance file disappeared from the reader snapshot.
2771
+ * - ENTRY_NOT_FILE: A discovered guidance entry is no longer a regular file.
2772
+ * - ACCESS_DENIED: Access to the repository source was denied.
2773
+ * - SOURCE_UNAVAILABLE: The repository source is unavailable.
2774
+ * - SNAPSHOT_CHANGED: The repository snapshot changed during guidance reads.
2775
+ * - INVALID_SOURCE_DATA: The repository reader returned invalid contract data.
2776
+ * - RESOURCE_LIMIT_EXCEEDED: A Core or repository resource limit was exceeded.
2777
+ * - ABORTED: Guidance inspection or a repository operation was aborted.
2778
+ */
2779
+ var readRuntimeGuidance = async (repository, manifestPath, manifest, discovery, options, signal) => {
2780
+ options = createCoreOperationOptionsSnapshot(options);
2781
+ const collector = createCoreDiagnosticCollector(options.limits, "validate-project");
2782
+ const runtimes = [];
2783
+ const discoveredPaths = new Set(discovery.inventory.runtimeGuidance);
2784
+ const blockedPaths = new Set(discovery.diagnostics.flatMap((diagnostic) => diagnostic.path === null ? [] : [diagnostic.path]));
2785
+ for (const path of [...discoveredPaths].sort(compareExactStrings)) {
2786
+ const result = await readRepositoryTextAsset(repository, path, options.limits, signal);
2787
+ addDiagnostics$1(collector, result.diagnostics);
2788
+ if (result.asset === null) continue;
2789
+ if (!hasNonWhitespace(result.asset.content)) {
2790
+ collector.add({
2791
+ code: "MOLDEA_RUNTIME_GUIDANCE_EMPTY",
2792
+ path
2793
+ });
2794
+ continue;
2795
+ }
2796
+ runtimes.push({ asset: result.asset });
2797
+ }
2798
+ for (const agentId of Object.keys(manifest?.agents ?? {}).sort(compareExactStrings)) {
2799
+ const guidance = manifest?.agents?.[agentId]?.runtime.guidance;
2800
+ if (guidance === void 0 || discoveredPaths.has(guidance) || isBlockedPath(guidance, blockedPaths)) continue;
2801
+ collector.add({
2802
+ code: "MOLDEA_RUNTIME_GUIDANCE_MISSING",
2803
+ details: { referencedPath: guidance },
2804
+ entity: { agentId },
2805
+ path: manifestPath,
2806
+ pointer: `/agents/${escapeJsonPointerSegment(agentId)}/runtime/guidance`
2807
+ });
2808
+ }
2809
+ const diagnostics = collector.finalize();
2810
+ return freezeRecursively({
2811
+ diagnostics,
2812
+ runtimes,
2813
+ valid: diagnostics.length === 0
2814
+ });
2815
+ };
2816
+ //#endregion
2817
+ //#region src/universal-project-inspection/index.ts
2818
+ var MOLDEA_ROOT = parseRepositoryPath("/moldea");
2819
+ var MANIFEST_PATH = parseRepositoryPath("/moldea/moldea.yaml");
2820
+ var PROJECT_PATH = parseRepositoryPath("/moldea/project.md");
2821
+ var addDiagnostics = (collector, diagnostics) => {
2822
+ for (const diagnostic of diagnostics) collector.merge(diagnostic);
2823
+ };
2824
+ /**
2825
+ * Executes every universal repository-format phase with syntax-only export checks.
2826
+ * @param context The shared inspection session and optional cancellation signal.
2827
+ * @param options The immutable Core configuration snapshot.
2828
+ * @returns The frozen provisional index only when no universal diagnostic remains.
2829
+ * @throws
2830
+ * - INVALID_REPOSITORY_PATH: The repository path is invalid.
2831
+ * - ENTRY_NOT_FOUND: The requested repository entry was not found.
2832
+ * - ENTRY_NOT_FILE: The requested repository entry is not a file.
2833
+ * - ENTRY_NOT_DIRECTORY: The requested repository entry is not a directory.
2834
+ * - ACCESS_DENIED: Access to the repository source was denied.
2835
+ * - SOURCE_UNAVAILABLE: The repository source is unavailable.
2836
+ * - SNAPSHOT_CHANGED: The repository snapshot changed during the operation.
2837
+ * - INVALID_SOURCE_DATA: The repository source returned invalid data.
2838
+ * - RESOURCE_LIMIT_EXCEEDED: A Core resource limit was exceeded.
2839
+ * - RESOURCE_LIMIT_EXCEEDED: A named repository resource limit was exceeded.
2840
+ * - ABORTED: The Core operation was aborted.
2841
+ * - ABORTED: The repository operation was aborted.
2842
+ */
2843
+ var inspectUniversalProject = async (context, options) => {
2844
+ options = createCoreOperationOptionsSnapshot(options);
2845
+ const { session, signal } = context;
2846
+ const coverage = [];
2847
+ const collector = createCoreDiagnosticCollector(options.limits, "validate-project");
2848
+ const operationOptions = signal === void 0 ? void 0 : { signal };
2849
+ const moldeaRoot = await session.reader.getEntry(MOLDEA_ROOT, operationOptions);
2850
+ let manifestEntry = null;
2851
+ let projectEntry = null;
2852
+ let indexedManifest = null;
2853
+ let formatVersion = null;
2854
+ if (moldeaRoot?.type === "directory") {
2855
+ manifestEntry = await session.reader.getEntry(MANIFEST_PATH, operationOptions);
2856
+ if (manifestEntry?.type === "file") {
2857
+ const content = await session.reader.readCompleteFile(MANIFEST_PATH, operationOptions);
2858
+ const parsedManifest = await inspectManifestDocument({
2859
+ content,
2860
+ path: MANIFEST_PATH
2861
+ }, options, "validate-project");
2862
+ formatVersion = parsedManifest.formatVersion;
2863
+ addDiagnostics(collector, parsedManifest.diagnostics);
2864
+ if (parsedManifest.asset !== null && parsedManifest.manifest !== null) indexedManifest = {
2865
+ asset: parsedManifest.asset,
2866
+ value: parsedManifest.manifest
2867
+ };
2868
+ }
2869
+ projectEntry = await session.reader.getEntry(PROJECT_PATH, operationOptions);
2870
+ }
2871
+ const projectFile = await readProjectFile(session.reader, projectEntry?.type === "file" ? PROJECT_PATH : null, options, signal);
2872
+ addDiagnostics(collector, projectFile.diagnostics);
2873
+ const discovery = await discoverCanonicalAssets(session.reader, options.limits, signal, {
2874
+ manifest: manifestEntry,
2875
+ moldeaRoot,
2876
+ project: projectEntry
2877
+ });
2878
+ addDiagnostics(collector, discovery.diagnostics);
2879
+ session.throwIfAborted();
2880
+ const projectAssets = await readProjectAssets(session.reader, indexedManifest?.value ?? null, discovery, options, signal, projectFile);
2881
+ addDiagnostics(collector, projectAssets.diagnostics);
2882
+ const runtimeGuidance = await readRuntimeGuidance(session.reader, discovery.inventory.manifest ?? MANIFEST_PATH, indexedManifest?.value ?? null, discovery, options, signal);
2883
+ addDiagnostics(collector, runtimeGuidance.diagnostics);
2884
+ const decisionGraph = await readDecisionGraph(session.reader, discovery.inventory.decisions, options, signal);
2885
+ addDiagnostics(collector, decisionGraph.diagnostics);
2886
+ let agents = [];
2887
+ let agentMirrors = [];
2888
+ if (indexedManifest !== null) {
2889
+ const manifestPath = indexedManifest.asset.path;
2890
+ const agentAssets = await inspectAgentAssets(session.reader, indexedManifest.value, discovery, options, signal);
2891
+ agents = agentAssets.agents;
2892
+ addDiagnostics(collector, agentAssets.diagnostics);
2893
+ addDiagnostics(collector, validateManifestRelationships(manifestPath, indexedManifest.value, discovery, decisionGraph.decisions, options.limits));
2894
+ addDiagnostics(collector, await validateRepositoryReferences(session.reader, manifestPath, indexedManifest.value, discovery, options.limits, signal, coverage));
2895
+ const mirrorInspection = await inspectMirrors(session.reader, manifestPath, agents, options, signal);
2896
+ agentMirrors = mirrorInspection.agentMirrors;
2897
+ addDiagnostics(collector, mirrorInspection.diagnostics);
2898
+ }
2899
+ session.throwIfAborted();
2900
+ addDiagnostics(collector, await inspectCodingAgentIntegration(session.reader, options.limits, signal));
2901
+ const patterns = indexedManifest === null ? {
2902
+ completed: false,
2903
+ diagnostics: []
2904
+ } : await inspectImpactPatterns(session.reader, indexedManifest.value, options.limits, signal);
2905
+ session.throwIfAborted();
2906
+ addDiagnostics(collector, patterns.diagnostics);
2907
+ const diagnostics = applyWarningAcceptances(collector.finalize(), indexedManifest?.value.acceptedWarnings ?? [], /* @__PURE__ */ new Set([...[
2908
+ "MOLDEA_INTEGRATION_BLOCK_MISSING",
2909
+ "MOLDEA_INTEGRATION_SKILL_MISSING",
2910
+ "MOLDEA_INTEGRATION_BLOCK_STALE"
2911
+ ], ...patterns.completed ? ["MOLDEA_IMPACT_PATTERN_UNMATCHED"] : []]), options.limits);
2912
+ const project = !diagnostics.some((diagnostic) => diagnostic.severity === "error") && indexedManifest !== null && projectAssets.project !== null ? createProjectIndex({
2913
+ agentMirrors,
2914
+ agents,
2915
+ context: projectAssets.context,
2916
+ decisions: decisionGraph.decisions,
2917
+ manifest: indexedManifest,
2918
+ project: projectAssets.project,
2919
+ runtimes: runtimeGuidance.runtimes
2920
+ }) : null;
2921
+ return freezeRecursively({
2922
+ diagnostics,
2923
+ coverage,
2924
+ formatVersion,
2925
+ project
2926
+ });
2927
+ };
2928
+ //#endregion
2929
+ //#region src/project-validation/index.ts
2930
+ var isRecord = (candidate) => {
2931
+ return typeof candidate === "object" && candidate !== null && !Array.isArray(candidate);
2932
+ };
2933
+ var invalidArgument$1 = () => {
2934
+ throw new CoreOperationException({
2935
+ code: "INVALID_ARGUMENT",
2936
+ operation: "validate-project"
2937
+ });
2938
+ };
2939
+ var isRepositoryReader = (candidate) => {
2940
+ return isRecord(candidate) && isRecord(candidate["snapshot"]) && typeof candidate["snapshot"]["id"] === "string" && typeof candidate["snapshot"]["sourceKind"] === "string" && typeof candidate["compare"] === "function" && typeof candidate["getEntry"] === "function" && typeof candidate["listEntriesPage"] === "function" && typeof candidate["readFilePage"] === "function";
2941
+ };
2942
+ var isAbortSignal = (candidate) => {
2943
+ return isRecord(candidate) && typeof candidate["aborted"] === "boolean" && typeof candidate["addEventListener"] === "function" && typeof candidate["removeEventListener"] === "function";
2944
+ };
2945
+ var validateInput = (candidate) => {
2946
+ try {
2947
+ if (!isRecord(candidate)) return invalidArgument$1();
2948
+ const repository = candidate["repository"];
2949
+ const signal = candidate["signal"];
2950
+ if (Reflect.ownKeys(candidate).some((key) => key !== "repository" && key !== "signal") || !isRepositoryReader(repository) || signal !== void 0 && !isAbortSignal(signal)) return invalidArgument$1();
2951
+ return {
2952
+ repository,
2953
+ ...signal === void 0 ? {} : { signal }
2954
+ };
2955
+ } catch (error) {
2956
+ if (error instanceof CoreOperationException) throw error;
2957
+ return invalidArgument$1();
2958
+ }
2959
+ };
2960
+ /**
2961
+ * Inspects one coherent repository snapshot through universal file and export validation.
2962
+ * @param input The untrusted source-neutral reader and optional cancellation signal.
2963
+ * @param options The immutable Core configuration snapshot.
2964
+ * @returns A promise resolving to the frozen all-or-nothing project inspection result.
2965
+ * @throws
2966
+ * - INVALID_ARGUMENT: The Core operation received an invalid argument.
2967
+ * - INVALID_REPOSITORY_PATH: The repository path is invalid.
2968
+ * - ENTRY_NOT_FOUND: The requested repository entry was not found.
2969
+ * - ENTRY_NOT_FILE: The requested repository entry is not a file.
2970
+ * - ENTRY_NOT_DIRECTORY: The requested repository entry is not a directory.
2971
+ * - ACCESS_DENIED: Access to the repository source was denied.
2972
+ * - SOURCE_UNAVAILABLE: The repository source is unavailable.
2973
+ * - SNAPSHOT_CHANGED: The repository snapshot changed during the operation.
2974
+ * - PROVIDER_INCOMPLETE: The repository provider cannot expose a complete result.
2975
+ * - INVALID_SOURCE_DATA: The repository source returned invalid data.
2976
+ * - RESOURCE_LIMIT_EXCEEDED: A named repository resource limit was exceeded.
2977
+ * - RESOURCE_LIMIT_EXCEEDED: A Core resource limit was exceeded.
2978
+ * - ABORTED: The repository operation was aborted.
2979
+ * - ABORTED: The Core operation was aborted.
2980
+ */
2981
+ var validateProjectState = async (input, options) => {
2982
+ const validatedInput = validateInput(input);
2983
+ const operationOptions = createCoreOperationOptionsSnapshot(options);
2984
+ const session = createRepositoryInspectionSession(validatedInput.repository, operationOptions.limits, validatedInput.signal);
2985
+ const universal = await inspectUniversalProject({
2986
+ session,
2987
+ ...validatedInput.signal === void 0 ? {} : { signal: validatedInput.signal }
2988
+ }, operationOptions);
2989
+ session.throwIfAborted();
2990
+ const counts = countDiagnosticsBySeverity(universal.diagnostics);
2991
+ return freezeRecursively({
2992
+ project: universal.project,
2993
+ resourceUsage: session.getResourceUsage(),
2994
+ result: {
2995
+ diagnostics: universal.diagnostics,
2996
+ ...counts,
2997
+ coverage: universal.coverage,
2998
+ coverageCounts: countBindingCoverage(universal.coverage),
2999
+ formatVersion: universal.formatVersion,
3000
+ source: validatedInput.repository.snapshot,
3001
+ summary: universal.project === null ? null : createProjectSummary(universal.project),
3002
+ valid: counts.errorCount === 0
3003
+ }
3004
+ });
3005
+ };
3006
+ /**
3007
+ * Validates one project without returning canonical document bodies.
3008
+ * @param input The source-neutral reader and optional cancellation signal.
3009
+ * @param options The immutable operation limits.
3010
+ * @returns A promise resolving to the complete validation result.
3011
+ * @throws
3012
+ * - INVALID_ARGUMENT: The Core operation received an invalid argument.
3013
+ * - INVALID_REPOSITORY_PATH: The repository path is invalid.
3014
+ * - ENTRY_NOT_FOUND: The requested repository entry was not found.
3015
+ * - ENTRY_NOT_FILE: The requested repository entry is not a file.
3016
+ * - ENTRY_NOT_DIRECTORY: The requested repository entry is not a directory.
3017
+ * - ACCESS_DENIED: Access to the repository source was denied.
3018
+ * - SOURCE_UNAVAILABLE: The repository source is unavailable.
3019
+ * - SNAPSHOT_CHANGED: The repository snapshot changed during the operation.
3020
+ * - PROVIDER_INCOMPLETE: The repository provider cannot expose a complete result.
3021
+ * - INVALID_SOURCE_DATA: The repository source returned invalid data.
3022
+ * - RESOURCE_LIMIT_EXCEEDED: A named repository resource limit was exceeded.
3023
+ * - RESOURCE_LIMIT_EXCEEDED: A Core resource limit was exceeded.
3024
+ * - ABORTED: The repository operation was aborted.
3025
+ * - ABORTED: The Core operation was aborted.
3026
+ */
3027
+ var validateProject = async (input, options) => (await validateProjectState(input, options)).result;
3028
+ //#endregion
3029
+ //#region src/project-inspection/index.ts
3030
+ var CURSOR_PREFIX = "core7";
3031
+ var PREPARED_FIXED_BYTES = 512;
3032
+ var PREPARED_ITEM_FIXED_BYTES = 64;
3033
+ var PREPARED_TEXT_BYTE_MULTIPLIER = 2;
3034
+ var PREPARED_VIEW_REFERENCE_BYTES = 8;
3035
+ var encoder = new TextEncoder();
3036
+ var invalidArgument = () => {
3037
+ throw new CoreOperationException({
3038
+ code: "INVALID_ARGUMENT",
3039
+ operation: "create-project-inspection"
3040
+ });
3041
+ };
3042
+ var resourceLimitExceeded = (limitMaximum, observedUsage) => {
3043
+ throw new CoreOperationException({
3044
+ code: "RESOURCE_LIMIT_EXCEEDED",
3045
+ limit: "maxRetainedBytes",
3046
+ limitMaximum,
3047
+ nextAction: "reduce-input-or-increase-limit",
3048
+ observedUsage,
3049
+ operation: "create-project-inspection"
3050
+ });
3051
+ };
3052
+ /** Serializes content-free inspection state with recursively sorted object keys. */
3053
+ var serializeDeterministically = (candidate) => {
3054
+ if (candidate === null || typeof candidate !== "object") {
3055
+ const serialized = JSON.stringify(candidate);
3056
+ return serialized === void 0 ? "null" : serialized;
3057
+ }
3058
+ if (Array.isArray(candidate)) return `[${candidate.map((item) => serializeDeterministically(item)).join(",")}]`;
3059
+ return `{${Object.entries(candidate).filter(([, value]) => value !== void 0).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0).map(([key, value]) => `${JSON.stringify(key)}:${serializeDeterministically(value)}`).join(",")}}`;
3060
+ };
3061
+ var createIdentity = (parts) => createRepositoryIdentity((function* () {
3062
+ for (const part of parts) yield encoder.encode(part);
3063
+ })());
3064
+ var createItemBaseKey = (item) => {
3065
+ if (item.kind === "agent") return [
3066
+ "3",
3067
+ item.agent.agentId,
3068
+ item.agent.runtimeId
3069
+ ].join("\0");
3070
+ if (item.kind === "metadata") return [
3071
+ "0",
3072
+ item.metadata.path,
3073
+ item.metadata.kind,
3074
+ item.metadata.agentId ?? "",
3075
+ item.metadata.decisionId ?? "",
3076
+ item.metadata.digest
3077
+ ].join(":");
3078
+ if (item.kind === "diagnostic") return [
3079
+ "1",
3080
+ item.diagnostic.source,
3081
+ item.diagnostic.code,
3082
+ item.diagnostic.path ?? "",
3083
+ createIdentity([serializeDeterministically(item.diagnostic)])
3084
+ ].join(":");
3085
+ return [
3086
+ "2",
3087
+ item.coverage.path,
3088
+ item.coverage.relationship,
3089
+ item.coverage.entity.agentId ?? "",
3090
+ createIdentity([serializeDeterministically(item.coverage)])
3091
+ ].join(":");
3092
+ };
3093
+ /** Assigns stable unique keys once without relying on collection offsets. */
3094
+ var createKeyedItems = (items) => {
3095
+ const sorted = Array.from(items, (item) => ({
3096
+ item,
3097
+ key: createItemBaseKey(item)
3098
+ })).sort((left, right) => left.key < right.key ? -1 : left.key > right.key ? 1 : 0);
3099
+ let previousBaseKey = null;
3100
+ let occurrence = 0;
3101
+ for (const item of sorted) {
3102
+ const baseKey = item.key;
3103
+ occurrence = baseKey === previousBaseKey ? occurrence + 1 : 0;
3104
+ previousBaseKey = baseKey;
3105
+ item.key = `${baseKey}:${String(occurrence).padStart(10, "0")}`;
3106
+ }
3107
+ return sorted;
3108
+ };
3109
+ var createCursorChecksum = (inspectionDigest, lastKey, view) => createIdentity([
3110
+ CURSOR_PREFIX,
3111
+ inspectionDigest,
3112
+ lastKey,
3113
+ view
3114
+ ]);
3115
+ var encodeCursor = (inspectionDigest, view, lastKey) => [
3116
+ CURSOR_PREFIX,
3117
+ view,
3118
+ encodeURIComponent(lastKey),
3119
+ inspectionDigest,
3120
+ createCursorChecksum(inspectionDigest, lastKey, view)
3121
+ ].join(":");
3122
+ var decodeCursor = (cursor, inspectionDigest, view) => {
3123
+ if (cursor === void 0) return null;
3124
+ const match = /^core7:(all|diagnostics|coverage|metadata):([^:]+):(sha256:[0-9a-f]{64}):(sha256:[0-9a-f]{64})$/u.exec(cursor);
3125
+ if (match === null || match[1] !== view || match[3] !== inspectionDigest) return invalidArgument();
3126
+ let lastKey;
3127
+ try {
3128
+ lastKey = decodeURIComponent(match[2]);
3129
+ } catch {
3130
+ return invalidArgument();
3131
+ }
3132
+ if (lastKey.length === 0 || match[4] !== createCursorChecksum(inspectionDigest, lastKey, view)) return invalidArgument();
3133
+ return lastKey;
3134
+ };
3135
+ var createViews = (items) => freezeRecursively({
3136
+ all: items,
3137
+ diagnostics: items.filter(({ item }) => item.kind === "diagnostic"),
3138
+ coverage: items.filter(({ item }) => item.kind === "coverage"),
3139
+ metadata: items.filter(({ item }) => item.kind === "metadata" || item.kind === "agent")
3140
+ });
3141
+ var addRetainedBytes = (current, additional, retainedBeforePreparation, maximum) => {
3142
+ const projectedUsage = retainedBeforePreparation + current + additional;
3143
+ if (!Number.isSafeInteger(additional) || additional < 0 || !Number.isSafeInteger(projectedUsage) || projectedUsage > maximum) return resourceLimitExceeded(maximum, Number.isSafeInteger(projectedUsage) ? projectedUsage : Number.MAX_SAFE_INTEGER);
3144
+ return current + additional;
3145
+ };
3146
+ /** Iterates every content-free inspection item without retaining preparation state. */
3147
+ var iterateProjectInspectionItems = function* (state) {
3148
+ if (state.project !== null) for (const metadata of iterateProjectMetadata(state.project)) yield {
3149
+ kind: "metadata",
3150
+ metadata
3151
+ };
3152
+ for (const diagnostic of state.result.diagnostics) yield {
3153
+ diagnostic,
3154
+ kind: "diagnostic"
3155
+ };
3156
+ for (const coverage of state.result.coverage) yield {
3157
+ coverage,
3158
+ kind: "coverage"
3159
+ };
3160
+ if (state.project !== null) for (const agent of iterateProjectAgentAssignments(state.project)) yield {
3161
+ agent,
3162
+ kind: "agent"
3163
+ };
3164
+ };
3165
+ /** Preflights the complete logical prepared-state cost before retaining its collections. */
3166
+ var estimatePreparedProjectInspection = (state, baseCounts, maximum) => {
3167
+ const retainedBeforePreparation = state.resourceUsage.retainedBytes;
3168
+ let bytes = addRetainedBytes(0, PREPARED_FIXED_BYTES, retainedBeforePreparation, maximum);
3169
+ let metadataCount = 0;
3170
+ for (const item of iterateProjectInspectionItems(state)) {
3171
+ const key = `${createItemBaseKey(item)}:0000000000`;
3172
+ const encodedBytes = encoder.encode(key).byteLength + encoder.encode(serializeDeterministically(item)).byteLength;
3173
+ bytes = addRetainedBytes(bytes, PREPARED_ITEM_FIXED_BYTES + encodedBytes * PREPARED_TEXT_BYTE_MULTIPLIER + PREPARED_VIEW_REFERENCE_BYTES, retainedBeforePreparation, maximum);
3174
+ if (item.kind === "metadata") metadataCount += 1;
3175
+ }
3176
+ const counts = {
3177
+ agents: baseCounts.agents,
3178
+ context: baseCounts.context,
3179
+ decisions: baseCounts.decisions,
3180
+ diagnostics: baseCounts.diagnostics,
3181
+ errors: baseCounts.errors,
3182
+ coverage: baseCounts.coverage,
3183
+ metadata: metadataCount,
3184
+ mirrors: baseCounts.mirrors,
3185
+ runtimes: baseCounts.runtimes,
3186
+ unresolved: baseCounts.unresolved,
3187
+ warnings: baseCounts.warnings,
3188
+ acceptedWarnings: baseCounts.acceptedWarnings
3189
+ };
3190
+ bytes = addRetainedBytes(bytes, encoder.encode(serializeDeterministically({
3191
+ counts,
3192
+ formatVersion: state.result.formatVersion,
3193
+ inspectionDigest: "sha256:0000000000000000000000000000000000000000000000000000000000000000",
3194
+ source: state.result.source,
3195
+ summary: state.result.summary,
3196
+ valid: state.result.valid
3197
+ })).byteLength * PREPARED_TEXT_BYTE_MULTIPLIER, retainedBeforePreparation, maximum);
3198
+ return {
3199
+ counts,
3200
+ preparedBytes: bytes
3201
+ };
3202
+ };
3203
+ /** Creates the inspection digest without materializing a project-sized key projection. */
3204
+ var createInspectionDigest = (counts, coverageCounts, formatVersion, items, summary, valid) => createIdentity((function* () {
3205
+ yield "core7-prepared-inspection";
3206
+ yield serializeDeterministically({
3207
+ counts,
3208
+ coverageCounts,
3209
+ formatVersion,
3210
+ summary,
3211
+ valid
3212
+ });
3213
+ for (const { key } of items) yield key;
3214
+ })());
3215
+ var findStartIndex = (items, lastKey) => {
3216
+ if (lastKey === null) return 0;
3217
+ let lower = 0;
3218
+ let upper = items.length - 1;
3219
+ while (lower <= upper) {
3220
+ const middle = lower + Math.floor((upper - lower) / 2);
3221
+ const candidate = items[middle];
3222
+ if (candidate === void 0) return invalidArgument();
3223
+ if (candidate.key === lastKey) return middle + 1;
3224
+ if (candidate.key < lastKey) lower = middle + 1;
3225
+ else upper = middle - 1;
3226
+ }
3227
+ return invalidArgument();
3228
+ };
3229
+ /** Creates the returned inspection from content-free state only. */
3230
+ var createPreparedProjectInspection = (input) => {
3231
+ const { counts, coverageCounts, formatVersion, items, maxEntries, preparedBytes, resourceUsage: validationUsage, source, summary, valid } = input;
3232
+ const views = createViews(items);
3233
+ const inspectionDigest = createInspectionDigest(counts, coverageCounts, formatVersion, items, summary, valid);
3234
+ const resourceUsage = freezeRecursively({
3235
+ canonicalBytes: validationUsage.canonicalBytes,
3236
+ peakRetainedBytes: Math.max(validationUsage.peakRetainedBytes, validationUsage.retainedBytes + preparedBytes),
3237
+ preparedBytes,
3238
+ retainedBytes: preparedBytes,
3239
+ totalBytesRead: validationUsage.totalBytesRead
3240
+ });
3241
+ const readPage = (pageInput) => {
3242
+ if (typeof pageInput !== "object" || pageInput === null || Reflect.ownKeys(pageInput).some((key) => key !== "cursor" && key !== "maxItems" && key !== "view") || !Number.isSafeInteger(pageInput.maxItems) || pageInput.maxItems < 1 || pageInput.maxItems > maxEntries || pageInput.cursor !== void 0 && typeof pageInput.cursor !== "string" || pageInput.view !== "all" && pageInput.view !== "diagnostics" && pageInput.view !== "coverage" && pageInput.view !== "metadata") return invalidArgument();
3243
+ const viewItems = views[pageInput.view];
3244
+ const startIndex = findStartIndex(viewItems, decodeCursor(pageInput.cursor, inspectionDigest, pageInput.view));
3245
+ const records = viewItems.slice(startIndex, startIndex + pageInput.maxItems).map(({ item, key }, index) => {
3246
+ return {
3247
+ item,
3248
+ nextCursor: startIndex + index + 1 >= viewItems.length ? null : encodeCursor(inspectionDigest, pageInput.view, key)
3249
+ };
3250
+ });
3251
+ const nextCursor = records.at(-1)?.nextCursor ?? null;
3252
+ return freezeRecursively({
3253
+ counts,
3254
+ coverageCounts,
3255
+ formatVersion,
3256
+ inspectionDigest,
3257
+ page: {
3258
+ isComplete: nextCursor === null,
3259
+ nextCursor,
3260
+ records,
3261
+ totalItems: viewItems.length
3262
+ },
3263
+ source,
3264
+ summary,
3265
+ valid,
3266
+ view: pageInput.view
3267
+ });
3268
+ };
3269
+ return freezeRecursively({
3270
+ counts,
3271
+ coverageCounts,
3272
+ formatVersion,
3273
+ inspectionDigest,
3274
+ readPage,
3275
+ resourceUsage,
3276
+ source,
3277
+ summary,
3278
+ valid
3279
+ });
3280
+ };
3281
+ /**
3282
+ * Prepares one immutable content-free inspection for synchronous bounded page reads.
3283
+ * @param input The source-neutral reader and optional cancellation signal.
3284
+ * @param options The immutable operation limits.
3285
+ * @returns A promise resolving to the complete prepared inspection.
3286
+ * @throws
3287
+ * - INVALID_ARGUMENT: The Core operation received an invalid argument.
3288
+ * - INVALID_REPOSITORY_PATH: The repository path is invalid.
3289
+ * - ENTRY_NOT_FOUND: The requested repository entry was not found.
3290
+ * - ENTRY_NOT_FILE: The requested repository entry is not a file.
3291
+ * - ENTRY_NOT_DIRECTORY: The requested repository entry is not a directory.
3292
+ * - ACCESS_DENIED: Access to the repository source was denied.
3293
+ * - SOURCE_UNAVAILABLE: The repository source is unavailable.
3294
+ * - SNAPSHOT_CHANGED: The repository snapshot changed during the operation.
3295
+ * - PROVIDER_INCOMPLETE: The repository provider cannot expose a complete result.
3296
+ * - INVALID_SOURCE_DATA: The repository source returned invalid data.
3297
+ * - RESOURCE_LIMIT_EXCEEDED: A named repository resource limit was exceeded.
3298
+ * - RESOURCE_LIMIT_EXCEEDED: A Core resource limit was exceeded.
3299
+ * - ABORTED: The repository operation was aborted.
3300
+ * - ABORTED: The Core operation was aborted.
3301
+ */
3302
+ var createProjectInspection = async (input, options) => {
3303
+ const state = await validateProjectState(input, options);
3304
+ const estimate = estimatePreparedProjectInspection(state, {
3305
+ agents: state.result.summary?.counts.agents ?? 0,
3306
+ context: state.result.summary?.counts.context ?? 0,
3307
+ decisions: state.result.summary?.counts.decisions ?? 0,
3308
+ diagnostics: state.result.diagnostics.length,
3309
+ errors: state.result.errorCount,
3310
+ coverage: state.result.coverage.length,
3311
+ mirrors: state.result.summary?.counts.mirrors ?? 0,
3312
+ runtimes: state.result.summary?.counts.runtimes ?? 0,
3313
+ unresolved: state.result.summary?.counts.unresolved ?? 0,
3314
+ warnings: state.result.warningCount,
3315
+ acceptedWarnings: state.result.acceptedWarningCount
3316
+ }, options.limits.maxRetainedBytes);
3317
+ const counts = freezeRecursively(estimate.counts);
3318
+ const items = freezeRecursively(createKeyedItems(iterateProjectInspectionItems(state)));
3319
+ return createPreparedProjectInspection({
3320
+ counts,
3321
+ coverageCounts: state.result.coverageCounts,
3322
+ formatVersion: state.result.formatVersion,
3323
+ items,
3324
+ maxEntries: options.limits.maxEntries,
3325
+ preparedBytes: estimate.preparedBytes,
3326
+ resourceUsage: state.resourceUsage,
3327
+ source: state.result.source,
3328
+ summary: state.result.summary,
3329
+ valid: state.result.valid
3330
+ });
3331
+ };
3332
+ //#endregion
3333
+ //#region src/core/index.ts
3334
+ var core_exports = /* @__PURE__ */ __exportAll({ createCore: () => createCore });
3335
+ /**
3336
+ * Creates one immutable Core instance from detached configuration snapshots.
3337
+ * @param options Optional resource-limit overrides.
3338
+ * @returns A frozen Core instance safe for concurrent independent operations.
3339
+ * @throws
3340
+ * - INVALID_RESOURCE_LIMIT: A Core resource limit is invalid.
3341
+ */
3342
+ var createCore = (options) => {
3343
+ const snapshot = normalizeCoreOptions(options);
3344
+ return freezeRecursively({
3345
+ calculateContentDigest: (input) => {
3346
+ const operation = createCoreOperationOptionsSnapshot(snapshot);
3347
+ return calculateContentDigest(input, operation.limits);
3348
+ },
3349
+ createProjectInspection: (input) => createProjectInspection(input, createCoreOperationOptionsSnapshot(snapshot)),
3350
+ validateProject: (input) => validateProject(input, createCoreOperationOptionsSnapshot(snapshot)),
3351
+ matchManifestScope: (input) => matchManifestScope(input, createCoreOperationOptionsSnapshot(snapshot)),
3352
+ normalizeText: (input) => {
3353
+ const operation = createCoreOperationOptionsSnapshot(snapshot);
3354
+ return normalizeTextDocument(input, operation.limits, "normalize-text");
3355
+ },
3356
+ parseDecision: (input) => parseDecisionDocument(input, createCoreOperationOptionsSnapshot(snapshot)),
3357
+ parseManifest: (input) => parseManifestDocument(input, createCoreOperationOptionsSnapshot(snapshot)),
3358
+ readCanonicalContentPage: (input) => readCanonicalContentPage(input, createCoreOperationOptionsSnapshot(snapshot))
3359
+ });
3360
+ };
3361
+ //#endregion
3362
+ export { createCore as n, parseIntegrationBlock as r, core_exports as t };
3363
+
3364
+ //# sourceMappingURL=core-Cdeiu6xG.js.map