@yansirplus/cli 0.5.17

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 (47) hide show
  1. package/PUBLIC_API.md +22 -0
  2. package/README.md +34 -0
  3. package/dist/build/agent-authoring/config.d.ts +177 -0
  4. package/dist/build/agent-authoring/config.js +607 -0
  5. package/dist/build/agent-authoring/manifest-compiler.d.ts +159 -0
  6. package/dist/build/agent-authoring/manifest-compiler.js +737 -0
  7. package/dist/build/agent-authoring/shared.d.ts +10 -0
  8. package/dist/build/agent-authoring/shared.js +57 -0
  9. package/dist/build/agent-authoring/static-target.d.ts +59 -0
  10. package/dist/build/agent-authoring/static-target.js +1857 -0
  11. package/dist/build/agent-authoring.d.ts +9 -0
  12. package/dist/build/agent-authoring.js +5 -0
  13. package/dist/build/build-cli.d.ts +2 -0
  14. package/dist/build/build-cli.js +264 -0
  15. package/dist/check/algorithmic/architecture-checks.mjs +971 -0
  16. package/dist/check/algorithmic/client-boundary-checks.mjs +337 -0
  17. package/dist/check/algorithmic/convergence-smoke-checks.mjs +608 -0
  18. package/dist/check/algorithmic/distribution-checks.mjs +919 -0
  19. package/dist/check/algorithmic/owner-checks.mjs +647 -0
  20. package/dist/check/algorithmic/package-boundary-checks.mjs +985 -0
  21. package/dist/check/algorithmic/projection-boundary-checks.mjs +302 -0
  22. package/dist/check/algorithmic/repo-surface-checks.mjs +267 -0
  23. package/dist/check/algorithmic/runtime-structural-checks.mjs +264 -0
  24. package/dist/check/algorithmic/source-alias-checks.mjs +106 -0
  25. package/dist/check/algorithmic/static-target-checks.mjs +447 -0
  26. package/dist/check/algorithmic-checks.mjs +482 -0
  27. package/dist/check/check-coverage.mjs +231 -0
  28. package/dist/check/command-runner.mjs +22 -0
  29. package/dist/check/default-gate.mjs +51 -0
  30. package/dist/check/gate-selector.mjs +305 -0
  31. package/dist/check/manifest-rules.mjs +223 -0
  32. package/dist/check/package-graph.mjs +464 -0
  33. package/dist/generate/generate-agent-docs.mjs +435 -0
  34. package/dist/generate/generate-carrier-reference.mjs +514 -0
  35. package/dist/generate/generate-docs.mjs +345 -0
  36. package/dist/generate/generate-effect-skill-manifests.mjs +193 -0
  37. package/dist/generate/project-docs-site.mjs +190 -0
  38. package/dist/index.d.ts +2 -0
  39. package/dist/index.js +25 -0
  40. package/dist/lib/agent-docs-model.mjs +888 -0
  41. package/dist/lib/boundary-rules.mjs +63 -0
  42. package/dist/lib/capability-routes.mjs +354 -0
  43. package/dist/lib/projection-sink.mjs +113 -0
  44. package/dist/lib/public-api-model.mjs +306 -0
  45. package/dist/main.mjs +233 -0
  46. package/dist/runner.mjs +127 -0
  47. package/package.json +32 -0
