@mrciphersmith/keryx 0.2.32 → 0.2.33
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 +170 -2
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -35991,6 +35991,165 @@ async function resolvePolicySelectionSafely(workspaceRoot, canonicalFallback) {
|
|
|
35991
35991
|
return canonicalFallback;
|
|
35992
35992
|
}
|
|
35993
35993
|
}
|
|
35994
|
+
async function diagnosePolicyReadiness(workspaceRoot) {
|
|
35995
|
+
const steps = [];
|
|
35996
|
+
const msg = (error2) => error2 instanceof Error ? error2.message : String(error2);
|
|
35997
|
+
const pass = (step, detail) => {
|
|
35998
|
+
steps.push(detail === undefined ? { step, status: "pass" } : { step, status: "pass", detail });
|
|
35999
|
+
};
|
|
36000
|
+
const fail = (step, detail) => {
|
|
36001
|
+
steps.push({ step, status: "fail", detail });
|
|
36002
|
+
};
|
|
36003
|
+
const finalize = (configPresent, enabled2, killSwitch2) => {
|
|
36004
|
+
const integrityReady = steps.every((entry) => entry.step === "activation-flags" || entry.status === "pass");
|
|
36005
|
+
return Object.freeze({ configPresent, enabled: enabled2, killSwitch: killSwitch2, integrityReady, candidateWouldActivate: integrityReady && enabled2 && !killSwitch2, steps: Object.freeze([...steps]) });
|
|
36006
|
+
};
|
|
36007
|
+
const configPath3 = path118.join(workspaceRoot, ...policyExperimentConfigPath);
|
|
36008
|
+
let configJson;
|
|
36009
|
+
try {
|
|
36010
|
+
const raw = await readFile64(configPath3, "utf8").catch((error2) => {
|
|
36011
|
+
if (isMissing(error2))
|
|
36012
|
+
return;
|
|
36013
|
+
throw error2;
|
|
36014
|
+
});
|
|
36015
|
+
if (raw === undefined) {
|
|
36016
|
+
fail("config", "no policy-experiment config at .metaproject/context-operations/policy-experiment/config.json");
|
|
36017
|
+
return finalize(false, false, true);
|
|
36018
|
+
}
|
|
36019
|
+
const parsed = JSON.parse(raw);
|
|
36020
|
+
if (!isRecord3(parsed) || !isConfigRecord(parsed)) {
|
|
36021
|
+
fail("config", "config is not a valid policy-experiment record (needs boolean enabled + killSwitch)");
|
|
36022
|
+
return finalize(true, false, true);
|
|
36023
|
+
}
|
|
36024
|
+
configJson = parsed;
|
|
36025
|
+
} catch (error2) {
|
|
36026
|
+
fail("config", `config could not be read or parsed: ${msg(error2)}`);
|
|
36027
|
+
return finalize(true, false, true);
|
|
36028
|
+
}
|
|
36029
|
+
pass("config");
|
|
36030
|
+
const enabled = configJson.enabled === true;
|
|
36031
|
+
const killSwitch = configJson.killSwitch !== false;
|
|
36032
|
+
if (enabled && !killSwitch)
|
|
36033
|
+
pass("activation-flags", "enabled and kill-switch released");
|
|
36034
|
+
else
|
|
36035
|
+
fail("activation-flags", `candidate stays off by config: enabled=${String(configJson.enabled)}, killSwitch=${String(configJson.killSwitch)}`);
|
|
36036
|
+
const requiredPins = ["candidateArtifactRef", "candidateArtifactDigest", "candidateVersion", "baselineArtifactRef", "baselineArtifactDigest", "baselineVersion", "corpusRef", "corpusDigest", "corpusVersion", "evaluationReportRef", "evaluationDigest"];
|
|
36037
|
+
const missing = requiredPins.filter((name) => typeof configJson[name] !== "string");
|
|
36038
|
+
if (missing.length > 0) {
|
|
36039
|
+
fail("config-pins", `missing or non-string pins: ${missing.join(", ")}`);
|
|
36040
|
+
return finalize(true, enabled, killSwitch);
|
|
36041
|
+
}
|
|
36042
|
+
const candidateRef = configJson.candidateArtifactRef;
|
|
36043
|
+
const candidateDigest = configJson.candidateArtifactDigest;
|
|
36044
|
+
const baselineRef = configJson.baselineArtifactRef;
|
|
36045
|
+
const baselineDigest = configJson.baselineArtifactDigest;
|
|
36046
|
+
const corpusRef = configJson.corpusRef;
|
|
36047
|
+
const corpusDigest = configJson.corpusDigest;
|
|
36048
|
+
const evaluationRef = configJson.evaluationReportRef;
|
|
36049
|
+
const evaluationDigest = configJson.evaluationDigest;
|
|
36050
|
+
if (!asString4(candidateRef) || !asString4(candidateDigest) || !asString4(baselineRef) || !asString4(baselineDigest) || !asString4(corpusRef) || !asString4(corpusDigest) || !asString4(evaluationRef) || !asString4(evaluationDigest)) {
|
|
36051
|
+
fail("config-pins", "pins are present but not non-empty strings");
|
|
36052
|
+
return finalize(true, enabled, killSwitch);
|
|
36053
|
+
}
|
|
36054
|
+
pass("config-pins");
|
|
36055
|
+
const refsOk = workspacePathPattern3.test(candidateRef) && workspacePathPattern3.test(baselineRef) && workspacePathPattern3.test(corpusRef) && workspacePathPattern3.test(evaluationRef);
|
|
36056
|
+
if (refsOk)
|
|
36057
|
+
pass("reference-paths");
|
|
36058
|
+
else
|
|
36059
|
+
fail("reference-paths", "one or more artifact refs are not contained workspace-relative './\u2026' paths");
|
|
36060
|
+
const hashesOk = validHash(candidateDigest) && validHash(baselineDigest) && validHash(corpusDigest) && validHash(evaluationDigest);
|
|
36061
|
+
if (hashesOk)
|
|
36062
|
+
pass("digest-format");
|
|
36063
|
+
else
|
|
36064
|
+
fail("digest-format", "one or more pinned digests are not sha256 hex");
|
|
36065
|
+
const versionsOk = isImmutableVersion2(configJson.candidateVersion) && isImmutableVersion2(configJson.baselineVersion) && isImmutableVersion2(configJson.corpusVersion);
|
|
36066
|
+
if (versionsOk)
|
|
36067
|
+
pass("immutable-versions");
|
|
36068
|
+
else
|
|
36069
|
+
fail("immutable-versions", "candidate/baseline/corpus versions must be immutable (no latest/main/head/\u2026)");
|
|
36070
|
+
const policyRefsOk = policyRefPattern.test(candidateRef) && policyRefPattern.test(baselineRef);
|
|
36071
|
+
if (policyRefsOk)
|
|
36072
|
+
pass("policy-refs");
|
|
36073
|
+
else
|
|
36074
|
+
fail("policy-refs", "candidate/baseline refs must be './\u2026' policy references");
|
|
36075
|
+
if (!(refsOk && hashesOk && versionsOk && policyRefsOk))
|
|
36076
|
+
return finalize(true, enabled, killSwitch);
|
|
36077
|
+
let baselineArtifact;
|
|
36078
|
+
let candidateArtifact;
|
|
36079
|
+
let corpusPayload;
|
|
36080
|
+
let evaluationPayload;
|
|
36081
|
+
try {
|
|
36082
|
+
baselineArtifact = await readPinnedJson({ workspaceRoot, uri: baselineRef, digest: baselineDigest });
|
|
36083
|
+
if (isBaselineArtifact(baselineArtifact.artifact))
|
|
36084
|
+
pass("baseline-artifact");
|
|
36085
|
+
else
|
|
36086
|
+
fail("baseline-artifact", "not a valid deterministic-baseline artifact");
|
|
36087
|
+
} catch (error2) {
|
|
36088
|
+
fail("baseline-artifact", `unreadable or digest mismatch: ${msg(error2)}`);
|
|
36089
|
+
}
|
|
36090
|
+
try {
|
|
36091
|
+
candidateArtifact = await readPinnedJson({ workspaceRoot, uri: candidateRef, digest: candidateDigest });
|
|
36092
|
+
if (isCandidateArtifact(candidateArtifact.artifact))
|
|
36093
|
+
pass("candidate-artifact");
|
|
36094
|
+
else
|
|
36095
|
+
fail("candidate-artifact", "not a valid offline-selection-advisor artifact");
|
|
36096
|
+
} catch (error2) {
|
|
36097
|
+
fail("candidate-artifact", `unreadable or digest mismatch: ${msg(error2)}`);
|
|
36098
|
+
}
|
|
36099
|
+
try {
|
|
36100
|
+
corpusPayload = await readWorkspaceJson({ workspaceRoot, uri: corpusRef });
|
|
36101
|
+
if (!isCompleteCorpus(corpusPayload.artifact))
|
|
36102
|
+
fail("corpus", "corpus failed structural / manifest verification");
|
|
36103
|
+
else if (corpusPayload.artifact.manifest.corpusVersion !== configJson.corpusVersion || corpusPayload.artifact.manifest.corpusDigest !== corpusDigest)
|
|
36104
|
+
fail("corpus", "corpus manifest version/digest does not match pins");
|
|
36105
|
+
else
|
|
36106
|
+
pass("corpus");
|
|
36107
|
+
} catch (error2) {
|
|
36108
|
+
fail("corpus", `unreadable: ${msg(error2)}`);
|
|
36109
|
+
}
|
|
36110
|
+
try {
|
|
36111
|
+
evaluationPayload = await readWorkspaceJson({ workspaceRoot, uri: evaluationRef });
|
|
36112
|
+
if (!isEvaluationReport(evaluationPayload.artifact) || !hasReportIntegrity(evaluationPayload.artifact))
|
|
36113
|
+
fail("evaluation-report", "report is malformed or its recomputed digest does not match");
|
|
36114
|
+
else if (evaluationPayload.artifact.reportDigest !== evaluationDigest)
|
|
36115
|
+
fail("evaluation-report", "report digest does not match pin");
|
|
36116
|
+
else
|
|
36117
|
+
pass("evaluation-report");
|
|
36118
|
+
} catch (error2) {
|
|
36119
|
+
fail("evaluation-report", `unreadable: ${msg(error2)}`);
|
|
36120
|
+
}
|
|
36121
|
+
if (baselineArtifact && candidateArtifact && corpusPayload && evaluationPayload && isBaselineArtifact(baselineArtifact.artifact) && isCandidateArtifact(candidateArtifact.artifact) && isCompleteCorpus(corpusPayload.artifact) && isEvaluationReport(evaluationPayload.artifact) && hasReportIntegrity(evaluationPayload.artifact) && corpusPayload.artifact.manifest.corpusVersion === configJson.corpusVersion && corpusPayload.artifact.manifest.corpusDigest === corpusDigest && evaluationPayload.artifact.reportDigest === evaluationDigest) {
|
|
36122
|
+
try {
|
|
36123
|
+
const config = {
|
|
36124
|
+
...configJson,
|
|
36125
|
+
enabled: true,
|
|
36126
|
+
killSwitch: false,
|
|
36127
|
+
candidateArtifactDigest: candidateArtifact.digest,
|
|
36128
|
+
candidateDigest: candidateArtifact.digest,
|
|
36129
|
+
baselineArtifactDigest: baselineArtifact.digest,
|
|
36130
|
+
baselineDigest: baselineArtifact.digest,
|
|
36131
|
+
corpusDigest,
|
|
36132
|
+
evaluationDigest,
|
|
36133
|
+
candidateVersion: configJson.candidateVersion,
|
|
36134
|
+
baselineVersion: configJson.baselineVersion,
|
|
36135
|
+
corpusVersion: configJson.corpusVersion,
|
|
36136
|
+
rollbackBaselineVersion: configJson.rollbackBaselineVersion ?? configJson.baselineVersion
|
|
36137
|
+
};
|
|
36138
|
+
const baseline = { selectedIds: evaluationPayload.artifact.candidateSelectedIds, source: "deterministic-baseline", version: baselineArtifact.artifact.version, artifactDigest: baselineArtifact.digest };
|
|
36139
|
+
const candidate = { version: candidateArtifact.artifact.version, artifactDigest: candidateArtifact.digest };
|
|
36140
|
+
const outcome = resolvePolicyExperiment({ config, evaluation: evaluationPayload.artifact, candidate, corpus: corpusPayload.artifact, baseline });
|
|
36141
|
+
if (outcome.source === "candidate")
|
|
36142
|
+
pass("activation-gate", "evidence gates pass: security non-regression, holdout, adversarial, pins and candidate subset");
|
|
36143
|
+
else
|
|
36144
|
+
fail("activation-gate", `evidence gates reject candidate; report reasons: ${evaluationPayload.artifact.reasons.join(", ") || "none"}`);
|
|
36145
|
+
} catch (error2) {
|
|
36146
|
+
fail("activation-gate", `activation check errored: ${msg(error2)}`);
|
|
36147
|
+
}
|
|
36148
|
+
} else {
|
|
36149
|
+
fail("activation-gate", "skipped: one or more prerequisite artifact checks did not pass");
|
|
36150
|
+
}
|
|
36151
|
+
return finalize(true, enabled, killSwitch);
|
|
36152
|
+
}
|
|
35994
36153
|
function isCompleteCorpus(value) {
|
|
35995
36154
|
return isRecord3(value) && isRecord3(value.manifest) && Array.isArray(value.rows) && Array.isArray(value.quarantine) && verifyPolicyCorpus(value);
|
|
35996
36155
|
}
|
|
@@ -48466,7 +48625,7 @@ init_shell_config();
|
|
|
48466
48625
|
// package.json
|
|
48467
48626
|
var package_default = {
|
|
48468
48627
|
name: "@mrciphersmith/keryx",
|
|
48469
|
-
version: "0.2.
|
|
48628
|
+
version: "0.2.33",
|
|
48470
48629
|
description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
|
|
48471
48630
|
private: false,
|
|
48472
48631
|
publishConfig: {
|
|
@@ -54294,6 +54453,14 @@ async function workspaceCommand(args2) {
|
|
|
54294
54453
|
console.log(JSON.stringify(await createLocalCollaborationService(process.cwd()).overview({ workspaceId, request: undefined, requestCorrelationId: randomUUID20() }), null, 2));
|
|
54295
54454
|
return;
|
|
54296
54455
|
}
|
|
54456
|
+
if (subcommand === "policy-readiness") {
|
|
54457
|
+
rejectUnknownOptions(args2.slice(1), new Set);
|
|
54458
|
+
const report = await diagnosePolicyReadiness(process.cwd());
|
|
54459
|
+
console.log(JSON.stringify(report, null, 2));
|
|
54460
|
+
if (!report.integrityReady)
|
|
54461
|
+
process.exitCode = 1;
|
|
54462
|
+
return;
|
|
54463
|
+
}
|
|
54297
54464
|
throw new Error(`Unknown workspace command: ${subcommand}`);
|
|
54298
54465
|
} catch (error2) {
|
|
54299
54466
|
console.error(error2 instanceof Error ? error2.message : String(error2));
|
|
@@ -54318,7 +54485,8 @@ keryx workspace overview <workspace-id> [--max-items N] [--max-tokens N]
|
|
|
54318
54485
|
keryx workspace read <workspace-id> <item-id> [--max-items N] [--max-tokens N]
|
|
54319
54486
|
keryx workspace propose <workspace-id> --kind <kind> --summary <explicit-summary> --evidence <workspace-relative-ref> [--revision <revision>]
|
|
54320
54487
|
keryx workspace review <workspace-id> <proposal-id> --decision <accepted|rejected|dismissed> [--reason <reason>] [--idempotency-key <key>]
|
|
54321
|
-
keryx workspace collaboration <workspace-id
|
|
54488
|
+
keryx workspace collaboration <workspace-id>
|
|
54489
|
+
keryx workspace policy-readiness`);
|
|
54322
54490
|
}
|
|
54323
54491
|
|
|
54324
54492
|
// src/cli.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrciphersmith/keryx",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.33",
|
|
4
4
|
"description": "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"publishConfig": {
|