create-agdf 0.11.4 → 0.12.0
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 +1 -1
- package/generated/.agdf/control/templates/artefacts/BROWNFIELD_REVIEW.md +25 -0
- package/generated/.github/skills/agdf-brownfield-analysis/SKILL.md +26 -0
- package/generated/.github/skills/agdf-gate-check/SKILL.md +40 -18
- package/generated/.github/skills/agdf-interaction-locales.json +50 -0
- package/generated/.github/skills/agdf-runtime-contract.md +1 -0
- package/generated/.github/skills/contracts/gate-transition.md +7 -3
- package/generated/.github/skills/contracts/interaction.md +22 -0
- package/generated/.github/skills/contracts/modes.md +81 -0
- package/generated/.github/skills/contracts/task-target-resolution.md +102 -0
- package/generated/.opencode/AGDF.md +2 -0
- package/generated/.opencode/agdf-interaction-locales.json +50 -0
- package/generated/.opencode/agdf-runtime-contract.md +1 -0
- package/generated/.opencode/contracts/gate-transition.md +7 -3
- package/generated/.opencode/contracts/interaction.md +22 -0
- package/generated/.opencode/contracts/modes.md +81 -0
- package/generated/.opencode/contracts/task-target-resolution.md +102 -0
- package/generated/.opencode/skills/agdf-brownfield-analysis/SKILL.md +26 -0
- package/generated/.opencode/skills/agdf-gate-check/SKILL.md +40 -18
- package/generated/AGENTS.md +1 -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/artefacts/BROWNFIELD_REVIEW.md +25 -0
- package/generated/plugins/agdf/meta/agdf-agent-router.md +16 -0
- package/generated/plugins/agdf/meta/agdf-interaction-locales.json +50 -0
- package/generated/plugins/agdf/meta/agdf-plugin.definition.json +1 -1
- package/generated/plugins/agdf/meta/agdf-runtime-contract.md +1 -0
- package/generated/plugins/agdf/meta/contracts/gate-transition.md +7 -3
- package/generated/plugins/agdf/meta/contracts/interaction.md +22 -0
- package/generated/plugins/agdf/meta/contracts/modes.md +81 -0
- package/generated/plugins/agdf/meta/contracts/task-target-resolution.md +102 -0
- package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-interaction-locales.json +50 -0
- package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-plugin.definition.json +1 -1
- package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/gate-policy.js +14 -7
- package/generated/plugins/agdf/runtime/create-agdf/lib/interaction-presentation.js +85 -0
- package/generated/plugins/agdf/runtime/create-agdf/package.json +5 -2
- package/generated/plugins/agdf/runtime/runtime-manifest.json +2 -2
- package/generated/plugins/agdf/scripts/check-runtime-integrity.mjs +119 -3
- package/generated/plugins/agdf/skills/brownfield-analysis/SKILL.md +26 -0
- package/generated/plugins/agdf/skills/gate-check/SKILL.md +40 -18
- package/lib/cli/application.js +13 -2
- package/lib/control-evaluation/gate-policy.js +14 -7
- package/lib/installers/opencode.js +128 -1
- package/lib/interaction-presentation.js +85 -0
- package/lib/live-agent/read-only-structured.js +43 -0
- package/lib/proportionality-benchmark/blind-prompt.js +37 -0
- package/lib/proportionality-benchmark/contracts.js +120 -0
- package/lib/proportionality-benchmark/corpus-loader.js +110 -0
- package/lib/proportionality-benchmark/evaluator.js +250 -0
- package/lib/proportionality-benchmark/index.js +7 -0
- package/lib/proportionality-benchmark/live-recorder.js +100 -0
- package/lib/proportionality-benchmark/report.js +51 -0
- package/lib/proportionality-benchmark/source-fingerprint.js +30 -0
- package/lib/skill-evals/live-recorder.js +3 -26
- package/opencode-plugin.js +40 -1
- package/package.json +5 -2
|
@@ -22,6 +22,7 @@ The skill answers:
|
|
|
22
22
|
Use these focused runtime-contract modules:
|
|
23
23
|
|
|
24
24
|
- `../../meta/contracts/gate-transition.md`
|
|
25
|
+
- `../../meta/contracts/modes.md`
|
|
25
26
|
- `../../meta/contracts/context-graph.md`
|
|
26
27
|
- `../../meta/contracts/quality.md`
|
|
27
28
|
|
|
@@ -54,6 +55,19 @@ not applicable; Brownfield records cite repository evidence. Do not create a sec
|
|
|
54
55
|
11. Large UI surfaces and state hooks must be checked for mixed render, view-model, derived state, orchestration, persistence, and recovery ownership.
|
|
55
56
|
12. Context Graph impact must be curated; it is not a review log or version index.
|
|
56
57
|
13. Specification archive migrations must follow the archive index if present.
|
|
58
|
+
14. In `post_ur_review`, evaluate unchanged compact paths first. For a structured candidate, apply
|
|
59
|
+
only the `Structured Depth Decision` in `modes.md`; do not recreate its trigger/check matrix in
|
|
60
|
+
this skill.
|
|
61
|
+
15. A positive structured decision requires `depth_policy_version: 1`,
|
|
62
|
+
`depth_facts_status: complete`, complete evidence for all seven bounded-slice checks, a primary
|
|
63
|
+
reason code, rejected alternative and evidence references. A decisive full-depth trigger may
|
|
64
|
+
support `structured_delivery`; `structured_slice` requires every bounded-slice check to pass.
|
|
65
|
+
16. Missing or conflicting decisive facts without an already-evidenced full-depth trigger persist
|
|
66
|
+
the existing `block` decision with `depth_facts_missing | depth_facts_conflicting`, named facts,
|
|
67
|
+
their evidence owner where known, a Brownfield Review link and a precise next action for evidence
|
|
68
|
+
completion and Brownfield/Mode-Slice re-evaluation.
|
|
69
|
+
17. Owner, file, consumer, task or derived-path counts must never select a structured depth by
|
|
70
|
+
themselves.
|
|
57
71
|
|
|
58
72
|
## When To Use
|
|
59
73
|
- after `gate-check` permits `Brownfield Review` or the selected canonical run record names Brownfield Review as the next allowed action
|
|
@@ -107,6 +121,11 @@ When used as Brownfield Review after `Approval: UR`, do not recommend PRD, SD, T
|
|
|
107
121
|
9. Check UI monolith risk for large surfaces or central hooks.
|
|
108
122
|
10. Check Context Graph impact according to `../../meta/contracts/context-graph.md`.
|
|
109
123
|
11. Recommend the minimal clean implementation path.
|
|
124
|
+
12. In `post_ur_review`, record `depth_policy_version`, `depth_facts_status`,
|
|
125
|
+
`primary_reason_code`, `decisive_full_depth_triggers`, `rejected_alternative`,
|
|
126
|
+
`missing_or_conflicting_facts`, `depth_evidence_refs` and evidence for all seven bounded-slice
|
|
127
|
+
check IDs in the Brownfield Review. Then persist the completed review and the existing
|
|
128
|
+
Mode/Slice Decision atomically.
|
|
110
129
|
|
|
111
130
|
## Output
|
|
112
131
|
Use a concise structure:
|
|
@@ -133,6 +152,13 @@ For `post_ur_review`, include the four UI/UX routing fields immediately after `s
|
|
|
133
152
|
definition is required, its `ready | blocked | not_applicable` result must be visible before PRD
|
|
134
153
|
readiness. A required `blocked` result is at least `revise` for this routing step.
|
|
135
154
|
|
|
155
|
+
For a structured `post_ur_review` candidate, also include the complete `Structured Depth Evidence`
|
|
156
|
+
section from `BROWNFIELD_REVIEW.md`. The decision projection must show the primary reason, decisive
|
|
157
|
+
dimensions, bounded-slice result, rejected alternative, evidence and required next gate. For
|
|
158
|
+
missing/conflicting facts, show product-language `depth_unresolved` while persisting `block`; name
|
|
159
|
+
the gap and exact recovery action. Structural instruction checks can detect missing contract
|
|
160
|
+
elements but do not prove semantic model compliance or live-host behavior.
|
|
161
|
+
|
|
136
162
|
## Pass / Revise / Block Guidance
|
|
137
163
|
- `pass`: existing owners are understood, reuse path is clear, and no blocking drift or parallel structure risk remains.
|
|
138
164
|
- `revise`: relevant evidence, tests, ownership, or reuse path is incomplete.
|
|
@@ -20,6 +20,7 @@ This skill must not create later artefacts such as PRD, SD, TP, CD, CR, QA, or U
|
|
|
20
20
|
## Runtime Contract
|
|
21
21
|
Use these focused runtime-contract modules:
|
|
22
22
|
|
|
23
|
+
- `../../meta/contracts/task-target-resolution.md`
|
|
23
24
|
- `../../meta/contracts/gate-transition.md`
|
|
24
25
|
- `../../meta/contracts/interaction.md`
|
|
25
26
|
- `../../meta/contracts/control-scaffold.md`
|
|
@@ -75,6 +76,12 @@ The CLI reports are validators and JSON evidence, not the primary user experienc
|
|
|
75
76
|
|
|
76
77
|
Plugin `AGDF_*` environment variables set by the OpenCode `shell.env` hook are convenience only and must not be used as the only proof of activation; host shell-env propagation to spawned tool shells is not guaranteed and is OpenCode-owned, not AGDF-owned. A relative glob or `grep` for `.agdf/control/config.json` must not be used as proof of presence or absence of `.agdf/control/config.json`; an absolute `read` or the canonical CLI probe is required.
|
|
77
78
|
|
|
79
|
+
## OpenCode Subagent Enforcement Boundary
|
|
80
|
+
|
|
81
|
+
OpenCode plugin hooks (`tool.execute.before`) do not intercept tool calls from subagents spawned via the `task` tool (anomalyco/opencode issue #5894, PR #36238 open). AGDF enforcement through plugin hooks applies to primary-agent tool calls only; in the subagent path, AGDF governance is auditing-only, not enforcement.
|
|
82
|
+
|
|
83
|
+
This is a host limitation, not an AGDF-owned defect. Do not claim that AGDF gates are technically enforced in the OpenCode subagent path. Do not route work to a subagent to bypass a primary-agent gate. When subagent work touches gate-relevant files, verify the result through the canonical validator (`doctor --json`, `gate-check --json`) after the subagent returns, not during.
|
|
84
|
+
|
|
78
85
|
## Native Interaction Path
|
|
79
86
|
|
|
80
87
|
`../../meta/contracts/interaction.md` is the complete normative owner for interaction kinds, locale,
|
|
@@ -84,12 +91,15 @@ do not restate or infer a surface matrix in this skill.
|
|
|
84
91
|
|
|
85
92
|
This skill owns only these operational responsibilities:
|
|
86
93
|
|
|
87
|
-
1.
|
|
88
|
-
2.
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
94
|
+
1. Resolve or revalidate the primary task target before selecting repository control state.
|
|
95
|
+
2. Derive repository activation only from the resolved governance target; an evidence source or
|
|
96
|
+
working directory is not sufficient.
|
|
97
|
+
3. Select exactly one run and evaluate its current gate.
|
|
98
|
+
4. Confirm that the required durable artefact is present and ready.
|
|
99
|
+
5. Consume the canonical `approval_presentation` verbatim for the selected run, gate and revision.
|
|
100
|
+
6. Present that projection and obtain deliberate input through the contract-selected native or exact-text path.
|
|
101
|
+
7. Revalidate the same target, run, gate and revision immediately after the response and before persistence.
|
|
102
|
+
8. Persist only a currently valid exact approval through the existing control-state workflow.
|
|
93
103
|
|
|
94
104
|
For status, blocked, read-only or rationale interactions, consume the canonical
|
|
95
105
|
`status_presentation.markdown` verbatim and apply the locale contract without asking for approval.
|
|
@@ -156,18 +166,30 @@ Use what is available:
|
|
|
156
166
|
If a status is not explicit, do not assume it is satisfied.
|
|
157
167
|
|
|
158
168
|
## Workflow
|
|
159
|
-
1.
|
|
160
|
-
2.
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
169
|
+
1. Resolve or revalidate the primary target through `task-target-resolution.md`.
|
|
170
|
+
2. If resolution is unresolved, consume the canonical target orientation, request only its
|
|
171
|
+
clarification/recovery action and stop before repository activation, gate evaluation or mutation.
|
|
172
|
+
3. Derive the governance target from the primary target; never from `cwd` or an evidence source alone.
|
|
173
|
+
4. Check exact approvals.
|
|
174
|
+
5. Check artefact status.
|
|
175
|
+
6. Determine the earliest blocking user gate or internal mandatory step.
|
|
176
|
+
7. Derive allowed and forbidden outputs.
|
|
177
|
+
8. Name the exact missing approval, if any.
|
|
178
|
+
9. If consent was only implicit, say it is not yet approval and provide the exact formula.
|
|
179
|
+
10. Ensure the next step follows the gate transition table. In particular, never jump from `Approval: UR` to implementation.
|
|
180
|
+
11. Treat a generic "start", "continue" or "leg los" request as a request to perform only the current next allowed action.
|
|
181
|
+
12. After Brownfield Review, choose the smallest safe process path before creating later artefacts.
|
|
182
|
+
13. If the selected path is not visibly recorded with scope reason and evidence, keep the run at `Mode/Slice Decision`.
|
|
183
|
+
14. 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.
|
|
184
|
+
15. If branch, workspace and durable artefacts disagree, do not choose a scope silently; report the ambiguity and ask for the smallest clarifying gate action.
|
|
185
|
+
|
|
186
|
+
### Task Target Orientation
|
|
187
|
+
|
|
188
|
+
When target/context separation is material, the target changed, or resolution is unresolved, consume
|
|
189
|
+
`task_target_orientation.markdown` verbatim from `renderTaskTargetOrientation` in
|
|
190
|
+
`../../meta/contracts/interaction.md`. Do not reconstruct its fields or maintain a skill-local target
|
|
191
|
+
template. If the renderer returns `null`, fail closed to target clarification and do not proceed to
|
|
192
|
+
repository activation, Scope Classification or gate evaluation.
|
|
171
193
|
|
|
172
194
|
### Scope Classification Output
|
|
173
195
|
When this skill classifies a fresh scope as ungated (Quick Task or Trivial Change Boundary), consume
|
package/lib/cli/application.js
CHANGED
|
@@ -115,10 +115,19 @@ function createHandlers({ io, env, exec, prepare }) {
|
|
|
115
115
|
const result = runLifecyclePhase("plugin_operation", () => installOpenCodeGlobalPlugin(configDir));
|
|
116
116
|
runLifecyclePhase("global_surface", () => installOpenCodeGlobalSurface(configDir));
|
|
117
117
|
const report = runLifecyclePhase("verification", () => evaluateOpenCodeStatus(options.dir, configDir, result.transition));
|
|
118
|
+
const alignmentHealthy = ["already_matching", "aligned"].includes(result.sdk_alignment.status);
|
|
118
119
|
const verificationHealthy = report.status === "configured"
|
|
119
120
|
&& report.package.version_status === "current"
|
|
120
121
|
&& report.global_native_surface.complete
|
|
121
|
-
&& report.experimental_hooks.aggregate === "declared_supported"
|
|
122
|
+
&& report.experimental_hooks.aggregate === "declared_supported"
|
|
123
|
+
&& report.host_sdk_version.status === "matching"
|
|
124
|
+
&& alignmentHealthy;
|
|
125
|
+
const nextAction = verificationHealthy
|
|
126
|
+
? globalInstallRestartAction(options.target)
|
|
127
|
+
: {
|
|
128
|
+
kind: "recovery",
|
|
129
|
+
text: `Retry the OpenCode installation to align @opencode-ai/plugin to ${result.sdk_alignment.target_version || "the exact host version"}; observed SDK: ${result.sdk_alignment.installed_version || "unknown"}.`,
|
|
130
|
+
};
|
|
122
131
|
printLifecycleResult(createLifecycleResult({
|
|
123
132
|
operation: result.transition.status === "updated" ? "update" : "install",
|
|
124
133
|
result: verificationHealthy ? "success" : "partial",
|
|
@@ -140,13 +149,15 @@ function createHandlers({ io, env, exec, prepare }) {
|
|
|
140
149
|
`plugin_sdk=${report.plugin_sdk.installed_version || "unknown"}`,
|
|
141
150
|
`experimental_hooks=${report.experimental_hooks.aggregate}`,
|
|
142
151
|
`host_sdk_version=${report.host_sdk_version.status};policy=${report.host_sdk_version.policy}`,
|
|
152
|
+
`sdk_alignment=${result.sdk_alignment.status};target=${result.sdk_alignment.target_version || "unknown"};installed=${result.sdk_alignment.installed_version || "unknown"}`,
|
|
143
153
|
],
|
|
144
154
|
},
|
|
145
155
|
restart: { required: true, reason: "host_reload" },
|
|
146
|
-
next_action:
|
|
156
|
+
next_action: nextAction,
|
|
147
157
|
}), { json: options.json, io });
|
|
148
158
|
if (!options.json) {
|
|
149
159
|
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})`);
|
|
160
|
+
io.log(`Plugin SDK alignment: ${result.sdk_alignment.status} (target ${result.sdk_alignment.target_version || "unknown"}; installed ${result.sdk_alignment.installed_version || "unknown"})`);
|
|
150
161
|
io.log(`Experimental hook declarations: ${report.experimental_hooks.aggregate} (SDK declaration evidence; live invocation not observed)`);
|
|
151
162
|
}
|
|
152
163
|
return verificationHealthy ? 0 : 1;
|
|
@@ -29,8 +29,9 @@ export function isGateSatisfied(runState, gate) {
|
|
|
29
29
|
return isDurableGateArtefactSatisfied(runState, gate);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
function
|
|
33
|
-
|
|
32
|
+
function qaNonPassDecision(runState) {
|
|
33
|
+
const status = gateArtefactStatus(runState, "QA").status;
|
|
34
|
+
return status === "revise" || status === "block" ? status : null;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
export function transitionDecisionForRunState(runState, verifiedChange = null) {
|
|
@@ -233,15 +234,21 @@ export function transitionDecisionForRunState(runState, verifiedChange = null) {
|
|
|
233
234
|
};
|
|
234
235
|
}
|
|
235
236
|
|
|
236
|
-
|
|
237
|
+
const qaNonPass = qaNonPassDecision(runState);
|
|
238
|
+
if (qaNonPass) {
|
|
239
|
+
const blocked = qaNonPass === "block";
|
|
237
240
|
return {
|
|
238
|
-
status: "open",
|
|
241
|
+
status: blocked ? "blocked" : "open",
|
|
239
242
|
current_gate: "QA",
|
|
240
|
-
blocking_reason: "qa_revise_required",
|
|
243
|
+
blocking_reason: blocked ? "qa_blocked" : "qa_revise_required",
|
|
241
244
|
missing_approval: "none",
|
|
242
|
-
allowed:
|
|
245
|
+
allowed: blocked
|
|
246
|
+
? ["route the blocking QA findings to their authoritative owner", "record the next permitted remediation or upstream decision", "rerun QA only after the blocker is resolved"]
|
|
247
|
+
: ["revise the implementation against the QA findings", "refresh CD+Tests and mandatory reviews", "rerun QA with refreshed evidence"],
|
|
243
248
|
forbidden: ["request QA approval", "request UAT approval", "release", "claim delivery readiness"],
|
|
244
|
-
next_allowed_action:
|
|
249
|
+
next_allowed_action: blocked
|
|
250
|
+
? "Resolve or route the blocking QA findings through their authoritative owner, then rerun the required delivery steps. Do not request Approval: QA from a block report."
|
|
251
|
+
: "Resolve the QA revise findings, refresh CD+Tests and reviews, then rerun QA. Do not request Approval: QA from a revise report.",
|
|
245
252
|
};
|
|
246
253
|
}
|
|
247
254
|
|
|
@@ -116,11 +116,13 @@ export function installOpenCodeGlobalPlugin(configDir) {
|
|
|
116
116
|
throw openCodeLifecycleError("configuration", `Failed to write OpenCode config ${configPath}: ${error.message}`, { configPath });
|
|
117
117
|
}
|
|
118
118
|
const installedPackage = resolveOpenCodePackage(configDir);
|
|
119
|
+
const sdkAlignment = alignOpenCodePluginSdk(configDir);
|
|
119
120
|
|
|
120
121
|
return {
|
|
121
122
|
configPath,
|
|
122
123
|
added: !alreadyInstalled,
|
|
123
124
|
transition: openCodePackageTransition(previousPackage, installedPackage),
|
|
125
|
+
sdk_alignment: sdkAlignment,
|
|
124
126
|
};
|
|
125
127
|
}
|
|
126
128
|
|
|
@@ -519,6 +521,131 @@ export function evaluateOpenCodeHostSdk(configDir, dependencies = {}) {
|
|
|
519
521
|
};
|
|
520
522
|
}
|
|
521
523
|
|
|
524
|
+
const exactOpenCodeVersionPattern = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
|
|
525
|
+
|
|
526
|
+
function openCodeSdkAlignmentResult(status, initial, overrides = {}) {
|
|
527
|
+
return {
|
|
528
|
+
status,
|
|
529
|
+
attempted: false,
|
|
530
|
+
host_version: initial.host.installed_version || null,
|
|
531
|
+
previous_version: initial.plugin_sdk.installed_version || null,
|
|
532
|
+
target_version: null,
|
|
533
|
+
installed_version: initial.plugin_sdk.installed_version || null,
|
|
534
|
+
error: "",
|
|
535
|
+
...overrides,
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
function openCodeRegistryVersion(raw) {
|
|
540
|
+
const value = String(raw ?? "").trim();
|
|
541
|
+
if (!value) return "";
|
|
542
|
+
try {
|
|
543
|
+
const parsed = JSON.parse(value);
|
|
544
|
+
return typeof parsed === "string" ? parsed.trim() : "";
|
|
545
|
+
} catch {
|
|
546
|
+
return value;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
function openCodeSdkUnavailable(error) {
|
|
551
|
+
return /(?:ETARGET|E404|404 Not Found|No matching version)/i.test(
|
|
552
|
+
(error?.stderr || error?.message || "").toString(),
|
|
553
|
+
);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
export function alignOpenCodePluginSdk(configDir, dependencies = {}) {
|
|
557
|
+
const initial = evaluateOpenCodeHostSdk(configDir, dependencies);
|
|
558
|
+
const hostVersion = initial.host.installed_version || "";
|
|
559
|
+
const sdkVersion = initial.plugin_sdk.installed_version || "";
|
|
560
|
+
if (!initial.host.inspectable || !initial.plugin_sdk.loadable || !exactOpenCodeVersionPattern.test(hostVersion)) {
|
|
561
|
+
return openCodeSdkAlignmentResult("not_attempted", initial, {
|
|
562
|
+
target_version: exactOpenCodeVersionPattern.test(hostVersion) ? hostVersion : null,
|
|
563
|
+
error: !initial.host.inspectable
|
|
564
|
+
? initial.host.error || "OpenCode host version is not inspectable."
|
|
565
|
+
: !initial.plugin_sdk.loadable
|
|
566
|
+
? initial.plugin_sdk.error || "OpenCode plugin SDK is not inspectable."
|
|
567
|
+
: `OpenCode host version is not an exact semantic version: ${hostVersion || "unknown"}`,
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
if (sdkVersion === hostVersion) {
|
|
571
|
+
return openCodeSdkAlignmentResult("already_matching", initial, {
|
|
572
|
+
target_version: hostVersion,
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
const run = dependencies.execFileSync ?? execFileSync;
|
|
577
|
+
const packageSpecifier = `@opencode-ai/plugin@${hostVersion}`;
|
|
578
|
+
const registryInvocation = openCodeNpmInvocation(["view", packageSpecifier, "version", "--json"]);
|
|
579
|
+
try {
|
|
580
|
+
const availableVersion = openCodeRegistryVersion(run(registryInvocation.executable, registryInvocation.args, {
|
|
581
|
+
cwd: configDir,
|
|
582
|
+
encoding: "utf8",
|
|
583
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
584
|
+
timeout: 15000,
|
|
585
|
+
}));
|
|
586
|
+
if (availableVersion !== hostVersion) {
|
|
587
|
+
return openCodeSdkAlignmentResult("unavailable", initial, {
|
|
588
|
+
target_version: hostVersion,
|
|
589
|
+
error: `Exact plugin SDK version is unavailable: ${packageSpecifier}`,
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
} catch (error) {
|
|
593
|
+
return openCodeSdkAlignmentResult(openCodeSdkUnavailable(error) ? "unavailable" : "failed", initial, {
|
|
594
|
+
target_version: hostVersion,
|
|
595
|
+
error: (error.stderr || error.message || "plugin SDK registry lookup failed").toString().trim(),
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
const installInvocation = openCodeNpmInvocation([
|
|
600
|
+
"install",
|
|
601
|
+
"--silent",
|
|
602
|
+
"--ignore-scripts",
|
|
603
|
+
"--no-audit",
|
|
604
|
+
"--no-fund",
|
|
605
|
+
"--save-prod",
|
|
606
|
+
"--save-exact",
|
|
607
|
+
packageSpecifier,
|
|
608
|
+
]);
|
|
609
|
+
let installError = null;
|
|
610
|
+
try {
|
|
611
|
+
run(installInvocation.executable, installInvocation.args, {
|
|
612
|
+
cwd: configDir,
|
|
613
|
+
encoding: "utf8",
|
|
614
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
615
|
+
timeout: 60000,
|
|
616
|
+
});
|
|
617
|
+
} catch (error) {
|
|
618
|
+
installError = error;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
const observed = evaluateOpenCodeHostSdk(configDir, dependencies);
|
|
622
|
+
const verified = observed.plugin_sdk.installed_version === hostVersion
|
|
623
|
+
&& observed.experimental_hooks.aggregate === "declared_supported";
|
|
624
|
+
if (installError) {
|
|
625
|
+
return openCodeSdkAlignmentResult("failed", initial, {
|
|
626
|
+
attempted: true,
|
|
627
|
+
target_version: hostVersion,
|
|
628
|
+
installed_version: observed.plugin_sdk.installed_version || null,
|
|
629
|
+
error: (installError.stderr || installError.message || "plugin SDK installation failed").toString().trim(),
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
if (!verified) {
|
|
633
|
+
return openCodeSdkAlignmentResult("verification_failed", initial, {
|
|
634
|
+
attempted: true,
|
|
635
|
+
target_version: hostVersion,
|
|
636
|
+
installed_version: observed.plugin_sdk.installed_version || null,
|
|
637
|
+
error: observed.plugin_sdk.installed_version !== hostVersion
|
|
638
|
+
? `Observed plugin SDK ${observed.plugin_sdk.installed_version || "unknown"} after targeting ${hostVersion}.`
|
|
639
|
+
: `Plugin SDK ${hostVersion} does not declare all required experimental hooks.`,
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
return openCodeSdkAlignmentResult("aligned", initial, {
|
|
643
|
+
attempted: true,
|
|
644
|
+
target_version: hostVersion,
|
|
645
|
+
installed_version: observed.plugin_sdk.installed_version,
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
|
|
522
649
|
function openCodePackageVersionStatus(packageState) {
|
|
523
650
|
if (!packageState.loadable) return "unloadable";
|
|
524
651
|
if (!packageState.installed_version) return "unknown";
|
|
@@ -680,7 +807,7 @@ export function evaluateOpenCodeStatus(targetDir, configDir = defaultOpenCodeCon
|
|
|
680
807
|
: hostSdk.experimental_hooks.aggregate === "degraded"
|
|
681
808
|
? "Use static AGDF instructions and review OpenCode compatibility before relying on dynamic hook injection."
|
|
682
809
|
: hostSdk.host_sdk_version.status === "divergent"
|
|
683
|
-
? "
|
|
810
|
+
? "Run npx --yes @agdf/cli@latest opencode to align the plugin SDK to the exact OpenCode host version; status itself remains read-only."
|
|
684
811
|
: repositoryActivation.state === "invalid_control"
|
|
685
812
|
? "Repair .agdf/control/config.json so it contains valid artifact_language, chat_language and runtime_language values."
|
|
686
813
|
: repositoryActivation.active
|
|
@@ -349,6 +349,91 @@ export function renderOperationalStatusCard(statusCard, {
|
|
|
349
349
|
});
|
|
350
350
|
}
|
|
351
351
|
|
|
352
|
+
export function renderTaskTargetOrientation(resolution, {
|
|
353
|
+
registry,
|
|
354
|
+
requestedLocale,
|
|
355
|
+
} = {}) {
|
|
356
|
+
if (!plainObject(resolution)) return null;
|
|
357
|
+
|
|
358
|
+
const resolutionState = String(resolution.resolution_state ?? "").trim();
|
|
359
|
+
const reasonCode = String(resolution.reason_code ?? "").trim();
|
|
360
|
+
const primaryTarget = String(resolution.primary_target ?? "").trim();
|
|
361
|
+
const governanceTarget = String(resolution.governance_target ?? "").trim();
|
|
362
|
+
const workingDirectory = String(resolution.working_directory ?? "").trim();
|
|
363
|
+
const nextAction = String(resolution.next_action ?? "").trim();
|
|
364
|
+
if (typeof resolution.target_changed !== "boolean") return null;
|
|
365
|
+
const targetChanged = resolution.target_changed === true;
|
|
366
|
+
const evidenceSources = Array.isArray(resolution.evidence_sources)
|
|
367
|
+
? resolution.evidence_sources.map((item) => String(item ?? "").trim()).filter(Boolean)
|
|
368
|
+
: null;
|
|
369
|
+
|
|
370
|
+
const resolvedReasons = new Set(["explicit_target", "continued_target"]);
|
|
371
|
+
const unresolvedReasons = new Set([
|
|
372
|
+
"multiple_plausible_targets",
|
|
373
|
+
"target_content_mismatch",
|
|
374
|
+
"target_unavailable",
|
|
375
|
+
"no_reliable_target",
|
|
376
|
+
]);
|
|
377
|
+
|
|
378
|
+
if (!["resolved", "unresolved"].includes(resolutionState)) return null;
|
|
379
|
+
if (!workingDirectory || evidenceSources === null) return null;
|
|
380
|
+
if (resolutionState === "resolved") {
|
|
381
|
+
if (!resolvedReasons.has(reasonCode) || !primaryTarget || nextAction) return null;
|
|
382
|
+
} else if (!unresolvedReasons.has(reasonCode) || primaryTarget || governanceTarget || !nextAction || targetChanged) {
|
|
383
|
+
return null;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
let locale;
|
|
387
|
+
try {
|
|
388
|
+
locale = resolvePresentationLocale(registry, requestedLocale);
|
|
389
|
+
} catch {
|
|
390
|
+
return null;
|
|
391
|
+
}
|
|
392
|
+
if (!locale) return null;
|
|
393
|
+
|
|
394
|
+
const pack = localePack(registry, locale);
|
|
395
|
+
const labels = pack?.taskTargetResolution;
|
|
396
|
+
if (!plainObject(labels) || !plainObject(labels.reasonCodes)) return null;
|
|
397
|
+
const reason = labels.reasonCodes[reasonCode];
|
|
398
|
+
if (!reason) return null;
|
|
399
|
+
|
|
400
|
+
const rows = resolutionState === "resolved"
|
|
401
|
+
? [
|
|
402
|
+
[labels.state, labels.resolved],
|
|
403
|
+
[labels.primaryTarget, primaryTarget],
|
|
404
|
+
[labels.governanceTarget, governanceTarget || labels.none],
|
|
405
|
+
[labels.evidenceSources, evidenceSources.join("; ") || labels.none],
|
|
406
|
+
[labels.workingDirectory, workingDirectory],
|
|
407
|
+
[labels.reason, reason],
|
|
408
|
+
...(targetChanged ? [[labels.targetChanged, labels.yes]] : []),
|
|
409
|
+
]
|
|
410
|
+
: [
|
|
411
|
+
[labels.state, labels.unresolved],
|
|
412
|
+
[labels.reason, reason],
|
|
413
|
+
[labels.evidenceSources, evidenceSources.join("; ") || labels.none],
|
|
414
|
+
[labels.workingDirectory, workingDirectory],
|
|
415
|
+
[labels.nextAction, nextAction],
|
|
416
|
+
];
|
|
417
|
+
|
|
418
|
+
const markdown = [
|
|
419
|
+
`## ${labels.title}`,
|
|
420
|
+
"",
|
|
421
|
+
`| ${labels.field} | ${labels.value} |`,
|
|
422
|
+
"|---|---|",
|
|
423
|
+
...rows.map(([label, value]) => `| ${markdownCell(label)} | ${markdownCell(value)} |`),
|
|
424
|
+
].join("\n");
|
|
425
|
+
|
|
426
|
+
return Object.freeze({
|
|
427
|
+
schema_version: "1",
|
|
428
|
+
semantic_block: "task_target_orientation",
|
|
429
|
+
presentation_language: locale,
|
|
430
|
+
resolution_state: resolutionState,
|
|
431
|
+
reason_code: reasonCode,
|
|
432
|
+
markdown,
|
|
433
|
+
authorizes: false,
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
|
|
352
437
|
export function renderScopeClassificationCard(classification, {
|
|
353
438
|
registry,
|
|
354
439
|
requestedLocale,
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { guardedExecFileSync } from "../delivery-path-search/transports/read-only-guard.js";
|
|
5
|
+
|
|
6
|
+
export function executeStructuredAgent({ surface, cwd, prompt, model, outputSchema, timeoutMs = 120000 }) {
|
|
7
|
+
if (surface === "codex") {
|
|
8
|
+
const temp = mkdtempSync(join(tmpdir(), "agdf-live-codex-"));
|
|
9
|
+
try {
|
|
10
|
+
const schemaPath = join(temp, "schema.json");
|
|
11
|
+
const outputPath = join(temp, "output.json");
|
|
12
|
+
writeFileSync(schemaPath, `${JSON.stringify(outputSchema, null, 2)}\n`, "utf8");
|
|
13
|
+
const args = [
|
|
14
|
+
"exec", "--sandbox", "read-only", "--ephemeral", "--ignore-user-config",
|
|
15
|
+
"--skip-git-repo-check", "--output-schema", schemaPath,
|
|
16
|
+
"--output-last-message", outputPath, "--color", "never",
|
|
17
|
+
];
|
|
18
|
+
if (model) args.push("--model", model);
|
|
19
|
+
args.push(prompt);
|
|
20
|
+
guardedExecFileSync("codex", args, {
|
|
21
|
+
cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: timeoutMs,
|
|
22
|
+
});
|
|
23
|
+
return readFileSync(outputPath, "utf8");
|
|
24
|
+
} finally {
|
|
25
|
+
rmSync(temp, { recursive: true, force: true });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (surface === "claude") {
|
|
29
|
+
const args = [
|
|
30
|
+
"-p", "--disallowedTools", "Edit,Write,Bash", "--output-format", "json",
|
|
31
|
+
"--json-schema", JSON.stringify(outputSchema),
|
|
32
|
+
];
|
|
33
|
+
if (model) args.push("--model", model);
|
|
34
|
+
args.push(prompt);
|
|
35
|
+
const raw = guardedExecFileSync("claude", args, {
|
|
36
|
+
cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: timeoutMs,
|
|
37
|
+
});
|
|
38
|
+
const envelope = JSON.parse(raw);
|
|
39
|
+
if (envelope.is_error) throw new Error(`claude live adapter failed: ${envelope.result ?? "unknown error"}`);
|
|
40
|
+
return envelope.result;
|
|
41
|
+
}
|
|
42
|
+
throw new Error(`unsupported live surface: ${surface}`);
|
|
43
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { DELIVERY_PATHS } from "./contracts.js";
|
|
2
|
+
|
|
3
|
+
export function buildBlindPrompt(testCase, behaviorSources) {
|
|
4
|
+
if (testCase.profile_id === "staged-v2") {
|
|
5
|
+
return [
|
|
6
|
+
"Perform a read-only, non-authorizing AGDF benchmark classification. Do not modify files, invoke tools, persist control state, or claim a real approval.",
|
|
7
|
+
"Synthetic fixture state is measurement input only. Return only JSON matching the supplied schema.",
|
|
8
|
+
`Allowed stages: ${testCase.allowed_stages.join(", ")}.`,
|
|
9
|
+
`Allowed paths: ${DELIVERY_PATHS.join(", ")}.`,
|
|
10
|
+
`Requested axes: ${testCase.requested_axes.join(", ")}. Every requested axis must use evaluated with one non-null allowed value. Non-requested axes must be null with not_evaluable_yet.`,
|
|
11
|
+
"eventual_delivery_path is a benchmark candidate, never an operative Mode/Slice Decision.",
|
|
12
|
+
"compact_delivery requires visible approved UR, completed Brownfield analysis, and stored quick_task context in decision_grounds.",
|
|
13
|
+
`Scenario ID: ${testCase.scenario_id}`,
|
|
14
|
+
`Case ID: ${testCase.case_id}`,
|
|
15
|
+
`Lifecycle stage: ${testCase.lifecycle_stage}`,
|
|
16
|
+
`Task: ${testCase.task_summary}`,
|
|
17
|
+
`Repository context: ${testCase.repository_context}`,
|
|
18
|
+
`Control-state context: ${testCase.control_state_context}`,
|
|
19
|
+
`Evidence pack: ${JSON.stringify(testCase.evidence_pack ?? {})}`,
|
|
20
|
+
"Current canonical routing sources follow:",
|
|
21
|
+
behaviorSources,
|
|
22
|
+
].join("\n\n");
|
|
23
|
+
}
|
|
24
|
+
return [
|
|
25
|
+
"Classify the delivery path AGDF would select for this task. Do not modify files or invoke tools.",
|
|
26
|
+
"Return only JSON matching the supplied schema. Do not reveal hidden reasoning.",
|
|
27
|
+
`Allowed paths: ${DELIVERY_PATHS.join(", ")}.`,
|
|
28
|
+
"Use null plus ambiguous=true when the evidence does not support one path.",
|
|
29
|
+
"compact_delivery requires decision_grounds that visibly reference approved UR, completed Brownfield analysis, and stored quick_task context.",
|
|
30
|
+
`Case ID: ${testCase.case_id}`,
|
|
31
|
+
`Task: ${testCase.task_summary}`,
|
|
32
|
+
`Repository context: ${testCase.repository_context}`,
|
|
33
|
+
`Control-state context: ${testCase.control_state_context}`,
|
|
34
|
+
"Current canonical routing sources follow:",
|
|
35
|
+
behaviorSources,
|
|
36
|
+
].join("\n\n");
|
|
37
|
+
}
|