@@ -0,0 +1,737 @@
1
+ import { isAgentSchema } from "@yansirplus/core/agent-schema";
2
+ import { authoredValue } from "@yansirplus/core/authored-value";
3
+ import { isAuthorityRef } from "@yansirplus/core/effect-claim";
4
+ import { isMaterialRef } from "@yansirplus/core/material-ref";
5
+ import { BUILTIN_HANDLER_KINDS } from "@yansirplus/core/runtime-protocol";
6
+ import { WORKSPACE_TOOL_DEFAULT_DECLARATIONS, } from "@yansirplus/runtime";
7
+ import { AUTHORING_DEFAULTS_VERSION, digestText, findFunctionPath, hasFunction, isNonEmptyString, isRecord, isWorkspaceToolName, } from "./shared.js";
8
+ const defaultOrigin = (factKey) => `default:${AUTHORING_DEFAULTS_VERSION}#${factKey}`;
9
+ export const workspaceManifestMacroOrigin = (factKey) => `macro(workspace@1)#${factKey}`;
10
+ const authoredPath = (path) => (path.startsWith("agent/") ? path : `agent/${path}`);
11
+ const authorOrigin = (path, pointer) => `author:${authoredPath(path)}#${pointer}`;
12
+ const pathOrigin = (path) => `path:${authoredPath(path)}`;
13
+ const isManifestMapId = (value) => value.length > 0 && !value.includes("/") && value !== "." && value !== "..";
14
+ const isExtensionHandlerKind = (value) => {
15
+ const separator = value.indexOf(".");
16
+ return separator > 0 && separator < value.length - 1;
17
+ };
18
+ const isHandlerKind = (value) => typeof value === "string" &&
19
+ (BUILTIN_HANDLER_KINDS.includes(value) ||
20
+ isExtensionHandlerKind(value));
21
+ const invalidAuthoredValue = (state, path, field, reason) => {
22
+ state.issues.push({ kind: "invalid_authored_value", path, field, reason });
23
+ };
24
+ const parseStringField = (state, path, field, value) => {
25
+ if (!isNonEmptyString(value)) {
26
+ invalidAuthoredValue(state, path, field, "non_empty_string_required");
27
+ return null;
28
+ }
29
+ return value;
30
+ };
31
+ const parseOptionalStringField = (state, path, field, value) => {
32
+ if (value === undefined)
33
+ return undefined;
34
+ return parseStringField(state, path, field, value) ?? undefined;
35
+ };
36
+ const parseStringArrayField = (state, path, field, value) => {
37
+ if (!Array.isArray(value)) {
38
+ invalidAuthoredValue(state, path, field, "array_required");
39
+ return null;
40
+ }
41
+ const out = [];
42
+ for (let index = 0; index < value.length; index += 1) {
43
+ const item = parseStringField(state, path, `${field}[${index}]`, value[index]);
44
+ if (item !== null)
45
+ out.push(item);
46
+ }
47
+ return out;
48
+ };
49
+ const parseHandlers = (state, path, value) => {
50
+ if (!Array.isArray(value)) {
51
+ invalidAuthoredValue(state, path, "/handlers", "array_required");
52
+ return null;
53
+ }
54
+ const handlers = [];
55
+ for (let index = 0; index < value.length; index += 1) {
56
+ const item = value[index];
57
+ if (!isHandlerKind(item)) {
58
+ invalidAuthoredValue(state, path, `/handlers/${index}`, "handler_kind_invalid");
59
+ continue;
60
+ }
61
+ handlers.push(item);
62
+ }
63
+ return handlers;
64
+ };
65
+ const parseScope = (state, path, value) => {
66
+ if (!isRecord(value)) {
67
+ invalidAuthoredValue(state, path, "/scope", "object_required");
68
+ return null;
69
+ }
70
+ assertAllowedFields(state, path, value, new Set(["kind", "idSource", "stableScopeId"]));
71
+ const kind = value.kind;
72
+ if (kind !== "realm" && kind !== "conversation" && kind !== "session" && kind !== "artifact") {
73
+ invalidAuthoredValue(state, path, "/scope/kind", "scope_kind_invalid");
74
+ return null;
75
+ }
76
+ const idSource = value.idSource;
77
+ if (idSource !== "submit_scope" && idSource !== "manifest" && idSource !== "extension") {
78
+ invalidAuthoredValue(state, path, "/scope/idSource", "scope_id_source_invalid");
79
+ return null;
80
+ }
81
+ const stableScopeId = parseOptionalStringField(state, path, "/scope/stableScopeId", value.stableScopeId);
82
+ return {
83
+ kind,
84
+ idSource,
85
+ ...(stableScopeId === undefined ? {} : { stableScopeId }),
86
+ };
87
+ };
88
+ const parseBindingRefObject = (state, path, field, value) => {
89
+ if (!isRecord(value)) {
90
+ invalidAuthoredValue(state, path, field, "object_required");
91
+ return null;
92
+ }
93
+ assertAllowedFields(state, path, value, new Set(["bindingRef"]));
94
+ const bindingRef = parseStringField(state, path, `${field}/bindingRef`, value.bindingRef);
95
+ return bindingRef === null ? null : { bindingRef };
96
+ };
97
+ const parseRecordMap = (state, path, field, value, parse) => {
98
+ if (!isRecord(value)) {
99
+ invalidAuthoredValue(state, path, field, "object_required");
100
+ return null;
101
+ }
102
+ const out = {};
103
+ for (const [id, child] of Object.entries(value)) {
104
+ if (!isManifestMapId(id)) {
105
+ invalidAuthoredValue(state, path, `${field}/${id}`, "id_invalid");
106
+ continue;
107
+ }
108
+ const parsed = parse(id, child);
109
+ if (parsed !== null)
110
+ out[id] = parsed;
111
+ }
112
+ return out;
113
+ };
114
+ const parseMaterialRef = (state, path, field, value) => {
115
+ if (!isMaterialRef(value)) {
116
+ invalidAuthoredValue(state, path, field, "material_ref_invalid");
117
+ return null;
118
+ }
119
+ return value;
120
+ };
121
+ const parseOutputSchema = (state, path, value) => {
122
+ if (!isRecord(value)) {
123
+ invalidAuthoredValue(state, path, "/outputSchema", "object_required");
124
+ return null;
125
+ }
126
+ assertAllowedFields(state, path, value, new Set(["agentSchema", "fingerprint"]));
127
+ if (!isAgentSchema(value.agentSchema) || !isNonEmptyString(value.fingerprint)) {
128
+ invalidAuthoredValue(state, path, "/outputSchema", "agent_schema_spec_invalid");
129
+ return null;
130
+ }
131
+ return {
132
+ agentSchema: value.agentSchema,
133
+ fingerprint: value.fingerprint,
134
+ };
135
+ };
136
+ const stripAgentPrefix = (path) => path.startsWith("agent/") ? path.slice("agent/".length) : path;
137
+ const normalizePath = (path) => {
138
+ if (path.length === 0 || path.startsWith("/") || path.includes("\\"))
139
+ return null;
140
+ const parts = stripAgentPrefix(path).split("/");
141
+ if (parts.some((part) => part.length === 0 || part === "." || part === ".."))
142
+ return null;
143
+ return parts.join("/");
144
+ };
145
+ const registerPath = (state, path) => {
146
+ const normalized = normalizePath(path);
147
+ if (normalized === null) {
148
+ state.issues.push({ kind: "unsupported_path", path, reason: "path_not_normalized" });
149
+ return null;
150
+ }
151
+ const lower = normalized.toLocaleLowerCase();
152
+ const existing = state.pathKeys.get(lower);
153
+ if (existing !== undefined) {
154
+ state.issues.push({ kind: "duplicate_path", path: normalized, existingPath: existing });
155
+ return null;
156
+ }
157
+ state.pathKeys.set(lower, normalized);
158
+ return normalized;
159
+ };
160
+ const putFact = (state, factKey, value, origin, layer, overrideable) => {
161
+ const existing = state.facts.get(factKey);
162
+ if (existing === undefined) {
163
+ state.facts.set(factKey, { value, origin, layer, overrideable });
164
+ return;
165
+ }
166
+ if (existing.layer === layer) {
167
+ state.issues.push({ kind: "duplicate_fact", factKey, origins: [existing.origin, origin] });
168
+ return;
169
+ }
170
+ if (existing.layer > layer)
171
+ return;
172
+ if (!existing.overrideable) {
173
+ state.issues.push({
174
+ kind: "non_overrideable_fact",
175
+ factKey,
176
+ origins: [existing.origin, origin],
177
+ });
178
+ return;
179
+ }
180
+ state.facts.set(factKey, { value, origin, layer, overrideable });
181
+ };
182
+ const putDefault = (state, factKey, value) => putFact(state, factKey, value, defaultOrigin(factKey), 1, true);
183
+ const putAuthored = (state, factKey, value, origin, overrideable = false) => putFact(state, factKey, value, origin, 3, overrideable);
184
+ const assertAllowedFields = (state, path, value, allowed) => {
185
+ for (const field of Object.keys(value)) {
186
+ if (!allowed.has(field))
187
+ state.issues.push({ kind: "unknown_field", path, field });
188
+ }
189
+ };
190
+ const assertNoRuntimeFactFields = (state, path, value) => {
191
+ const forbidden = new Set([
192
+ "continuation",
193
+ "continuationRef",
194
+ "inputRequestRef",
195
+ "snapshot",
196
+ "actualTriggerTime",
197
+ "resumePayload",
198
+ "resolvedMaterial",
199
+ "secret",
200
+ "credential",
201
+ ]);
202
+ const visit = (record, fieldPrefix) => {
203
+ for (const [field, child] of Object.entries(record)) {
204
+ const fieldPath = fieldPrefix.length === 0 ? field : `${fieldPrefix}.${field}`;
205
+ if (forbidden.has(field)) {
206
+ state.issues.push({ kind: "runtime_fact_forbidden", path, field: fieldPath });
207
+ }
208
+ if (isRecord(child))
209
+ visit(child, fieldPath);
210
+ if (Array.isArray(child)) {
211
+ for (let index = 0; index < child.length; index += 1) {
212
+ const item = child[index];
213
+ if (isRecord(item))
214
+ visit(item, `${fieldPath}[${index}]`);
215
+ }
216
+ }
217
+ }
218
+ };
219
+ visit(value, "");
220
+ };
221
+ const assertNoPathIdentityFields = (state, path, value) => {
222
+ for (const field of ["id", "name"]) {
223
+ if (Object.prototype.hasOwnProperty.call(value, field)) {
224
+ state.issues.push({ kind: "identity_field_forbidden", path, field });
225
+ }
226
+ }
227
+ };
228
+ const toolAllowedFields = new Set([
229
+ "bindingRef",
230
+ "executionDomain",
231
+ "interaction",
232
+ "materialRefs",
233
+ "effects",
234
+ "receiptPolicy",
235
+ ]);
236
+ const domainAllowedFields = new Set(["bindingRef"]);
237
+ const interactionAllowedFields = new Set(["bindingRef"]);
238
+ const agentAllowedFields = new Set([
239
+ "agentId",
240
+ "version",
241
+ "scope",
242
+ "effectAuthorityRef",
243
+ "handlers",
244
+ "llmRoutes",
245
+ "tools",
246
+ "materials",
247
+ "executionDomains",
248
+ "interactions",
249
+ "outputSchema",
250
+ ]);
251
+ const materialEffectNames = new Set(["material", "provider_call"]);
252
+ const workspaceDefaultToolByName = new Map(WORKSPACE_TOOL_DEFAULT_DECLARATIONS.map((tool) => [tool.name, tool]));
253
+ const workspaceInteractionRank = {
254
+ never: 0,
255
+ approval: 1,
256
+ };
257
+ const isEffectfulTool = (tool) => (tool.effects?.length ?? 0) > 0 || (tool.materialRefs?.length ?? 0) > 0;
258
+ const requiresMaterial = (tool) => tool.materialRefs !== undefined ||
259
+ (tool.effects?.some((effect) => materialEffectNames.has(effect)) ?? false);
260
+ const parseWorkspaceDefaultToolInteraction = (state, path, toolId, value) => {
261
+ if (value !== "never" && value !== "approval") {
262
+ invalidAuthoredValue(state, path, `/tools/${toolId}/interaction`, "interaction_invalid");
263
+ return null;
264
+ }
265
+ return value;
266
+ };
267
+ const recordWorkspaceDefaultToolControl = (state, path, toolId, control) => {
268
+ if (!isWorkspaceToolName(toolId)) {
269
+ state.issues.push({ kind: "unknown_workspace_default_tool_control", path, toolId });
270
+ return;
271
+ }
272
+ if (control === false) {
273
+ state.workspaceToolControls.set(toolId, {
274
+ kind: "disabled",
275
+ origin: authorOrigin(path, `/tools/${toolId}`),
276
+ });
277
+ return;
278
+ }
279
+ if (!isRecord(control)) {
280
+ invalidAuthoredValue(state, path, `/tools/${toolId}`, "object_or_false_required");
281
+ return;
282
+ }
283
+ for (const field of Object.keys(control)) {
284
+ if (field !== "interaction") {
285
+ state.issues.push({
286
+ kind: "workspace_default_tool_control_field_forbidden",
287
+ path,
288
+ toolId,
289
+ field,
290
+ });
291
+ }
292
+ }
293
+ const defaultTool = workspaceDefaultToolByName.get(toolId);
294
+ if (defaultTool === undefined) {
295
+ state.issues.push({ kind: "unknown_workspace_default_tool_control", path, toolId });
296
+ return;
297
+ }
298
+ const next = {
299
+ kind: "override",
300
+ };
301
+ if (Object.prototype.hasOwnProperty.call(control, "interaction")) {
302
+ const attempted = parseWorkspaceDefaultToolInteraction(state, path, toolId, control.interaction);
303
+ if (attempted !== null) {
304
+ if (workspaceInteractionRank[attempted] < workspaceInteractionRank[defaultTool.interaction]) {
305
+ state.issues.push({
306
+ kind: "workspace_default_tool_interaction_weakened",
307
+ path,
308
+ toolId,
309
+ floor: defaultTool.interaction,
310
+ attempted,
311
+ });
312
+ }
313
+ else {
314
+ state.workspaceToolControls.set(toolId, {
315
+ ...next,
316
+ interaction: {
317
+ value: attempted,
318
+ origin: authorOrigin(path, `/tools/${toolId}/interaction`),
319
+ },
320
+ });
321
+ }
322
+ }
323
+ }
324
+ else {
325
+ state.workspaceToolControls.set(toolId, next);
326
+ }
327
+ };
328
+ const recordToolFacts = (state, toolId, path, declaration, originFor) => {
329
+ state.toolIds.add(toolId);
330
+ const declarationRecord = declaration;
331
+ assertNoPathIdentityFields(state, path, declarationRecord);
332
+ if (Object.prototype.hasOwnProperty.call(declarationRecord, "kind")) {
333
+ state.issues.push({ kind: "identity_field_forbidden", path, field: "kind" });
334
+ }
335
+ assertAllowedFields(state, path, declarationRecord, toolAllowedFields);
336
+ assertNoRuntimeFactFields(state, path, declarationRecord);
337
+ const bindingRef = parseOptionalStringField(state, path, "/bindingRef", declaration.bindingRef);
338
+ const executionDomain = parseOptionalStringField(state, path, "/executionDomain", declaration.executionDomain);
339
+ const interaction = parseOptionalStringField(state, path, "/interaction", declaration.interaction);
340
+ const materialRefs = declaration.materialRefs === undefined
341
+ ? undefined
342
+ : parseStringArrayField(state, path, "/materialRefs", declaration.materialRefs);
343
+ const effects = declaration.effects === undefined
344
+ ? undefined
345
+ : parseStringArrayField(state, path, "/effects", declaration.effects);
346
+ const receiptPolicy = parseOptionalStringField(state, path, "/receiptPolicy", declaration.receiptPolicy);
347
+ putAuthored(state, `/tools/${toolId}/bindingRef`, bindingRef ?? `tool.${toolId}`, bindingRef === undefined ? pathOrigin(path) : originFor("bindingRef"));
348
+ if (executionDomain !== undefined) {
349
+ putAuthored(state, `/tools/${toolId}/executionDomain`, executionDomain, originFor("executionDomain"));
350
+ }
351
+ if (interaction !== undefined) {
352
+ putAuthored(state, `/tools/${toolId}/interaction`, interaction, originFor("interaction"));
353
+ }
354
+ if (materialRefs !== undefined) {
355
+ putAuthored(state, `/tools/${toolId}/materialRefs`, materialRefs, originFor("materialRefs"));
356
+ }
357
+ if (effects !== undefined) {
358
+ putAuthored(state, `/tools/${toolId}/effects`, effects, originFor("effects"));
359
+ }
360
+ if (receiptPolicy !== undefined) {
361
+ putAuthored(state, `/tools/${toolId}/receiptPolicy`, receiptPolicy, originFor("receiptPolicy"));
362
+ }
363
+ };
364
+ const recordAgentJson = (state, path, value) => {
365
+ if (!isRecord(value)) {
366
+ state.issues.push({ kind: "invalid_json_file", path, reason: "agent_json_not_object" });
367
+ return;
368
+ }
369
+ assertAllowedFields(state, path, value, agentAllowedFields);
370
+ assertNoRuntimeFactFields(state, path, value);
371
+ const agentId = parseOptionalStringField(state, path, "/agentId", value.agentId);
372
+ const version = parseOptionalStringField(state, path, "/version", value.version);
373
+ const scope = value.scope === undefined ? undefined : parseScope(state, path, value.scope);
374
+ const effectAuthorityRef = value.effectAuthorityRef === undefined
375
+ ? undefined
376
+ : isAuthorityRef(value.effectAuthorityRef)
377
+ ? value.effectAuthorityRef
378
+ : null;
379
+ if (value.effectAuthorityRef !== undefined && effectAuthorityRef === null) {
380
+ invalidAuthoredValue(state, path, "/effectAuthorityRef", "authority_ref_invalid");
381
+ }
382
+ const handlers = value.handlers === undefined ? undefined : parseHandlers(state, path, value.handlers);
383
+ const llmRoutes = value.llmRoutes === undefined
384
+ ? undefined
385
+ : parseRecordMap(state, path, "/llmRoutes", value.llmRoutes, (_route, child) => parseBindingRefObject(state, path, "/llmRoutes", child));
386
+ const outputSchema = value.outputSchema === undefined
387
+ ? undefined
388
+ : parseOutputSchema(state, path, value.outputSchema);
389
+ const materials = value.materials === undefined
390
+ ? undefined
391
+ : parseRecordMap(state, path, "/materials", value.materials, (_id, child) => parseMaterialRef(state, path, "/materials", child));
392
+ const executionDomains = value.executionDomains === undefined
393
+ ? undefined
394
+ : parseRecordMap(state, path, "/executionDomains", value.executionDomains, (_domainId, child) => parseBindingRefObject(state, path, "/executionDomains", child));
395
+ const interactions = value.interactions === undefined
396
+ ? undefined
397
+ : parseRecordMap(state, path, "/interactions", value.interactions, (_interactionId, child) => parseBindingRefObject(state, path, "/interactions", child));
398
+ if (value.tools !== undefined) {
399
+ if (!isRecord(value.tools)) {
400
+ invalidAuthoredValue(state, path, "/tools", "object_required");
401
+ }
402
+ else {
403
+ for (const [toolId, child] of Object.entries(value.tools)) {
404
+ if (!isManifestMapId(toolId)) {
405
+ invalidAuthoredValue(state, path, `/tools/${toolId}`, "id_invalid");
406
+ continue;
407
+ }
408
+ recordWorkspaceDefaultToolControl(state, path, toolId, child);
409
+ }
410
+ }
411
+ }
412
+ if (agentId !== undefined)
413
+ putAuthored(state, "/agentId", agentId, authorOrigin(path, "/agentId"));
414
+ if (version !== undefined)
415
+ putAuthored(state, "/version", version, authorOrigin(path, "/version"));
416
+ if (scope !== undefined && scope !== null) {
417
+ putAuthored(state, "/scope", scope, authorOrigin(path, "/scope"));
418
+ }
419
+ if (effectAuthorityRef !== undefined && effectAuthorityRef !== null) {
420
+ putAuthored(state, "/effectAuthorityRef", effectAuthorityRef, authorOrigin(path, "/effectAuthorityRef"));
421
+ }
422
+ if (handlers !== undefined && handlers !== null)
423
+ putAuthored(state, "/handlers", handlers, authorOrigin(path, "/handlers"));
424
+ if (llmRoutes !== undefined && llmRoutes !== null) {
425
+ for (const [route, ref] of Object.entries(llmRoutes)) {
426
+ putAuthored(state, `/llmRoutes/${route}/bindingRef`, ref.bindingRef, authorOrigin(path, `/llmRoutes/${route}/bindingRef`));
427
+ }
428
+ }
429
+ if (outputSchema !== undefined && outputSchema !== null) {
430
+ putAuthored(state, "/outputSchema", outputSchema, authorOrigin(path, "/outputSchema"));
431
+ }
432
+ if (materials !== undefined && materials !== null) {
433
+ for (const [materialId, materialRef] of Object.entries(materials)) {
434
+ putAuthored(state, `/materials/${materialId}`, materialRef, authorOrigin(path, `/materials/${materialId}`));
435
+ }
436
+ }
437
+ if (executionDomains !== undefined && executionDomains !== null) {
438
+ for (const [domainId, domainRef] of Object.entries(executionDomains)) {
439
+ putAuthored(state, `/executionDomains/${domainId}/bindingRef`, domainRef.bindingRef, authorOrigin(path, `/executionDomains/${domainId}/bindingRef`));
440
+ }
441
+ }
442
+ if (interactions !== undefined && interactions !== null) {
443
+ for (const [interactionId, interactionRef] of Object.entries(interactions)) {
444
+ putAuthored(state, `/interactions/${interactionId}/bindingRef`, interactionRef.bindingRef, authorOrigin(path, `/interactions/${interactionId}/bindingRef`));
445
+ }
446
+ }
447
+ };
448
+ const recordJsonFile = (state, path, value) => {
449
+ const parts = path.split("/");
450
+ if (path === "agent.json") {
451
+ recordAgentJson(state, path, value);
452
+ return;
453
+ }
454
+ if (parts.length !== 2 || !parts[1]?.endsWith(".json")) {
455
+ state.issues.push({ kind: "unsupported_path", path, reason: "json_path_not_in_grammar" });
456
+ return;
457
+ }
458
+ const id = parts[1].slice(0, -".json".length);
459
+ if (id.length === 0) {
460
+ state.issues.push({ kind: "unsupported_path", path, reason: "empty_path_identity" });
461
+ return;
462
+ }
463
+ if (!isRecord(value)) {
464
+ state.issues.push({ kind: "invalid_json_file", path, reason: "json_value_not_object" });
465
+ return;
466
+ }
467
+ assertNoPathIdentityFields(state, path, value);
468
+ assertNoRuntimeFactFields(state, path, value);
469
+ switch (parts[0]) {
470
+ case "materials": {
471
+ if (!isMaterialRef(value)) {
472
+ state.issues.push({ kind: "invalid_json_file", path, reason: "material_ref_invalid" });
473
+ return;
474
+ }
475
+ putAuthored(state, `/materials/${id}`, value, pathOrigin(path));
476
+ return;
477
+ }
478
+ case "domains":
479
+ if (Object.prototype.hasOwnProperty.call(value, "kind")) {
480
+ state.issues.push({ kind: "identity_field_forbidden", path, field: "kind" });
481
+ }
482
+ assertAllowedFields(state, path, value, domainAllowedFields);
483
+ const domainBindingRef = Object.prototype.hasOwnProperty.call(value, "bindingRef")
484
+ ? parseStringField(state, path, "/bindingRef", value.bindingRef)
485
+ : id;
486
+ putAuthored(state, `/executionDomains/${id}/bindingRef`, domainBindingRef ?? id, Object.prototype.hasOwnProperty.call(value, "bindingRef")
487
+ ? authorOrigin(path, "/bindingRef")
488
+ : pathOrigin(path));
489
+ return;
490
+ case "interactions":
491
+ if (Object.prototype.hasOwnProperty.call(value, "kind")) {
492
+ state.issues.push({ kind: "identity_field_forbidden", path, field: "kind" });
493
+ }
494
+ assertAllowedFields(state, path, value, interactionAllowedFields);
495
+ const interactionBindingRef = Object.prototype.hasOwnProperty.call(value, "bindingRef")
496
+ ? parseStringField(state, path, "/bindingRef", value.bindingRef)
497
+ : id;
498
+ putAuthored(state, `/interactions/${id}/bindingRef`, interactionBindingRef ?? id, Object.prototype.hasOwnProperty.call(value, "bindingRef")
499
+ ? authorOrigin(path, "/bindingRef")
500
+ : pathOrigin(path));
501
+ return;
502
+ default:
503
+ state.issues.push({ kind: "unsupported_path", path, reason: "json_path_not_in_grammar" });
504
+ }
505
+ };
506
+ const recordMarkdownFile = (state, path, text) => {
507
+ if (path !== "instructions.md") {
508
+ state.issues.push({ kind: "unsupported_path", path, reason: "markdown_path_not_in_grammar" });
509
+ return;
510
+ }
511
+ if (text.trim().length === 0)
512
+ state.issues.push({ kind: "empty_instructions", path });
513
+ const instructions = {
514
+ path: "agent/instructions.md",
515
+ digest: digestText(text),
516
+ };
517
+ putAuthored(state, "/instructions", instructions, pathOrigin(path));
518
+ };
519
+ const recordToolFile = (state, path, declaration) => {
520
+ const parts = path.split("/");
521
+ if (parts.length !== 2 || parts[0] !== "tools" || !parts[1]?.endsWith(".ts")) {
522
+ state.issues.push({ kind: "unsupported_path", path, reason: "tool_path_not_in_grammar" });
523
+ return;
524
+ }
525
+ const toolId = parts[1].slice(0, -".ts".length);
526
+ if (toolId.length === 0) {
527
+ state.issues.push({ kind: "unsupported_path", path, reason: "empty_path_identity" });
528
+ return;
529
+ }
530
+ state.toolFilePaths.set(toolId, path);
531
+ recordToolFacts(state, toolId, path, declaration ?? {}, (field) => authorOrigin(path, field));
532
+ };
533
+ const applyDefaults = (state) => {
534
+ putDefault(state, "/agentId", "agent");
535
+ const agentId = state.facts.get("/agentId")?.value;
536
+ putDefault(state, "/scope", { kind: "conversation", idSource: "submit_scope" });
537
+ putDefault(state, "/llmRoutes/default/bindingRef", "llm.default");
538
+ putDefault(state, "/handlers", []);
539
+ putDefault(state, "/executionDomains/app-runtime/bindingRef", "app-runtime");
540
+ putDefault(state, "/interactions/never/bindingRef", "never");
541
+ putDefault(state, "/interactions/approval/bindingRef", "approval");
542
+ putDefault(state, "/effectAuthorityRef", {
543
+ authorityClass: "agent",
544
+ authorityId: typeof agentId === "string" ? agentId : "agent",
545
+ });
546
+ for (const toolId of [...state.toolIds].sort()) {
547
+ const tool = collectToolConstraintState(state, toolId);
548
+ if (!tool.effectful) {
549
+ putDefault(state, `/tools/${toolId}/executionDomain`, "app-runtime");
550
+ putDefault(state, `/tools/${toolId}/interaction`, "never");
551
+ }
552
+ }
553
+ };
554
+ const enforceL0 = (state) => {
555
+ if (!state.facts.has("/instructions")) {
556
+ state.issues.push({ kind: "missing_required_file", path: "agent/instructions.md" });
557
+ }
558
+ for (const toolId of [...state.toolIds].sort()) {
559
+ const tool = collectToolConstraintState(state, toolId);
560
+ if (!tool.effectful)
561
+ continue;
562
+ if (tool.needsMaterial && (tool.materialRefs?.length ?? 0) === 0) {
563
+ state.issues.push({ kind: "effectful_tool_missing_material", toolId });
564
+ }
565
+ if (tool.executionDomain === undefined) {
566
+ state.issues.push({ kind: "effectful_tool_missing_execution_domain", toolId });
567
+ }
568
+ if (tool.interaction === undefined) {
569
+ state.issues.push({ kind: "effectful_tool_missing_interaction", toolId });
570
+ }
571
+ if (tool.receiptPolicy === undefined) {
572
+ state.issues.push({ kind: "effectful_tool_missing_receipt_policy", toolId });
573
+ }
574
+ }
575
+ };
576
+ const factValue = (state, factKey) => state.facts.get(factKey)?.value;
577
+ const collectRecord = (state, prefix, make) => {
578
+ const ids = new Set();
579
+ for (const key of state.facts.keys()) {
580
+ if (!key.startsWith(prefix))
581
+ continue;
582
+ const rest = key.slice(prefix.length);
583
+ const id = rest.split("/")[0];
584
+ if (id.length > 0)
585
+ ids.add(id);
586
+ }
587
+ if (ids.size === 0)
588
+ return undefined;
589
+ const out = {};
590
+ for (const id of [...ids].sort()) {
591
+ const value = make(id);
592
+ if (value !== null)
593
+ out[id] = value;
594
+ }
595
+ return out;
596
+ };
597
+ const collectToolConstraintState = (state, toolId) => {
598
+ const effects = factValue(state, `/tools/${toolId}/effects`) ?? [];
599
+ const materialRefs = factValue(state, `/tools/${toolId}/materialRefs`);
600
+ const tool = { effects, materialRefs };
601
+ return {
602
+ executionDomain: factValue(state, `/tools/${toolId}/executionDomain`),
603
+ interaction: factValue(state, `/tools/${toolId}/interaction`),
604
+ materialRefs,
605
+ receiptPolicy: factValue(state, `/tools/${toolId}/receiptPolicy`),
606
+ effectful: isEffectfulTool(tool),
607
+ needsMaterial: requiresMaterial(tool),
608
+ };
609
+ };
610
+ const collectTool = (state, toolId) => {
611
+ const executionDomain = factValue(state, `/tools/${toolId}/executionDomain`);
612
+ const interaction = factValue(state, `/tools/${toolId}/interaction`);
613
+ const materialRefs = factValue(state, `/tools/${toolId}/materialRefs`);
614
+ const effects = factValue(state, `/tools/${toolId}/effects`);
615
+ const receiptPolicy = factValue(state, `/tools/${toolId}/receiptPolicy`);
616
+ return {
617
+ bindingRef: factValue(state, `/tools/${toolId}/bindingRef`) ?? `tool.${toolId}`,
618
+ ...(executionDomain === undefined ? {} : { executionDomain }),
619
+ ...(interaction === undefined ? {} : { interaction }),
620
+ ...(materialRefs === undefined ? {} : { materialRefs }),
621
+ ...(effects === undefined ? {} : { effects }),
622
+ ...(receiptPolicy === undefined ? {} : { receiptPolicy }),
623
+ };
624
+ };
625
+ const buildManifest = (state) => {
626
+ const version = factValue(state, "/version");
627
+ const instructions = factValue(state, "/instructions");
628
+ const llmRoutes = collectRecord(state, "/llmRoutes/", (id) => {
629
+ const bindingRef = factValue(state, `/llmRoutes/${id}/bindingRef`);
630
+ return bindingRef === undefined ? null : { bindingRef };
631
+ });
632
+ const tools = collectRecord(state, "/tools/", (id) => collectTool(state, id));
633
+ const materials = collectRecord(state, "/materials/", (id) => factValue(state, `/materials/${id}`) ?? null);
634
+ const executionDomains = collectRecord(state, "/executionDomains/", (id) => {
635
+ const bindingRef = factValue(state, `/executionDomains/${id}/bindingRef`);
636
+ return bindingRef === undefined ? null : { bindingRef };
637
+ });
638
+ const interactions = collectRecord(state, "/interactions/", (id) => {
639
+ const bindingRef = factValue(state, `/interactions/${id}/bindingRef`);
640
+ return bindingRef === undefined ? null : { bindingRef };
641
+ });
642
+ const outputSchema = factValue(state, "/outputSchema");
643
+ return {
644
+ agentId: factValue(state, "/agentId") ?? "agent",
645
+ scope: factValue(state, "/scope") ??
646
+ { kind: "conversation", idSource: "submit_scope" },
647
+ effectAuthorityRef: factValue(state, "/effectAuthorityRef") ??
648
+ { authorityClass: "agent", authorityId: "agent" },
649
+ handlers: factValue(state, "/handlers") ?? [],
650
+ ...(version === undefined ? {} : { version }),
651
+ ...(instructions === undefined ? {} : { instructions }),
652
+ ...(llmRoutes === undefined ? {} : { llmRoutes }),
653
+ ...(tools === undefined ? {} : { tools }),
654
+ ...(materials === undefined ? {} : { materials }),
655
+ ...(executionDomains === undefined ? {} : { executionDomains }),
656
+ ...(interactions === undefined ? {} : { interactions }),
657
+ ...(outputSchema === undefined ? {} : { outputSchema }),
658
+ };
659
+ };
660
+ const buildProvenance = (state) => {
661
+ const provenance = {};
662
+ for (const [key, fact] of [...state.facts.entries()].sort(([left], [right]) => left.localeCompare(right))) {
663
+ provenance[key] = fact.origin;
664
+ }
665
+ return provenance;
666
+ };
667
+ const buildWorkspaceToolControls = (state) => {
668
+ const controls = {};
669
+ for (const [toolId, control] of [...state.workspaceToolControls.entries()].sort(([left], [right]) => left.localeCompare(right))) {
670
+ controls[toolId] = control;
671
+ }
672
+ return controls;
673
+ };
674
+ const buildToolFilePaths = (state) => {
675
+ const paths = {};
676
+ for (const [toolId, path] of [...state.toolFilePaths.entries()].sort(([left], [right]) => left.localeCompare(right))) {
677
+ paths[toolId] = path;
678
+ }
679
+ return paths;
680
+ };
681
+ /**
682
+ * Compile an authored `agent/` tree into one normalized manifest plus
683
+ * provenance. This is the app-author entrypoint; runtime facts and provider
684
+ * material are rejected before they can become manifest truth.
685
+ *
686
+ * @agentosPrimitive primitive.agent-authoring.compileAgentTree
687
+ * @agentosInvariant invariant.docs.agent-projection
688
+ * @agentosInvariant invariant.algebra.single-code-source
689
+ * @agentosDocs docs/guides/build-natural-language-workspace-agent.md
690
+ */
691
+ export const compileAgentTree = (tree) => {
692
+ const state = {
693
+ facts: new Map(),
694
+ issues: [],
695
+ pathKeys: new Map(),
696
+ toolIds: new Set(),
697
+ toolFilePaths: new Map(),
698
+ workspaceToolControls: new Map(),
699
+ };
700
+ for (const file of tree.files) {
701
+ const path = registerPath(state, file.path);
702
+ if (path === null)
703
+ continue;
704
+ switch (file.kind) {
705
+ case "markdown":
706
+ recordMarkdownFile(state, path, file.text);
707
+ break;
708
+ case "json":
709
+ recordJsonFile(state, path, file.value);
710
+ break;
711
+ case "tool":
712
+ recordToolFile(state, path, file.declaration);
713
+ break;
714
+ }
715
+ }
716
+ applyDefaults(state);
717
+ enforceL0(state);
718
+ if (state.issues.length > 0)
719
+ return { ok: false, issues: state.issues };
720
+ const manifest = buildManifest(state);
721
+ const functionPath = findFunctionPath(manifest, "manifest");
722
+ if (functionPath !== null || hasFunction(manifest)) {
723
+ return {
724
+ ok: false,
725
+ issues: [{ kind: "function_in_manifest", path: functionPath ?? "manifest" }],
726
+ };
727
+ }
728
+ return {
729
+ ok: true,
730
+ value: {
731
+ manifest: authoredValue(manifest),
732
+ provenance: buildProvenance(state),
733
+ workspaceToolControls: buildWorkspaceToolControls(state),
734
+ toolFilePaths: buildToolFilePaths(state),
735
+ },
736
+ };
737
+ };