create-agdf 0.14.1 → 0.14.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 +8 -2
- package/generated/plugins/agdf/.claude-plugin/plugin.json +1 -1
- package/generated/plugins/agdf/.codex-plugin/plugin.json +1 -1
- package/generated/plugins/agdf/meta/agdf-plugin.definition.json +6 -1
- package/generated/plugins/agdf/meta/copilot-payload-baseline.json +7 -0
- package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-plugin.definition.json +6 -1
- package/generated/plugins/agdf/runtime/create-agdf/lib/runtime/local-validator.js +29 -17
- package/generated/plugins/agdf/runtime/create-agdf/lib/runtime/plugin-provenance.js +50 -1
- package/generated/plugins/agdf/runtime/create-agdf/package.json +1 -1
- package/generated/plugins/agdf/runtime/runtime-manifest.json +2 -2
- package/generated/plugins/agdf/scripts/check-runtime-integrity.mjs +2 -1
- package/generated/plugins/agdf/submission/openai/availability.md +1 -1
- package/generated/plugins/agdf/submission/openai/capability-matrix.json +1 -1
- package/generated/plugins/agdf/submission/openai/release-notes.md +1 -1
- package/generated/plugins/agdf/submission/openai/reviewer-cases.json +1 -1
- package/generated/plugins/copilot/agdf/.agdf-payload-inventory.json +771 -0
- package/generated/plugins/copilot/agdf/LICENSE +201 -0
- package/generated/plugins/copilot/agdf/meta/agdf-agent-router.md +129 -0
- package/generated/plugins/copilot/agdf/meta/agdf-constitution.md +329 -0
- package/generated/plugins/copilot/agdf/meta/agdf-plugin.definition.json +331 -0
- package/generated/plugins/copilot/agdf/meta/agdf-runtime-contract.md +16 -0
- package/generated/plugins/{agdf → copilot/agdf}/plugin.json +1 -1
- package/generated/plugins/copilot/agdf/runtime/agdf-local.js +18 -0
- package/generated/plugins/copilot/agdf/runtime/agdf-session-check.js +97 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/NOTICE +10 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/bin/agdf-validator.js +11 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-interaction-locales.json +512 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-plugin.definition.json +331 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/command-registry.js +144 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/delivery-path-search-command.js +139 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/parse-args.js +173 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/runtime-context.js +83 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/validation-handlers.js +46 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/delivery-map.js +301 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/doctor.js +272 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/gate-check.js +455 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/gate-policy.js +305 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/parent-reconciliation.js +284 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/required-files.js +9 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/run-state.js +217 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/shared.js +345 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/verified-change.js +156 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-state/aggregate.js +18 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-state/gate-approval-validator.js +49 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-state/index.js +7 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-state/legacy-migration.js +95 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-state/run-state-parser.js +265 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-state/run-state-repository.js +68 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-state/run-state-resolver.js +45 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-state/run-state-writer.js +97 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/candidate-policy.js +99 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/contracts.js +237 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/claude.js +35 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/codex.js +44 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/opencode.js +234 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/prompt.js +13 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/protocol.js +13 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/generators/claude.js +40 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/generators/codex.js +38 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/generators/protocol.js +12 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/persistence.js +39 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/scoring.js +21 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/search-engine.js +155 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/state-adapter.js +161 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/surfaces/capabilities.js +27 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/transports/read-only-guard.js +43 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/interaction-presentation.js +842 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/runtime/local-validator.js +239 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/runtime/plugin-provenance.js +255 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/runtime/validator-application.js +40 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/runtime-check-consent/contract.js +73 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/package.json +6 -0
- package/generated/plugins/copilot/agdf/runtime/runtime-manifest.json +8 -0
- package/generated/submissions/openai/agdf/.codex-plugin/plugin.json +1 -1
- package/generated/submissions/openai/agdf/meta/agdf-plugin.definition.json +6 -1
- package/generated/submissions/openai/agdf/meta/copilot-payload-baseline.json +7 -0
- package/generated/submissions/openai/agdf/submission/openai/availability.md +1 -1
- package/generated/submissions/openai/agdf/submission/openai/capability-matrix.json +1 -1
- package/generated/submissions/openai/agdf/submission/openai/inventory.json +13 -9
- package/generated/submissions/openai/agdf/submission/openai/listing.json +1 -1
- package/generated/submissions/openai/agdf/submission/openai/readiness.json +2 -2
- package/generated/submissions/openai/agdf/submission/openai/readiness.md +2 -2
- package/generated/submissions/openai/agdf/submission/openai/release-notes.md +1 -1
- package/generated/submissions/openai/agdf/submission/openai/reviewer-cases.json +1 -1
- package/lib/installers/local-marketplace.js +112 -30
- package/lib/installers/plugin-installers.js +45 -9
- package/lib/public-plugin/copilot-profile.js +126 -0
- package/lib/release/version-coherence.js +4 -1
- package/lib/runtime/local-validator.js +29 -17
- package/lib/runtime/plugin-provenance.js +50 -1
- package/package.json +3 -2
- /package/generated/plugins/{agdf → copilot/agdf}/copilot-skills/agdf-brownfield-analysis/SKILL.md +0 -0
- /package/generated/plugins/{agdf → copilot/agdf}/copilot-skills/agdf-clean-implementation-review/SKILL.md +0 -0
- /package/generated/plugins/{agdf → copilot/agdf}/copilot-skills/agdf-code-review/SKILL.md +0 -0
- /package/generated/plugins/{agdf → copilot/agdf}/copilot-skills/agdf-delivery-closeout/SKILL.md +0 -0
- /package/generated/plugins/{agdf → copilot/agdf}/copilot-skills/agdf-delivery-path-search/SKILL.md +0 -0
- /package/generated/plugins/{agdf → copilot/agdf}/copilot-skills/agdf-gate-check/SKILL.md +0 -0
- /package/generated/plugins/{agdf → copilot/agdf}/copilot-skills/agdf-interaction-locales.json +0 -0
- /package/generated/plugins/{agdf → copilot/agdf}/copilot-skills/agdf-qa-gate/SKILL.md +0 -0
- /package/generated/plugins/{agdf → copilot/agdf}/copilot-skills/agdf-release-or/SKILL.md +0 -0
- /package/generated/plugins/{agdf → copilot/agdf}/copilot-skills/agdf-runtime-contract.md +0 -0
- /package/generated/plugins/{agdf → copilot/agdf}/copilot-skills/agdf-task-plan-review/SKILL.md +0 -0
- /package/generated/plugins/{agdf → copilot/agdf}/copilot-skills/agdf-ux-intent-definition/SKILL.md +0 -0
- /package/generated/plugins/{agdf → copilot/agdf}/copilot-skills/contracts/closeout.md +0 -0
- /package/generated/plugins/{agdf → copilot/agdf}/copilot-skills/contracts/context-graph.md +0 -0
- /package/generated/plugins/{agdf → copilot/agdf}/copilot-skills/contracts/control-scaffold.md +0 -0
- /package/generated/plugins/{agdf → copilot/agdf}/copilot-skills/contracts/gate-transition.md +0 -0
- /package/generated/plugins/{agdf → copilot/agdf}/copilot-skills/contracts/interaction.md +0 -0
- /package/generated/plugins/{agdf → copilot/agdf}/copilot-skills/contracts/modes.md +0 -0
- /package/generated/plugins/{agdf → copilot/agdf}/copilot-skills/contracts/quality.md +0 -0
- /package/generated/plugins/{agdf → copilot/agdf}/copilot-skills/contracts/task-target-resolution.md +0 -0
- /package/generated/plugins/{agdf → copilot/agdf}/hooks/copilot-hooks.json +0 -0
package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-state/run-state-resolver.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { discoverRuns } from "./run-state-repository.js";
|
|
2
|
+
export function resolveRuns(
|
|
3
|
+
root,
|
|
4
|
+
{ runIdArg, runIdEnv, allActive = false } = {},
|
|
5
|
+
) {
|
|
6
|
+
if (
|
|
7
|
+
(allActive && (runIdArg || runIdEnv)) ||
|
|
8
|
+
(runIdArg && runIdEnv && runIdArg !== runIdEnv)
|
|
9
|
+
)
|
|
10
|
+
throw Error("AGDF_SELECTOR_CONFLICT");
|
|
11
|
+
const runs = discoverRuns(root),
|
|
12
|
+
active = runs.filter((r) => r.valid && r.meta.lifecycle === "active");
|
|
13
|
+
const findings = runs
|
|
14
|
+
.filter((run) => !run.valid)
|
|
15
|
+
.flatMap((run) =>
|
|
16
|
+
run.findings.map((finding) => ({ ...finding, run_id: run.run_id })),
|
|
17
|
+
);
|
|
18
|
+
if (allActive)
|
|
19
|
+
return { selection_source: "all_active", runs: active, findings };
|
|
20
|
+
const id = runIdArg || runIdEnv;
|
|
21
|
+
if (id) {
|
|
22
|
+
const run = runs.find((r) => r.run_id === id);
|
|
23
|
+
if (!run?.valid) {
|
|
24
|
+
throw Error(
|
|
25
|
+
`AGDF_RUN_NOT_SELECTABLE:${id}; discovered=${runs.map((item) => item.run_id).join(",")}; next=select a valid run`,
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
selection_source: runIdArg ? "cli" : "environment",
|
|
30
|
+
run,
|
|
31
|
+
active_run_ids: active.map((r) => r.run_id),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (active.length !== 1)
|
|
35
|
+
throw Error(
|
|
36
|
+
active.length
|
|
37
|
+
? `AGDF_ACTIVE_RUN_AMBIGUOUS:${active.map((r) => r.run_id)}`
|
|
38
|
+
: "AGDF_ACTIVE_RUN_MISSING",
|
|
39
|
+
);
|
|
40
|
+
return {
|
|
41
|
+
selection_source: "single_active",
|
|
42
|
+
run: active[0],
|
|
43
|
+
active_run_ids: [active[0].run_id],
|
|
44
|
+
};
|
|
45
|
+
}
|
package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-state/run-state-writer.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import {
|
|
3
|
+
closeSync,
|
|
4
|
+
fsyncSync,
|
|
5
|
+
existsSync,
|
|
6
|
+
lstatSync,
|
|
7
|
+
openSync,
|
|
8
|
+
readFileSync,
|
|
9
|
+
renameSync,
|
|
10
|
+
unlinkSync,
|
|
11
|
+
writeFileSync,
|
|
12
|
+
} from "node:fs";
|
|
13
|
+
import { dirname } from "node:path";
|
|
14
|
+
|
|
15
|
+
import { parseRunState } from "./run-state-parser.js";
|
|
16
|
+
|
|
17
|
+
function fsyncDirectory(path) {
|
|
18
|
+
if (process.platform === "win32") return;
|
|
19
|
+
const descriptor = openSync(path, "r");
|
|
20
|
+
try {
|
|
21
|
+
fsyncSync(descriptor);
|
|
22
|
+
} finally {
|
|
23
|
+
closeSync(descriptor);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function atomicWrite(path, content) {
|
|
28
|
+
if (existsSync(path)) {
|
|
29
|
+
const destination = lstatSync(path);
|
|
30
|
+
if (destination.isSymbolicLink() || !destination.isFile()) {
|
|
31
|
+
throw new Error("AGDF_RUN_PATH_INVALID");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const parent = lstatSync(dirname(path));
|
|
36
|
+
if (parent.isSymbolicLink() || !parent.isDirectory()) {
|
|
37
|
+
throw new Error("AGDF_RUN_PATH_INVALID");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const temp = `${path}.tmp-${process.pid}-${randomUUID()}`;
|
|
41
|
+
let descriptor;
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
descriptor = openSync(temp, "wx");
|
|
45
|
+
writeFileSync(descriptor, content, "utf8");
|
|
46
|
+
fsyncSync(descriptor);
|
|
47
|
+
closeSync(descriptor);
|
|
48
|
+
descriptor = undefined;
|
|
49
|
+
|
|
50
|
+
renameSync(temp, path);
|
|
51
|
+
fsyncDirectory(dirname(path));
|
|
52
|
+
} catch (error) {
|
|
53
|
+
if (descriptor !== undefined) closeSync(descriptor);
|
|
54
|
+
try {
|
|
55
|
+
unlinkSync(temp);
|
|
56
|
+
} catch (cleanupError) {
|
|
57
|
+
if (cleanupError.code !== "ENOENT") throw cleanupError;
|
|
58
|
+
}
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function writeRun(path, content, expectedRevisionId) {
|
|
64
|
+
const lockPath = `${path}.lock`;
|
|
65
|
+
let lockDescriptor;
|
|
66
|
+
try {
|
|
67
|
+
lockDescriptor = openSync(lockPath, "wx");
|
|
68
|
+
} catch (error) {
|
|
69
|
+
if (error.code === "EEXIST") throw new Error("AGDF_RUN_WRITE_LOCKED");
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
const current = parseRunState(readFileSync(path, "utf8"));
|
|
75
|
+
if (!current.valid) throw new Error("AGDF_RUN_STATE_INVALID");
|
|
76
|
+
if (current.meta.revision_id !== expectedRevisionId) {
|
|
77
|
+
throw new Error("AGDF_STALE_RUN_REVISION");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const next = content
|
|
81
|
+
.replace(
|
|
82
|
+
/^- revision:\s*.*$/m,
|
|
83
|
+
`- revision: ${Number(current.meta.revision) + 1}`,
|
|
84
|
+
)
|
|
85
|
+
.replace(/^- revision_id:\s*.*$/m, `- revision_id: ${randomUUID()}`);
|
|
86
|
+
const candidate = parseRunState(next);
|
|
87
|
+
if (!candidate.valid || candidate.meta.run_id !== current.meta.run_id) {
|
|
88
|
+
throw new Error("AGDF_RUN_STATE_INVALID");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
atomicWrite(path, next);
|
|
92
|
+
return candidate;
|
|
93
|
+
} finally {
|
|
94
|
+
closeSync(lockDescriptor);
|
|
95
|
+
unlinkSync(lockPath);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { validateCandidate } from "./contracts.js";
|
|
2
|
+
|
|
3
|
+
function normalized(value) {
|
|
4
|
+
return String(value).normalize("NFKC").toLowerCase().replace(/[`*_]/g, "").replace(/[^\p{L}\p{N}\s-]/gu, " ").replace(/\s+/g, " ").trim();
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const STOP_WORDS = new Set(["a", "an", "and", "der", "die", "das", "ein", "eine", "the", "to", "und", "zu"]);
|
|
8
|
+
|
|
9
|
+
function tokens(value) {
|
|
10
|
+
return new Set(normalized(value).split(/\s+/).filter((item) => item && !STOP_WORDS.has(item)));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function jaccard(left, right) {
|
|
14
|
+
const union = new Set([...left, ...right]);
|
|
15
|
+
if (!union.size) return 1;
|
|
16
|
+
let intersection = 0;
|
|
17
|
+
for (const item of left) if (right.has(item)) intersection += 1;
|
|
18
|
+
return intersection / union.size;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function signature(candidate) {
|
|
22
|
+
return JSON.stringify({
|
|
23
|
+
gate_action: normalized(candidate.gate_action ?? candidate.action),
|
|
24
|
+
affected_boundaries: [...(candidate.affected_boundaries ?? [])].map(normalized).sort(),
|
|
25
|
+
evidence: [...(candidate.expected_evidence ?? [])].map(normalized).sort(),
|
|
26
|
+
tests: [...(candidate.tests ?? [])].map(normalized).sort(),
|
|
27
|
+
risk_strategy: normalized(candidate.risk_strategy ?? ""),
|
|
28
|
+
reversibility: normalized(candidate.reversibility ?? ""),
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function candidateLegality(candidateValue, input) {
|
|
33
|
+
const candidate = validateCandidate(candidateValue);
|
|
34
|
+
const action = normalized(candidate.gate_action ?? candidate.action);
|
|
35
|
+
const forbiddenMatch = input.forbidden_actions.find((item) => {
|
|
36
|
+
const forbidden = normalized(item);
|
|
37
|
+
return forbidden && action === forbidden;
|
|
38
|
+
});
|
|
39
|
+
if (forbiddenMatch) return { legal: false, reason: `forbidden_by_gate: ${forbiddenMatch}`, candidate };
|
|
40
|
+
|
|
41
|
+
const allowedMatch = input.allowed_actions.some((item) => {
|
|
42
|
+
const allowed = normalized(item);
|
|
43
|
+
return allowed && action === allowed;
|
|
44
|
+
});
|
|
45
|
+
if (!allowedMatch) return { legal: false, reason: "not_in_allowed_actions", candidate };
|
|
46
|
+
return { legal: true, reason: "allowed_by_current_gate", candidate };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function candidatesFromInput(input) {
|
|
50
|
+
return input.allowed_actions.slice(0, input.budgets.max_candidates).map((action, index) => ({
|
|
51
|
+
id: `candidate-${index + 1}`,
|
|
52
|
+
action,
|
|
53
|
+
expected_evidence: input.evidence_refs,
|
|
54
|
+
tests: [],
|
|
55
|
+
assumptions: [],
|
|
56
|
+
depth: 0,
|
|
57
|
+
parent_id: null,
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function generatedCandidatesFromResponse(response, input, existingCandidates = []) {
|
|
62
|
+
const accepted = [];
|
|
63
|
+
const rejected = [];
|
|
64
|
+
for (const proposal of response.proposals) {
|
|
65
|
+
const candidate = {
|
|
66
|
+
id: `generated-${proposal.proposal_id}`,
|
|
67
|
+
action: proposal.intent,
|
|
68
|
+
source: "generated",
|
|
69
|
+
gate_action: proposal.gate_action,
|
|
70
|
+
intent: proposal.intent,
|
|
71
|
+
expected_evidence: proposal.expected_evidence,
|
|
72
|
+
tests: proposal.tests,
|
|
73
|
+
assumptions: proposal.assumptions,
|
|
74
|
+
affected_boundaries: proposal.affected_boundaries,
|
|
75
|
+
risk_strategy: proposal.risk_strategy,
|
|
76
|
+
reversibility: proposal.reversibility,
|
|
77
|
+
generator_proposal_id: proposal.proposal_id,
|
|
78
|
+
depth: 0,
|
|
79
|
+
parent_id: null,
|
|
80
|
+
};
|
|
81
|
+
const legality = candidateLegality(candidate, input);
|
|
82
|
+
if (!legality.legal) {
|
|
83
|
+
rejected.push({ proposal_id: proposal.proposal_id, reason: legality.reason });
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
const peers = [...existingCandidates, ...accepted].filter((item) => normalized(item.gate_action ?? item.action) === normalized(candidate.gate_action));
|
|
87
|
+
const duplicate = peers.find((item) => {
|
|
88
|
+
const same = normalized(item.intent ?? item.action) === normalized(candidate.intent);
|
|
89
|
+
const sameDecision = signature(item) === signature(candidate);
|
|
90
|
+
return same || sameDecision || jaccard(tokens(item.intent ?? item.action), tokens(candidate.intent)) >= 0.8;
|
|
91
|
+
});
|
|
92
|
+
if (duplicate) {
|
|
93
|
+
rejected.push({ proposal_id: proposal.proposal_id, reason: "cosmetic_or_material_duplicate" });
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
accepted.push(candidate);
|
|
97
|
+
}
|
|
98
|
+
return { accepted, rejected };
|
|
99
|
+
}
|
package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/contracts.js
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
export const CONTRACT_VERSION = "1";
|
|
2
|
+
export const GENERATOR_CONTRACT_VERSION = "1";
|
|
3
|
+
export const SCORING_POLICY_VERSION = "1";
|
|
4
|
+
export const SCORE_DIMENSIONS = [
|
|
5
|
+
"scope_fit",
|
|
6
|
+
"gate_readiness",
|
|
7
|
+
"risk_reduction",
|
|
8
|
+
"evidence_gain",
|
|
9
|
+
"testability",
|
|
10
|
+
"reversibility",
|
|
11
|
+
"cost",
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
function requireObject(value, label) {
|
|
15
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`${label} must be an object`);
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function requireString(value, label) {
|
|
20
|
+
if (typeof value !== "string" || !value.trim()) throw new Error(`${label} must be a non-empty string`);
|
|
21
|
+
return value.trim();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function stringArray(value, label) {
|
|
25
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) throw new Error(`${label} must be a string array`);
|
|
26
|
+
return value.map((item) => item.trim()).filter(Boolean);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function optionalBoundedString(value, label, maxLength = 1000) {
|
|
30
|
+
if (value === undefined) return undefined;
|
|
31
|
+
const result = requireString(value, label);
|
|
32
|
+
if (result.length > maxLength) throw new Error(`${label} must be at most ${maxLength} characters`);
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function rejectUnknownKeys(value, allowed, label) {
|
|
37
|
+
const unknown = Object.keys(value).filter((key) => !allowed.includes(key));
|
|
38
|
+
if (unknown.length) throw new Error(`${label} contains unknown fields: ${unknown.join(", ")}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function generationConfig(value, wholeRunBudgets) {
|
|
42
|
+
if (value === undefined) return undefined;
|
|
43
|
+
const generation = requireObject(value, "generation");
|
|
44
|
+
if (typeof generation.enabled !== "boolean") throw new Error("generation.enabled must be a boolean");
|
|
45
|
+
const limits = {
|
|
46
|
+
max_calls: 1,
|
|
47
|
+
max_proposals: 5,
|
|
48
|
+
max_duration_ms: 30000,
|
|
49
|
+
max_cost_units: 5,
|
|
50
|
+
};
|
|
51
|
+
for (const [key, maximum] of Object.entries(limits)) {
|
|
52
|
+
if (!Number.isInteger(generation[key]) || generation[key] < 1 || generation[key] > maximum) {
|
|
53
|
+
throw new Error(`generation.${key} must be an integer from 1 to ${maximum}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (generation.max_calls !== 1) throw new Error("generation.max_calls must equal 1 in this contract version");
|
|
57
|
+
if (generation.max_duration_ms > wholeRunBudgets.max_duration_ms) throw new Error("generation.max_duration_ms cannot exceed budgets.max_duration_ms");
|
|
58
|
+
if (generation.max_cost_units > wholeRunBudgets.max_cost_units) throw new Error("generation.max_cost_units cannot exceed budgets.max_cost_units");
|
|
59
|
+
return structuredClone(generation);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function validateSearchInput(value) {
|
|
63
|
+
const input = requireObject(value, "search input");
|
|
64
|
+
if (input.contract_version !== CONTRACT_VERSION) throw new Error(`unsupported search input contract_version: ${input.contract_version}`);
|
|
65
|
+
requireString(input.scope_key, "scope_key");
|
|
66
|
+
if (!/^[a-z0-9][a-z0-9._-]*$/i.test(input.scope_key) || input.scope_key.includes("..")) {
|
|
67
|
+
throw new Error("scope_key must be a safe path segment");
|
|
68
|
+
}
|
|
69
|
+
requireString(input.objective, "objective");
|
|
70
|
+
requireString(input.current_gate, "current_gate");
|
|
71
|
+
stringArray(input.allowed_actions, "allowed_actions");
|
|
72
|
+
stringArray(input.forbidden_actions, "forbidden_actions");
|
|
73
|
+
stringArray(input.evidence_refs ?? [], "evidence_refs");
|
|
74
|
+
stringArray(input.risks ?? [], "risks");
|
|
75
|
+
validateEnforcement(input.enforcement);
|
|
76
|
+
const budgets = requireObject(input.budgets, "budgets");
|
|
77
|
+
for (const key of ["max_candidates", "max_depth", "max_evaluations", "max_duration_ms", "max_cost_units", "stability_window"]) {
|
|
78
|
+
if (!Number.isInteger(budgets[key]) || budgets[key] < 1) throw new Error(`budgets.${key} must be a positive integer`);
|
|
79
|
+
}
|
|
80
|
+
generationConfig(input.generation, budgets);
|
|
81
|
+
return structuredClone(input);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function validateCandidate(value) {
|
|
85
|
+
const candidate = requireObject(value, "candidate");
|
|
86
|
+
requireString(candidate.id, "candidate.id");
|
|
87
|
+
requireString(candidate.action, "candidate.action");
|
|
88
|
+
stringArray(candidate.expected_evidence ?? [], "candidate.expected_evidence");
|
|
89
|
+
stringArray(candidate.tests ?? [], "candidate.tests");
|
|
90
|
+
stringArray(candidate.assumptions ?? [], "candidate.assumptions");
|
|
91
|
+
if (candidate.source !== undefined && !["deterministic", "generated", "expanded"].includes(candidate.source)) {
|
|
92
|
+
throw new Error("candidate.source must be deterministic, generated or expanded");
|
|
93
|
+
}
|
|
94
|
+
optionalBoundedString(candidate.gate_action, "candidate.gate_action");
|
|
95
|
+
optionalBoundedString(candidate.intent, "candidate.intent");
|
|
96
|
+
stringArray(candidate.affected_boundaries ?? [], "candidate.affected_boundaries");
|
|
97
|
+
optionalBoundedString(candidate.risk_strategy, "candidate.risk_strategy");
|
|
98
|
+
optionalBoundedString(candidate.reversibility, "candidate.reversibility");
|
|
99
|
+
optionalBoundedString(candidate.generator_proposal_id, "candidate.generator_proposal_id", 200);
|
|
100
|
+
return structuredClone(candidate);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function validateGeneratorRequest(value) {
|
|
104
|
+
const request = requireObject(value, "generator request");
|
|
105
|
+
rejectUnknownKeys(request, ["contract_version", "scope_key", "objective", "scope_summary", "current_gate", "allowed_actions", "forbidden_actions", "artefact_refs", "evidence", "missing_evidence", "risks", "constraints", "enforcement", "budgets"], "generator request");
|
|
106
|
+
if (request.contract_version !== GENERATOR_CONTRACT_VERSION) throw new Error(`unsupported generator contract_version: ${request.contract_version}`);
|
|
107
|
+
requireString(request.scope_key, "generator scope_key");
|
|
108
|
+
optionalBoundedString(request.objective, "generator objective", 2000);
|
|
109
|
+
optionalBoundedString(request.scope_summary, "generator scope_summary", 2000);
|
|
110
|
+
requireString(request.current_gate, "generator current_gate");
|
|
111
|
+
for (const key of ["allowed_actions", "forbidden_actions", "artefact_refs", "evidence", "missing_evidence", "risks", "constraints"]) {
|
|
112
|
+
const items = stringArray(request[key] ?? [], `generator ${key}`);
|
|
113
|
+
if (items.length > 20 || items.some((item) => item.length > 500)) throw new Error(`generator ${key} exceeds context bounds`);
|
|
114
|
+
}
|
|
115
|
+
validateEnforcement(request.enforcement);
|
|
116
|
+
const budgets = requireObject(request.budgets, "generator budgets");
|
|
117
|
+
generationConfig({ enabled: true, ...budgets }, { max_duration_ms: 120000, max_cost_units: 20 });
|
|
118
|
+
const serialized = JSON.stringify(request);
|
|
119
|
+
if (/(secret|credential|environment|raw_prompt|hidden_reasoning|source_snapshot)/i.test(serialized)) {
|
|
120
|
+
throw new Error("generator request contains disallowed context");
|
|
121
|
+
}
|
|
122
|
+
return structuredClone(request);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function validateGeneratorResponse(value) {
|
|
126
|
+
const response = requireObject(value, "generator response");
|
|
127
|
+
rejectUnknownKeys(response, ["contract_version", "proposals", "cost_units", "metadata"], "generator response");
|
|
128
|
+
if (response.contract_version !== GENERATOR_CONTRACT_VERSION) throw new Error(`unsupported generator contract_version: ${response.contract_version}`);
|
|
129
|
+
if (!Array.isArray(response.proposals) || response.proposals.length > 5) throw new Error("generator proposals must be an array with at most 5 items");
|
|
130
|
+
if (!Number.isInteger(response.cost_units) || response.cost_units < 0 || response.cost_units > 5) throw new Error("generator cost_units must be an integer from 0 to 5");
|
|
131
|
+
if (response.metadata !== undefined) {
|
|
132
|
+
const metadata = requireObject(response.metadata, "generator metadata");
|
|
133
|
+
rejectUnknownKeys(metadata, ["name", "runtime", "model"], "generator metadata");
|
|
134
|
+
for (const [key, item] of Object.entries(metadata)) optionalBoundedString(item, `generator metadata.${key}`, 500);
|
|
135
|
+
}
|
|
136
|
+
const proposals = response.proposals.map((proposal, index) => {
|
|
137
|
+
const item = requireObject(proposal, `proposal ${index}`);
|
|
138
|
+
rejectUnknownKeys(item, ["proposal_id", "gate_action", "intent", "expected_evidence", "tests", "assumptions", "affected_boundaries", "risk_strategy", "reversibility"], `proposal ${index}`);
|
|
139
|
+
const normalized = {
|
|
140
|
+
proposal_id: requireString(item.proposal_id, `proposal ${index}.proposal_id`),
|
|
141
|
+
gate_action: requireString(item.gate_action, `proposal ${index}.gate_action`),
|
|
142
|
+
intent: requireString(item.intent, `proposal ${index}.intent`),
|
|
143
|
+
expected_evidence: stringArray(item.expected_evidence ?? [], `proposal ${index}.expected_evidence`),
|
|
144
|
+
tests: stringArray(item.tests ?? [], `proposal ${index}.tests`),
|
|
145
|
+
assumptions: stringArray(item.assumptions ?? [], `proposal ${index}.assumptions`),
|
|
146
|
+
affected_boundaries: stringArray(item.affected_boundaries ?? [], `proposal ${index}.affected_boundaries`),
|
|
147
|
+
risk_strategy: requireString(item.risk_strategy, `proposal ${index}.risk_strategy`),
|
|
148
|
+
reversibility: requireString(item.reversibility, `proposal ${index}.reversibility`),
|
|
149
|
+
};
|
|
150
|
+
if (JSON.stringify(normalized).length > 5000) throw new Error(`proposal ${index} exceeds size limit`);
|
|
151
|
+
if (/(^|\s)(rm|sudo|curl|wget|bash|sh|exec)\s/i.test(normalized.intent)) throw new Error(`proposal ${index} contains executable instructions`);
|
|
152
|
+
return normalized;
|
|
153
|
+
});
|
|
154
|
+
return {
|
|
155
|
+
contract_version: response.contract_version,
|
|
156
|
+
proposals,
|
|
157
|
+
cost_units: response.cost_units,
|
|
158
|
+
metadata: response.metadata ? structuredClone(response.metadata) : {},
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export function generatorOutputSchema() {
|
|
163
|
+
return {
|
|
164
|
+
type: "object",
|
|
165
|
+
additionalProperties: false,
|
|
166
|
+
required: ["contract_version", "proposals", "cost_units"],
|
|
167
|
+
properties: {
|
|
168
|
+
contract_version: { type: "string", const: GENERATOR_CONTRACT_VERSION },
|
|
169
|
+
cost_units: { type: "integer", minimum: 0, maximum: 5 },
|
|
170
|
+
proposals: {
|
|
171
|
+
type: "array", maxItems: 5, items: {
|
|
172
|
+
type: "object", additionalProperties: false,
|
|
173
|
+
required: ["proposal_id", "gate_action", "intent", "expected_evidence", "tests", "assumptions", "affected_boundaries", "risk_strategy", "reversibility"],
|
|
174
|
+
properties: {
|
|
175
|
+
proposal_id: { type: "string", minLength: 1 }, gate_action: { type: "string", minLength: 1 }, intent: { type: "string", minLength: 1 },
|
|
176
|
+
expected_evidence: { type: "array", items: { type: "string" } }, tests: { type: "array", items: { type: "string" } },
|
|
177
|
+
assumptions: { type: "array", items: { type: "string" } }, affected_boundaries: { type: "array", items: { type: "string" } },
|
|
178
|
+
risk_strategy: { type: "string", minLength: 1 }, reversibility: { type: "string", minLength: 1 },
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export function validateEvaluation(value, candidateId) {
|
|
187
|
+
const evaluation = requireObject(value, "evaluation");
|
|
188
|
+
if (evaluation.contract_version !== CONTRACT_VERSION) throw new Error(`unsupported evaluator contract_version: ${evaluation.contract_version}`);
|
|
189
|
+
if (evaluation.candidate_id !== candidateId) throw new Error(`evaluation candidate_id must be ${candidateId}`);
|
|
190
|
+
for (const dimension of SCORE_DIMENSIONS) {
|
|
191
|
+
if (!Number.isInteger(evaluation[dimension]) || evaluation[dimension] < 0 || evaluation[dimension] > 5) {
|
|
192
|
+
throw new Error(`${dimension} must be an integer from 0 to 5`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (!Number.isInteger(evaluation.uncertainty) || evaluation.uncertainty < 0 || evaluation.uncertainty > 5) {
|
|
196
|
+
throw new Error("uncertainty must be an integer from 0 to 5");
|
|
197
|
+
}
|
|
198
|
+
requireString(evaluation.rationale, "evaluation.rationale");
|
|
199
|
+
stringArray(evaluation.risks ?? [], "evaluation.risks");
|
|
200
|
+
stringArray(evaluation.assumptions ?? [], "evaluation.assumptions");
|
|
201
|
+
stringArray(evaluation.child_actions ?? [], "evaluation.child_actions");
|
|
202
|
+
if (/(^|\s)(rm|sudo|curl|wget|bash|sh|exec)\s/i.test(evaluation.rationale)) {
|
|
203
|
+
throw new Error("evaluation rationale contains executable instructions");
|
|
204
|
+
}
|
|
205
|
+
return structuredClone(evaluation);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export function validateEnforcement(value) {
|
|
209
|
+
const enforcement = requireObject(value, "enforcement");
|
|
210
|
+
if (!["full", "tool_enforced", "instruction_only"].includes(enforcement.level)) {
|
|
211
|
+
throw new Error("enforcement.level must be full, tool_enforced or instruction_only");
|
|
212
|
+
}
|
|
213
|
+
const evidence = stringArray(enforcement.evidence ?? [], "enforcement.evidence");
|
|
214
|
+
if (enforcement.level !== "instruction_only" && evidence.length === 0) {
|
|
215
|
+
throw new Error(`${enforcement.level} requires enforcement evidence`);
|
|
216
|
+
}
|
|
217
|
+
return { level: enforcement.level, evidence };
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export function evaluatorOutputSchema() {
|
|
221
|
+
const scoreProperties = Object.fromEntries(SCORE_DIMENSIONS.map((key) => [key, { type: "integer", minimum: 0, maximum: 5 }]));
|
|
222
|
+
return {
|
|
223
|
+
type: "object",
|
|
224
|
+
additionalProperties: false,
|
|
225
|
+
required: ["contract_version", "candidate_id", ...SCORE_DIMENSIONS, "uncertainty", "rationale", "risks", "assumptions", "child_actions"],
|
|
226
|
+
properties: {
|
|
227
|
+
contract_version: { type: "string", const: CONTRACT_VERSION },
|
|
228
|
+
candidate_id: { type: "string" },
|
|
229
|
+
...scoreProperties,
|
|
230
|
+
uncertainty: { type: "integer", minimum: 0, maximum: 5 },
|
|
231
|
+
rationale: { type: "string", minLength: 1, maxLength: 1000 },
|
|
232
|
+
risks: { type: "array", items: { type: "string" } },
|
|
233
|
+
assumptions: { type: "array", items: { type: "string" } },
|
|
234
|
+
child_actions: { type: "array", items: { type: "string" }, maxItems: 5 },
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { evaluatorOutputSchema, validateEvaluation } from "../contracts.js";
|
|
3
|
+
import { guardedExecFileSync } from "../transports/read-only-guard.js";
|
|
4
|
+
import { buildEvaluatorPrompt } from "./prompt.js";
|
|
5
|
+
|
|
6
|
+
export function claudeEvaluator(options = {}) {
|
|
7
|
+
const claudeBin = options.claudeBin ?? "claude";
|
|
8
|
+
let runtime = "claude version unavailable";
|
|
9
|
+
try {
|
|
10
|
+
runtime = execFileSync(claudeBin, ["--version"], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
11
|
+
} catch {}
|
|
12
|
+
|
|
13
|
+
return {
|
|
14
|
+
name: "claude",
|
|
15
|
+
metadata: { name: "claude", runtime, model: options.model ?? "configured-default" },
|
|
16
|
+
async evaluate(input, candidate) {
|
|
17
|
+
const prompt = buildEvaluatorPrompt(input, candidate);
|
|
18
|
+
const args = [
|
|
19
|
+
"-p", "--disallowedTools", "Edit,Write,Bash",
|
|
20
|
+
"--output-format", "json", "--json-schema", JSON.stringify(evaluatorOutputSchema()),
|
|
21
|
+
];
|
|
22
|
+
if (options.model) args.push("--model", options.model);
|
|
23
|
+
args.push(prompt);
|
|
24
|
+
const raw = guardedExecFileSync(claudeBin, args, {
|
|
25
|
+
cwd: options.cwd,
|
|
26
|
+
encoding: "utf8",
|
|
27
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
28
|
+
timeout: options.timeoutMs ?? 120000,
|
|
29
|
+
});
|
|
30
|
+
const response = JSON.parse(raw);
|
|
31
|
+
if (response.is_error) throw new Error(`claude evaluator returned an error: ${response.result ?? "unknown error"}`);
|
|
32
|
+
return validateEvaluation(JSON.parse(response.result), candidate.id);
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { evaluatorOutputSchema, validateEvaluation } from "../contracts.js";
|
|
6
|
+
import { guardedExecFileSync } from "../transports/read-only-guard.js";
|
|
7
|
+
import { buildEvaluatorPrompt } from "./prompt.js";
|
|
8
|
+
|
|
9
|
+
export function codexEvaluator(options = {}) {
|
|
10
|
+
const codexBin = options.codexBin ?? "codex";
|
|
11
|
+
let runtime = "codex version unavailable";
|
|
12
|
+
try {
|
|
13
|
+
runtime = execFileSync(codexBin, ["--version"], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
14
|
+
} catch {}
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
name: "codex",
|
|
18
|
+
metadata: { name: "codex", runtime, model: options.model ?? "configured-default" },
|
|
19
|
+
async evaluate(input, candidate) {
|
|
20
|
+
const temp = mkdtempSync(join(tmpdir(), "agdf-dps-"));
|
|
21
|
+
const schemaPath = join(temp, "schema.json");
|
|
22
|
+
const outputPath = join(temp, "output.json");
|
|
23
|
+
try {
|
|
24
|
+
writeFileSync(schemaPath, `${JSON.stringify(evaluatorOutputSchema(), null, 2)}\n`, "utf8");
|
|
25
|
+
const prompt = buildEvaluatorPrompt(input, candidate);
|
|
26
|
+
const args = [
|
|
27
|
+
"exec", "--sandbox", "read-only", "--ephemeral", "--ignore-user-config",
|
|
28
|
+
"--output-schema", schemaPath, "--output-last-message", outputPath, "--color", "never",
|
|
29
|
+
];
|
|
30
|
+
if (options.model) args.push("--model", options.model);
|
|
31
|
+
args.push(prompt);
|
|
32
|
+
guardedExecFileSync(codexBin, args, {
|
|
33
|
+
cwd: options.cwd,
|
|
34
|
+
encoding: "utf8",
|
|
35
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
36
|
+
timeout: options.timeoutMs ?? 120000,
|
|
37
|
+
});
|
|
38
|
+
return validateEvaluation(JSON.parse(readFileSync(outputPath, "utf8")), candidate.id);
|
|
39
|
+
} finally {
|
|
40
|
+
rmSync(temp, { recursive: true, force: true });
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|