create-agdf 0.8.1 → 0.8.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/bin/create-agdf.js +35 -0
- package/generated/.github/skills/agdf-gate-check/SKILL.md +7 -0
- package/generated/.github/skills/agdf-runtime-contract.md +9 -0
- package/generated/.opencode/agdf-runtime-contract.md +9 -0
- package/generated/.opencode/skills/agdf-gate-check/SKILL.md +7 -0
- package/generated/plugins/agdf/.codex-plugin/plugin.json +1 -1
- package/generated/plugins/agdf/meta/agdf-plugin.definition.json +10 -1
- package/generated/plugins/agdf/meta/agdf-runtime-contract.md +9 -0
- package/generated/plugins/agdf/skills/gate-check/SKILL.md +7 -0
- package/lib/interaction-presentation.js +41 -0
- package/package.json +1 -1
package/bin/create-agdf.js
CHANGED
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
} from "../lib/control-state/index.js";
|
|
28
28
|
import {
|
|
29
29
|
buildArtefactRefs,
|
|
30
|
+
buildRunCandidates,
|
|
30
31
|
canonicalizeLanguageTag,
|
|
31
32
|
formatArtefactRefs,
|
|
32
33
|
gateTitle,
|
|
@@ -1916,6 +1917,7 @@ function readRunState(targetDir, selection = {}) {
|
|
|
1916
1917
|
let runPath = join(".agdf", "control", "AGDF_RUN.md");
|
|
1917
1918
|
const canonicalRoot = join(targetDir, ".agdf", "control", "runs");
|
|
1918
1919
|
let resolutionError;
|
|
1920
|
+
let candidateRuns = [];
|
|
1919
1921
|
if (existsSync(canonicalRoot)) {
|
|
1920
1922
|
try {
|
|
1921
1923
|
const selected = resolveRuns(targetDir, {
|
|
@@ -1927,6 +1929,21 @@ function readRunState(targetDir, selection = {}) {
|
|
|
1927
1929
|
: selected.run.path;
|
|
1928
1930
|
} catch (error) {
|
|
1929
1931
|
resolutionError = error.message;
|
|
1932
|
+
if (resolutionError.startsWith("AGDF_ACTIVE_RUN_AMBIGUOUS")) {
|
|
1933
|
+
const active = resolveRuns(targetDir, { allActive: true }).runs.map((run) => {
|
|
1934
|
+
const controlState = parseControlState(run.content, {
|
|
1935
|
+
userGates: userGateOrder,
|
|
1936
|
+
internalSteps: [...internalStepArtefacts],
|
|
1937
|
+
});
|
|
1938
|
+
return {
|
|
1939
|
+
...run,
|
|
1940
|
+
control_state: controlState,
|
|
1941
|
+
current_artefact_heading: readArtefactHeading(targetDir, controlState.artefacts.get(controlState.current_gate)),
|
|
1942
|
+
ur_heading: readArtefactHeading(targetDir, controlState.artefacts.get("UR")),
|
|
1943
|
+
};
|
|
1944
|
+
});
|
|
1945
|
+
candidateRuns = buildRunCandidates(active);
|
|
1946
|
+
}
|
|
1930
1947
|
}
|
|
1931
1948
|
}
|
|
1932
1949
|
if (resolutionError || !existsSync(join(targetDir, runPath))) {
|
|
@@ -1946,6 +1963,7 @@ function readRunState(targetDir, selection = {}) {
|
|
|
1946
1963
|
quality_outlook: "",
|
|
1947
1964
|
source_scope: {},
|
|
1948
1965
|
memory: {},
|
|
1966
|
+
candidate_runs: candidateRuns,
|
|
1949
1967
|
resolution_error: resolutionError,
|
|
1950
1968
|
};
|
|
1951
1969
|
}
|
|
@@ -2333,6 +2351,10 @@ function isGateSatisfied(runState, gate) {
|
|
|
2333
2351
|
return isDurableGateArtefactSatisfied(runState, gate);
|
|
2334
2352
|
}
|
|
2335
2353
|
|
|
2354
|
+
function qaRevisionRequired(runState) {
|
|
2355
|
+
return gateArtefactStatus(runState, "QA").status === "revise";
|
|
2356
|
+
}
|
|
2357
|
+
|
|
2336
2358
|
function transitionDecisionForRunState(runState, verifiedChange = null) {
|
|
2337
2359
|
if (gateApprovalStatus(runState, "UR") === "approved" && !isGateSatisfied(runState, "UR")) return durableArtefactBlock("UR", "PRD");
|
|
2338
2360
|
|
|
@@ -2533,6 +2555,18 @@ function transitionDecisionForRunState(runState, verifiedChange = null) {
|
|
|
2533
2555
|
};
|
|
2534
2556
|
}
|
|
2535
2557
|
|
|
2558
|
+
if (qaRevisionRequired(runState)) {
|
|
2559
|
+
return {
|
|
2560
|
+
status: "open",
|
|
2561
|
+
current_gate: "QA",
|
|
2562
|
+
blocking_reason: "qa_revise_required",
|
|
2563
|
+
missing_approval: "none",
|
|
2564
|
+
allowed: ["revise the implementation against the QA findings", "refresh CD+Tests and mandatory reviews", "rerun QA with refreshed evidence"],
|
|
2565
|
+
forbidden: ["request QA approval", "request UAT approval", "release", "claim delivery readiness"],
|
|
2566
|
+
next_allowed_action: "Resolve the QA revise findings, refresh CD+Tests and reviews, then rerun QA. Do not request Approval: QA from a revise report.",
|
|
2567
|
+
};
|
|
2568
|
+
}
|
|
2569
|
+
|
|
2536
2570
|
if (gateApprovalStatus(runState, "QA") === "approved" && !isGateSatisfied(runState, "QA")) return durableArtefactBlock("QA", "UAT");
|
|
2537
2571
|
|
|
2538
2572
|
if (isGateSatisfied(runState, "QA") && !isGateSatisfied(runState, "UAT")) {
|
|
@@ -2658,6 +2692,7 @@ function evaluateGateCheck(targetDir, selection = {}) {
|
|
|
2658
2692
|
doctor_summary: doctorReport.summary,
|
|
2659
2693
|
evidence_refs: runState.evidence_refs,
|
|
2660
2694
|
quality_outlook: deriveQualityOutlook(runState, deliveryMap.findings),
|
|
2695
|
+
candidate_runs: runState.candidate_runs ?? [],
|
|
2661
2696
|
status_card: statusCard,
|
|
2662
2697
|
delivery_map: {
|
|
2663
2698
|
relationships: deliveryMap.relationships,
|
|
@@ -84,6 +84,13 @@ apply or safely return the native question on that attempt, switch immediately
|
|
|
84
84
|
to the exact textual approval. Do not ask the user to request the buttons again
|
|
85
85
|
and do not create a retry loop or simulated control.
|
|
86
86
|
|
|
87
|
+
State the outcome visibly: `presented`, `unavailable_before_invocation`,
|
|
88
|
+
`attempted_not_applied` or `unsafe_to_wait`. For every fallback, say in the
|
|
89
|
+
configured locale why a native control was not usable, show the exact approval
|
|
90
|
+
value and confirm that authority is unchanged. This transient outcome is not
|
|
91
|
+
approval evidence. A new explicit user request may reopen the unchanged decision
|
|
92
|
+
only after fresh run/gate/artefact revalidation; never retry automatically.
|
|
93
|
+
|
|
87
94
|
Surface behavior:
|
|
88
95
|
|
|
89
96
|
- Codex: invoke the native short-question/request-user-input control on the first eligible attempt when callable, ask one gate question and omit auto-resolution; if it is not rendered or applied, use exact text immediately.
|
|
@@ -382,6 +382,15 @@ host control is presented, or the agent immediately uses the exact-text
|
|
|
382
382
|
fallback. A host that does not apply the control does not trigger a second
|
|
383
383
|
native prompt. AGDF must not simulate or force host-owned presentation.
|
|
384
384
|
|
|
385
|
+
An eligible interaction must make its presentation outcome visible and
|
|
386
|
+
distinguishable: `presented`, `unavailable_before_invocation`,
|
|
387
|
+
`attempted_not_applied`, or `unsafe_to_wait`. This is transient presentation
|
|
388
|
+
evidence only, never a persisted approval, selected-run authority or substitute
|
|
389
|
+
for post-response revalidation. A textual fallback names the outcome, gives the
|
|
390
|
+
exact approval value and confirms that authority is unchanged. A fresh explicit
|
|
391
|
+
user request may reopen the unchanged decision after revalidation; it is not an
|
|
392
|
+
automatic retry.
|
|
393
|
+
|
|
385
394
|
A free-form native response is valid only when the existing exact-approval validator accepts it for the current gate after revalidation. A localized label, description, option position, recommendation style or host action never authorizes a gate. Revise, decline and cancel outcomes never advance a gate.
|
|
386
395
|
|
|
387
396
|
Surface adapter rules:
|
|
@@ -382,6 +382,15 @@ host control is presented, or the agent immediately uses the exact-text
|
|
|
382
382
|
fallback. A host that does not apply the control does not trigger a second
|
|
383
383
|
native prompt. AGDF must not simulate or force host-owned presentation.
|
|
384
384
|
|
|
385
|
+
An eligible interaction must make its presentation outcome visible and
|
|
386
|
+
distinguishable: `presented`, `unavailable_before_invocation`,
|
|
387
|
+
`attempted_not_applied`, or `unsafe_to_wait`. This is transient presentation
|
|
388
|
+
evidence only, never a persisted approval, selected-run authority or substitute
|
|
389
|
+
for post-response revalidation. A textual fallback names the outcome, gives the
|
|
390
|
+
exact approval value and confirms that authority is unchanged. A fresh explicit
|
|
391
|
+
user request may reopen the unchanged decision after revalidation; it is not an
|
|
392
|
+
automatic retry.
|
|
393
|
+
|
|
385
394
|
A free-form native response is valid only when the existing exact-approval validator accepts it for the current gate after revalidation. A localized label, description, option position, recommendation style or host action never authorizes a gate. Revise, decline and cancel outcomes never advance a gate.
|
|
386
395
|
|
|
387
396
|
Surface adapter rules:
|
|
@@ -84,6 +84,13 @@ apply or safely return the native question on that attempt, switch immediately
|
|
|
84
84
|
to the exact textual approval. Do not ask the user to request the buttons again
|
|
85
85
|
and do not create a retry loop or simulated control.
|
|
86
86
|
|
|
87
|
+
State the outcome visibly: `presented`, `unavailable_before_invocation`,
|
|
88
|
+
`attempted_not_applied` or `unsafe_to_wait`. For every fallback, say in the
|
|
89
|
+
configured locale why a native control was not usable, show the exact approval
|
|
90
|
+
value and confirm that authority is unchanged. This transient outcome is not
|
|
91
|
+
approval evidence. A new explicit user request may reopen the unchanged decision
|
|
92
|
+
only after fresh run/gate/artefact revalidation; never retry automatically.
|
|
93
|
+
|
|
87
94
|
Surface behavior:
|
|
88
95
|
|
|
89
96
|
- Codex: invoke the native short-question/request-user-input control on the first eligible attempt when callable, ask one gate question and omit auto-resolution; if it is not rendered or applied, use exact text immediately.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"id": "agdf",
|
|
4
|
-
"version": "0.8.
|
|
4
|
+
"version": "0.8.2",
|
|
5
5
|
"displayName": "AI Governance & Delivery Framework",
|
|
6
6
|
"developerName": "Arndt Gold",
|
|
7
7
|
"description": "Codex-first operating system for governed AI-assisted delivery.",
|
|
@@ -140,46 +140,55 @@
|
|
|
140
140
|
"skillSet": [
|
|
141
141
|
{
|
|
142
142
|
"slug": "delivery-path-search",
|
|
143
|
+
"discovery": "optional",
|
|
143
144
|
"useFor": "high-impact planning decisions with several plausible next delivery steps before implementation",
|
|
144
145
|
"boundary": "read-only advisory search; never grants gate permission or replaces gate-check"
|
|
145
146
|
},
|
|
146
147
|
{
|
|
147
148
|
"slug": "brownfield-analysis",
|
|
149
|
+
"discovery": "automatic",
|
|
148
150
|
"useFor": "after gate-check permits Brownfield Review or implementation preparation, before non-trivial changes in existing systems",
|
|
149
151
|
"boundary": "clarifies reuse, owners, risks and Mode/Slice Decision; never bypasses gate-check; Brownfield Review is not implementation permission"
|
|
150
152
|
},
|
|
151
153
|
{
|
|
152
154
|
"slug": "clean-implementation-review",
|
|
155
|
+
"discovery": "automatic",
|
|
153
156
|
"useFor": "inspect workarounds, fallbacks, parallel structures or symptom fixes",
|
|
154
157
|
"boundary": "not a TP or QA substitute"
|
|
155
158
|
},
|
|
156
159
|
{
|
|
157
160
|
"slug": "code-review",
|
|
161
|
+
"discovery": "automatic",
|
|
158
162
|
"useFor": "mandatory CR step after code changes, focused on defects, regression and security findings",
|
|
159
163
|
"boundary": "does not replace TP review, clean review or QA"
|
|
160
164
|
},
|
|
161
165
|
{
|
|
162
166
|
"slug": "delivery-closeout",
|
|
167
|
+
"discovery": "automatic",
|
|
163
168
|
"useFor": "commit/PR-near handoff after QA/OR/UAT",
|
|
164
169
|
"boundary": "never performs VCS actions automatically"
|
|
165
170
|
},
|
|
166
171
|
{
|
|
167
172
|
"slug": "gate-check",
|
|
173
|
+
"discovery": "start_here",
|
|
168
174
|
"useFor": "new build/change intent, unclear approval, Structured Delivery, later-gate artefact requested",
|
|
169
175
|
"boundary": "does not create later artefacts or skip Mode/Slice Decision after Brownfield Review"
|
|
170
176
|
},
|
|
171
177
|
{
|
|
172
178
|
"slug": "qa-gate",
|
|
179
|
+
"discovery": "automatic",
|
|
173
180
|
"useFor": "final QA decision",
|
|
174
181
|
"boundary": "only instance for `pass | revise | block`"
|
|
175
182
|
},
|
|
176
183
|
{
|
|
177
184
|
"slug": "release-or",
|
|
185
|
+
"discovery": "automatic",
|
|
178
186
|
"useFor": "auditable closeout for every relevant run",
|
|
179
187
|
"boundary": "not a QA substitute"
|
|
180
188
|
},
|
|
181
189
|
{
|
|
182
190
|
"slug": "task-plan-review",
|
|
191
|
+
"discovery": "automatic",
|
|
183
192
|
"useFor": "after implementation and before QA, verify TP coverage",
|
|
184
193
|
"boundary": "no final QA decision"
|
|
185
194
|
}
|
|
@@ -382,6 +382,15 @@ host control is presented, or the agent immediately uses the exact-text
|
|
|
382
382
|
fallback. A host that does not apply the control does not trigger a second
|
|
383
383
|
native prompt. AGDF must not simulate or force host-owned presentation.
|
|
384
384
|
|
|
385
|
+
An eligible interaction must make its presentation outcome visible and
|
|
386
|
+
distinguishable: `presented`, `unavailable_before_invocation`,
|
|
387
|
+
`attempted_not_applied`, or `unsafe_to_wait`. This is transient presentation
|
|
388
|
+
evidence only, never a persisted approval, selected-run authority or substitute
|
|
389
|
+
for post-response revalidation. A textual fallback names the outcome, gives the
|
|
390
|
+
exact approval value and confirms that authority is unchanged. A fresh explicit
|
|
391
|
+
user request may reopen the unchanged decision after revalidation; it is not an
|
|
392
|
+
automatic retry.
|
|
393
|
+
|
|
385
394
|
A free-form native response is valid only when the existing exact-approval validator accepts it for the current gate after revalidation. A localized label, description, option position, recommendation style or host action never authorizes a gate. Revise, decline and cancel outcomes never advance a gate.
|
|
386
395
|
|
|
387
396
|
Surface adapter rules:
|
|
@@ -84,6 +84,13 @@ apply or safely return the native question on that attempt, switch immediately
|
|
|
84
84
|
to the exact textual approval. Do not ask the user to request the buttons again
|
|
85
85
|
and do not create a retry loop or simulated control.
|
|
86
86
|
|
|
87
|
+
State the outcome visibly: `presented`, `unavailable_before_invocation`,
|
|
88
|
+
`attempted_not_applied` or `unsafe_to_wait`. For every fallback, say in the
|
|
89
|
+
configured locale why a native control was not usable, show the exact approval
|
|
90
|
+
value and confirm that authority is unchanged. This transient outcome is not
|
|
91
|
+
approval evidence. A new explicit user request may reopen the unchanged decision
|
|
92
|
+
only after fresh run/gate/artefact revalidation; never retry automatically.
|
|
93
|
+
|
|
87
94
|
Surface behavior:
|
|
88
95
|
|
|
89
96
|
- Codex: invoke the native short-question/request-user-input control on the first eligible attempt when callable, ask one gate question and omit auto-resolution; if it is not rendered or applied, use exact text immediately.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const REQUIRED_GATES = ["UR", "PRD", "SD", "TP", "QA", "UAT"];
|
|
2
2
|
const ARTEFACT_ORDER = ["UR", "PRD", "SD", "TP"];
|
|
3
3
|
const OUTCOMES = new Set(["approve", "revise", "decline", "cancel", "no_response", "timeout", "empty", "invalid", "stale"]);
|
|
4
|
+
const ATTEMPT_OUTCOMES = new Set(["presented", "unavailable_before_invocation", "attempted_not_applied", "unsafe_to_wait"]);
|
|
4
5
|
|
|
5
6
|
function plainObject(value) {
|
|
6
7
|
return value && typeof value === "object" && !Array.isArray(value);
|
|
@@ -111,6 +112,45 @@ export function resolveHumanRunTitle({ currentArtefactHeading, urHeading, runCon
|
|
|
111
112
|
return [currentArtefactHeading, urHeading, objective].map(stripMarkdown).find(Boolean) || normalizedRunTitle(runId);
|
|
112
113
|
}
|
|
113
114
|
|
|
115
|
+
function displaySafeTitle(value, fallback) {
|
|
116
|
+
const title = stripMarkdown(value).replace(/[\r\n]+/g, " ").replace(/\s+/g, " ").trim();
|
|
117
|
+
return (title || fallback).slice(0, 100);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function buildRunCandidates(runs) {
|
|
121
|
+
return [...(runs ?? [])]
|
|
122
|
+
.filter((run) => run?.valid && run?.meta?.lifecycle === "active" && typeof run.run_id === "string")
|
|
123
|
+
.map((run) => {
|
|
124
|
+
const currentGate = run.control_state?.current_gate || run.meta?.current_gate || "unknown";
|
|
125
|
+
const title = resolveHumanRunTitle({
|
|
126
|
+
currentArtefactHeading: run.current_artefact_heading,
|
|
127
|
+
urHeading: run.ur_heading,
|
|
128
|
+
runContent: "",
|
|
129
|
+
runId: run.run_id,
|
|
130
|
+
});
|
|
131
|
+
return {
|
|
132
|
+
run_id: run.run_id,
|
|
133
|
+
display_title: displaySafeTitle(title, normalizedRunTitle(run.run_id)),
|
|
134
|
+
current_gate: currentGate,
|
|
135
|
+
next_allowed_action: String(run.control_state?.next_allowed_action ?? "").trim(),
|
|
136
|
+
revision_id: String(run.meta?.revision_id ?? "").trim(),
|
|
137
|
+
};
|
|
138
|
+
})
|
|
139
|
+
.sort((left, right) => left.display_title.localeCompare(right.display_title) || left.run_id.localeCompare(right.run_id));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function buildInteractionAttempt({ interactionId, runId, currentGate, surface, attemptOutcome, expectedApproval, fallbackReason = "" }) {
|
|
143
|
+
if (!ATTEMPT_OUTCOMES.has(attemptOutcome)) throw new Error("invalid interaction attempt outcome");
|
|
144
|
+
if (!String(interactionId ?? "").trim() || !String(runId ?? "").trim() || !String(currentGate ?? "").trim())
|
|
145
|
+
throw new Error("interaction attempt identity missing");
|
|
146
|
+
return Object.freeze({
|
|
147
|
+
interaction_id: String(interactionId), run_id: String(runId), current_gate: String(currentGate),
|
|
148
|
+
surface: String(surface ?? "fallback"), attempt_outcome: attemptOutcome,
|
|
149
|
+
expected_approval: String(expectedApproval ?? ""), fallback_reason: String(fallbackReason ?? ""),
|
|
150
|
+
authorizes: false,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
114
154
|
function safeArtefactPath(value) {
|
|
115
155
|
const path = String(value ?? "").replace(/^`|`$/g, "").trim();
|
|
116
156
|
if (!path || !/^[A-Za-z0-9._/-]+$/.test(path) || /^([a-z]+:|\/)/i.test(path)) return "";
|
|
@@ -166,4 +206,5 @@ export function normalizeInteractionOutcome(value, { expectedApproval, stale = f
|
|
|
166
206
|
export const interactionPresentationConstants = Object.freeze({
|
|
167
207
|
artefactOrder: Object.freeze([...ARTEFACT_ORDER]),
|
|
168
208
|
outcomes: Object.freeze([...OUTCOMES]),
|
|
209
|
+
attemptOutcomes: Object.freeze([...ATTEMPT_OUTCOMES]),
|
|
169
210
|
});
|
package/package.json
CHANGED