agent-contracts 0.22.3 → 0.22.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli-contract.yaml +11 -8
- package/dist/cli.js +442 -42
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +16 -3
- package/dist/index.js +443 -43
- package/dist/index.js.map +1 -1
- package/dsl_base/agents/dsl-auditor.yaml +31 -2
- package/dsl_base/agents/dsl-designer.yaml +0 -2
- package/dsl_base/artifacts.yaml +1 -1
- package/dsl_base/handoff-types.yaml +33 -11
- package/dsl_base/tasks.yaml +43 -14
- package/dsl_base/validations.yaml +6 -6
- package/dsl_base/workflow.yaml +30 -8
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -49436,7 +49436,7 @@ function createProgram(handlers2, version) {
|
|
|
49436
49436
|
}
|
|
49437
49437
|
await handlers2.score(dir, opts, globalOpts);
|
|
49438
49438
|
});
|
|
49439
|
-
program2.command("audit").description("Run LLM-based semantic audit on DSL definitions and generated outputs.").argument("[type]", "Audit type to run: render (semantic diff of generated outputs vs DSL), dsl (design coherence review), prompt (generated prompt fidelity check), or all (run all
|
|
49439
|
+
program2.command("audit").description("Run LLM-based semantic audit on DSL definitions and generated outputs.").argument("[type]", "Audit type to run: render (semantic diff of generated outputs vs DSL), dsl (design coherence review), prompt (generated prompt fidelity check), extensions (unconsumed x-* property detection), or all (run all four).").option("-c, --config <path>", "Path to agent-contracts.config.yaml.").option("--team <id>", "Limit to one team (multi-team config only).").option("--format <format>", "Output format.", "text").option("--scope <entities>", "Limit audit scope to specified entities (e.g. agents:architect,implementer).").option("--dry-run", "Output the audit prompt without calling LLM.", false).option("--adapter <name>", "SDK adapter to use for LLM calls (overrides config audit.adapter).").option("--model <name>", "LLM model override (overrides config audit.model).").option("--fail-on <level>", "Minimum finding severity that causes exit 10 (info|warning|error|critical).", "critical").option("-o, --output <file>", "Write result to a file instead of stdout.").option("--report-format <fmt>", "Alias for --format. When both are specified, --report-format takes precedence.", "text").action(async (type, opts, cmd) => {
|
|
49440
49440
|
const globalOpts = cmd.optsWithGlobals();
|
|
49441
49441
|
if (globalOpts.introspect) {
|
|
49442
49442
|
const policy = deriveCommandPolicy("audit", opts);
|
|
@@ -49533,6 +49533,7 @@ var ArtifactSchema = z2.object({
|
|
|
49533
49533
|
states: z2.array(z2.string()),
|
|
49534
49534
|
required_validations: z2.array(z2.string()).default([]),
|
|
49535
49535
|
visibility: z2.string().optional(),
|
|
49536
|
+
classification: z2.string().optional(),
|
|
49536
49537
|
guardrails: z2.array(z2.string()).optional()
|
|
49537
49538
|
}).passthrough();
|
|
49538
49539
|
|
|
@@ -49737,7 +49738,7 @@ var ExecutionStepSchema = z9.object({
|
|
|
49737
49738
|
var TaskSchema = z9.object({
|
|
49738
49739
|
description: z9.string(),
|
|
49739
49740
|
target_agent: z9.string(),
|
|
49740
|
-
allowed_from_agents: z9.array(z9.string()),
|
|
49741
|
+
allowed_from_agents: z9.array(z9.string()).default([]),
|
|
49741
49742
|
workflow: z9.string(),
|
|
49742
49743
|
input_artifacts: z9.array(z9.string()),
|
|
49743
49744
|
invocation_handoff: z9.string(),
|
|
@@ -49810,7 +49811,8 @@ var ValidationSchema = z13.object({
|
|
|
49810
49811
|
executor_type: z13.enum(["tool", "agent"]),
|
|
49811
49812
|
executor: z13.string(),
|
|
49812
49813
|
blocking: z13.boolean(),
|
|
49813
|
-
produces_evidence: z13.string().optional()
|
|
49814
|
+
produces_evidence: z13.string().optional(),
|
|
49815
|
+
description: z13.string().optional()
|
|
49814
49816
|
}).passthrough();
|
|
49815
49817
|
|
|
49816
49818
|
// src/schema/workflow.ts
|
|
@@ -50194,7 +50196,8 @@ ${issues}`,
|
|
|
50194
50196
|
bindings: [],
|
|
50195
50197
|
activeGuardrailPolicy: void 0,
|
|
50196
50198
|
paths: void 0,
|
|
50197
|
-
teams: resolveTeamConfigs(config.teams, configDir)
|
|
50199
|
+
teams: resolveTeamConfigs(config.teams, configDir),
|
|
50200
|
+
audit: config.audit ?? void 0
|
|
50198
50201
|
};
|
|
50199
50202
|
}
|
|
50200
50203
|
return {
|
|
@@ -50204,7 +50207,8 @@ ${issues}`,
|
|
|
50204
50207
|
configDir,
|
|
50205
50208
|
bindings: (config.bindings ?? []).map((b3) => resolve(configDir, b3)),
|
|
50206
50209
|
activeGuardrailPolicy: config.active_guardrail_policy,
|
|
50207
|
-
paths: config.paths
|
|
50210
|
+
paths: config.paths,
|
|
50211
|
+
audit: config.audit ?? void 0
|
|
50208
50212
|
};
|
|
50209
50213
|
}
|
|
50210
50214
|
function resolveDslPath(dirArg, dirArgDefault, config) {
|
|
@@ -50248,7 +50252,7 @@ function deepClone(value) {
|
|
|
50248
50252
|
}
|
|
50249
50253
|
return result;
|
|
50250
50254
|
}
|
|
50251
|
-
function
|
|
50255
|
+
function tryResolveJsonPointer(root, pointer) {
|
|
50252
50256
|
const path = pointer.slice(2);
|
|
50253
50257
|
const segments = path.split("/").map(
|
|
50254
50258
|
(s2) => s2.replace(/~1/g, "/").replace(/~0/g, "~")
|
|
@@ -50262,12 +50266,19 @@ function resolveJsonPointer(root, pointer) {
|
|
|
50262
50266
|
}
|
|
50263
50267
|
current = current[segment];
|
|
50264
50268
|
if (current === void 0) {
|
|
50265
|
-
|
|
50266
|
-
`Cannot resolve JSON Pointer "${pointer}": path segment "${segment}" not found`
|
|
50267
|
-
);
|
|
50269
|
+
return { found: false };
|
|
50268
50270
|
}
|
|
50269
50271
|
}
|
|
50270
|
-
return current;
|
|
50272
|
+
return { found: true, value: current };
|
|
50273
|
+
}
|
|
50274
|
+
function resolveJsonPointer(root, pointer) {
|
|
50275
|
+
const result = tryResolveJsonPointer(root, pointer);
|
|
50276
|
+
if (!result.found) {
|
|
50277
|
+
throw new DslLoadError(
|
|
50278
|
+
`Cannot resolve JSON Pointer "${pointer}": target not found`
|
|
50279
|
+
);
|
|
50280
|
+
}
|
|
50281
|
+
return result.value;
|
|
50271
50282
|
}
|
|
50272
50283
|
function hasRefs(value) {
|
|
50273
50284
|
if (!("$refs" in value)) return false;
|
|
@@ -50311,7 +50322,7 @@ function deepMergeRefs(a3, b3, sourcePath) {
|
|
|
50311
50322
|
}
|
|
50312
50323
|
return result;
|
|
50313
50324
|
}
|
|
50314
|
-
async function loadRefsSource(refPath, baseDir, resolving
|
|
50325
|
+
async function loadRefsSource(refPath, baseDir, resolving) {
|
|
50315
50326
|
const target = resolve2(baseDir, refPath);
|
|
50316
50327
|
const s2 = await fsStat(target).catch(() => null);
|
|
50317
50328
|
if (s2?.isDirectory()) {
|
|
@@ -50319,7 +50330,7 @@ async function loadRefsSource(refPath, baseDir, resolving, rootDoc) {
|
|
|
50319
50330
|
throw new DslLoadError(`Circular $refs detected: ${target}`, target);
|
|
50320
50331
|
}
|
|
50321
50332
|
resolving.add(target);
|
|
50322
|
-
const result = await loadDirectoryAsMap(target, resolving
|
|
50333
|
+
const result = await loadDirectoryAsMap(target, resolving);
|
|
50323
50334
|
resolving.delete(target);
|
|
50324
50335
|
return result;
|
|
50325
50336
|
}
|
|
@@ -50337,16 +50348,16 @@ async function loadRefsSource(refPath, baseDir, resolving, rootDoc) {
|
|
|
50337
50348
|
target
|
|
50338
50349
|
);
|
|
50339
50350
|
}
|
|
50340
|
-
const resolved = await
|
|
50351
|
+
const resolved = await assembleRefs(
|
|
50341
50352
|
content,
|
|
50342
50353
|
dirname2(target),
|
|
50343
50354
|
resolving,
|
|
50344
|
-
|
|
50355
|
+
content
|
|
50345
50356
|
);
|
|
50346
50357
|
resolving.delete(target);
|
|
50347
50358
|
return resolved;
|
|
50348
50359
|
}
|
|
50349
|
-
async function loadDirectoryAsMap(dirPath, resolving
|
|
50360
|
+
async function loadDirectoryAsMap(dirPath, resolving) {
|
|
50350
50361
|
let entries;
|
|
50351
50362
|
try {
|
|
50352
50363
|
entries = await readdir(dirPath);
|
|
@@ -50373,17 +50384,17 @@ async function loadDirectoryAsMap(dirPath, resolving, rootDoc) {
|
|
|
50373
50384
|
filePath
|
|
50374
50385
|
);
|
|
50375
50386
|
}
|
|
50376
|
-
const resolved = await
|
|
50387
|
+
const resolved = await assembleRefs(
|
|
50377
50388
|
content,
|
|
50378
50389
|
dirPath,
|
|
50379
50390
|
resolving,
|
|
50380
|
-
|
|
50391
|
+
content
|
|
50381
50392
|
);
|
|
50382
50393
|
merged = deepMergeRefs(merged, resolved, filePath);
|
|
50383
50394
|
}
|
|
50384
50395
|
return merged;
|
|
50385
50396
|
}
|
|
50386
|
-
async function processRefs(obj, baseDir, resolving
|
|
50397
|
+
async function processRefs(obj, baseDir, resolving) {
|
|
50387
50398
|
const refPaths = obj["$refs"];
|
|
50388
50399
|
const inline = {};
|
|
50389
50400
|
for (const [key, value] of Object.entries(obj)) {
|
|
@@ -50393,17 +50404,17 @@ async function processRefs(obj, baseDir, resolving, rootDoc) {
|
|
|
50393
50404
|
}
|
|
50394
50405
|
let merged = {};
|
|
50395
50406
|
for (const refPath of refPaths) {
|
|
50396
|
-
const loaded = await loadRefsSource(refPath, baseDir, resolving
|
|
50407
|
+
const loaded = await loadRefsSource(refPath, baseDir, resolving);
|
|
50397
50408
|
merged = deepMergeRefs(merged, loaded, refPath);
|
|
50398
50409
|
}
|
|
50399
50410
|
merged = deepMergeRefs(merged, inline, "(inline)");
|
|
50400
50411
|
return merged;
|
|
50401
50412
|
}
|
|
50402
|
-
async function
|
|
50413
|
+
async function assembleRefs(data, baseDir, resolving, fileRoot) {
|
|
50403
50414
|
if (typeof data !== "object" || data === null) return data;
|
|
50404
50415
|
if (Array.isArray(data)) {
|
|
50405
50416
|
return Promise.all(
|
|
50406
|
-
data.map((item) =>
|
|
50417
|
+
data.map((item) => assembleRefs(item, baseDir, resolving, fileRoot))
|
|
50407
50418
|
);
|
|
50408
50419
|
}
|
|
50409
50420
|
if (isRef(data)) {
|
|
@@ -50412,13 +50423,16 @@ async function resolveRefsDeep(data, baseDir, resolving, rootDoc) {
|
|
|
50412
50423
|
if (resolving.has(refValue)) {
|
|
50413
50424
|
throw new DslLoadError(`Circular $ref detected: ${refValue}`);
|
|
50414
50425
|
}
|
|
50426
|
+
const result2 = tryResolveJsonPointer(fileRoot, refValue);
|
|
50427
|
+
if (!result2.found) {
|
|
50428
|
+
return data;
|
|
50429
|
+
}
|
|
50415
50430
|
resolving.add(refValue);
|
|
50416
|
-
const
|
|
50417
|
-
|
|
50418
|
-
deepClone(target),
|
|
50431
|
+
const resolved = await assembleRefs(
|
|
50432
|
+
deepClone(result2.value),
|
|
50419
50433
|
baseDir,
|
|
50420
50434
|
resolving,
|
|
50421
|
-
|
|
50435
|
+
fileRoot
|
|
50422
50436
|
);
|
|
50423
50437
|
resolving.delete(refValue);
|
|
50424
50438
|
return resolved;
|
|
@@ -50442,7 +50456,7 @@ async function resolveRefsDeep(data, baseDir, resolving, rootDoc) {
|
|
|
50442
50456
|
);
|
|
50443
50457
|
}
|
|
50444
50458
|
resolving.add(refTarget);
|
|
50445
|
-
const result2 = await loadDirectoryAsMap(refTarget, resolving
|
|
50459
|
+
const result2 = await loadDirectoryAsMap(refTarget, resolving);
|
|
50446
50460
|
resolving.delete(refTarget);
|
|
50447
50461
|
return result2;
|
|
50448
50462
|
}
|
|
@@ -50457,12 +50471,12 @@ async function resolveRefsDeep(data, baseDir, resolving, rootDoc) {
|
|
|
50457
50471
|
}
|
|
50458
50472
|
resolving.add(refTarget);
|
|
50459
50473
|
const content = await readYaml(refTarget);
|
|
50460
|
-
const
|
|
50461
|
-
let fileData = await
|
|
50474
|
+
const newFileRoot = isRecord(content) ? content : fileRoot;
|
|
50475
|
+
let fileData = await assembleRefs(
|
|
50462
50476
|
content,
|
|
50463
50477
|
dirname2(refTarget),
|
|
50464
50478
|
resolving,
|
|
50465
|
-
|
|
50479
|
+
newFileRoot
|
|
50466
50480
|
);
|
|
50467
50481
|
resolving.delete(refTarget);
|
|
50468
50482
|
if (fragment && fragment.startsWith("#/")) {
|
|
@@ -50478,11 +50492,31 @@ async function resolveRefsDeep(data, baseDir, resolving, rootDoc) {
|
|
|
50478
50492
|
}
|
|
50479
50493
|
let obj = data;
|
|
50480
50494
|
if (hasRefs(obj)) {
|
|
50481
|
-
obj = await processRefs(obj, baseDir, resolving
|
|
50495
|
+
obj = await processRefs(obj, baseDir, resolving);
|
|
50496
|
+
}
|
|
50497
|
+
const result = {};
|
|
50498
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
50499
|
+
result[key] = await assembleRefs(value, baseDir, resolving, fileRoot);
|
|
50500
|
+
}
|
|
50501
|
+
return result;
|
|
50502
|
+
}
|
|
50503
|
+
function linkDocPointers(data, rootDoc) {
|
|
50504
|
+
if (typeof data !== "object" || data === null) return data;
|
|
50505
|
+
if (Array.isArray(data)) {
|
|
50506
|
+
return data.map((item) => linkDocPointers(item, rootDoc));
|
|
50482
50507
|
}
|
|
50508
|
+
if (isRef(data)) {
|
|
50509
|
+
const refValue = data.$ref;
|
|
50510
|
+
if (refValue.startsWith("#/")) {
|
|
50511
|
+
const target = resolveJsonPointer(rootDoc, refValue);
|
|
50512
|
+
return linkDocPointers(deepClone(target), rootDoc);
|
|
50513
|
+
}
|
|
50514
|
+
return data;
|
|
50515
|
+
}
|
|
50516
|
+
const obj = data;
|
|
50483
50517
|
const result = {};
|
|
50484
50518
|
for (const [key, value] of Object.entries(obj)) {
|
|
50485
|
-
result[key] =
|
|
50519
|
+
result[key] = linkDocPointers(value, rootDoc);
|
|
50486
50520
|
}
|
|
50487
50521
|
return result;
|
|
50488
50522
|
}
|
|
@@ -50513,13 +50547,16 @@ async function loadDsl(entryPath) {
|
|
|
50513
50547
|
const data = raw;
|
|
50514
50548
|
checkVersion(data, absPath);
|
|
50515
50549
|
const baseDir = dirname2(absPath);
|
|
50516
|
-
const
|
|
50517
|
-
const resolved = await resolveRefsDeep(
|
|
50550
|
+
const assembled = await assembleRefs(
|
|
50518
50551
|
data,
|
|
50519
50552
|
baseDir,
|
|
50520
|
-
|
|
50553
|
+
/* @__PURE__ */ new Set([absPath]),
|
|
50521
50554
|
data
|
|
50522
50555
|
);
|
|
50556
|
+
const resolved = linkDocPointers(
|
|
50557
|
+
assembled,
|
|
50558
|
+
assembled
|
|
50559
|
+
);
|
|
50523
50560
|
return { data: resolved, filePath: absPath };
|
|
50524
50561
|
}
|
|
50525
50562
|
|
|
@@ -52316,6 +52353,7 @@ var taskAgentBindingRule = {
|
|
|
52316
52353
|
}
|
|
52317
52354
|
for (const [taskId, task] of Object.entries(dsl.tasks)) {
|
|
52318
52355
|
for (const fromAgentId of task.allowed_from_agents) {
|
|
52356
|
+
if (fromAgentId === task.target_agent) continue;
|
|
52319
52357
|
const fromAgent = dsl.agents[fromAgentId];
|
|
52320
52358
|
if (fromAgent && !fromAgent.can_invoke_agents.includes(task.target_agent)) {
|
|
52321
52359
|
diagnostics.push({
|
|
@@ -52890,6 +52928,176 @@ var validationExecutorNoContextRule = {
|
|
|
52890
52928
|
}
|
|
52891
52929
|
};
|
|
52892
52930
|
|
|
52931
|
+
// src/linter/rules/extension-consumption.ts
|
|
52932
|
+
function isRecord5(v2) {
|
|
52933
|
+
return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
|
|
52934
|
+
}
|
|
52935
|
+
function collectXUsages(dsl) {
|
|
52936
|
+
const usages = /* @__PURE__ */ new Map();
|
|
52937
|
+
function record(key, path, nodeType) {
|
|
52938
|
+
let list = usages.get(key);
|
|
52939
|
+
if (!list) {
|
|
52940
|
+
list = [];
|
|
52941
|
+
usages.set(key, list);
|
|
52942
|
+
}
|
|
52943
|
+
list.push({ path, nodeType });
|
|
52944
|
+
}
|
|
52945
|
+
function walkObj(obj, path, nodeType) {
|
|
52946
|
+
for (const key of Object.keys(obj)) {
|
|
52947
|
+
if (key.startsWith("x-") && key !== "x-extensions" && key !== "x-extensions-strict") {
|
|
52948
|
+
record(key, path ? `${path}.${key}` : key, nodeType);
|
|
52949
|
+
}
|
|
52950
|
+
}
|
|
52951
|
+
}
|
|
52952
|
+
walkObj(dsl, "", "root");
|
|
52953
|
+
if (isRecord5(dsl.system)) {
|
|
52954
|
+
walkObj(dsl.system, "system", "system");
|
|
52955
|
+
}
|
|
52956
|
+
for (const [id, agent] of Object.entries(dsl.agents)) {
|
|
52957
|
+
const agentObj = agent;
|
|
52958
|
+
walkObj(agentObj, `agents.${id}`, "agent");
|
|
52959
|
+
if (Array.isArray(agentObj["rules"])) {
|
|
52960
|
+
for (let i3 = 0; i3 < agentObj["rules"].length; i3++) {
|
|
52961
|
+
const r3 = agentObj["rules"][i3];
|
|
52962
|
+
if (isRecord5(r3)) walkObj(r3, `agents.${id}.rules[${i3}]`, "rule");
|
|
52963
|
+
}
|
|
52964
|
+
}
|
|
52965
|
+
if (Array.isArray(agentObj["escalation_criteria"])) {
|
|
52966
|
+
for (let i3 = 0; i3 < agentObj["escalation_criteria"].length; i3++) {
|
|
52967
|
+
const e3 = agentObj["escalation_criteria"][i3];
|
|
52968
|
+
if (isRecord5(e3)) walkObj(e3, `agents.${id}.escalation_criteria[${i3}]`, "escalation_criterion");
|
|
52969
|
+
}
|
|
52970
|
+
}
|
|
52971
|
+
if (Array.isArray(agentObj["prerequisites"])) {
|
|
52972
|
+
for (let i3 = 0; i3 < agentObj["prerequisites"].length; i3++) {
|
|
52973
|
+
const p2 = agentObj["prerequisites"][i3];
|
|
52974
|
+
if (isRecord5(p2)) walkObj(p2, `agents.${id}.prerequisites[${i3}]`, "prerequisite");
|
|
52975
|
+
}
|
|
52976
|
+
}
|
|
52977
|
+
}
|
|
52978
|
+
for (const [id, task] of Object.entries(dsl.tasks)) {
|
|
52979
|
+
const taskObj = task;
|
|
52980
|
+
walkObj(taskObj, `tasks.${id}`, "task");
|
|
52981
|
+
if (Array.isArray(taskObj["execution_steps"])) {
|
|
52982
|
+
for (let i3 = 0; i3 < taskObj["execution_steps"].length; i3++) {
|
|
52983
|
+
const s2 = taskObj["execution_steps"][i3];
|
|
52984
|
+
if (isRecord5(s2)) walkObj(s2, `tasks.${id}.execution_steps[${i3}]`, "execution_step");
|
|
52985
|
+
}
|
|
52986
|
+
}
|
|
52987
|
+
}
|
|
52988
|
+
for (const [id, art] of Object.entries(dsl.artifacts)) {
|
|
52989
|
+
walkObj(art, `artifacts.${id}`, "artifact");
|
|
52990
|
+
}
|
|
52991
|
+
for (const [id, tool] of Object.entries(dsl.tools)) {
|
|
52992
|
+
const toolObj = tool;
|
|
52993
|
+
walkObj(toolObj, `tools.${id}`, "tool");
|
|
52994
|
+
if (Array.isArray(toolObj["commands"])) {
|
|
52995
|
+
for (let i3 = 0; i3 < toolObj["commands"].length; i3++) {
|
|
52996
|
+
const c2 = toolObj["commands"][i3];
|
|
52997
|
+
if (isRecord5(c2)) walkObj(c2, `tools.${id}.commands[${i3}]`, "tool_command");
|
|
52998
|
+
}
|
|
52999
|
+
}
|
|
53000
|
+
}
|
|
53001
|
+
for (const [id, val] of Object.entries(dsl.validations)) {
|
|
53002
|
+
walkObj(val, `validations.${id}`, "validation");
|
|
53003
|
+
}
|
|
53004
|
+
for (const [id, ht] of Object.entries(dsl.handoff_types)) {
|
|
53005
|
+
walkObj(ht, `handoff_types.${id}`, "handoff_type");
|
|
53006
|
+
}
|
|
53007
|
+
for (const [id, wf] of Object.entries(dsl.workflow)) {
|
|
53008
|
+
const wfObj = wf;
|
|
53009
|
+
walkObj(wfObj, `workflow.${id}`, "workflow");
|
|
53010
|
+
if (Array.isArray(wfObj["steps"])) {
|
|
53011
|
+
for (let i3 = 0; i3 < wfObj["steps"].length; i3++) {
|
|
53012
|
+
const s2 = wfObj["steps"][i3];
|
|
53013
|
+
if (isRecord5(s2)) walkObj(s2, `workflow.${id}.steps[${i3}]`, "workflow_step");
|
|
53014
|
+
}
|
|
53015
|
+
}
|
|
53016
|
+
}
|
|
53017
|
+
for (const [id, pol] of Object.entries(dsl.policies)) {
|
|
53018
|
+
walkObj(pol, `policies.${id}`, "policy");
|
|
53019
|
+
}
|
|
53020
|
+
for (const [id, gr] of Object.entries(dsl.guardrails)) {
|
|
53021
|
+
walkObj(gr, `guardrails.${id}`, "guardrail");
|
|
53022
|
+
}
|
|
53023
|
+
for (const [id, gp] of Object.entries(dsl.guardrail_policies)) {
|
|
53024
|
+
walkObj(gp, `guardrail_policies.${id}`, "guardrail_policy");
|
|
53025
|
+
}
|
|
53026
|
+
return usages;
|
|
53027
|
+
}
|
|
53028
|
+
var extensionDeclaredButUnusedRule = {
|
|
53029
|
+
id: "extension-declared-unused",
|
|
53030
|
+
description: "Declared extension in `extensions` is never used on any entity",
|
|
53031
|
+
run(dsl) {
|
|
53032
|
+
const diagnostics = [];
|
|
53033
|
+
const declaredKeys = Object.keys(dsl.extensions);
|
|
53034
|
+
if (declaredKeys.length === 0) return diagnostics;
|
|
53035
|
+
const usages = collectXUsages(dsl);
|
|
53036
|
+
for (const key of declaredKeys) {
|
|
53037
|
+
if (!usages.has(key)) {
|
|
53038
|
+
diagnostics.push({
|
|
53039
|
+
ruleId: "extension-declared-unused",
|
|
53040
|
+
severity: "warning",
|
|
53041
|
+
path: `extensions.${key}`,
|
|
53042
|
+
message: `Extension "${key}" is declared but never used on any entity`
|
|
53043
|
+
});
|
|
53044
|
+
}
|
|
53045
|
+
}
|
|
53046
|
+
return diagnostics;
|
|
53047
|
+
}
|
|
53048
|
+
};
|
|
53049
|
+
var extensionScopeMismatchRule = {
|
|
53050
|
+
id: "extension-scope-mismatch",
|
|
53051
|
+
description: "Extension used on a node type outside its declared scope",
|
|
53052
|
+
run(dsl) {
|
|
53053
|
+
const diagnostics = [];
|
|
53054
|
+
const extensions = dsl.extensions;
|
|
53055
|
+
if (Object.keys(extensions).length === 0) return diagnostics;
|
|
53056
|
+
const usages = collectXUsages(dsl);
|
|
53057
|
+
for (const [key, decl] of Object.entries(extensions)) {
|
|
53058
|
+
const scope = decl.scope;
|
|
53059
|
+
if (!scope || scope.length === 0) continue;
|
|
53060
|
+
const scopeSet = new Set(scope);
|
|
53061
|
+
const keyUsages = usages.get(key);
|
|
53062
|
+
if (!keyUsages) continue;
|
|
53063
|
+
for (const usage of keyUsages) {
|
|
53064
|
+
if (!scopeSet.has(usage.nodeType)) {
|
|
53065
|
+
diagnostics.push({
|
|
53066
|
+
ruleId: "extension-scope-mismatch",
|
|
53067
|
+
severity: "warning",
|
|
53068
|
+
path: usage.path,
|
|
53069
|
+
message: `Extension "${key}" is used on ${usage.nodeType} but declared scope is [${scope.join(", ")}]`
|
|
53070
|
+
});
|
|
53071
|
+
}
|
|
53072
|
+
}
|
|
53073
|
+
}
|
|
53074
|
+
return diagnostics;
|
|
53075
|
+
}
|
|
53076
|
+
};
|
|
53077
|
+
var extensionUndeclaredUsageRule = {
|
|
53078
|
+
id: "extension-undeclared-usage",
|
|
53079
|
+
description: "Entity uses x-* property that is not declared in extensions (when extensions section exists)",
|
|
53080
|
+
run(dsl) {
|
|
53081
|
+
const diagnostics = [];
|
|
53082
|
+
const extensions = dsl.extensions;
|
|
53083
|
+
if (Object.keys(extensions).length === 0) return diagnostics;
|
|
53084
|
+
const declaredKeys = new Set(Object.keys(extensions));
|
|
53085
|
+
const usages = collectXUsages(dsl);
|
|
53086
|
+
for (const [key, keyUsages] of usages) {
|
|
53087
|
+
if (declaredKeys.has(key)) continue;
|
|
53088
|
+
for (const usage of keyUsages) {
|
|
53089
|
+
diagnostics.push({
|
|
53090
|
+
ruleId: "extension-undeclared-usage",
|
|
53091
|
+
severity: "info",
|
|
53092
|
+
path: usage.path,
|
|
53093
|
+
message: `Extension "${key}" is used but not declared in extensions \u2014 consider adding a declaration`
|
|
53094
|
+
});
|
|
53095
|
+
}
|
|
53096
|
+
}
|
|
53097
|
+
return diagnostics;
|
|
53098
|
+
}
|
|
53099
|
+
};
|
|
53100
|
+
|
|
52893
53101
|
// src/linter/linter.ts
|
|
52894
53102
|
var builtinRules = [
|
|
52895
53103
|
validationCoverageRule,
|
|
@@ -52906,7 +53114,10 @@ var builtinRules = [
|
|
|
52906
53114
|
entityGuardrailUndefinedRule,
|
|
52907
53115
|
entityNoGuardrailsRule,
|
|
52908
53116
|
guardrailOrphanedRule,
|
|
52909
|
-
validationExecutorNoContextRule
|
|
53117
|
+
validationExecutorNoContextRule,
|
|
53118
|
+
extensionDeclaredButUnusedRule,
|
|
53119
|
+
extensionScopeMismatchRule,
|
|
53120
|
+
extensionUndeclaredUsageRule
|
|
52910
53121
|
];
|
|
52911
53122
|
function lint(dsl, rules = builtinRules) {
|
|
52912
53123
|
const diagnostics = [];
|
|
@@ -55839,6 +56050,121 @@ function formatDslOverview(dsl) {
|
|
|
55839
56050
|
`- Validations: ${Object.keys(dsl.validations).join(", ")}`
|
|
55840
56051
|
].join("\n");
|
|
55841
56052
|
}
|
|
56053
|
+
function isRecord6(v2) {
|
|
56054
|
+
return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
|
|
56055
|
+
}
|
|
56056
|
+
function collectAllXUsages(dsl) {
|
|
56057
|
+
const entries = [];
|
|
56058
|
+
function walk2(obj, path, nodeType) {
|
|
56059
|
+
for (const key of Object.keys(obj)) {
|
|
56060
|
+
if (key.startsWith("x-") && key !== "x-extensions" && key !== "x-extensions-strict") {
|
|
56061
|
+
entries.push({ path: path ? `${path}.${key}` : key, nodeType, key });
|
|
56062
|
+
}
|
|
56063
|
+
}
|
|
56064
|
+
}
|
|
56065
|
+
walk2(dsl, "", "root");
|
|
56066
|
+
if (isRecord6(dsl.system)) walk2(dsl.system, "system", "system");
|
|
56067
|
+
for (const [id, a3] of Object.entries(dsl.agents))
|
|
56068
|
+
walk2(a3, `agents.${id}`, "agent");
|
|
56069
|
+
for (const [id, t3] of Object.entries(dsl.tasks))
|
|
56070
|
+
walk2(t3, `tasks.${id}`, "task");
|
|
56071
|
+
for (const [id, a3] of Object.entries(dsl.artifacts))
|
|
56072
|
+
walk2(a3, `artifacts.${id}`, "artifact");
|
|
56073
|
+
for (const [id, t3] of Object.entries(dsl.tools))
|
|
56074
|
+
walk2(t3, `tools.${id}`, "tool");
|
|
56075
|
+
for (const [id, v2] of Object.entries(dsl.validations))
|
|
56076
|
+
walk2(v2, `validations.${id}`, "validation");
|
|
56077
|
+
for (const [id, h2] of Object.entries(dsl.handoff_types))
|
|
56078
|
+
walk2(h2, `handoff_types.${id}`, "handoff_type");
|
|
56079
|
+
for (const [id, w2] of Object.entries(dsl.workflow))
|
|
56080
|
+
walk2(w2, `workflow.${id}`, "workflow");
|
|
56081
|
+
for (const [id, p2] of Object.entries(dsl.policies))
|
|
56082
|
+
walk2(p2, `policies.${id}`, "policy");
|
|
56083
|
+
for (const [id, g2] of Object.entries(dsl.guardrails))
|
|
56084
|
+
walk2(g2, `guardrails.${id}`, "guardrail");
|
|
56085
|
+
for (const [id, gp] of Object.entries(dsl.guardrail_policies))
|
|
56086
|
+
walk2(gp, `guardrail_policies.${id}`, "guardrail_policy");
|
|
56087
|
+
return entries;
|
|
56088
|
+
}
|
|
56089
|
+
function extractTemplateXReferences(config) {
|
|
56090
|
+
const refs = [];
|
|
56091
|
+
try {
|
|
56092
|
+
const { readFileSync: readFileSync3 } = __require("fs");
|
|
56093
|
+
for (const target of config.renders) {
|
|
56094
|
+
try {
|
|
56095
|
+
const content = readFileSync3(target.template, "utf8");
|
|
56096
|
+
const matches = content.matchAll(/\{\{[^}]*?(x-[\w-]+)[^}]*?\}\}/g);
|
|
56097
|
+
for (const m2 of matches) refs.push(m2[1]);
|
|
56098
|
+
} catch {
|
|
56099
|
+
}
|
|
56100
|
+
}
|
|
56101
|
+
} catch {
|
|
56102
|
+
}
|
|
56103
|
+
return [...new Set(refs)];
|
|
56104
|
+
}
|
|
56105
|
+
function buildExtensionsContext(dsl, config) {
|
|
56106
|
+
const parts = [];
|
|
56107
|
+
parts.push("## Extension Declarations");
|
|
56108
|
+
const declaredKeys = Object.keys(dsl.extensions);
|
|
56109
|
+
if (declaredKeys.length === 0) {
|
|
56110
|
+
parts.push("(No extensions declared in `extensions` section)");
|
|
56111
|
+
} else {
|
|
56112
|
+
parts.push("```yaml\n" + yaml.stringify({ extensions: dsl.extensions }) + "```");
|
|
56113
|
+
}
|
|
56114
|
+
parts.push("## x-* Usage Map");
|
|
56115
|
+
const usages = collectAllXUsages(dsl);
|
|
56116
|
+
if (usages.length === 0) {
|
|
56117
|
+
parts.push("(No x-* properties found on any entity)");
|
|
56118
|
+
} else {
|
|
56119
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
56120
|
+
for (const u2 of usages) {
|
|
56121
|
+
let list = byKey.get(u2.key);
|
|
56122
|
+
if (!list) {
|
|
56123
|
+
list = [];
|
|
56124
|
+
byKey.set(u2.key, list);
|
|
56125
|
+
}
|
|
56126
|
+
list.push(u2);
|
|
56127
|
+
}
|
|
56128
|
+
const lines = ["| Extension | Node Type | Path |", "|-----------|-----------|------|"];
|
|
56129
|
+
for (const [key, entries] of byKey) {
|
|
56130
|
+
for (const e3 of entries) {
|
|
56131
|
+
lines.push(`| ${key} | ${e3.nodeType} | ${e3.path} |`);
|
|
56132
|
+
}
|
|
56133
|
+
}
|
|
56134
|
+
parts.push(lines.join("\n"));
|
|
56135
|
+
}
|
|
56136
|
+
parts.push("## Template x-* References");
|
|
56137
|
+
const templateRefs = extractTemplateXReferences(config);
|
|
56138
|
+
if (templateRefs.length === 0) {
|
|
56139
|
+
parts.push("(No x-* references found in render templates, or no templates configured)");
|
|
56140
|
+
} else {
|
|
56141
|
+
parts.push(templateRefs.map((r3) => `- ${r3}`).join("\n"));
|
|
56142
|
+
}
|
|
56143
|
+
parts.push("## Runtime Codegen Fixed Fields");
|
|
56144
|
+
parts.push(
|
|
56145
|
+
"The agent-contracts-runtime codegen templates emit only these fixed fields (x-* properties are not included in generated TypeScript contracts):\n- **AgentContract**: id, role_name, purpose, mode, dispatch_only, can_read_artifacts, can_write_artifacts, can_execute_tools, can_invoke_agents, can_return_handoffs, responsibilities, constraints, rules, escalation_criteria\n- **TaskContract**: id, description, target_agent, allowed_from_agents, workflow, invocation_handoff, result_handoff, input_artifacts, responsibilities, completion_criteria, optional\n- **WorkflowContract**: id, description, trigger, entry_conditions, steps"
|
|
56146
|
+
);
|
|
56147
|
+
const declaredSet = new Set(declaredKeys);
|
|
56148
|
+
const usedKeys = new Set(usages.map((u2) => u2.key));
|
|
56149
|
+
const templateRefSet = new Set(templateRefs);
|
|
56150
|
+
parts.push("## Gap Summary");
|
|
56151
|
+
const gaps = [];
|
|
56152
|
+
for (const key of declaredKeys) {
|
|
56153
|
+
if (!usedKeys.has(key)) gaps.push(`- **${key}**: declared but never populated on any entity`);
|
|
56154
|
+
}
|
|
56155
|
+
for (const key of usedKeys) {
|
|
56156
|
+
if (declaredKeys.length > 0 && !declaredSet.has(key))
|
|
56157
|
+
gaps.push(`- **${key}**: used on entities but not declared in extensions`);
|
|
56158
|
+
if (!templateRefSet.has(key))
|
|
56159
|
+
gaps.push(`- **${key}**: populated on entities but not referenced in any render template`);
|
|
56160
|
+
}
|
|
56161
|
+
if (gaps.length === 0) {
|
|
56162
|
+
parts.push("(No obvious gaps detected by static analysis)");
|
|
56163
|
+
} else {
|
|
56164
|
+
parts.push(gaps.join("\n"));
|
|
56165
|
+
}
|
|
56166
|
+
return parts.join("\n\n");
|
|
56167
|
+
}
|
|
55842
56168
|
async function buildAuditContext(auditType, dsl, config) {
|
|
55843
56169
|
const sections = [];
|
|
55844
56170
|
sections.push(formatDslOverview(dsl));
|
|
@@ -55859,6 +56185,9 @@ ${entry.content}`);
|
|
|
55859
56185
|
sections.push("(No rendered agent prompt files found. Run `agent-contracts render` first.)");
|
|
55860
56186
|
}
|
|
55861
56187
|
}
|
|
56188
|
+
if (auditType === "extensions") {
|
|
56189
|
+
sections.push(buildExtensionsContext(dsl, config));
|
|
56190
|
+
}
|
|
55862
56191
|
if (auditType === "dsl") {
|
|
55863
56192
|
sections.push("## Agent Definitions");
|
|
55864
56193
|
for (const [agentId, agentDef] of Object.entries(dsl.agents)) {
|
|
@@ -55925,7 +56254,8 @@ var dslAuditor = {
|
|
|
55925
56254
|
"Prioritize improvement recommendations (P0/P1/P2) with concrete fix proposals",
|
|
55926
56255
|
"Report score-based improvement areas as audit recommendations (read-only; consumes dsl-score-report produced by dsl-designer)",
|
|
55927
56256
|
"Review DSL design for semantic coherence (role overlap, scope breadth, gate placement)",
|
|
55928
|
-
"Verify generated prompts faithfully represent DSL intent (no hallucinated permissions)"
|
|
56257
|
+
"Verify generated prompts faithfully represent DSL intent (no hallucinated permissions)",
|
|
56258
|
+
"Audit x-* extension consumption across render templates and runtime codegen paths"
|
|
55929
56259
|
],
|
|
55930
56260
|
constraints: [
|
|
55931
56261
|
"Do not directly modify DSL definitions (read-only analysis)",
|
|
@@ -56186,12 +56516,14 @@ var auditSemanticDesign = {
|
|
|
56186
56516
|
"Verify handoff schemas carry sufficient fields for task completion_criteria",
|
|
56187
56517
|
"Check workflow gates are placed effectively",
|
|
56188
56518
|
"Detect guardrails declared but absent from execution path",
|
|
56189
|
-
"Check semantic validations are distributed across phases"
|
|
56519
|
+
"Check semantic validations are distributed across phases",
|
|
56520
|
+
"Detect custom x- properties that replicate standard DSL control-flow features (gate, decision, entry_conditions)"
|
|
56190
56521
|
],
|
|
56191
56522
|
completion_criteria: [
|
|
56192
56523
|
"All agents reviewed for scope and overlap",
|
|
56193
56524
|
"Workflow gate placement analyzed",
|
|
56194
56525
|
"Guardrail enforcement path verified",
|
|
56526
|
+
"Custom x- property misuse flagged",
|
|
56195
56527
|
"Findings classified with severity and category"
|
|
56196
56528
|
],
|
|
56197
56529
|
optional: false
|
|
@@ -56224,6 +56556,35 @@ var auditGeneratedPrompts = {
|
|
|
56224
56556
|
],
|
|
56225
56557
|
optional: false
|
|
56226
56558
|
};
|
|
56559
|
+
var auditExtensionConsumption = {
|
|
56560
|
+
id: "audit-extension-consumption",
|
|
56561
|
+
description: "Audit declared x-* extensions for consumption gaps across render and runtime paths",
|
|
56562
|
+
target_agent: "dsl-auditor",
|
|
56563
|
+
allowed_from_agents: [
|
|
56564
|
+
"dsl-auditor"
|
|
56565
|
+
],
|
|
56566
|
+
workflow: "dsl-audit",
|
|
56567
|
+
invocation_handoff: "dsl-task-request",
|
|
56568
|
+
result_handoff: "dsl-audit-result",
|
|
56569
|
+
input_artifacts: [
|
|
56570
|
+
"dsl-source",
|
|
56571
|
+
"dsl-generated-output"
|
|
56572
|
+
],
|
|
56573
|
+
responsibilities: [
|
|
56574
|
+
"Cross-check extensions declarations against entity x-* usage",
|
|
56575
|
+
"Identify x-* properties populated in DSL but not consumed by any render template",
|
|
56576
|
+
"Detect semantic overlap between x-* extensions and standard DSL features",
|
|
56577
|
+
"Report runtime codegen reachability for each extension",
|
|
56578
|
+
"Distinguish intentional metadata-only extensions from consumption gaps"
|
|
56579
|
+
],
|
|
56580
|
+
completion_criteria: [
|
|
56581
|
+
"All declared extensions checked for template and runtime consumption",
|
|
56582
|
+
"Unused extensions flagged with suggested action (remove, migrate to standard, or add template support)",
|
|
56583
|
+
"Runtime-unreachable extensions documented with explanation",
|
|
56584
|
+
"Findings classified with severity and category"
|
|
56585
|
+
],
|
|
56586
|
+
optional: false
|
|
56587
|
+
};
|
|
56227
56588
|
var taskRegistry = {
|
|
56228
56589
|
"update-dsl-definitions": updateDslDefinitions,
|
|
56229
56590
|
"update-dsl-binding": updateDslBinding,
|
|
@@ -56231,7 +56592,8 @@ var taskRegistry = {
|
|
|
56231
56592
|
"check-dsl-score": checkDslScore,
|
|
56232
56593
|
"audit-dsl-completeness": auditDslCompleteness,
|
|
56233
56594
|
"audit-semantic-design": auditSemanticDesign,
|
|
56234
|
-
"audit-generated-prompts": auditGeneratedPrompts
|
|
56595
|
+
"audit-generated-prompts": auditGeneratedPrompts,
|
|
56596
|
+
"audit-extension-consumption": auditExtensionConsumption
|
|
56235
56597
|
};
|
|
56236
56598
|
|
|
56237
56599
|
// src/generated/dsl-base/handoffs.ts
|
|
@@ -56253,8 +56615,44 @@ var DslTaskResultSchema = z20.object({
|
|
|
56253
56615
|
score_dimensions: z20.record(z20.string(), z20.unknown()).optional(),
|
|
56254
56616
|
notes: z20.string().optional()
|
|
56255
56617
|
});
|
|
56618
|
+
var AuditResultSchema = z20.object({
|
|
56619
|
+
summary: z20.string(),
|
|
56620
|
+
riskLevel: z20.enum(["low", "medium", "high", "critical"]),
|
|
56621
|
+
findings: z20.array(z20.object({
|
|
56622
|
+
id: z20.string().optional(),
|
|
56623
|
+
severity: z20.enum(["info", "warning", "error", "critical"]),
|
|
56624
|
+
category: z20.string(),
|
|
56625
|
+
target: z20.string().optional(),
|
|
56626
|
+
location: z20.string().optional(),
|
|
56627
|
+
message: z20.string(),
|
|
56628
|
+
recommendation: z20.string().optional(),
|
|
56629
|
+
confidence: z20.number().optional(),
|
|
56630
|
+
evidence: z20.array(z20.object({
|
|
56631
|
+
kind: z20.enum(["file", "command", "schema", "diff", "stdout", "stderr", "text"]),
|
|
56632
|
+
target: z20.string().optional(),
|
|
56633
|
+
location: z20.string().optional(),
|
|
56634
|
+
excerpt: z20.string().optional()
|
|
56635
|
+
})).optional(),
|
|
56636
|
+
details: z20.record(z20.string(), z20.unknown()).optional()
|
|
56637
|
+
})),
|
|
56638
|
+
recommendedActions: z20.array(z20.object({
|
|
56639
|
+
kind: z20.enum(["run_command", "edit_file", "review", "confirm", "block", "ignore"]),
|
|
56640
|
+
title: z20.string(),
|
|
56641
|
+
command: z20.string().optional(),
|
|
56642
|
+
target: z20.string().optional(),
|
|
56643
|
+
rationale: z20.string().optional()
|
|
56644
|
+
})).optional(),
|
|
56645
|
+
metadata: z20.object({
|
|
56646
|
+
tool: z20.string().optional(),
|
|
56647
|
+
command: z20.string().optional(),
|
|
56648
|
+
version: z20.string().optional(),
|
|
56649
|
+
generatedAt: z20.string().optional(),
|
|
56650
|
+
adapter: z20.string().optional(),
|
|
56651
|
+
model: z20.string().optional()
|
|
56652
|
+
}).optional()
|
|
56653
|
+
});
|
|
56256
56654
|
var DslAuditResultSchema = z20.object({
|
|
56257
|
-
audit_type: z20.enum(["completeness", "semantic", "prompt"]),
|
|
56655
|
+
audit_type: z20.enum(["completeness", "semantic", "prompt", "extensions"]),
|
|
56258
56656
|
total_dimensions: z20.number(),
|
|
56259
56657
|
pass_count: z20.number(),
|
|
56260
56658
|
miss_count: z20.number(),
|
|
@@ -56278,6 +56676,7 @@ var DslAuditResultSchema = z20.object({
|
|
|
56278
56676
|
var handoffSchemas = {
|
|
56279
56677
|
"dsl-task-request": DslTaskRequestSchema,
|
|
56280
56678
|
"dsl-task-result": DslTaskResultSchema,
|
|
56679
|
+
"audit-result": AuditResultSchema,
|
|
56281
56680
|
"dsl-audit-result": DslAuditResultSchema
|
|
56282
56681
|
};
|
|
56283
56682
|
|
|
@@ -56330,7 +56729,8 @@ async function createAdapter(runtimePkg, name, config) {
|
|
|
56330
56729
|
var AUDIT_TYPE_TO_TASK = {
|
|
56331
56730
|
render: "audit-dsl-completeness",
|
|
56332
56731
|
dsl: "audit-semantic-design",
|
|
56333
|
-
prompt: "audit-generated-prompts"
|
|
56732
|
+
prompt: "audit-generated-prompts",
|
|
56733
|
+
extensions: "audit-extension-consumption"
|
|
56334
56734
|
};
|
|
56335
56735
|
async function runAudit(dsl, config, auditConfig, options) {
|
|
56336
56736
|
const taskId = AUDIT_TYPE_TO_TASK[options.auditType];
|
|
@@ -56384,7 +56784,7 @@ async function runAudit(dsl, config, auditConfig, options) {
|
|
|
56384
56784
|
};
|
|
56385
56785
|
}
|
|
56386
56786
|
async function runAllAudits(dsl, config, auditConfig, options) {
|
|
56387
|
-
const types = ["render", "dsl", "prompt"];
|
|
56787
|
+
const types = ["render", "dsl", "prompt", "extensions"];
|
|
56388
56788
|
const results = [];
|
|
56389
56789
|
for (const auditType of types) {
|
|
56390
56790
|
results.push(await runAudit(dsl, config, auditConfig, { ...options, auditType }));
|
|
@@ -57092,7 +57492,7 @@ ${issues}
|
|
|
57092
57492
|
process.exit(1);
|
|
57093
57493
|
}
|
|
57094
57494
|
};
|
|
57095
|
-
var AUDIT_TYPES = ["render", "dsl", "prompt", "all"];
|
|
57495
|
+
var AUDIT_TYPES = ["render", "dsl", "prompt", "extensions", "all"];
|
|
57096
57496
|
function parseAuditConfig(configObj) {
|
|
57097
57497
|
if (!configObj) return {};
|
|
57098
57498
|
const audit = configObj;
|