create-agdf 0.11.2 → 0.11.4
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 +5 -4
- package/generated/.agdf/control/templates/MASTER_BACKLOG.md +1 -1
- package/generated/.github/skills/agdf-gate-check/SKILL.md +9 -0
- package/generated/.github/skills/agdf-interaction-locales.json +38 -0
- package/generated/.github/skills/contracts/control-scaffold.md +2 -0
- package/generated/.github/skills/contracts/interaction.md +19 -0
- package/generated/.opencode/agdf-interaction-locales.json +38 -0
- package/generated/.opencode/contracts/control-scaffold.md +2 -0
- package/generated/.opencode/contracts/interaction.md +19 -0
- package/generated/.opencode/skills/agdf-gate-check/SKILL.md +9 -0
- package/generated/plugins/agdf/.claude-plugin/plugin.json +1 -1
- package/generated/plugins/agdf/.codex-plugin/plugin.json +1 -1
- package/generated/plugins/agdf/control/templates/MASTER_BACKLOG.md +1 -1
- package/generated/plugins/agdf/meta/agdf-interaction-locales.json +38 -0
- package/generated/plugins/agdf/meta/agdf-plugin.definition.json +2 -1
- package/generated/plugins/agdf/meta/contracts/control-scaffold.md +2 -0
- package/generated/plugins/agdf/meta/contracts/interaction.md +19 -0
- package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-interaction-locales.json +38 -0
- package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-plugin.definition.json +2 -1
- package/generated/plugins/agdf/runtime/create-agdf/lib/cli/command-registry.js +2 -2
- package/generated/plugins/agdf/runtime/create-agdf/lib/cli/delivery-path-search-command.js +78 -14
- package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/shared.js +1 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/claude.js +2 -11
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/codex.js +2 -11
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/opencode.js +234 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/prompt.js +13 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/search-engine.js +1 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/surfaces/capabilities.js +15 -2
- package/generated/plugins/agdf/runtime/create-agdf/lib/interaction-presentation.js +63 -0
- package/generated/plugins/agdf/runtime/create-agdf/package.json +3 -2
- package/generated/plugins/agdf/runtime/runtime-manifest.json +2 -2
- package/generated/plugins/agdf/scripts/check-runtime-integrity.mjs +22 -0
- package/generated/plugins/agdf/skills/gate-check/SKILL.md +9 -0
- package/lib/cli/application.js +17 -2
- package/lib/cli/command-registry.js +2 -2
- package/lib/cli/delivery-path-search-command.js +78 -14
- package/lib/control-evaluation/shared.js +1 -0
- package/lib/delivery-path-search/evaluators/claude.js +2 -11
- package/lib/delivery-path-search/evaluators/codex.js +2 -11
- package/lib/delivery-path-search/evaluators/opencode.js +234 -0
- package/lib/delivery-path-search/evaluators/prompt.js +13 -0
- package/lib/delivery-path-search/search-engine.js +1 -0
- package/lib/delivery-path-search/surfaces/capabilities.js +15 -2
- package/lib/installers/opencode.js +214 -10
- package/lib/interaction-presentation.js +63 -0
- package/lib/lifecycle/operations.js +4 -0
- package/opencode-plugin.js +19 -2
- package/package.json +3 -2
package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/claude.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { execFileSync } from "node:child_process";
|
|
2
2
|
import { evaluatorOutputSchema, validateEvaluation } from "../contracts.js";
|
|
3
3
|
import { guardedExecFileSync } from "../transports/read-only-guard.js";
|
|
4
|
+
import { buildEvaluatorPrompt } from "./prompt.js";
|
|
4
5
|
|
|
5
6
|
export function claudeEvaluator(options = {}) {
|
|
6
7
|
const claudeBin = options.claudeBin ?? "claude";
|
|
@@ -13,17 +14,7 @@ export function claudeEvaluator(options = {}) {
|
|
|
13
14
|
name: "claude",
|
|
14
15
|
metadata: { name: "claude", runtime, model: options.model ?? "configured-default" },
|
|
15
16
|
async evaluate(input, candidate) {
|
|
16
|
-
const prompt =
|
|
17
|
-
"You are an evaluation-only component. Do not use tools, execute commands, or modify files.",
|
|
18
|
-
`Return JSON matching contract version ${input.contract_version}.`,
|
|
19
|
-
`Objective: ${input.objective}`,
|
|
20
|
-
`Current gate: ${input.current_gate}`,
|
|
21
|
-
`Candidate id: ${candidate.id}`,
|
|
22
|
-
`Candidate action: ${candidate.action}`,
|
|
23
|
-
"Score scope_fit, gate_readiness, risk_reduction, evidence_gain, testability, reversibility and cost from 0 to 5.",
|
|
24
|
-
"Cost 0 is low and 5 is high. uncertainty is 0 low to 5 high.",
|
|
25
|
-
"Keep rationale concise. child_actions must only contain actions permitted by the current gate.",
|
|
26
|
-
].join("\n");
|
|
17
|
+
const prompt = buildEvaluatorPrompt(input, candidate);
|
|
27
18
|
const args = [
|
|
28
19
|
"-p", "--disallowedTools", "Edit,Write,Bash",
|
|
29
20
|
"--output-format", "json", "--json-schema", JSON.stringify(evaluatorOutputSchema()),
|
package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/codex.js
CHANGED
|
@@ -4,6 +4,7 @@ import { tmpdir } from "node:os";
|
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { evaluatorOutputSchema, validateEvaluation } from "../contracts.js";
|
|
6
6
|
import { guardedExecFileSync } from "../transports/read-only-guard.js";
|
|
7
|
+
import { buildEvaluatorPrompt } from "./prompt.js";
|
|
7
8
|
|
|
8
9
|
export function codexEvaluator(options = {}) {
|
|
9
10
|
const codexBin = options.codexBin ?? "codex";
|
|
@@ -21,17 +22,7 @@ export function codexEvaluator(options = {}) {
|
|
|
21
22
|
const outputPath = join(temp, "output.json");
|
|
22
23
|
try {
|
|
23
24
|
writeFileSync(schemaPath, `${JSON.stringify(evaluatorOutputSchema(), null, 2)}\n`, "utf8");
|
|
24
|
-
const prompt =
|
|
25
|
-
"You are an evaluation-only component. Do not use tools, execute commands, or modify files.",
|
|
26
|
-
`Return JSON matching contract version ${input.contract_version}.`,
|
|
27
|
-
`Objective: ${input.objective}`,
|
|
28
|
-
`Current gate: ${input.current_gate}`,
|
|
29
|
-
`Candidate id: ${candidate.id}`,
|
|
30
|
-
`Candidate action: ${candidate.action}`,
|
|
31
|
-
"Score scope_fit, gate_readiness, risk_reduction, evidence_gain, testability, reversibility and cost from 0 to 5.",
|
|
32
|
-
"Cost 0 is low and 5 is high. uncertainty is 0 low to 5 high.",
|
|
33
|
-
"Keep rationale concise. child_actions must only contain actions permitted by the current gate.",
|
|
34
|
-
].join("\n");
|
|
25
|
+
const prompt = buildEvaluatorPrompt(input, candidate);
|
|
35
26
|
const args = [
|
|
36
27
|
"exec", "--sandbox", "read-only", "--ephemeral", "--ignore-user-config",
|
|
37
28
|
"--output-schema", schemaPath, "--output-last-message", outputPath, "--color", "never",
|
package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/opencode.js
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { execFileSync, spawnSync } from "node:child_process";
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
import { validateEvaluation } from "../contracts.js";
|
|
4
|
+
import { guardedExecFileSync } from "../transports/read-only-guard.js";
|
|
5
|
+
import { buildEvaluatorPrompt } from "./prompt.js";
|
|
6
|
+
|
|
7
|
+
export const OPENCODE_EVALUATOR_AGENT = "agdf-evaluator";
|
|
8
|
+
|
|
9
|
+
export const OPENCODE_DENY_PERMISSIONS = Object.freeze({
|
|
10
|
+
"*": "deny",
|
|
11
|
+
read: "deny",
|
|
12
|
+
edit: "deny",
|
|
13
|
+
bash: "deny",
|
|
14
|
+
task: "deny",
|
|
15
|
+
webfetch: "deny",
|
|
16
|
+
websearch: "deny",
|
|
17
|
+
skill: "deny",
|
|
18
|
+
lsp: "deny",
|
|
19
|
+
todowrite: "deny",
|
|
20
|
+
question: "deny",
|
|
21
|
+
external_directory: "deny",
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const executablePermissions = Object.freeze([
|
|
25
|
+
"edit", "bash", "task", "webfetch", "websearch", "skill", "lsp", "todowrite", "question",
|
|
26
|
+
]);
|
|
27
|
+
|
|
28
|
+
export function openCodePermissionEnvironment(env = process.env) {
|
|
29
|
+
return {
|
|
30
|
+
...env,
|
|
31
|
+
OPENCODE_PERMISSION: JSON.stringify(OPENCODE_DENY_PERMISSIONS),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function preflightFailure(code, detail, evidence = []) {
|
|
36
|
+
return {
|
|
37
|
+
surface: "opencode",
|
|
38
|
+
status: "failed",
|
|
39
|
+
code,
|
|
40
|
+
detail,
|
|
41
|
+
evidence,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function extractAgentPermissions(output, agentName) {
|
|
46
|
+
const marker = `${agentName} (`;
|
|
47
|
+
const lines = output.split(/\r?\n/);
|
|
48
|
+
const start = lines.findIndex((line) => line.startsWith(marker));
|
|
49
|
+
if (start < 0) return null;
|
|
50
|
+
const mode = lines[start].slice(marker.length).split(")")[0];
|
|
51
|
+
let jsonStart = -1;
|
|
52
|
+
let depth = 0;
|
|
53
|
+
for (let index = start + 1; index < lines.length; index += 1) {
|
|
54
|
+
const line = lines[index].trim();
|
|
55
|
+
if (jsonStart < 0 && line === "[") {
|
|
56
|
+
jsonStart = index;
|
|
57
|
+
depth = 1;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (jsonStart >= 0) {
|
|
61
|
+
for (const character of line) {
|
|
62
|
+
if (character === "[") depth += 1;
|
|
63
|
+
if (character === "]") depth -= 1;
|
|
64
|
+
}
|
|
65
|
+
if (depth === 0) return { mode, permissions: JSON.parse(lines.slice(jsonStart, index + 1).join("\n")) };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function terminalPermissionDecision(permissions, permissionName) {
|
|
72
|
+
let decision = null;
|
|
73
|
+
for (const entry of permissions) {
|
|
74
|
+
if (entry?.pattern === "*" && (entry.permission === "*" || entry.permission === permissionName)) {
|
|
75
|
+
decision = entry.action;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return decision;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function preflightOpenCodeEvaluator(options = {}) {
|
|
82
|
+
const executable = options.openCodeBin ?? process.env.AGDF_OPENCODE_BIN ?? "opencode";
|
|
83
|
+
const run = options.execFileSync ?? execFileSync;
|
|
84
|
+
const cwd = options.cwd ?? process.cwd();
|
|
85
|
+
const agentName = options.agentName ?? OPENCODE_EVALUATOR_AGENT;
|
|
86
|
+
const env = openCodePermissionEnvironment(options.env ?? process.env);
|
|
87
|
+
let runtime;
|
|
88
|
+
let help;
|
|
89
|
+
let agents;
|
|
90
|
+
try {
|
|
91
|
+
runtime = run(executable, ["--version"], {
|
|
92
|
+
cwd, env, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: 5000,
|
|
93
|
+
}).trim();
|
|
94
|
+
} catch (error) {
|
|
95
|
+
return preflightFailure("opencode_host_unavailable", (error.stderr || error.message).toString().trim());
|
|
96
|
+
}
|
|
97
|
+
try {
|
|
98
|
+
if (options.execFileSync) {
|
|
99
|
+
help = run(executable, ["run", "--help"], {
|
|
100
|
+
cwd, env, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: 5000,
|
|
101
|
+
});
|
|
102
|
+
} else {
|
|
103
|
+
const helpProbe = (options.spawnSync ?? spawnSync)(executable, ["run", "--help"], {
|
|
104
|
+
cwd, env, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: 5000,
|
|
105
|
+
});
|
|
106
|
+
if (helpProbe.error || helpProbe.status !== 0) throw helpProbe.error ?? new Error(helpProbe.stderr || "OpenCode run help failed.");
|
|
107
|
+
help = `${helpProbe.stdout ?? ""}\n${helpProbe.stderr ?? ""}`;
|
|
108
|
+
}
|
|
109
|
+
} catch (error) {
|
|
110
|
+
return preflightFailure("opencode_run_unavailable", (error.stderr || error.message).toString().trim(), [`opencode ${runtime}`]);
|
|
111
|
+
}
|
|
112
|
+
const requiredFlags = ["--pure", "--agent", "--format", "--dir"];
|
|
113
|
+
const missingFlags = requiredFlags.filter((flag) => !help.includes(flag));
|
|
114
|
+
if (missingFlags.length) {
|
|
115
|
+
return preflightFailure("opencode_run_capability_missing", `Missing required flags: ${missingFlags.join(", ")}`, [`opencode ${runtime}`]);
|
|
116
|
+
}
|
|
117
|
+
try {
|
|
118
|
+
agents = run(executable, ["agent", "list", "--pure"], {
|
|
119
|
+
cwd, env, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: 10000,
|
|
120
|
+
});
|
|
121
|
+
} catch (error) {
|
|
122
|
+
return preflightFailure("opencode_agent_probe_failed", (error.stderr || error.message).toString().trim(), [`opencode ${runtime}`]);
|
|
123
|
+
}
|
|
124
|
+
let projection;
|
|
125
|
+
try {
|
|
126
|
+
projection = extractAgentPermissions(agents, agentName);
|
|
127
|
+
} catch (error) {
|
|
128
|
+
return preflightFailure("opencode_agent_permissions_unparseable", error.message, [`opencode ${runtime}`]);
|
|
129
|
+
}
|
|
130
|
+
if (!projection) {
|
|
131
|
+
return preflightFailure("opencode_evaluator_agent_missing", `OpenCode agent ${agentName} is not available.`, [`opencode ${runtime}`]);
|
|
132
|
+
}
|
|
133
|
+
if (projection.mode !== "primary") {
|
|
134
|
+
return preflightFailure("opencode_evaluator_agent_incompatible", `OpenCode agent ${agentName} must be primary for opencode run --agent; observed ${projection.mode || "unknown"}.`, [
|
|
135
|
+
`opencode ${runtime}`,
|
|
136
|
+
`agent:${agentName}`,
|
|
137
|
+
]);
|
|
138
|
+
}
|
|
139
|
+
const unsafe = executablePermissions.filter((permission) => terminalPermissionDecision(projection.permissions, permission) !== "deny");
|
|
140
|
+
if (unsafe.length) {
|
|
141
|
+
return preflightFailure("opencode_evaluator_permissions_unsafe", `Terminal deny is not effective for: ${unsafe.join(", ")}`, [
|
|
142
|
+
`opencode ${runtime}`,
|
|
143
|
+
`agent:${agentName}`,
|
|
144
|
+
]);
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
surface: "opencode",
|
|
148
|
+
status: "passed",
|
|
149
|
+
code: "opencode_evaluator_ready",
|
|
150
|
+
invocation_id: `${process.pid}-${Date.now()}`,
|
|
151
|
+
runtime,
|
|
152
|
+
agent: agentName,
|
|
153
|
+
evidence: [
|
|
154
|
+
`opencode ${runtime}`,
|
|
155
|
+
"opencode run --pure --agent agdf-evaluator --format json",
|
|
156
|
+
"effective executable permissions terminal-deny",
|
|
157
|
+
],
|
|
158
|
+
env,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export function parseOpenCodeEvaluatorOutput(raw) {
|
|
163
|
+
const text = [];
|
|
164
|
+
for (const line of raw.split(/\r?\n/).filter(Boolean)) {
|
|
165
|
+
const event = JSON.parse(line);
|
|
166
|
+
if (event?.type === "error") {
|
|
167
|
+
const status = event.error?.data?.statusCode;
|
|
168
|
+
const detail = event.error?.data?.message || event.error?.message || "unknown OpenCode evaluator error";
|
|
169
|
+
const error = new Error(`OpenCode evaluator error${status ? ` (${status})` : ""}: ${detail}`);
|
|
170
|
+
error.code = status === 401 || /auth|credential|provider available/i.test(detail)
|
|
171
|
+
? "OPENCODE_EVALUATOR_AUTHENTICATION_FAILED"
|
|
172
|
+
: "OPENCODE_EVALUATOR_UNAVAILABLE";
|
|
173
|
+
throw error;
|
|
174
|
+
}
|
|
175
|
+
if (event?.part?.type === "text" && typeof event.part.text === "string") text.push(event.part.text);
|
|
176
|
+
else if (event?.type === "text" && typeof event.text === "string") text.push(event.text);
|
|
177
|
+
}
|
|
178
|
+
if (!text.length) throw new Error("OpenCode evaluator returned no text event.");
|
|
179
|
+
if (text.length !== 1) throw new Error(`OpenCode evaluator returned ${text.length} text events; exactly one final payload is required.`);
|
|
180
|
+
return JSON.parse(text[0]);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function fatalEvaluatorError(error) {
|
|
184
|
+
const wrapped = new Error(error.message);
|
|
185
|
+
wrapped.code = typeof error.code === "string" && error.code.startsWith("OPENCODE_EVALUATOR_")
|
|
186
|
+
? error.code
|
|
187
|
+
: error.code === "GENERATOR_MUTATION_DETECTED"
|
|
188
|
+
? "OPENCODE_EVALUATOR_MUTATION_DETECTED"
|
|
189
|
+
: error.code === "GENERATOR_TIMEOUT"
|
|
190
|
+
? "OPENCODE_EVALUATOR_TIMEOUT"
|
|
191
|
+
: error.code === "ENOENT"
|
|
192
|
+
? "OPENCODE_EVALUATOR_UNAVAILABLE"
|
|
193
|
+
: /auth|unauthorized|credential/i.test(`${error.message}\n${error.stderr ?? ""}`)
|
|
194
|
+
? "OPENCODE_EVALUATOR_AUTHENTICATION_FAILED"
|
|
195
|
+
: "OPENCODE_EVALUATOR_OUTPUT_INVALID";
|
|
196
|
+
wrapped.fatalEvaluator = true;
|
|
197
|
+
return wrapped;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export function openCodeEvaluator(options = {}) {
|
|
201
|
+
if (options.preflight?.status !== "passed" || options.preflight.surface !== "opencode") {
|
|
202
|
+
throw new Error("OpenCode evaluator requires a successful current-invocation preflight.");
|
|
203
|
+
}
|
|
204
|
+
const executable = options.openCodeBin ?? process.env.AGDF_OPENCODE_BIN ?? "opencode";
|
|
205
|
+
const agentName = options.preflight.agent ?? OPENCODE_EVALUATOR_AGENT;
|
|
206
|
+
return {
|
|
207
|
+
name: "opencode",
|
|
208
|
+
metadata: {
|
|
209
|
+
name: "opencode",
|
|
210
|
+
runtime: options.preflight.runtime,
|
|
211
|
+
agent: agentName,
|
|
212
|
+
preflight: options.preflight.code,
|
|
213
|
+
},
|
|
214
|
+
async evaluate(input, candidate) {
|
|
215
|
+
const args = [
|
|
216
|
+
"run", "--pure", "--agent", agentName, "--format", "json", "--dir", options.cwd,
|
|
217
|
+
];
|
|
218
|
+
if (options.model) args.push("--model", options.model);
|
|
219
|
+
args.push(buildEvaluatorPrompt(input, candidate));
|
|
220
|
+
try {
|
|
221
|
+
const raw = guardedExecFileSync(executable, args, {
|
|
222
|
+
cwd: options.cwd,
|
|
223
|
+
env: options.preflight.env,
|
|
224
|
+
encoding: "utf8",
|
|
225
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
226
|
+
timeout: options.timeoutMs ?? 120000,
|
|
227
|
+
});
|
|
228
|
+
return validateEvaluation(parseOpenCodeEvaluatorOutput(raw), candidate.id);
|
|
229
|
+
} catch (error) {
|
|
230
|
+
throw fatalEvaluatorError(error);
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
}
|
package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/prompt.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function buildEvaluatorPrompt(input, candidate) {
|
|
2
|
+
return [
|
|
3
|
+
"You are an evaluation-only component. Do not use tools, execute commands, inspect files, delegate work or modify state.",
|
|
4
|
+
`Return only one JSON object matching contract version ${input.contract_version}.`,
|
|
5
|
+
`Objective: ${input.objective}`,
|
|
6
|
+
`Current gate: ${input.current_gate}`,
|
|
7
|
+
`Candidate id: ${candidate.id}`,
|
|
8
|
+
`Candidate action: ${candidate.action}`,
|
|
9
|
+
"Score scope_fit, gate_readiness, risk_reduction, evidence_gain, testability, reversibility and cost from 0 to 5.",
|
|
10
|
+
"Cost 0 is low and 5 is high. uncertainty is 0 low to 5 high.",
|
|
11
|
+
"Keep rationale concise. child_actions must only contain actions permitted by the current gate.",
|
|
12
|
+
].join("\n");
|
|
13
|
+
}
|
package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/search-engine.js
CHANGED
|
@@ -114,6 +114,7 @@ export async function runDeliveryPathSearch(inputValue, evaluator, options = {})
|
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
} catch (error) {
|
|
117
|
+
if (error?.fatalEvaluator === true) throw error;
|
|
117
118
|
rejected.push({ candidate_id: candidate.id, action: candidate.action, reason: `invalid_evaluation: ${error.message}` });
|
|
118
119
|
}
|
|
119
120
|
}
|
package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/surfaces/capabilities.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { validateEnforcement } from "../contracts.js";
|
|
2
2
|
|
|
3
|
-
export function enforcementForSurface(surface, evidence = []) {
|
|
3
|
+
export function enforcementForSurface(surface, evidence = [], context = {}) {
|
|
4
4
|
const defaults = {
|
|
5
5
|
codex: { level: "tool_enforced", evidence: ["codex exec --sandbox read-only --ephemeral"] },
|
|
6
6
|
claude: { level: "tool_enforced", evidence: ["claude -p --disallowedTools Edit,Write,Bash"] },
|
|
@@ -9,6 +9,19 @@ export function enforcementForSurface(surface, evidence = []) {
|
|
|
9
9
|
generic: { level: "instruction_only", evidence: [] },
|
|
10
10
|
};
|
|
11
11
|
const selected = structuredClone(defaults[surface] ?? defaults.generic);
|
|
12
|
-
if (
|
|
12
|
+
if (surface === "opencode") {
|
|
13
|
+
const preflight = context.preflight;
|
|
14
|
+
if (preflight?.surface === "opencode"
|
|
15
|
+
&& preflight.status === "passed"
|
|
16
|
+
&& typeof preflight.invocation_id === "string"
|
|
17
|
+
&& preflight.invocation_id
|
|
18
|
+
&& Array.isArray(preflight.evidence)
|
|
19
|
+
&& preflight.evidence === evidence) {
|
|
20
|
+
selected.level = "tool_enforced";
|
|
21
|
+
selected.evidence = [...evidence];
|
|
22
|
+
}
|
|
23
|
+
} else if (evidence.length) {
|
|
24
|
+
selected.evidence = evidence;
|
|
25
|
+
}
|
|
13
26
|
return validateEnforcement(selected);
|
|
14
27
|
}
|
|
@@ -349,6 +349,69 @@ export function renderOperationalStatusCard(statusCard, {
|
|
|
349
349
|
});
|
|
350
350
|
}
|
|
351
351
|
|
|
352
|
+
export function renderScopeClassificationCard(classification, {
|
|
353
|
+
registry,
|
|
354
|
+
requestedLocale,
|
|
355
|
+
} = {}) {
|
|
356
|
+
if (!plainObject(classification)) return null;
|
|
357
|
+
const outcome = String(classification.outcome ?? "").trim();
|
|
358
|
+
const mode = String(classification.mode ?? "").trim();
|
|
359
|
+
const trivialBoundary = String(classification.trivial_boundary ?? "").trim();
|
|
360
|
+
const urTriggerEvaluation = String(classification.ur_trigger_evaluation ?? "").trim();
|
|
361
|
+
const allowedSummary = String(classification.allowed_summary ?? "").trim();
|
|
362
|
+
const forbiddenSummary = String(classification.forbidden_summary ?? "").trim();
|
|
363
|
+
const escalationTriggers = Array.isArray(classification.escalation_triggers)
|
|
364
|
+
? classification.escalation_triggers.map((item) => String(item ?? "").trim()).filter(Boolean)
|
|
365
|
+
: [];
|
|
366
|
+
const challengePath = String(classification.challenge_path ?? "").trim();
|
|
367
|
+
|
|
368
|
+
if (outcome !== "ungated") return null;
|
|
369
|
+
if (!["quick_task", "verified_change"].includes(mode)) return null;
|
|
370
|
+
if (!["inside", "outside"].includes(trivialBoundary)) return null;
|
|
371
|
+
if (!urTriggerEvaluation || !allowedSummary || !forbiddenSummary || !challengePath) return null;
|
|
372
|
+
if (escalationTriggers.length === 0) return null;
|
|
373
|
+
|
|
374
|
+
let locale;
|
|
375
|
+
try {
|
|
376
|
+
locale = resolvePresentationLocale(registry, requestedLocale);
|
|
377
|
+
} catch {
|
|
378
|
+
return null;
|
|
379
|
+
}
|
|
380
|
+
if (!locale) return null;
|
|
381
|
+
|
|
382
|
+
const pack = localePack(registry, locale);
|
|
383
|
+
const labels = pack?.scopeClassification;
|
|
384
|
+
if (!plainObject(labels)) return null;
|
|
385
|
+
|
|
386
|
+
const modeLabel = labels.mode?.[mode] ?? mode;
|
|
387
|
+
const boundaryLabel = labels.boundary?.[trivialBoundary] ?? trivialBoundary;
|
|
388
|
+
|
|
389
|
+
const rows = [
|
|
390
|
+
[labels.classification, `${modeLabel} · ${boundaryLabel}`],
|
|
391
|
+
[labels.grounds, urTriggerEvaluation],
|
|
392
|
+
[labels.allowed, allowedSummary],
|
|
393
|
+
[labels.forbidden, forbiddenSummary],
|
|
394
|
+
[labels.escalation, escalationTriggers.join("; ")],
|
|
395
|
+
[labels.challenge, challengePath],
|
|
396
|
+
];
|
|
397
|
+
|
|
398
|
+
const markdown = [
|
|
399
|
+
`## ${labels.title ?? "AGDF scope classification"}`,
|
|
400
|
+
"",
|
|
401
|
+
`| ${labels.field ?? "Field"} | ${labels.value ?? "Value"} |`,
|
|
402
|
+
"|---|---|",
|
|
403
|
+
...rows.map(([label, value]) => `| ${markdownCell(label)} | ${markdownCell(value)} |`),
|
|
404
|
+
].join("\n");
|
|
405
|
+
|
|
406
|
+
return Object.freeze({
|
|
407
|
+
schema_version: "1",
|
|
408
|
+
semantic_block: "scope_classification_card",
|
|
409
|
+
presentation_language: locale,
|
|
410
|
+
markdown,
|
|
411
|
+
authorizes: false,
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
|
|
352
415
|
export function gateOptions(registry, requestedLocale, gate, { includeCancel = false } = {}) {
|
|
353
416
|
const pack = localePack(registry, requestedLocale);
|
|
354
417
|
const options = [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-agdf",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.4",
|
|
4
4
|
"description": "Bootstrap AGDF repository-local plugin files, Copilot/OpenCode instructions, skills, control files and machine-readable checks.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"test:delivery-path-search": "node ./scripts/delivery-path-search-test.js",
|
|
25
25
|
"test:delivery-path-search-unit": "node ./scripts/delivery-path-search-unit-test.js",
|
|
26
26
|
"test:delivery-path-search-generator": "node ./scripts/delivery-path-search-generator-test.js",
|
|
27
|
+
"test:opencode-hardening": "node ./scripts/opencode-hardening-test.js",
|
|
27
28
|
"test:cli-modularization": "node ./scripts/cli-modularization-test.js",
|
|
28
29
|
"test:local-validator": "node ./scripts/local-validator-test.js",
|
|
29
30
|
"test:local-marketplace": "node ./scripts/local-marketplace-test.js",
|
|
@@ -40,7 +41,7 @@
|
|
|
40
41
|
"eval:skills:record": "node ./scripts/record-skill-evals.js",
|
|
41
42
|
"test:release-bootstrap": "node ./scripts/release-bootstrap-smoke-test.js",
|
|
42
43
|
"test:routing": "npm run sync-package-assets && node ./scripts/test-routing.js",
|
|
43
|
-
"smoke-test": "npm run sync-package-assets && npm run test:cli-modularization && npm run test:local-validator && npm run test:local-marketplace && npm run test:package-build && npm run test:package-contents && npm run test:lifecycle && npm run test:control-state && npm run test:interaction-presentation && npm run test:verified-change && npm run test:runtime-integrity-layout && npm run test:runtime-integrity-negative && npm run test:skill-evals && npm run eval:skills && npm run test:delivery-path-search && npm run test:delivery-path-search-unit && npm run test:delivery-path-search-generator && node ./scripts/smoke-test.js && node ./scripts/test-routing.js",
|
|
44
|
+
"smoke-test": "npm run sync-package-assets && npm run test:cli-modularization && npm run test:local-validator && npm run test:local-marketplace && npm run test:package-build && npm run test:package-contents && npm run test:lifecycle && npm run test:control-state && npm run test:interaction-presentation && npm run test:verified-change && npm run test:runtime-integrity-layout && npm run test:runtime-integrity-negative && npm run test:skill-evals && npm run eval:skills && npm run test:delivery-path-search && npm run test:delivery-path-search-unit && npm run test:delivery-path-search-generator && npm run test:opencode-hardening && node ./scripts/smoke-test.js && node ./scripts/test-routing.js",
|
|
44
45
|
"prepack": "npm run sync-package-assets"
|
|
45
46
|
},
|
|
46
47
|
"keywords": [
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schema_version": "1",
|
|
3
3
|
"generated": true,
|
|
4
4
|
"source": "create-agdf/cli",
|
|
5
|
-
"version": "0.11.
|
|
5
|
+
"version": "0.11.4",
|
|
6
6
|
"entrypoint": "create-agdf/bin/agdf-validator.js",
|
|
7
|
-
"digest": "
|
|
7
|
+
"digest": "a3dcdf6d1b66e4789ab10339253e69b967d2d4f2421b52a1d50212e9a8553ec1"
|
|
8
8
|
}
|
|
@@ -400,6 +400,28 @@ for (const antiPattern of [
|
|
|
400
400
|
if (!runtimeContract.includes("### Repository Activation Diagnosis Boundary")) {
|
|
401
401
|
failures.push("control-scaffold contract must own the repository activation diagnosis boundary");
|
|
402
402
|
}
|
|
403
|
+
if (!runtimeContract.includes("### Scope Classification Card")) {
|
|
404
|
+
failures.push("interaction contract must own the scope classification card section");
|
|
405
|
+
}
|
|
406
|
+
if (!gateCheckSkill.includes("scope_classification.markdown` verbatim")) {
|
|
407
|
+
failures.push("gate-check must consume the canonical scope classification projection verbatim");
|
|
408
|
+
}
|
|
409
|
+
if (gateCheckSkill.includes("## Scope Classification Card Template") || gateCheckSkill.includes("| Classification | Mode | Boundary |")) {
|
|
410
|
+
failures.push("gate-check must not maintain a skill-local scope classification card template");
|
|
411
|
+
}
|
|
412
|
+
const interactionPresentationPath = join(pluginRoot, "..", "create-agdf", "lib", "interaction-presentation.js");
|
|
413
|
+
if (sourceMode && isFile(interactionPresentationPath)) {
|
|
414
|
+
const interactionPresentation = read(interactionPresentationPath);
|
|
415
|
+
if (!interactionPresentation.includes("export function renderScopeClassificationCard")) {
|
|
416
|
+
failures.push("interaction-presentation.js must export renderScopeClassificationCard");
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
for (const locale of ["en", "de"]) {
|
|
420
|
+
const pack = interactionLocales?.locales?.[locale];
|
|
421
|
+
if (!pack?.scopeClassification?.title || !pack?.scopeClassification?.mode?.quick_task || !pack?.scopeClassification?.challenge) {
|
|
422
|
+
failures.push(`Interaction locale ${locale} missing scopeClassification section keys`);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
403
425
|
if (!runtimeContract.includes("not an agent-facing diagnosis proof")) {
|
|
404
426
|
failures.push("control-scaffold contract must classify AGDF_* env vars as non-agent-facing diagnosis");
|
|
405
427
|
}
|
|
@@ -169,6 +169,15 @@ If a status is not explicit, do not assume it is satisfied.
|
|
|
169
169
|
11. When `.agdf/control/` is missing or incomplete, make the next allowed artefact action explicit. For a fresh request, that means draft the minimal UR in the response, then request `Approval: UR`. Do not write a full control scaffold unless durable control state was explicitly requested or is already the repository's live AGDF working state.
|
|
170
170
|
12. If branch, workspace and durable artefacts disagree, do not choose a scope silently; report the ambiguity and ask for the smallest clarifying gate action.
|
|
171
171
|
|
|
172
|
+
### Scope Classification Output
|
|
173
|
+
When this skill classifies a fresh scope as ungated (Quick Task or Trivial Change Boundary), consume
|
|
174
|
+
`scope_classification.markdown` verbatim from `renderScopeClassificationCard` in
|
|
175
|
+
`../../meta/contracts/interaction.md` § Scope Classification Card. The card is a compact, localized,
|
|
176
|
+
non-authorizing projection: mode, boundary, UR-trigger evaluation, one allowed line, one forbidden
|
|
177
|
+
line, escalation triggers and the challenge path. Do not maintain or render a skill-local
|
|
178
|
+
classification card template. If the renderer returns `null`, fail closed to the existing ceremony
|
|
179
|
+
and do not model-reconstruct Markdown.
|
|
180
|
+
|
|
172
181
|
## Output
|
|
173
182
|
Keep the result short and operational. For a status-only response, consume the Runtime Contract's
|
|
174
183
|
code-owned `status_presentation.markdown` verbatim. It is the compact localized operational Run
|
package/lib/cli/application.js
CHANGED
|
@@ -117,7 +117,8 @@ function createHandlers({ io, env, exec, prepare }) {
|
|
|
117
117
|
const report = runLifecyclePhase("verification", () => evaluateOpenCodeStatus(options.dir, configDir, result.transition));
|
|
118
118
|
const verificationHealthy = report.status === "configured"
|
|
119
119
|
&& report.package.version_status === "current"
|
|
120
|
-
&& report.global_native_surface.complete
|
|
120
|
+
&& report.global_native_surface.complete
|
|
121
|
+
&& report.experimental_hooks.aggregate === "declared_supported";
|
|
121
122
|
printLifecycleResult(createLifecycleResult({
|
|
122
123
|
operation: result.transition.status === "updated" ? "update" : "install",
|
|
123
124
|
result: verificationHealthy ? "success" : "partial",
|
|
@@ -130,10 +131,24 @@ function createHandlers({ io, env, exec, prepare }) {
|
|
|
130
131
|
status: report.package.version_status === "current" ? "verified" : "unknown",
|
|
131
132
|
transition: result.transition.status,
|
|
132
133
|
},
|
|
133
|
-
verification: {
|
|
134
|
+
verification: {
|
|
135
|
+
status: verificationHealthy ? "healthy" : "degraded",
|
|
136
|
+
evidence: [
|
|
137
|
+
report.global_config.path,
|
|
138
|
+
report.global_native_surface.path,
|
|
139
|
+
`opencode_host=${report.host.installed_version || "unknown"}`,
|
|
140
|
+
`plugin_sdk=${report.plugin_sdk.installed_version || "unknown"}`,
|
|
141
|
+
`experimental_hooks=${report.experimental_hooks.aggregate}`,
|
|
142
|
+
`host_sdk_version=${report.host_sdk_version.status};policy=${report.host_sdk_version.policy}`,
|
|
143
|
+
],
|
|
144
|
+
},
|
|
134
145
|
restart: { required: true, reason: "host_reload" },
|
|
135
146
|
next_action: globalInstallRestartAction(options.target),
|
|
136
147
|
}), { json: options.json, io });
|
|
148
|
+
if (!options.json) {
|
|
149
|
+
io.log(`OpenCode host / plugin SDK: ${report.host.installed_version || "unknown"} / ${report.plugin_sdk.installed_version || "unknown"} (${report.host_sdk_version.status}; ${report.host_sdk_version.policy})`);
|
|
150
|
+
io.log(`Experimental hook declarations: ${report.experimental_hooks.aggregate} (SDK declaration evidence; live invocation not observed)`);
|
|
151
|
+
}
|
|
137
152
|
return verificationHealthy ? 0 : 1;
|
|
138
153
|
} catch (error) {
|
|
139
154
|
printInstallFailure(options.target, error, options, io);
|
|
@@ -27,8 +27,8 @@ export const commandRegistry = Object.freeze([
|
|
|
27
27
|
command("gate-check", { local: [" --approval-envelope", " --json"], scaffold: [""], legacy: [" --json"] }),
|
|
28
28
|
command("delivery-map", { local: [" --json"], scaffold: [""] }),
|
|
29
29
|
command("delivery-path-search", {
|
|
30
|
-
local: [" --surface codex --json", " --surface claude --json"],
|
|
31
|
-
scaffold: [" --surface codex", " --surface claude"],
|
|
30
|
+
local: [" --surface codex --json", " --surface claude --json", " --surface opencode --json"],
|
|
31
|
+
scaffold: [" --surface codex", " --surface claude", " --surface opencode"],
|
|
32
32
|
}),
|
|
33
33
|
command("run-create", { local: [" --run <run_id>"] }),
|
|
34
34
|
command("run-migrate", { local: [" [--run <run_id>]"] }),
|