@arbiterforge/ca-pi 0.8.1 → 0.10.2
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/README.md +29 -90
- package/package.json +1 -1
- package/plugins/ca-pi/CHANGELOG.md +89 -0
- package/plugins/ca-pi/COMMANDS.md +141 -64
- package/plugins/ca-pi/SKILLS.md +137 -28
- package/plugins/ca-pi/agents/INDEX.md +3 -2
- package/plugins/ca-pi/agents/checkpoint-aggregator.md +8 -7
- package/plugins/ca-pi/agents/finding-triage.md +31 -14
- package/plugins/ca-pi/agents/verdict-aggregator.md +64 -0
- package/plugins/ca-pi/arbiter.md +12 -3
- package/plugins/ca-pi/extensions/codearbiter.js +137 -15
- package/plugins/ca-pi/generated/command-catalog.json +386 -186
- package/plugins/ca-pi/generated/roles.json +9 -0
- package/plugins/ca-pi/hooks/_bashguardlib.py +33 -16
- package/plugins/ca-pi/hooks/_gitexec.py +23 -0
- package/plugins/ca-pi/hooks/_githooks.py +50 -23
- package/plugins/ca-pi/hooks/_hooklib.py +94 -7
- package/plugins/ca-pi/hooks/_host.py +9 -1
- package/plugins/ca-pi/hooks/_modelib.py +173 -55
- package/plugins/ca-pi/hooks/_protectedlib.py +13 -4
- package/plugins/ca-pi/hooks/_releaselib.py +278 -48
- package/plugins/ca-pi/hooks/_updatelib.py +230 -50
- package/plugins/ca-pi/hooks/doctor.py +56 -8
- package/plugins/ca-pi/hooks/git-enforce.py +10 -3
- package/plugins/ca-pi/hooks/hostapi.py +220 -22
- package/plugins/ca-pi/hooks/session-start.py +8 -6
- package/plugins/ca-pi/hooks/statusline.py +1 -1
- package/plugins/ca-pi/hooks/wire-statusline.py +13 -8
- package/plugins/ca-pi/includes/command-compatibility.md +16 -0
- package/plugins/ca-pi/includes/routing-table.md +13 -5
- package/plugins/ca-pi/routines/INDEX.md +1 -1
- package/plugins/ca-pi/routines/decision-lifecycle/SKILL.md +54 -2
- package/plugins/ca-pi/routines/decision-lifecycle/references/adr-template.md +9 -1
- package/plugins/ca-pi/routines/dispatching-parallel-agents/SKILL.md +4 -4
- package/plugins/ca-pi/routines/release/SKILL.md +1 -1
- package/plugins/ca-pi/skills/ca-checkpoint/SKILL.md +5 -4
- package/plugins/ca-pi/skills/ca-cleanup/SKILL.md +6 -0
- package/plugins/ca-pi/skills/ca-context-check/SKILL.md +6 -0
- package/plugins/ca-pi/skills/ca-create-context/SKILL.md +6 -0
- package/plugins/ca-pi/skills/ca-decompose/SKILL.md +6 -0
- package/plugins/ca-pi/skills/ca-doctor/SKILL.md +4 -0
- package/plugins/ca-pi/skills/ca-init/SKILL.md +18 -1
- package/plugins/ca-pi/skills/ca-pr/SKILL.md +17 -1
- package/plugins/ca-pi/skills/ca-review/SKILL.md +3 -4
- package/plugins/ca-pi/skills/ca-status/SKILL.md +13 -1
- package/plugins/ca-pi/skills/ca-watch/SKILL.md +6 -0
|
@@ -1546,10 +1546,14 @@ public static class CodeArbiterJob {
|
|
|
1546
1546
|
'@
|
|
1547
1547
|
try {
|
|
1548
1548
|
Add-Type -TypeDefinition $source -Language CSharp | Out-Null
|
|
1549
|
+
[Console]::Out.WriteLine('COMPILED')
|
|
1550
|
+
[Console]::Out.Flush()
|
|
1549
1551
|
$line = [Console]::In.ReadLine()
|
|
1550
1552
|
if ($null -eq $line -or $line -notmatch '^([1-9][0-9]*) ([1-9][0-9]*)$') { exit 40 }
|
|
1551
1553
|
[UInt32]$target = $Matches[1]
|
|
1552
1554
|
[UInt32]$parent = $Matches[2]
|
|
1555
|
+
[Console]::Out.WriteLine('PID_ACCEPTED')
|
|
1556
|
+
[Console]::Out.Flush()
|
|
1553
1557
|
$job = [CodeArbiterJob]::CreateAndAssign($target)
|
|
1554
1558
|
if ($job -eq [IntPtr]::Zero) { exit 41 }
|
|
1555
1559
|
try {
|
|
@@ -1642,12 +1646,31 @@ async function awaitProgressTokens(readLine, expected, options) {
|
|
|
1642
1646
|
if (idleMs > ceilingMs) throw new Error("progress idleMs must be bounded by the progress ceiling");
|
|
1643
1647
|
const now = options.now ?? Date.now;
|
|
1644
1648
|
const deadline = now() + ceilingMs;
|
|
1649
|
+
if (options.windowsJobStages && (expected.length !== 2 || expected[0] !== WINDOWS_JOB_STARTING || expected[1] !== WINDOWS_JOB_READY)) {
|
|
1650
|
+
throw new Error("Windows startup diagnostics require the bounded admission sequence");
|
|
1651
|
+
}
|
|
1652
|
+
let lastStage = "WAITING";
|
|
1645
1653
|
for (const token of expected) {
|
|
1646
|
-
const remaining = deadline - now();
|
|
1647
|
-
if (remaining <= 0) return Object.freeze({ state: "stalled", phase: token, waitedMs: 0 });
|
|
1648
1654
|
const started = now();
|
|
1649
|
-
const
|
|
1650
|
-
|
|
1655
|
+
const phaseDeadline = Math.min(deadline, started + idleMs);
|
|
1656
|
+
const stalled = () => Object.freeze({
|
|
1657
|
+
state: "stalled",
|
|
1658
|
+
phase: token,
|
|
1659
|
+
waitedMs: now() - started,
|
|
1660
|
+
...options.windowsJobStages ? { lastStage } : {}
|
|
1661
|
+
});
|
|
1662
|
+
const diagnostics = options.windowsJobStages && token === WINDOWS_JOB_READY ? ["COMPILED", "PID_ACCEPTED"] : [];
|
|
1663
|
+
for (const diagnostic of diagnostics) {
|
|
1664
|
+
const remaining2 = phaseDeadline - now();
|
|
1665
|
+
if (remaining2 <= 0) return stalled();
|
|
1666
|
+
if (await readLine(remaining2) !== diagnostic) return stalled();
|
|
1667
|
+
lastStage = diagnostic;
|
|
1668
|
+
}
|
|
1669
|
+
const remaining = phaseDeadline - now();
|
|
1670
|
+
if (remaining <= 0) return stalled();
|
|
1671
|
+
const line = await readLine(remaining);
|
|
1672
|
+
if (line !== token) return stalled();
|
|
1673
|
+
if (options.windowsJobStages && token === WINDOWS_JOB_STARTING) lastStage = "STARTING";
|
|
1651
1674
|
}
|
|
1652
1675
|
return Object.freeze({ state: "ready" });
|
|
1653
1676
|
}
|
|
@@ -1831,7 +1854,9 @@ function startWindowsJobGuard(pid, timing) {
|
|
|
1831
1854
|
let closePending;
|
|
1832
1855
|
let armed = false;
|
|
1833
1856
|
let outputEnded = false;
|
|
1857
|
+
let protocolFailed = false;
|
|
1834
1858
|
let outputBuffer = "";
|
|
1859
|
+
let queuedOutputBytes = 0;
|
|
1835
1860
|
const outputLines = [];
|
|
1836
1861
|
const outputWaiters = [];
|
|
1837
1862
|
let resolveExitCode;
|
|
@@ -1851,7 +1876,11 @@ function startWindowsJobGuard(pid, timing) {
|
|
|
1851
1876
|
settleExitCode();
|
|
1852
1877
|
};
|
|
1853
1878
|
const readOutputLine = (timeoutMs) => {
|
|
1854
|
-
if (outputLines.length > 0)
|
|
1879
|
+
if (outputLines.length > 0) {
|
|
1880
|
+
const { line, bytes } = outputLines.shift();
|
|
1881
|
+
queuedOutputBytes -= bytes;
|
|
1882
|
+
return Promise.resolve(line);
|
|
1883
|
+
}
|
|
1855
1884
|
if (outputEnded) return Promise.resolve(void 0);
|
|
1856
1885
|
return new Promise((resolveLine) => {
|
|
1857
1886
|
let timer;
|
|
@@ -1870,8 +1899,11 @@ function startWindowsJobGuard(pid, timing) {
|
|
|
1870
1899
|
helper.stdout.setEncoding("utf8");
|
|
1871
1900
|
helper.stdout.on("data", (chunk) => {
|
|
1872
1901
|
if (outputEnded) return;
|
|
1873
|
-
outputBuffer
|
|
1874
|
-
|
|
1902
|
+
if (queuedOutputBytes + Buffer.byteLength(outputBuffer, "utf8") + Buffer.byteLength(chunk, "utf8") > MAX_JOB_PROTOCOL_BYTES) {
|
|
1903
|
+
protocolFailed = true;
|
|
1904
|
+
outputLines.length = 0;
|
|
1905
|
+
queuedOutputBytes = 0;
|
|
1906
|
+
outputBuffer = "";
|
|
1875
1907
|
finishOutput();
|
|
1876
1908
|
try {
|
|
1877
1909
|
helper.stdin.end();
|
|
@@ -1879,13 +1911,17 @@ function startWindowsJobGuard(pid, timing) {
|
|
|
1879
1911
|
}
|
|
1880
1912
|
return;
|
|
1881
1913
|
}
|
|
1914
|
+
outputBuffer += chunk;
|
|
1882
1915
|
let newline = outputBuffer.indexOf("\n");
|
|
1883
1916
|
while (newline >= 0) {
|
|
1917
|
+
const bytes = Buffer.byteLength(outputBuffer.slice(0, newline + 1), "utf8");
|
|
1884
1918
|
const line = outputBuffer.slice(0, newline).replace(/\r$/u, "");
|
|
1885
1919
|
outputBuffer = outputBuffer.slice(newline + 1);
|
|
1886
1920
|
const waiter = outputWaiters.shift();
|
|
1887
|
-
if (waiter === void 0)
|
|
1888
|
-
|
|
1921
|
+
if (waiter === void 0) {
|
|
1922
|
+
outputLines.push({ line, bytes });
|
|
1923
|
+
queuedOutputBytes += bytes;
|
|
1924
|
+
} else waiter(line);
|
|
1889
1925
|
newline = outputBuffer.indexOf("\n");
|
|
1890
1926
|
}
|
|
1891
1927
|
});
|
|
@@ -1912,8 +1948,9 @@ function startWindowsJobGuard(pid, timing) {
|
|
|
1912
1948
|
const finish = (accepted) => {
|
|
1913
1949
|
if (settled) return false;
|
|
1914
1950
|
settled = true;
|
|
1915
|
-
|
|
1916
|
-
|
|
1951
|
+
const admitted = accepted && !protocolFailed;
|
|
1952
|
+
resolveReady(admitted);
|
|
1953
|
+
if (!admitted) {
|
|
1917
1954
|
try {
|
|
1918
1955
|
helper.stdin.end();
|
|
1919
1956
|
} catch {
|
|
@@ -1930,9 +1967,9 @@ function startWindowsJobGuard(pid, timing) {
|
|
|
1930
1967
|
if (!intentional) finish(false);
|
|
1931
1968
|
});
|
|
1932
1969
|
helper.once("error", () => finish(false));
|
|
1933
|
-
void awaitProgressTokens(readOutputLine, WINDOWS_JOB_READY_TOKENS, { ceilingMs, idleMs }).then((outcome) => {
|
|
1970
|
+
void awaitProgressTokens(readOutputLine, WINDOWS_JOB_READY_TOKENS, { ceilingMs, idleMs, windowsJobStages: true }).then((outcome) => {
|
|
1934
1971
|
const refused = finish(outcome.state === "ready");
|
|
1935
|
-
if (refused && outcome.state === "stalled") stallDiagnostic = `stalled at ${outcome.phase} after ${outcome.waitedMs}ms`;
|
|
1972
|
+
if (refused && outcome.state === "stalled") stallDiagnostic = `stalled at ${outcome.phase} after ${outcome.waitedMs}ms; last startup stage ${outcome.lastStage}`;
|
|
1936
1973
|
}, () => finish(false));
|
|
1937
1974
|
try {
|
|
1938
1975
|
helper.stdin.write(`${pid} ${process.pid}
|
|
@@ -1950,7 +1987,7 @@ function startWindowsJobGuard(pid, timing) {
|
|
|
1950
1987
|
return stallDiagnostic;
|
|
1951
1988
|
},
|
|
1952
1989
|
async arm(rootPid) {
|
|
1953
|
-
if (armed || !positivePid(rootPid) || !await ready || closed) return false;
|
|
1990
|
+
if (armed || !positivePid(rootPid) || !await ready || closed || protocolFailed) return false;
|
|
1954
1991
|
armed = true;
|
|
1955
1992
|
const watched = readOutputLine(idleMs);
|
|
1956
1993
|
const written = await new Promise((resolveWrite) => {
|
|
@@ -9722,6 +9759,88 @@ async function appendPiCompactionAudit(record2) {
|
|
|
9722
9759
|
}
|
|
9723
9760
|
|
|
9724
9761
|
// src/extension.ts
|
|
9762
|
+
var COMMAND_VISIBILITY_ORDER = ["core", "advanced", "alias", "internal", "deprecated"];
|
|
9763
|
+
var COMMAND_WORKFLOW_ORDER = [
|
|
9764
|
+
"evaluate",
|
|
9765
|
+
"initialize",
|
|
9766
|
+
"change",
|
|
9767
|
+
"review",
|
|
9768
|
+
"decide",
|
|
9769
|
+
"ship",
|
|
9770
|
+
"operate",
|
|
9771
|
+
"extend",
|
|
9772
|
+
"help"
|
|
9773
|
+
];
|
|
9774
|
+
function plainRecord2(value) {
|
|
9775
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype;
|
|
9776
|
+
}
|
|
9777
|
+
function sameStrings2(actual, expected) {
|
|
9778
|
+
return actual.length === expected.length && actual.every((item, index) => item === expected[index]);
|
|
9779
|
+
}
|
|
9780
|
+
function validLegacyRoutes(value) {
|
|
9781
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string" && /^[a-z][a-z0-9-]*$/u.test(item)) && new Set(value).size === value.length && sameStrings2(value, [...value].sort());
|
|
9782
|
+
}
|
|
9783
|
+
function commandCatalogEntries(value) {
|
|
9784
|
+
const envelopeKeys = ["commands", "compatibility", "schemaVersion", "visibilityOrder", "workflowOrder"];
|
|
9785
|
+
if (!plainRecord2(value) || !sameStrings2(Object.keys(value).sort(), envelopeKeys) || value.schemaVersion !== 1 || !Array.isArray(value.visibilityOrder) || !sameStrings2(value.visibilityOrder, COMMAND_VISIBILITY_ORDER) || !Array.isArray(value.workflowOrder) || !sameStrings2(value.workflowOrder, COMMAND_WORKFLOW_ORDER) || !plainRecord2(value.compatibility) || !plainRecord2(value.commands)) {
|
|
9786
|
+
throw new Error("codeArbiter Pi command catalog envelope is invalid; run /ca-doctor.");
|
|
9787
|
+
}
|
|
9788
|
+
const commands = value.commands;
|
|
9789
|
+
const names = Object.keys(commands);
|
|
9790
|
+
if (!sameStrings2(names, [...names].sort()) || names.length === 0) {
|
|
9791
|
+
throw new Error("codeArbiter Pi command catalog envelope has no sorted commands; run /ca-doctor.");
|
|
9792
|
+
}
|
|
9793
|
+
const entries = [];
|
|
9794
|
+
for (const name of names) {
|
|
9795
|
+
const fail2 = () => {
|
|
9796
|
+
throw new Error(`codeArbiter Pi command catalog entry ${name} is invalid; run /ca-doctor.`);
|
|
9797
|
+
};
|
|
9798
|
+
const value2 = commands[name];
|
|
9799
|
+
if (!plainRecord2(value2)) {
|
|
9800
|
+
throw new Error(`codeArbiter Pi command catalog entry ${name} is invalid; run /ca-doctor.`);
|
|
9801
|
+
}
|
|
9802
|
+
const raw = value2;
|
|
9803
|
+
if (raw.name !== name || typeof raw.description !== "string" || raw.description === "" || raw.skillPath !== `skills/ca-${name}/SKILL.md` || !COMMAND_VISIBILITY_ORDER.includes(raw.visibility) || !COMMAND_WORKFLOW_ORDER.includes(raw.workflow)) {
|
|
9804
|
+
fail2();
|
|
9805
|
+
}
|
|
9806
|
+
const visibility = raw.visibility;
|
|
9807
|
+
const commonKeys = ["description", "name", "skillPath", "visibility", "workflow"];
|
|
9808
|
+
let expectedKeys;
|
|
9809
|
+
if (visibility === "core" || visibility === "advanced" || visibility === "internal") {
|
|
9810
|
+
expectedKeys = [...commonKeys, "canonical", "legacyRoutes"].sort();
|
|
9811
|
+
if (raw.canonical !== name || !validLegacyRoutes(raw.legacyRoutes)) fail2();
|
|
9812
|
+
} else if (visibility === "alias") {
|
|
9813
|
+
expectedKeys = [...commonKeys, "canonical", "replacement"].sort();
|
|
9814
|
+
if (typeof raw.canonical !== "string" || !/^[a-z][a-z0-9-]*$/u.test(raw.canonical) || typeof raw.replacement !== "string" || !raw.replacement.startsWith(`${raw.canonical} `)) fail2();
|
|
9815
|
+
} else {
|
|
9816
|
+
expectedKeys = [...commonKeys, "replacement"].sort();
|
|
9817
|
+
if (typeof raw.replacement !== "string" || raw.replacement === "") fail2();
|
|
9818
|
+
}
|
|
9819
|
+
if (!sameStrings2(Object.keys(raw).sort(), expectedKeys)) fail2();
|
|
9820
|
+
entries.push(Object.freeze({ ...raw }));
|
|
9821
|
+
}
|
|
9822
|
+
const entriesByName = new Map(entries.map((entry) => [entry.name, entry]));
|
|
9823
|
+
const expectedLegacyRoutes = /* @__PURE__ */ new Map();
|
|
9824
|
+
for (const entry of entries) {
|
|
9825
|
+
if (entry.visibility === "alias") {
|
|
9826
|
+
const target = entriesByName.get(entry.canonical);
|
|
9827
|
+
if (target === void 0 || target.visibility === "alias" || target.visibility === "deprecated") {
|
|
9828
|
+
throw new Error(`codeArbiter Pi command catalog entry ${entry.name} has an invalid alias target; run /ca-doctor.`);
|
|
9829
|
+
}
|
|
9830
|
+
const routes = expectedLegacyRoutes.get(entry.canonical) ?? [];
|
|
9831
|
+
routes.push(entry.name);
|
|
9832
|
+
expectedLegacyRoutes.set(entry.canonical, routes);
|
|
9833
|
+
}
|
|
9834
|
+
}
|
|
9835
|
+
for (const entry of entries) {
|
|
9836
|
+
if (entry.visibility === "alias" || entry.visibility === "deprecated") continue;
|
|
9837
|
+
const expected = (expectedLegacyRoutes.get(entry.name) ?? []).sort();
|
|
9838
|
+
if (!sameStrings2(entry.legacyRoutes ?? [], expected)) {
|
|
9839
|
+
throw new Error(`codeArbiter Pi command catalog entry ${entry.name} has broken legacy-route closure; run /ca-doctor.`);
|
|
9840
|
+
}
|
|
9841
|
+
}
|
|
9842
|
+
return Object.freeze(entries);
|
|
9843
|
+
}
|
|
9725
9844
|
var PI_TRUST_REQUIRED_STATUS = "codeArbiter host: pi waiting for project trust - run /trust in Pi, approve this project, then start a new session";
|
|
9726
9845
|
function hasAffirmativeProjectTrust(context) {
|
|
9727
9846
|
try {
|
|
@@ -10257,7 +10376,9 @@ async function codeArbiterPi(pi) {
|
|
|
10257
10376
|
if (parent === packageRoot) throw new Error("codeArbiter could not locate the ca-pi package; run /ca-doctor.");
|
|
10258
10377
|
packageRoot = parent;
|
|
10259
10378
|
}
|
|
10260
|
-
const catalog =
|
|
10379
|
+
const catalog = commandCatalogEntries(
|
|
10380
|
+
JSON.parse(await readFile6(resolve15(packageRoot, "generated", "command-catalog.json"), "utf8"))
|
|
10381
|
+
);
|
|
10261
10382
|
const toolClasses = loadPiToolClasses(define_CODEARBITER_PI_TOOL_CLASSES_default);
|
|
10262
10383
|
const rawPermissionSurfaces = define_CODEARBITER_PI_PERMISSION_POLICY_SURFACES_default;
|
|
10263
10384
|
if (rawPermissionSurfaces === null || typeof rawPermissionSurfaces !== "object" || Array.isArray(rawPermissionSurfaces)) {
|
|
@@ -10532,6 +10653,7 @@ export {
|
|
|
10532
10653
|
PERSONA_SENTINEL,
|
|
10533
10654
|
PI_RUNTIME_DIAGNOSIS,
|
|
10534
10655
|
boundedPiEnvironment,
|
|
10656
|
+
commandCatalogEntries,
|
|
10535
10657
|
compatibilityDirection,
|
|
10536
10658
|
createCodeArbiterPi,
|
|
10537
10659
|
createPiFooterMetricsLoader,
|