@maintainabilityai/research-runner 0.1.46 → 0.1.47
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/runner/skills.js +57 -25
- package/package.json +1 -1
package/dist/runner/skills.js
CHANGED
|
@@ -1338,15 +1338,27 @@ const handleKnowledgeCode = async (input) => {
|
|
|
1338
1338
|
// Workflow gate consumes this to validate cited paths.
|
|
1339
1339
|
inventory_paths: inventoryPaths,
|
|
1340
1340
|
};
|
|
1341
|
-
// Bug-R / R6 (Codex round-
|
|
1342
|
-
// cache so knowledge-code-read can strict-
|
|
1343
|
-
// paths against the same list that lands
|
|
1344
|
-
//
|
|
1345
|
-
//
|
|
1341
|
+
// Bug-R / R6 + Bug-S / S6 (Codex round-4 hardening) — persist
|
|
1342
|
+
// inventory to the clone cache so knowledge-code-read can strict-
|
|
1343
|
+
// mode validate requested paths against the same list that lands
|
|
1344
|
+
// in the audit chain. Round-3 caught the inventory-persist write
|
|
1345
|
+
// being non-fatal; round-4 flagged that as fail-open — without
|
|
1346
|
+
// a written inventory, knowledge-code-read's path-not-in-inventory
|
|
1347
|
+
// check silently falls through (the file just isn't there to
|
|
1348
|
+
// check against). S6 fix: persist failure is now FATAL. The
|
|
1349
|
+
// brownfield grounding contract requires the inventory to exist;
|
|
1350
|
+
// a skill_call that succeeded without writing it is a coverage lie.
|
|
1346
1351
|
try {
|
|
1347
1352
|
fs.writeFileSync(path.join(cloneTarget, '.knowledge-code-inventory.json'), JSON.stringify({ inventory_paths: inventoryPaths, sha, cachedAt: new Date().toISOString() }), 'utf8');
|
|
1348
1353
|
}
|
|
1349
|
-
catch {
|
|
1354
|
+
catch (err) {
|
|
1355
|
+
return {
|
|
1356
|
+
ok: false,
|
|
1357
|
+
reason: `inventory-persist-failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
1358
|
+
repo: repoSlug,
|
|
1359
|
+
remediation: "knowledge-code MUST persist its file inventory so knowledge-code-read can strict-mode validate file reads against it. Check tmpdir permissions and disk space.",
|
|
1360
|
+
};
|
|
1361
|
+
}
|
|
1350
1362
|
return {
|
|
1351
1363
|
ok: true,
|
|
1352
1364
|
mode: 'brownfield',
|
|
@@ -1445,27 +1457,47 @@ const handleKnowledgeCodeRead = async (input) => {
|
|
|
1445
1457
|
remediation: `Could not access clone for ${repoUrl}. Underlying error: ${cloneResult.error ?? 'unknown'}`,
|
|
1446
1458
|
};
|
|
1447
1459
|
}
|
|
1448
|
-
// Bug-R / R6 (
|
|
1449
|
-
// against the inventory persisted by knowledge-
|
|
1450
|
-
//
|
|
1451
|
-
// readable
|
|
1452
|
-
//
|
|
1453
|
-
//
|
|
1460
|
+
// Bug-R / R6 + Bug-S / S6 (Codex round-4 hardening) — validate
|
|
1461
|
+
// the requested path against the inventory persisted by knowledge-
|
|
1462
|
+
// code. Only paths knowledge-code advertised in `inventory_paths`
|
|
1463
|
+
// are readable. Round-3 left missing/malformed inventory as a
|
|
1464
|
+
// fall-through (silent pass); round-4 caught that as fail-open.
|
|
1465
|
+
// S6: missing inventory file or malformed JSON is now a HARD
|
|
1466
|
+
// FAILURE in non-test mode. The cache exists (we passed the
|
|
1467
|
+
// earlier no-cache check), so the inventory file MUST exist —
|
|
1468
|
+
// its absence means knowledge-code didn't complete normally.
|
|
1454
1469
|
if (!allowUncached) {
|
|
1455
1470
|
const inventoryPath = path.join(cloneResult.path, '.knowledge-code-inventory.json');
|
|
1456
|
-
if (fs.existsSync(inventoryPath)) {
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1471
|
+
if (!fs.existsSync(inventoryPath)) {
|
|
1472
|
+
return {
|
|
1473
|
+
ok: false,
|
|
1474
|
+
reason: `inventory-missing: ${gh.owner}/${gh.name}'s clone exists but .knowledge-code-inventory.json is absent. knowledge-code did not complete normally — re-run it before invoking knowledge-code-read.`,
|
|
1475
|
+
};
|
|
1476
|
+
}
|
|
1477
|
+
let inv;
|
|
1478
|
+
try {
|
|
1479
|
+
inv = JSON.parse(fs.readFileSync(inventoryPath, 'utf8'));
|
|
1480
|
+
}
|
|
1481
|
+
catch (err) {
|
|
1482
|
+
return {
|
|
1483
|
+
ok: false,
|
|
1484
|
+
reason: `inventory-malformed: .knowledge-code-inventory.json could not be parsed: ${err instanceof Error ? err.message : String(err)}`,
|
|
1485
|
+
remediation: "Re-run knowledge-code to regenerate the inventory.",
|
|
1486
|
+
};
|
|
1487
|
+
}
|
|
1488
|
+
const allowed = new Set(inv.inventory_paths ?? []);
|
|
1489
|
+
if (allowed.size === 0) {
|
|
1490
|
+
return {
|
|
1491
|
+
ok: false,
|
|
1492
|
+
reason: `inventory-empty: .knowledge-code-inventory.json carries no inventory_paths. knowledge-code likely walked zero files (empty repo? maxFiles=0?). Cannot validate file reads.`,
|
|
1493
|
+
};
|
|
1494
|
+
}
|
|
1495
|
+
if (!allowed.has(normalized)) {
|
|
1496
|
+
return {
|
|
1497
|
+
ok: false,
|
|
1498
|
+
reason: `path-not-in-inventory: ${normalized} is not in the knowledge-code inventory_paths for ${gh.owner}/${gh.name}. The agent can only read files knowledge-code advertised in the chain.`,
|
|
1499
|
+
remediation: "If the file is real but missed by the bounded walk (default maxFiles=200), call knowledge-code with a higher maxFiles before retrying.",
|
|
1500
|
+
};
|
|
1469
1501
|
}
|
|
1470
1502
|
}
|
|
1471
1503
|
const absPath = path.join(cloneResult.path, normalized);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maintainabilityai/research-runner",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.47",
|
|
4
4
|
"description": "Research + PRD agent runner — orchestrates the Archeologist and PRD pipelines for the MaintainabilityAI governance mesh",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "MaintainabilityAI",
|