jorgex-stack 1.6.0 → 1.7.1
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/dist/cli.js +333 -46
- package/package.json +1 -1
- package/stack/contracts/quality-capabilities.v1.schema.json +117 -0
package/dist/cli.js
CHANGED
|
@@ -26,6 +26,7 @@ import * as p from "@clack/prompts";
|
|
|
26
26
|
// src/adapters/opencode.ts
|
|
27
27
|
import path6 from "path";
|
|
28
28
|
import fs3 from "fs";
|
|
29
|
+
import { isDeepStrictEqual } from "util";
|
|
29
30
|
import { pathToFileURL } from "url";
|
|
30
31
|
|
|
31
32
|
// src/lib/canonical.ts
|
|
@@ -300,15 +301,19 @@ function detectEngram() {
|
|
|
300
301
|
function markers(name) {
|
|
301
302
|
return { open: `<!-- jorgex:${name} -->`, close: `<!-- /jorgex:${name} -->` };
|
|
302
303
|
}
|
|
304
|
+
function hasHealthyManagedMarkdownMarkers(existing, name) {
|
|
305
|
+
const { open, close } = markers(name);
|
|
306
|
+
const count = (marker) => existing.split(marker).length - 1;
|
|
307
|
+
const onOwnLine = (marker) => existing.split("\n").some((line) => line.trim() === marker);
|
|
308
|
+
return count(open) === 1 && count(close) === 1 && existing.indexOf(close) > existing.indexOf(open) && onOwnLine(open) && onOwnLine(close);
|
|
309
|
+
}
|
|
303
310
|
function repairOrphanMarkers(existing, name) {
|
|
304
311
|
const { open, close } = markers(name);
|
|
305
312
|
const count = (marker) => existing.split(marker).length - 1;
|
|
306
313
|
const opens = count(open);
|
|
307
314
|
const closes = count(close);
|
|
308
315
|
if (opens === 0 && closes === 0) return existing;
|
|
309
|
-
|
|
310
|
-
const healthy = opens === 1 && closes === 1 && existing.indexOf(close) > existing.indexOf(open) && onOwnLine(open) && onOwnLine(close);
|
|
311
|
-
if (healthy) return existing;
|
|
316
|
+
if (hasHealthyManagedMarkdownMarkers(existing, name)) return existing;
|
|
312
317
|
return existing.split("\n").map((line) => line.trim() === open || line.trim() === close ? null : line.split(open).join("").split(close).join("")).filter((line) => line !== null).join("\n");
|
|
313
318
|
}
|
|
314
319
|
function upsertMarkdownSection(existing, name, content) {
|
|
@@ -540,6 +545,79 @@ var DESTRUCTIVE_GIT_DENY = [
|
|
|
540
545
|
];
|
|
541
546
|
var GIT_GUARD_SCRIPT = "block-destructive-git.cjs";
|
|
542
547
|
|
|
548
|
+
// src/lib/quality-capabilities.ts
|
|
549
|
+
var QUALITY_CAPABILITY_NAMESPACE = "jorgex.quality.capabilities";
|
|
550
|
+
var QUALITY_CAPABILITY_VERSION = 1;
|
|
551
|
+
var QUALITY_CAPABILITY_IDS = [
|
|
552
|
+
"policy-guidance",
|
|
553
|
+
"tool-approval",
|
|
554
|
+
"external-verification"
|
|
555
|
+
];
|
|
556
|
+
var UNAVAILABLE_REASON = "No reviewed local declaration is available";
|
|
557
|
+
var EXTERNAL_VERIFICATION_REASON = "External verification is available only through the external verifier";
|
|
558
|
+
function hasText(value) {
|
|
559
|
+
return typeof value === "string" && value.trim() !== "";
|
|
560
|
+
}
|
|
561
|
+
function isRuntime(value) {
|
|
562
|
+
return value === "claude-code" || value === "codex" || value === "opencode" || value === "pi";
|
|
563
|
+
}
|
|
564
|
+
function hasValidEvidence(value) {
|
|
565
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
566
|
+
const evidence = value;
|
|
567
|
+
return hasText(evidence.source) && hasText(evidence.version);
|
|
568
|
+
}
|
|
569
|
+
function unavailableCapability(id, reason = UNAVAILABLE_REASON) {
|
|
570
|
+
return { id, state: "unavailable", reason };
|
|
571
|
+
}
|
|
572
|
+
function declarationFor(id, declarations, runtime) {
|
|
573
|
+
if (runtime === "unknown") {
|
|
574
|
+
return unavailableCapability(id, "Runtime is unknown; local capability cannot be established");
|
|
575
|
+
}
|
|
576
|
+
if (id === "external-verification") {
|
|
577
|
+
return unavailableCapability(id, EXTERNAL_VERIFICATION_REASON);
|
|
578
|
+
}
|
|
579
|
+
const matches = declarations.filter((declaration2) => declaration2?.id === id);
|
|
580
|
+
if (matches.length === 0) return unavailableCapability(id);
|
|
581
|
+
if (matches.length !== 1) return unavailableCapability(id, "Duplicate capability declarations are ambiguous");
|
|
582
|
+
const declaration = matches[0];
|
|
583
|
+
const state = declaration.state;
|
|
584
|
+
const reason = hasText(declaration.reason) ? declaration.reason.trim() : void 0;
|
|
585
|
+
if (!reason) return unavailableCapability(id, "Capability declaration has no reason");
|
|
586
|
+
if (state !== "prompt-only" && state !== "manual" && state !== "unavailable") {
|
|
587
|
+
return unavailableCapability(id, "Capability state is not a supported local state");
|
|
588
|
+
}
|
|
589
|
+
if (state === "unavailable") return { id, state, reason };
|
|
590
|
+
if (!hasValidEvidence(declaration.evidence)) {
|
|
591
|
+
return unavailableCapability(id, "Capability declaration lacks reviewed source/version evidence");
|
|
592
|
+
}
|
|
593
|
+
const evidence = declaration.evidence;
|
|
594
|
+
return {
|
|
595
|
+
id,
|
|
596
|
+
state,
|
|
597
|
+
reason,
|
|
598
|
+
evidence: {
|
|
599
|
+
source: evidence.source.trim(),
|
|
600
|
+
version: evidence.version.trim()
|
|
601
|
+
}
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
function hasManagedMarkdownSection(content, name) {
|
|
605
|
+
return content !== null && hasHealthyManagedMarkdownMarkers(content, name);
|
|
606
|
+
}
|
|
607
|
+
function createLocalCapabilityReport(runtime, declarations) {
|
|
608
|
+
const normalizedRuntime = isRuntime(runtime) ? runtime : "unknown";
|
|
609
|
+
return {
|
|
610
|
+
namespace: QUALITY_CAPABILITY_NAMESPACE,
|
|
611
|
+
version: QUALITY_CAPABILITY_VERSION,
|
|
612
|
+
runtime: normalizedRuntime,
|
|
613
|
+
capabilities: QUALITY_CAPABILITY_IDS.map((id) => declarationFor(id, declarations, normalizedRuntime))
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
function localQualityStatus(profile, status) {
|
|
617
|
+
if ((profile === "high" || profile === "release") && status === "pass") return "incomplete";
|
|
618
|
+
return status;
|
|
619
|
+
}
|
|
620
|
+
|
|
543
621
|
// src/adapters/opencode.ts
|
|
544
622
|
function yamlString(value) {
|
|
545
623
|
return JSON.stringify(value);
|
|
@@ -580,10 +658,39 @@ function pruneEmpty(parent, key) {
|
|
|
580
658
|
const value = objectValue(parent[key]);
|
|
581
659
|
if (value !== null && Object.keys(value).length === 0) delete parent[key];
|
|
582
660
|
}
|
|
661
|
+
function hasOpenCodeManualApproval(configDir) {
|
|
662
|
+
const content = readTextIfExists(path6.join(configDir, "opencode.json"));
|
|
663
|
+
if (content === null) return false;
|
|
664
|
+
try {
|
|
665
|
+
const root = JSON.parse(content);
|
|
666
|
+
const permission = objectValue(objectValue(root)?.permission);
|
|
667
|
+
const expected = loadCanonicalDefaults(stackRoot())["opencode"]?.["permission"];
|
|
668
|
+
return permission !== null && expected !== void 0 && isDeepStrictEqual(permission, expected);
|
|
669
|
+
} catch {
|
|
670
|
+
return false;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
583
673
|
var opencodeAdapter = {
|
|
584
674
|
id: "opencode",
|
|
585
675
|
name: "OpenCode",
|
|
586
676
|
detect: detectOpenCode,
|
|
677
|
+
reportCapabilities(configDir) {
|
|
678
|
+
const prompt = readTextIfExists(path6.join(configDir, "AGENTS.md"));
|
|
679
|
+
return createLocalCapabilityReport("opencode", [
|
|
680
|
+
...hasManagedMarkdownSection(prompt, "system-prompt") ? [{
|
|
681
|
+
id: "policy-guidance",
|
|
682
|
+
state: "prompt-only",
|
|
683
|
+
reason: "The managed policy prompt is advisory and cannot enforce the policy",
|
|
684
|
+
evidence: { source: "jorgex-stack-system-prompt", version: "1" }
|
|
685
|
+
}] : [],
|
|
686
|
+
...hasOpenCodeManualApproval(configDir) ? [{
|
|
687
|
+
id: "tool-approval",
|
|
688
|
+
state: "manual",
|
|
689
|
+
reason: "Canonical approval declarations require a human decision; runtime activation is not certified",
|
|
690
|
+
evidence: { source: "jorgex-stack-opencode-approval-policy", version: "1" }
|
|
691
|
+
}] : []
|
|
692
|
+
]);
|
|
693
|
+
},
|
|
587
694
|
injectEngramProtocol() {
|
|
588
695
|
return false;
|
|
589
696
|
},
|
|
@@ -914,6 +1021,7 @@ ${agent.body}`,
|
|
|
914
1021
|
// src/adapters/claude-code.ts
|
|
915
1022
|
import path7 from "path";
|
|
916
1023
|
import fs4 from "fs";
|
|
1024
|
+
import { isDeepStrictEqual as isDeepStrictEqual2 } from "util";
|
|
917
1025
|
function yamlString2(value) {
|
|
918
1026
|
return JSON.stringify(value);
|
|
919
1027
|
}
|
|
@@ -924,6 +1032,21 @@ var ENGRAM_AGENT_TOOLS = [
|
|
|
924
1032
|
"Skill",
|
|
925
1033
|
...memoryTools(["mem_context", "mem_search", "mem_get_observation", "mem_timeline", "mem_current_project"])
|
|
926
1034
|
];
|
|
1035
|
+
function isRecord(value) {
|
|
1036
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1037
|
+
}
|
|
1038
|
+
function hasClaudeManualApproval(configDir) {
|
|
1039
|
+
const content = readTextIfExists(path7.join(configDir, "settings.json"));
|
|
1040
|
+
if (content === null) return false;
|
|
1041
|
+
try {
|
|
1042
|
+
const root = JSON.parse(content);
|
|
1043
|
+
const permissions = isRecord(root) ? root.permissions : void 0;
|
|
1044
|
+
const expected = loadCanonicalDefaults(stackRoot())["claude-code"]?.["permissions"];
|
|
1045
|
+
return isRecord(permissions) && expected !== void 0 && isDeepStrictEqual2(permissions, expected);
|
|
1046
|
+
} catch {
|
|
1047
|
+
return false;
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
927
1050
|
function toolsFor(agent) {
|
|
928
1051
|
if (agent.name === "engram") return ENGRAM_AGENT_TOOLS.join(", ");
|
|
929
1052
|
if (!agent.readonly) return null;
|
|
@@ -956,6 +1079,23 @@ var claudeCodeAdapter = {
|
|
|
956
1079
|
id: "claude-code",
|
|
957
1080
|
name: "Claude Code",
|
|
958
1081
|
detect: detectClaudeCode,
|
|
1082
|
+
reportCapabilities(configDir) {
|
|
1083
|
+
const prompt = readTextIfExists(path7.join(configDir, "CLAUDE.md"));
|
|
1084
|
+
return createLocalCapabilityReport("claude-code", [
|
|
1085
|
+
...hasManagedMarkdownSection(prompt, "system-prompt") ? [{
|
|
1086
|
+
id: "policy-guidance",
|
|
1087
|
+
state: "prompt-only",
|
|
1088
|
+
reason: "The managed policy prompt is advisory and cannot enforce the policy",
|
|
1089
|
+
evidence: { source: "jorgex-stack-system-prompt", version: "1" }
|
|
1090
|
+
}] : [],
|
|
1091
|
+
...hasClaudeManualApproval(configDir) ? [{
|
|
1092
|
+
id: "tool-approval",
|
|
1093
|
+
state: "manual",
|
|
1094
|
+
reason: "Canonical approval declarations require a human decision; runtime activation is not certified",
|
|
1095
|
+
evidence: { source: "jorgex-stack-claude-approval-policy", version: "1" }
|
|
1096
|
+
}] : []
|
|
1097
|
+
]);
|
|
1098
|
+
},
|
|
959
1099
|
injectEngramProtocol(ctx) {
|
|
960
1100
|
return !hasEngramPlugin(ctx.configDir);
|
|
961
1101
|
},
|
|
@@ -1172,10 +1312,167 @@ function hasEngramProtocol(configDir) {
|
|
|
1172
1312
|
const config = readTextIfExists(path8.join(configDir, "config.toml"));
|
|
1173
1313
|
return config !== null && /engram-instructions\.md/.test(config);
|
|
1174
1314
|
}
|
|
1315
|
+
var CODEX_JSON_STRING = String.raw`"(?:\\.|[^"\\\r\n])*"`;
|
|
1316
|
+
var CODEX_JSON_VALUE = String.raw`(?:${CODEX_JSON_STRING}|-?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?|true|false)`;
|
|
1317
|
+
var CODEX_JSON_STRING_ARRAY = String.raw`\[(?:\s*${CODEX_JSON_STRING}(?:\s*,\s*${CODEX_JSON_STRING})*\s*)?\]`;
|
|
1318
|
+
var CODEX_KEY = String.raw`(?:[A-Za-z0-9_-]+|${CODEX_JSON_STRING})`;
|
|
1319
|
+
var CODEX_ASSIGNMENT = new RegExp(String.raw`^\s*(${CODEX_KEY})\s*=\s*(${CODEX_JSON_STRING_ARRAY}|${CODEX_JSON_VALUE})\s*(?:#.*)?$`);
|
|
1320
|
+
var CODEX_HEADER = new RegExp(String.raw`^\[\s*(${CODEX_KEY}(?:\s*\.\s*${CODEX_KEY})*)\s*\]\s*(?:#.*)?$`);
|
|
1321
|
+
var CODEX_PERMISSION_HEADERS = {
|
|
1322
|
+
base: "permissions.jorgex-read-anywhere",
|
|
1323
|
+
filesystem: "permissions.jorgex-read-anywhere.filesystem",
|
|
1324
|
+
workspaceRoots: 'permissions.jorgex-read-anywhere.filesystem.":workspace_roots"'
|
|
1325
|
+
};
|
|
1326
|
+
var CODEX_PERMISSION_PROFILE = {
|
|
1327
|
+
base: [["extends", ":workspace"]],
|
|
1328
|
+
filesystem: [
|
|
1329
|
+
[":root", "read"],
|
|
1330
|
+
["*.env", "deny"],
|
|
1331
|
+
["*.env.*", "deny"],
|
|
1332
|
+
["~/.ssh/**", "deny"],
|
|
1333
|
+
["~/.aws/credentials", "deny"],
|
|
1334
|
+
["~/.npmrc", "deny"],
|
|
1335
|
+
["~/.git-credentials", "deny"],
|
|
1336
|
+
["**/id_rsa", "deny"],
|
|
1337
|
+
["**/id_ed25519", "deny"],
|
|
1338
|
+
["**/*.pem", "deny"],
|
|
1339
|
+
["**/*.key", "deny"]
|
|
1340
|
+
],
|
|
1341
|
+
workspaceRoots: [
|
|
1342
|
+
[".", "write"],
|
|
1343
|
+
["*.env", "deny"],
|
|
1344
|
+
["*.env.*", "deny"],
|
|
1345
|
+
[".ssh/**", "deny"],
|
|
1346
|
+
[".aws/credentials", "deny"],
|
|
1347
|
+
[".npmrc", "deny"],
|
|
1348
|
+
[".git-credentials", "deny"],
|
|
1349
|
+
["**/id_rsa", "deny"],
|
|
1350
|
+
["**/id_ed25519", "deny"],
|
|
1351
|
+
["**/*.pem", "deny"],
|
|
1352
|
+
["**/*.key", "deny"]
|
|
1353
|
+
]
|
|
1354
|
+
};
|
|
1355
|
+
var CODEX_PERMISSION_SECTIONS = [
|
|
1356
|
+
{ header: CODEX_PERMISSION_HEADERS.base, entries: CODEX_PERMISSION_PROFILE.base, quoteKeys: false },
|
|
1357
|
+
{ header: CODEX_PERMISSION_HEADERS.filesystem, entries: CODEX_PERMISSION_PROFILE.filesystem, quoteKeys: true },
|
|
1358
|
+
{ header: CODEX_PERMISSION_HEADERS.workspaceRoots, entries: CODEX_PERMISSION_PROFILE.workspaceRoots, quoteKeys: true }
|
|
1359
|
+
];
|
|
1360
|
+
function renderCodexPermissionEntries(entries, quoteKeys) {
|
|
1361
|
+
return entries.map(([key, value]) => `${quoteKeys ? JSON.stringify(key) : key} = ${JSON.stringify(value)}`).join("\n");
|
|
1362
|
+
}
|
|
1363
|
+
function parseCodexKey(raw) {
|
|
1364
|
+
if (!raw.startsWith('"')) return raw;
|
|
1365
|
+
try {
|
|
1366
|
+
const value = JSON.parse(raw);
|
|
1367
|
+
return typeof value === "string" ? value : null;
|
|
1368
|
+
} catch {
|
|
1369
|
+
return null;
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
function parseCodexValue(raw) {
|
|
1373
|
+
try {
|
|
1374
|
+
const value = JSON.parse(raw);
|
|
1375
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string") || !Array.isArray(value) && (value === null || typeof value !== "object") ? value : void 0;
|
|
1376
|
+
} catch {
|
|
1377
|
+
return void 0;
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
function parseCodexHeader(line) {
|
|
1381
|
+
const match = CODEX_HEADER.exec(line.trim());
|
|
1382
|
+
if (match === null) return null;
|
|
1383
|
+
for (const quoted of match[1].match(/"(?:\\.|[^"\\\r\n])*"/g) ?? []) {
|
|
1384
|
+
if (parseCodexKey(quoted) === null) return null;
|
|
1385
|
+
}
|
|
1386
|
+
return match[1].replace(/\s*\.\s*/g, ".");
|
|
1387
|
+
}
|
|
1388
|
+
function scanCodexToml(config) {
|
|
1389
|
+
if (config.includes("'''") || config.includes('"""')) return null;
|
|
1390
|
+
const root = /* @__PURE__ */ new Map();
|
|
1391
|
+
const sections = /* @__PURE__ */ new Map();
|
|
1392
|
+
const headers = /* @__PURE__ */ new Set();
|
|
1393
|
+
const keys = /* @__PURE__ */ new Set();
|
|
1394
|
+
let section = null;
|
|
1395
|
+
for (const line of config.replace(/\r\n/g, "\n").split("\n")) {
|
|
1396
|
+
const trimmed = line.trim();
|
|
1397
|
+
if (trimmed === "" || trimmed.startsWith("#")) continue;
|
|
1398
|
+
if (trimmed.startsWith("[")) {
|
|
1399
|
+
const header = parseCodexHeader(trimmed);
|
|
1400
|
+
if (header === null || headers.has(header)) return null;
|
|
1401
|
+
headers.add(header);
|
|
1402
|
+
if (header.startsWith(`${CODEX_PERMISSION_HEADERS.base}.`) && !CODEX_PERMISSION_SECTIONS.some((entry) => entry.header === header)) {
|
|
1403
|
+
return null;
|
|
1404
|
+
}
|
|
1405
|
+
section = header;
|
|
1406
|
+
if (CODEX_PERMISSION_SECTIONS.some((entry) => entry.header === header)) sections.set(header, /* @__PURE__ */ new Map());
|
|
1407
|
+
continue;
|
|
1408
|
+
}
|
|
1409
|
+
const relevant = section === null || CODEX_PERMISSION_SECTIONS.some((entry) => entry.header === section);
|
|
1410
|
+
const match = CODEX_ASSIGNMENT.exec(trimmed);
|
|
1411
|
+
if (!relevant && match === null) continue;
|
|
1412
|
+
if (match === null) return null;
|
|
1413
|
+
const key = parseCodexKey(match[1]);
|
|
1414
|
+
const value = parseCodexValue(match[2]);
|
|
1415
|
+
if (key === null || value === void 0) return null;
|
|
1416
|
+
if (section === null && (key === "profile" || key === "sandbox_mode")) return null;
|
|
1417
|
+
const scope = section ?? "<root>";
|
|
1418
|
+
const declaration = `${scope}\0${key}`;
|
|
1419
|
+
if (keys.has(declaration)) return null;
|
|
1420
|
+
keys.add(declaration);
|
|
1421
|
+
if (section === null) root.set(key, value);
|
|
1422
|
+
else if (sections.has(section)) sections.get(section).set(key, value);
|
|
1423
|
+
}
|
|
1424
|
+
return { root, sections };
|
|
1425
|
+
}
|
|
1426
|
+
function hasCanonicalCodexPermissionProfile(scan) {
|
|
1427
|
+
for (const { header, entries } of CODEX_PERMISSION_SECTIONS) {
|
|
1428
|
+
const actual = scan.sections.get(header);
|
|
1429
|
+
if (actual === void 0 || actual.size !== entries.length) return false;
|
|
1430
|
+
for (const [key, expected] of entries) {
|
|
1431
|
+
if (actual.get(key) !== expected) return false;
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
return true;
|
|
1435
|
+
}
|
|
1436
|
+
function hasCodexManualApproval(configDir) {
|
|
1437
|
+
const config = readTextIfExists(path8.join(configDir, "config.toml"));
|
|
1438
|
+
if (config === null) return false;
|
|
1439
|
+
const scan = scanCodexToml(config);
|
|
1440
|
+
if (scan === null) return false;
|
|
1441
|
+
try {
|
|
1442
|
+
const defaults = loadCanonicalDefaults(stackRoot())["codex"];
|
|
1443
|
+
const expectedApproval = defaults?.["approval_policy"];
|
|
1444
|
+
const expectedPermissions = defaults?.["default_permissions"];
|
|
1445
|
+
return typeof expectedApproval === "string" && typeof expectedPermissions === "string" && scan.root.get("approval_policy") === expectedApproval && scan.root.get("default_permissions") === expectedPermissions && hasCanonicalCodexPermissionProfile(scan);
|
|
1446
|
+
} catch {
|
|
1447
|
+
return false;
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1175
1450
|
var codexAdapter = {
|
|
1176
1451
|
id: "codex",
|
|
1177
1452
|
name: "Codex CLI",
|
|
1178
1453
|
detect: detectCodex,
|
|
1454
|
+
reportCapabilities(configDir) {
|
|
1455
|
+
const prompt = readTextIfExists(path8.join(configDir, "AGENTS.md"));
|
|
1456
|
+
return createLocalCapabilityReport("codex", [
|
|
1457
|
+
...hasManagedMarkdownSection(prompt, "system-prompt") ? [{
|
|
1458
|
+
id: "policy-guidance",
|
|
1459
|
+
state: "prompt-only",
|
|
1460
|
+
reason: "The managed policy prompt is advisory and cannot enforce the policy",
|
|
1461
|
+
evidence: { source: "jorgex-stack-system-prompt", version: "1" }
|
|
1462
|
+
}] : [],
|
|
1463
|
+
...hasCodexManualApproval(configDir) ? [{
|
|
1464
|
+
id: "tool-approval",
|
|
1465
|
+
state: "manual",
|
|
1466
|
+
reason: "Canonical approval declarations require a human decision; runtime activation is not certified",
|
|
1467
|
+
evidence: { source: "jorgex-stack-codex-approval-policy", version: "1" }
|
|
1468
|
+
}] : [],
|
|
1469
|
+
{
|
|
1470
|
+
id: "external-verification",
|
|
1471
|
+
state: "unavailable",
|
|
1472
|
+
reason: "External verification is available only through the external verifier"
|
|
1473
|
+
}
|
|
1474
|
+
]);
|
|
1475
|
+
},
|
|
1179
1476
|
injectEngramProtocol(ctx) {
|
|
1180
1477
|
return !hasEngramProtocol(ctx.configDir);
|
|
1181
1478
|
},
|
|
@@ -1275,37 +1572,20 @@ ${body}`
|
|
|
1275
1572
|
ctx.warnings.push(
|
|
1276
1573
|
"Codex: fresh config enables read-anywhere via the jorgex-read-anywhere permission profile; broad local reads can expose secrets not covered by deny rules."
|
|
1277
1574
|
);
|
|
1278
|
-
content = upsertTomlSection(content, "permissions.jorgex-read-anywhere", 'extends = ":workspace"');
|
|
1279
1575
|
content = upsertTomlSection(
|
|
1280
1576
|
content,
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
'"~/.npmrc" = "deny"',
|
|
1289
|
-
'"~/.git-credentials" = "deny"',
|
|
1290
|
-
'"**/id_rsa" = "deny"',
|
|
1291
|
-
'"**/id_ed25519" = "deny"',
|
|
1292
|
-
'"**/*.pem" = "deny"',
|
|
1293
|
-
'"**/*.key" = "deny"'
|
|
1294
|
-
].join("\n")
|
|
1577
|
+
CODEX_PERMISSION_HEADERS.base,
|
|
1578
|
+
renderCodexPermissionEntries(CODEX_PERMISSION_PROFILE.base, false)
|
|
1579
|
+
);
|
|
1580
|
+
content = upsertTomlSection(
|
|
1581
|
+
content,
|
|
1582
|
+
CODEX_PERMISSION_HEADERS.filesystem,
|
|
1583
|
+
renderCodexPermissionEntries(CODEX_PERMISSION_PROFILE.filesystem, true)
|
|
1295
1584
|
);
|
|
1296
1585
|
content += [
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
'"*.env.*" = "deny"',
|
|
1301
|
-
'".ssh/**" = "deny"',
|
|
1302
|
-
'".aws/credentials" = "deny"',
|
|
1303
|
-
'".npmrc" = "deny"',
|
|
1304
|
-
'".git-credentials" = "deny"',
|
|
1305
|
-
'"**/id_rsa" = "deny"',
|
|
1306
|
-
'"**/id_ed25519" = "deny"',
|
|
1307
|
-
'"**/*.pem" = "deny"',
|
|
1308
|
-
'"**/*.key" = "deny"',
|
|
1586
|
+
`
|
|
1587
|
+
[${CODEX_PERMISSION_HEADERS.workspaceRoots}]`,
|
|
1588
|
+
renderCodexPermissionEntries(CODEX_PERMISSION_PROFILE.workspaceRoots, true),
|
|
1309
1589
|
""
|
|
1310
1590
|
].join("\n");
|
|
1311
1591
|
}
|
|
@@ -1959,7 +2239,7 @@ function devtoolsMcpPreferenceFile(stateDir = dataDir()) {
|
|
|
1959
2239
|
function primaryModelOwnershipFile(stateDir = dataDir()) {
|
|
1960
2240
|
return path19.join(stateDir, "primary-model.json");
|
|
1961
2241
|
}
|
|
1962
|
-
function
|
|
2242
|
+
function isRecord2(value) {
|
|
1963
2243
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1964
2244
|
}
|
|
1965
2245
|
function isRuntimeId(value) {
|
|
@@ -1968,7 +2248,7 @@ function isRuntimeId(value) {
|
|
|
1968
2248
|
function parseDevtoolsMcpState(raw) {
|
|
1969
2249
|
try {
|
|
1970
2250
|
const value = JSON.parse(raw);
|
|
1971
|
-
if (!
|
|
2251
|
+
if (!isRecord2(value) || value.version !== DEVTOOLS_MCP_PREFERENCE_VERSION || !isRecord2(value.enabled) || !isRecord2(value.owned)) return null;
|
|
1972
2252
|
const enabled = {};
|
|
1973
2253
|
for (const [runtime, selected] of Object.entries(value.enabled)) {
|
|
1974
2254
|
if (!isRuntimeId(runtime) || typeof selected !== "boolean") return null;
|
|
@@ -1976,7 +2256,7 @@ function parseDevtoolsMcpState(raw) {
|
|
|
1976
2256
|
}
|
|
1977
2257
|
const owned = {};
|
|
1978
2258
|
for (const [runtime, servers] of Object.entries(value.owned)) {
|
|
1979
|
-
if (!isRuntimeId(runtime) || !
|
|
2259
|
+
if (!isRuntimeId(runtime) || !isRecord2(servers)) return null;
|
|
1980
2260
|
const managed = {};
|
|
1981
2261
|
for (const [server, marked] of Object.entries(servers)) {
|
|
1982
2262
|
if (marked !== true) return null;
|
|
@@ -2032,13 +2312,13 @@ function saveDevtoolsMcpOwnership(file, runtime, server, owned) {
|
|
|
2032
2312
|
function parsePrimaryModelOwnership(raw) {
|
|
2033
2313
|
try {
|
|
2034
2314
|
const value = JSON.parse(raw);
|
|
2035
|
-
if (!
|
|
2315
|
+
if (!isRecord2(value) || value.version !== PRIMARY_MODEL_OWNERSHIP_VERSION || !isRecord2(value.owned)) return null;
|
|
2036
2316
|
const owned = {};
|
|
2037
2317
|
for (const [runtime, configs] of Object.entries(value.owned)) {
|
|
2038
|
-
if (!isRuntimeId(runtime) || !
|
|
2318
|
+
if (!isRuntimeId(runtime) || !isRecord2(configs)) return null;
|
|
2039
2319
|
const markedConfigs = {};
|
|
2040
2320
|
for (const [configDir, fields] of Object.entries(configs)) {
|
|
2041
|
-
if (configDir === "" || !
|
|
2321
|
+
if (configDir === "" || !isRecord2(fields)) return null;
|
|
2042
2322
|
const markedFields = {};
|
|
2043
2323
|
for (const [field, state] of Object.entries(fields)) {
|
|
2044
2324
|
if (field === "" || state !== true) return null;
|
|
@@ -3522,6 +3802,9 @@ async function runDoctor() {
|
|
|
3522
3802
|
p3.log.warn(`${adapter.name}: no instalado en esta m\xE1quina.`);
|
|
3523
3803
|
continue;
|
|
3524
3804
|
}
|
|
3805
|
+
const capabilityReport = adapter.reportCapabilities(detection.configDir);
|
|
3806
|
+
const capabilitySummary = capabilityReport.capabilities.map((capability) => `${capability.id}=${capability.state}`).join(", ");
|
|
3807
|
+
p3.log.info(`${adapter.name}: capabilities diagnostic (${capabilitySummary}); no certifica enforcement local.`);
|
|
3525
3808
|
const ctx = makeContext(adapter, detection.configDir, modePreference);
|
|
3526
3809
|
if (!ctx) continue;
|
|
3527
3810
|
let pending;
|
|
@@ -5453,10 +5736,10 @@ function normalizeTimeout(value) {
|
|
|
5453
5736
|
return timeoutMs;
|
|
5454
5737
|
}
|
|
5455
5738
|
var COMMIT_SHA_PATTERN = /^[0-9a-f]{40}$/i;
|
|
5456
|
-
function
|
|
5739
|
+
function isRecord3(value) {
|
|
5457
5740
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
5458
5741
|
}
|
|
5459
|
-
function
|
|
5742
|
+
function hasText2(value) {
|
|
5460
5743
|
return typeof value === "string" && value.trim() !== "";
|
|
5461
5744
|
}
|
|
5462
5745
|
function isDenseStringArray(value) {
|
|
@@ -5473,14 +5756,14 @@ function isQualityProfile(value) {
|
|
|
5473
5756
|
return typeof value === "string" && QUALITY_PROFILES.includes(value);
|
|
5474
5757
|
}
|
|
5475
5758
|
function assertValidEnvironment(value, label) {
|
|
5476
|
-
if (!
|
|
5759
|
+
if (!isRecord3(value)) throw new Error(`Invalid ${label}`);
|
|
5477
5760
|
for (const [key, entry] of Object.entries(value)) {
|
|
5478
5761
|
if (typeof entry !== "string") throw new Error(`Invalid ${label}.${key}`);
|
|
5479
5762
|
}
|
|
5480
5763
|
}
|
|
5481
5764
|
function assertQualityPlanInput(value) {
|
|
5482
|
-
if (!
|
|
5483
|
-
if (!
|
|
5765
|
+
if (!isRecord3(value)) throw new Error("Invalid quality plan");
|
|
5766
|
+
if (!isRecord3(value.identity)) throw new Error("Invalid quality plan identity");
|
|
5484
5767
|
if (typeof value.identity.baseSha !== "string" || !COMMIT_SHA_PATTERN.test(value.identity.baseSha)) {
|
|
5485
5768
|
throw new Error("Invalid quality plan identity.baseSha");
|
|
5486
5769
|
}
|
|
@@ -5492,7 +5775,7 @@ function assertQualityPlanInput(value) {
|
|
|
5492
5775
|
const controlIds = /* @__PURE__ */ new Set();
|
|
5493
5776
|
for (let index = 0; index < value.controls.length; index += 1) {
|
|
5494
5777
|
const control = value.controls[index];
|
|
5495
|
-
if (!
|
|
5778
|
+
if (!isRecord3(control) || !hasText2(control.id) || control.requirement !== "required" && control.requirement !== "optional") {
|
|
5496
5779
|
throw new Error(`Invalid quality plan controls[${index}]`);
|
|
5497
5780
|
}
|
|
5498
5781
|
if (controlIds.has(control.id)) {
|
|
@@ -5508,9 +5791,9 @@ function assertQualityPlanInput(value) {
|
|
|
5508
5791
|
const commandControlIds = /* @__PURE__ */ new Set();
|
|
5509
5792
|
for (let index = 0; index < value.commands.length; index += 1) {
|
|
5510
5793
|
const command = value.commands[index];
|
|
5511
|
-
if (!
|
|
5794
|
+
if (!isRecord3(command)) throw new Error(`Invalid quality plan commands[${index}]`);
|
|
5512
5795
|
const timeoutMs = command.timeoutMs;
|
|
5513
|
-
if (!
|
|
5796
|
+
if (!hasText2(command.controlId) || !hasText2(command.commandId) || !hasText2(command.executable) || !isDenseStringArray(command.argv) || !isNonNegativeSafeInteger(timeoutMs)) {
|
|
5514
5797
|
throw new Error(`Invalid quality plan commands[${index}]`);
|
|
5515
5798
|
}
|
|
5516
5799
|
if (timeoutMs > MAX_NODE_TIMEOUT_MS) {
|
|
@@ -5753,7 +6036,7 @@ function missingRequiredResults(controls, commands) {
|
|
|
5753
6036
|
const commandControlIds = new Set(commands.map((command) => command.controlId));
|
|
5754
6037
|
const missing = /* @__PURE__ */ new Set();
|
|
5755
6038
|
for (const control of controls) {
|
|
5756
|
-
if (control.requirement !== "required" || !
|
|
6039
|
+
if (control.requirement !== "required" || !hasText2(control.id) || commandControlIds.has(control.id)) continue;
|
|
5757
6040
|
missing.add(control.id);
|
|
5758
6041
|
}
|
|
5759
6042
|
return [...missing].map((controlId) => ({
|
|
@@ -5791,11 +6074,15 @@ async function runQualityPlan(input) {
|
|
|
5791
6074
|
results.push(receiptResultFor(command.controlId, result));
|
|
5792
6075
|
}
|
|
5793
6076
|
results.push(...missingRequiredResults(input.controls, input.commands));
|
|
5794
|
-
const
|
|
6077
|
+
const policyEvaluation = evaluateQualityPolicy({
|
|
5795
6078
|
profile: input.profile,
|
|
5796
6079
|
controls: input.controls,
|
|
5797
6080
|
results
|
|
5798
6081
|
});
|
|
6082
|
+
const evaluation = {
|
|
6083
|
+
...policyEvaluation,
|
|
6084
|
+
status: localQualityStatus(input.profile, policyEvaluation.status)
|
|
6085
|
+
};
|
|
5799
6086
|
const receipt = createQualityReceipt({
|
|
5800
6087
|
authority: "local",
|
|
5801
6088
|
identity,
|
package/package.json
CHANGED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://jorgex.dev/contracts/quality-capabilities.v1.schema.json",
|
|
4
|
+
"title": "JorgeX local quality capabilities v1",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": ["namespace", "version", "runtime", "capabilities"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"namespace": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"const": "jorgex.quality.capabilities"
|
|
12
|
+
},
|
|
13
|
+
"version": {
|
|
14
|
+
"type": "integer",
|
|
15
|
+
"const": 1
|
|
16
|
+
},
|
|
17
|
+
"runtime": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"enum": ["claude-code", "codex", "opencode", "pi", "unknown"]
|
|
20
|
+
},
|
|
21
|
+
"capabilities": {
|
|
22
|
+
"type": "array",
|
|
23
|
+
"minItems": 3,
|
|
24
|
+
"maxItems": 3,
|
|
25
|
+
"items": {
|
|
26
|
+
"type": "object",
|
|
27
|
+
"additionalProperties": false,
|
|
28
|
+
"required": ["id", "state", "reason"],
|
|
29
|
+
"properties": {
|
|
30
|
+
"id": {
|
|
31
|
+
"type": "string",
|
|
32
|
+
"enum": ["policy-guidance", "tool-approval", "external-verification"]
|
|
33
|
+
},
|
|
34
|
+
"state": {
|
|
35
|
+
"$ref": "#/$defs/localCapabilityState"
|
|
36
|
+
},
|
|
37
|
+
"reason": {
|
|
38
|
+
"type": "string",
|
|
39
|
+
"pattern": "\\S"
|
|
40
|
+
},
|
|
41
|
+
"evidence": {
|
|
42
|
+
"type": "object",
|
|
43
|
+
"additionalProperties": false,
|
|
44
|
+
"required": ["source", "version"],
|
|
45
|
+
"properties": {
|
|
46
|
+
"source": {
|
|
47
|
+
"type": "string",
|
|
48
|
+
"pattern": "\\S"
|
|
49
|
+
},
|
|
50
|
+
"version": {
|
|
51
|
+
"type": "string",
|
|
52
|
+
"pattern": "\\S"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"allOf": [
|
|
58
|
+
{
|
|
59
|
+
"if": {
|
|
60
|
+
"properties": {"id": {"const": "external-verification"}},
|
|
61
|
+
"required": ["id"]
|
|
62
|
+
},
|
|
63
|
+
"then": {
|
|
64
|
+
"properties": {"state": {"const": "unavailable"}}
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"if": {
|
|
69
|
+
"properties": {"state": {"enum": ["prompt-only", "manual"]}},
|
|
70
|
+
"required": ["state"]
|
|
71
|
+
},
|
|
72
|
+
"then": {
|
|
73
|
+
"required": ["evidence"]
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
},
|
|
78
|
+
"allOf": [
|
|
79
|
+
{
|
|
80
|
+
"contains": {
|
|
81
|
+
"type": "object",
|
|
82
|
+
"properties": {"id": {"const": "policy-guidance"}},
|
|
83
|
+
"required": ["id"]
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"contains": {
|
|
88
|
+
"type": "object",
|
|
89
|
+
"properties": {"id": {"const": "tool-approval"}},
|
|
90
|
+
"required": ["id"]
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"contains": {
|
|
95
|
+
"type": "object",
|
|
96
|
+
"properties": {"id": {"const": "external-verification"}},
|
|
97
|
+
"required": ["id"]
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
"$defs": {
|
|
104
|
+
"capabilityState": {
|
|
105
|
+
"type": "string",
|
|
106
|
+
"enum": ["enforced", "prompt-only", "manual", "unavailable"]
|
|
107
|
+
},
|
|
108
|
+
"localCapabilityState": {
|
|
109
|
+
"type": "string",
|
|
110
|
+
"enum": ["prompt-only", "manual", "unavailable"]
|
|
111
|
+
},
|
|
112
|
+
"strictProfile": {
|
|
113
|
+
"type": "string",
|
|
114
|
+
"enum": ["high", "release"]
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|