create-agdf 0.7.3 → 0.8.1
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 +149 -35
- package/generated/.github/skills/agdf-gate-check/SKILL.md +27 -8
- package/generated/.github/skills/agdf-interaction-locales.json +184 -0
- package/generated/.github/skills/agdf-runtime-contract.md +134 -3
- package/generated/.opencode/agdf-interaction-locales.json +184 -0
- package/generated/.opencode/agdf-runtime-contract.md +134 -3
- package/generated/.opencode/skills/agdf-gate-check/SKILL.md +27 -8
- package/generated/plugins/agdf/.codex-plugin/plugin.json +1 -1
- package/generated/plugins/agdf/meta/agdf-interaction-locales.json +184 -0
- package/generated/plugins/agdf/meta/agdf-plugin.definition.json +44 -1
- package/generated/plugins/agdf/meta/agdf-runtime-contract.md +134 -3
- package/generated/plugins/agdf/skills/gate-check/SKILL.md +27 -8
- package/lib/control-state/gate-approval-validator.js +49 -0
- package/lib/control-state/index.js +1 -0
- package/lib/interaction-presentation.js +169 -0
- package/package.json +3 -2
package/bin/create-agdf.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { execFileSync } from "node:child_process";
|
|
5
5
|
import { homedir } from "node:os";
|
|
6
6
|
import { dirname, isAbsolute, join, posix, relative, resolve } from "node:path";
|
|
@@ -25,12 +25,23 @@ import {
|
|
|
25
25
|
parseControlState,
|
|
26
26
|
verifyLegacyProjection,
|
|
27
27
|
} from "../lib/control-state/index.js";
|
|
28
|
+
import {
|
|
29
|
+
buildArtefactRefs,
|
|
30
|
+
canonicalizeLanguageTag,
|
|
31
|
+
formatArtefactRefs,
|
|
32
|
+
gateTitle,
|
|
33
|
+
localePack,
|
|
34
|
+
resolveHumanRunTitle,
|
|
35
|
+
resolvePresentationLocale,
|
|
36
|
+
} from "../lib/interaction-presentation.js";
|
|
28
37
|
|
|
29
38
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
30
39
|
const packageRoot = resolve(__dirname, "..");
|
|
31
40
|
const generatedRoot = join(packageRoot, "generated");
|
|
32
41
|
const pluginDefinitionPath = join(generatedRoot, "plugins", "agdf", "meta", "agdf-plugin.definition.json");
|
|
33
42
|
const pluginDefinition = JSON.parse(readFileSync(pluginDefinitionPath, "utf8"));
|
|
43
|
+
const interactionLocalesPath = join(generatedRoot, "plugins", "agdf", "meta", "agdf-interaction-locales.json");
|
|
44
|
+
const interactionLocales = JSON.parse(readFileSync(interactionLocalesPath, "utf8"));
|
|
34
45
|
const pluginInstallCommand = "npx --yes @agdf/cli@latest claude";
|
|
35
46
|
const testNpmCliPath = process.env.NODE_ENV === "test" ? process.env.AGDF_TEST_NPM_CLI_PATH || "" : "";
|
|
36
47
|
const npmCommand = testNpmCliPath
|
|
@@ -221,9 +232,9 @@ Backward-compatible create-agdf usage:
|
|
|
221
232
|
Options:
|
|
222
233
|
--dir <path> Write files into a specific directory. With opencode, use this as the OpenCode config directory.
|
|
223
234
|
--force Overwrite existing generated files
|
|
224
|
-
--language <
|
|
235
|
+
--language <tag>
|
|
225
236
|
Set AGDF chat and artefact language. Defaults to detected system locale.
|
|
226
|
-
--lang <
|
|
237
|
+
--lang <tag> Alias for --language
|
|
227
238
|
--json Print machine-readable command output as JSON
|
|
228
239
|
--status-card Print compact gate-check status-card output for interactive use
|
|
229
240
|
--run <run_id> Select one canonical run
|
|
@@ -246,11 +257,17 @@ Options:
|
|
|
246
257
|
}
|
|
247
258
|
|
|
248
259
|
function normalizeLanguage(value) {
|
|
249
|
-
|
|
260
|
+
return canonicalizeLanguageTag(value);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function configuredLanguage(value) {
|
|
264
|
+
const normalized = normalizeLanguage(value);
|
|
250
265
|
if (!normalized) return "";
|
|
251
|
-
|
|
252
|
-
if (normalized.
|
|
253
|
-
|
|
266
|
+
const language = normalized.split("-")[0];
|
|
267
|
+
if (interactionLocales.locales[normalized] || interactionLocales.locales[language]) {
|
|
268
|
+
return resolvePresentationLocale(interactionLocales, normalized);
|
|
269
|
+
}
|
|
270
|
+
return normalized;
|
|
254
271
|
}
|
|
255
272
|
|
|
256
273
|
function detectSystemLocale() {
|
|
@@ -264,7 +281,7 @@ function detectSystemLocale() {
|
|
|
264
281
|
}
|
|
265
282
|
|
|
266
283
|
function resolveLanguagePreference(explicitLanguage) {
|
|
267
|
-
const explicit =
|
|
284
|
+
const explicit = configuredLanguage(explicitLanguage);
|
|
268
285
|
if (explicit) {
|
|
269
286
|
return {
|
|
270
287
|
artifact_language: explicit,
|
|
@@ -276,7 +293,7 @@ function resolveLanguagePreference(explicitLanguage) {
|
|
|
276
293
|
}
|
|
277
294
|
|
|
278
295
|
const detectedLocale = detectSystemLocale();
|
|
279
|
-
const detected =
|
|
296
|
+
const detected = configuredLanguage(detectedLocale) || interactionLocales.fallbackLocale;
|
|
280
297
|
return {
|
|
281
298
|
artifact_language: detected,
|
|
282
299
|
chat_language: detected,
|
|
@@ -286,6 +303,17 @@ function resolveLanguagePreference(explicitLanguage) {
|
|
|
286
303
|
};
|
|
287
304
|
}
|
|
288
305
|
|
|
306
|
+
function resolveConfiguredChatLanguage(targetDir) {
|
|
307
|
+
const configPath = join(targetDir, ".agdf", "control", "config.json");
|
|
308
|
+
if (!existsSync(configPath)) return interactionLocales.fallbackLocale;
|
|
309
|
+
try {
|
|
310
|
+
const config = JSON.parse(readFileSync(configPath, "utf8"));
|
|
311
|
+
return resolvePresentationLocale(interactionLocales, config.chat_language);
|
|
312
|
+
} catch {
|
|
313
|
+
return interactionLocales.fallbackLocale;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
289
317
|
function languageConfigContent(languagePreference) {
|
|
290
318
|
return `${JSON.stringify({
|
|
291
319
|
artifact_language: languagePreference.artifact_language,
|
|
@@ -403,9 +431,9 @@ function parseArgs(argv) {
|
|
|
403
431
|
console.error(`Missing value for ${arg}`);
|
|
404
432
|
process.exit(1);
|
|
405
433
|
}
|
|
406
|
-
const normalized =
|
|
434
|
+
const normalized = configuredLanguage(next);
|
|
407
435
|
if (!normalized) {
|
|
408
|
-
console.error("
|
|
436
|
+
console.error("Invalid language tag. Use a BCP 47 tag such as de, en or fr-CA.");
|
|
409
437
|
process.exit(1);
|
|
410
438
|
}
|
|
411
439
|
language = normalized;
|
|
@@ -2149,26 +2177,44 @@ function postApprovalTransition(missingApproval) {
|
|
|
2149
2177
|
["Approval: UR", {
|
|
2150
2178
|
next_gate_after_approval: "Brownfield Review",
|
|
2151
2179
|
allowed_after_approval: "Run Brownfield Review and record Mode/Slice Decision before PRD or implementation.",
|
|
2180
|
+
internal_next_step: "Brownfield Review and Mode/Slice Decision",
|
|
2181
|
+
next_user_gate: "PRD",
|
|
2182
|
+
user_action_required: "yes",
|
|
2152
2183
|
}],
|
|
2153
2184
|
["Approval: PRD", {
|
|
2154
2185
|
next_gate_after_approval: "SD",
|
|
2155
2186
|
allowed_after_approval: "Draft Solution Design; implementation remains forbidden.",
|
|
2187
|
+
internal_next_step: "draft Solution Design",
|
|
2188
|
+
next_user_gate: "SD",
|
|
2189
|
+
user_action_required: "yes",
|
|
2156
2190
|
}],
|
|
2157
2191
|
["Approval: SD", {
|
|
2158
2192
|
next_gate_after_approval: "TP",
|
|
2159
2193
|
allowed_after_approval: "Draft Task/Test Plan; implementation remains forbidden.",
|
|
2194
|
+
internal_next_step: "draft Task/Test Plan",
|
|
2195
|
+
next_user_gate: "TP",
|
|
2196
|
+
user_action_required: "yes",
|
|
2160
2197
|
}],
|
|
2161
2198
|
["Approval: TP", {
|
|
2162
|
-
next_gate_after_approval: "
|
|
2163
|
-
allowed_after_approval: "Run implementation-prep Brownfield Analysis before CD+Tests.",
|
|
2199
|
+
next_gate_after_approval: "none",
|
|
2200
|
+
allowed_after_approval: "Run implementation-prep Brownfield Analysis before CD+Tests; no further user approval is required at this internal step.",
|
|
2201
|
+
internal_next_step: "pre-implementation Brownfield Analysis",
|
|
2202
|
+
next_user_gate: "none",
|
|
2203
|
+
user_action_required: "no",
|
|
2164
2204
|
}],
|
|
2165
2205
|
["Approval: QA", {
|
|
2166
2206
|
next_gate_after_approval: "UAT",
|
|
2167
2207
|
allowed_after_approval: "Request UAT when QA has passed; release remains gated.",
|
|
2208
|
+
internal_next_step: "prepare UAT evidence",
|
|
2209
|
+
next_user_gate: "UAT",
|
|
2210
|
+
user_action_required: "yes",
|
|
2168
2211
|
}],
|
|
2169
2212
|
["Approval: UAT", {
|
|
2170
2213
|
next_gate_after_approval: "OR",
|
|
2171
2214
|
allowed_after_approval: "Produce OR or delivery closeout; VCS and release actions still require explicit instruction.",
|
|
2215
|
+
internal_next_step: "OR or delivery closeout",
|
|
2216
|
+
next_user_gate: "none",
|
|
2217
|
+
user_action_required: "no",
|
|
2172
2218
|
}],
|
|
2173
2219
|
]);
|
|
2174
2220
|
|
|
@@ -2187,11 +2233,15 @@ function buildStatusCard({
|
|
|
2187
2233
|
missingApproval = "none",
|
|
2188
2234
|
nextAllowedAction,
|
|
2189
2235
|
runState,
|
|
2236
|
+
chatLanguage = "en",
|
|
2190
2237
|
findings = [],
|
|
2191
2238
|
}) {
|
|
2192
2239
|
const qualityOutlook = deriveQualityOutlook(runState, findings);
|
|
2193
2240
|
const postApproval = postApprovalTransition(missingApproval);
|
|
2241
|
+
const isUserGateApproval = missingApproval !== "none";
|
|
2194
2242
|
return {
|
|
2243
|
+
run_id: extractField(runState.content ?? "", "run_id") || "unknown",
|
|
2244
|
+
presentation_language: chatLanguage,
|
|
2195
2245
|
mode: extractField(runState.content ?? "", "mode") || "unknown",
|
|
2196
2246
|
status,
|
|
2197
2247
|
current_gate: currentGate,
|
|
@@ -2202,6 +2252,10 @@ function buildStatusCard({
|
|
|
2202
2252
|
missing_approval: missingApproval || "none",
|
|
2203
2253
|
next_gate_after_approval: postApproval.next_gate_after_approval,
|
|
2204
2254
|
allowed_after_approval: postApproval.allowed_after_approval,
|
|
2255
|
+
user_visible_outcome_after_approval: postApproval.allowed_after_approval,
|
|
2256
|
+
internal_next_step: postApproval.internal_next_step || (isUserGateApproval ? "none" : nextAllowedAction),
|
|
2257
|
+
next_user_gate: postApproval.next_user_gate || "none",
|
|
2258
|
+
user_action_required: postApproval.user_action_required || (isUserGateApproval ? "yes" : "no"),
|
|
2205
2259
|
evidence: runState.evidence_refs,
|
|
2206
2260
|
next_skill: nextSkillByGate[currentGate] ?? "gate-check",
|
|
2207
2261
|
next_step: nextAllowedAction,
|
|
@@ -2209,6 +2263,48 @@ function buildStatusCard({
|
|
|
2209
2263
|
};
|
|
2210
2264
|
}
|
|
2211
2265
|
|
|
2266
|
+
function resolvedArtefactFile(targetDir, rawPath) {
|
|
2267
|
+
const normalizedPath = String(rawPath ?? "").replace(/^`|`$/g, "").trim();
|
|
2268
|
+
if (!normalizedPath || isAbsolute(normalizedPath) || normalizedPath.includes("<") || normalizedPath.includes(">")) return "";
|
|
2269
|
+
const absolutePath = resolve(targetDir, normalizedPath);
|
|
2270
|
+
if (relative(targetDir, absolutePath).startsWith("..") || !existsSync(absolutePath)) return "";
|
|
2271
|
+
try {
|
|
2272
|
+
const realPath = realpathSync(absolutePath);
|
|
2273
|
+
return relative(realpathSync(targetDir), realPath).startsWith("..") || !statSync(realPath).isFile() ? "" : realPath;
|
|
2274
|
+
} catch {
|
|
2275
|
+
return "";
|
|
2276
|
+
}
|
|
2277
|
+
}
|
|
2278
|
+
|
|
2279
|
+
function readArtefactHeading(targetDir, artefact) {
|
|
2280
|
+
const artefactPath = resolvedArtefactFile(targetDir, artefact?.path);
|
|
2281
|
+
if (!artefactPath) return "";
|
|
2282
|
+
try {
|
|
2283
|
+
return readFileSync(artefactPath, "utf8").match(/^#\s+(.+)$/m)?.[1]?.trim() ?? "";
|
|
2284
|
+
} catch {
|
|
2285
|
+
return "";
|
|
2286
|
+
}
|
|
2287
|
+
}
|
|
2288
|
+
|
|
2289
|
+
function buildHumanPresentation(targetDir, runState, currentGate, presentationLocale) {
|
|
2290
|
+
const currentArtefactHeading = readArtefactHeading(targetDir, runState.artefacts.get(currentGate));
|
|
2291
|
+
const urHeading = readArtefactHeading(targetDir, runState.artefacts.get("UR"));
|
|
2292
|
+
return {
|
|
2293
|
+
runTitle: resolveHumanRunTitle({
|
|
2294
|
+
currentArtefactHeading,
|
|
2295
|
+
urHeading,
|
|
2296
|
+
runContent: runState.content,
|
|
2297
|
+
runId: extractField(runState.content ?? "", "run_id") || "unknown",
|
|
2298
|
+
}),
|
|
2299
|
+
gateTitle: gateTitle(interactionLocales, presentationLocale, currentGate),
|
|
2300
|
+
artefactRefs: buildArtefactRefs(runState.artefacts, interactionLocales, presentationLocale, {
|
|
2301
|
+
pathExists(path) {
|
|
2302
|
+
return Boolean(resolvedArtefactFile(targetDir, path));
|
|
2303
|
+
},
|
|
2304
|
+
}),
|
|
2305
|
+
};
|
|
2306
|
+
}
|
|
2307
|
+
|
|
2212
2308
|
function durableArtefactBlock(gate, nextGate) {
|
|
2213
2309
|
const label = gate === "QA" ? "QA report" : `${gate} artefact`;
|
|
2214
2310
|
const stablePath = gate === "QA" ? ".agdf/control/artefacts/<key>/QA_REPORT.md" : `.agdf/control/artefacts/<key>/${gate}.md`;
|
|
@@ -2529,6 +2625,23 @@ function evaluateGateCheck(targetDir, selection = {}) {
|
|
|
2529
2625
|
}
|
|
2530
2626
|
|
|
2531
2627
|
const postApproval = postApprovalTransition(missingApproval);
|
|
2628
|
+
const presentationLocale = resolveConfiguredChatLanguage(targetDir);
|
|
2629
|
+
const statusCard = buildStatusCard({
|
|
2630
|
+
status,
|
|
2631
|
+
currentGate,
|
|
2632
|
+
allowed,
|
|
2633
|
+
forbidden,
|
|
2634
|
+
blockingReason,
|
|
2635
|
+
missingApproval,
|
|
2636
|
+
nextAllowedAction,
|
|
2637
|
+
runState,
|
|
2638
|
+
chatLanguage: presentationLocale,
|
|
2639
|
+
findings: deliveryMap.findings,
|
|
2640
|
+
});
|
|
2641
|
+
Object.defineProperty(statusCard, "humanPresentation", {
|
|
2642
|
+
value: buildHumanPresentation(targetDir, runState, currentGate, presentationLocale),
|
|
2643
|
+
enumerable: false,
|
|
2644
|
+
});
|
|
2532
2645
|
|
|
2533
2646
|
return {
|
|
2534
2647
|
schema_version: "1",
|
|
@@ -2545,17 +2658,7 @@ function evaluateGateCheck(targetDir, selection = {}) {
|
|
|
2545
2658
|
doctor_summary: doctorReport.summary,
|
|
2546
2659
|
evidence_refs: runState.evidence_refs,
|
|
2547
2660
|
quality_outlook: deriveQualityOutlook(runState, deliveryMap.findings),
|
|
2548
|
-
status_card:
|
|
2549
|
-
status,
|
|
2550
|
-
currentGate,
|
|
2551
|
-
allowed,
|
|
2552
|
-
forbidden,
|
|
2553
|
-
blockingReason,
|
|
2554
|
-
missingApproval,
|
|
2555
|
-
nextAllowedAction,
|
|
2556
|
-
runState,
|
|
2557
|
-
findings: deliveryMap.findings,
|
|
2558
|
-
}),
|
|
2661
|
+
status_card: statusCard,
|
|
2559
2662
|
delivery_map: {
|
|
2560
2663
|
relationships: deliveryMap.relationships,
|
|
2561
2664
|
mode_slice_decision: runState.mode_slice_decision,
|
|
@@ -2571,17 +2674,27 @@ function evaluateGateCheck(targetDir, selection = {}) {
|
|
|
2571
2674
|
|
|
2572
2675
|
function printGateCheckStatusCard(report) {
|
|
2573
2676
|
const card = report.status_card;
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
console.log(
|
|
2582
|
-
console.log(
|
|
2583
|
-
|
|
2584
|
-
|
|
2677
|
+
const labels = localePack(interactionLocales, card.presentation_language).statusCard;
|
|
2678
|
+
const primary = localePack(interactionLocales, card.presentation_language).primary;
|
|
2679
|
+
const presentation = card.humanPresentation ?? {
|
|
2680
|
+
runTitle: card.run_id,
|
|
2681
|
+
gateTitle: gateTitle(interactionLocales, card.presentation_language, card.current_gate),
|
|
2682
|
+
artefactRefs: buildArtefactRefs({}, interactionLocales, card.presentation_language),
|
|
2683
|
+
};
|
|
2684
|
+
console.log(`${labels.title}: ${primary.status[card.status] ?? card.status}`);
|
|
2685
|
+
console.log(`${labels.run}: ${card.run_id}`);
|
|
2686
|
+
console.log(`${labels.humanTitle}: ${presentation.runTitle}`);
|
|
2687
|
+
console.log(`${labels.gate}: ${card.current_gate} — ${presentation.gateTitle}`);
|
|
2688
|
+
console.log(`${labels.artefacts}: ${formatArtefactRefs(presentation.artefactRefs)}`);
|
|
2689
|
+
console.log(`${labels.blocked}: ${card.blocking_condition === "none" ? primary.none : primary.blocked}`);
|
|
2690
|
+
console.log(`${labels.missing}: ${card.missing_approval === "none" ? primary.none : card.missing_approval}`);
|
|
2691
|
+
if (card.next_gate_after_approval !== "none") {
|
|
2692
|
+
console.log(`${labels.nextGate}: ${card.next_gate_after_approval} — ${gateTitle(interactionLocales, card.presentation_language, card.next_gate_after_approval)}`);
|
|
2693
|
+
console.log(`${labels.allowedAfter}: ${primary.afterApproval[card.current_gate] ?? primary.actions[card.current_gate]}`);
|
|
2694
|
+
}
|
|
2695
|
+
console.log(`${labels.allowed}: ${primary.actions[card.current_gate] ?? primary.none}`);
|
|
2696
|
+
console.log(`${labels.step}: ${primary.actions[card.current_gate] ?? primary.none}`);
|
|
2697
|
+
console.log(`${labels.quality}: ${primary.quality}`);
|
|
2585
2698
|
}
|
|
2586
2699
|
|
|
2587
2700
|
function printGateCheckReport(report, json, statusCard = false) {
|
|
@@ -2698,6 +2811,7 @@ function evaluateDeliveryMap(targetDir, selection = {}) {
|
|
|
2698
2811
|
missingApproval: gateDecision.missing_approval,
|
|
2699
2812
|
nextAllowedAction,
|
|
2700
2813
|
runState,
|
|
2814
|
+
chatLanguage: resolveConfiguredChatLanguage(targetDir),
|
|
2701
2815
|
findings: map.findings,
|
|
2702
2816
|
}),
|
|
2703
2817
|
backlog_pointers: readBacklogPointers(targetDir),
|
|
@@ -54,7 +54,7 @@ The CLI reports are validators and JSON evidence, not the primary user experienc
|
|
|
54
54
|
|
|
55
55
|
## Native Interaction Path
|
|
56
56
|
|
|
57
|
-
Use the Runtime Contract's Native Interaction Contract to classify every candidate interaction as `clarification`, `tool_permission` or `
|
|
57
|
+
Use the Runtime Contract's Native Interaction Contract to classify every candidate interaction as `clarification`, `tool_permission`, `gate_approval`, `blocked` or `status` before selecting a host control.
|
|
58
58
|
|
|
59
59
|
Prefer inspection over asking. Do not invoke a structured question for status reporting, facts available in the repository, routine read-only work or a gate that is not ready. Do not repeatedly prompt for the same non-ready gate.
|
|
60
60
|
|
|
@@ -62,12 +62,22 @@ For a ready `gate_approval`:
|
|
|
62
62
|
|
|
63
63
|
1. Resolve exactly one selected run and evaluate the current gate.
|
|
64
64
|
2. Confirm the required durable artefact is present and ready before presenting a question.
|
|
65
|
-
3.
|
|
66
|
-
4.
|
|
67
|
-
5.
|
|
68
|
-
6.
|
|
69
|
-
7.
|
|
70
|
-
8.
|
|
65
|
+
3. Render a separate localized Gate Transition Card immediately before any native question or exact-text fallback. It includes the deterministic human run title and `UR · PRD · SD · TP` links from the selected run. Never put the card only into the question, button description or hidden tool context.
|
|
66
|
+
4. Treat the operational Run Status Card as evaluation and audit input, not as the approval-time product surface. Do not paste its table, raw keys, machine statuses, evidence or diagnostic detail into the transition card.
|
|
67
|
+
5. Compose the transition card as one human-readable gate title with `run_id`, one ready-for-decision line, one short approval-effect block and one short next-transition block. It must answer only: where am I, what does this decision do, and what happens next.
|
|
68
|
+
6. Distinguish internal process steps from user decisions in natural language. For example, after `Approval: TP`, say that pre-implementation Brownfield Analysis runs next and that no further user action is required now; do not expose `next_user_gate: none` or `user_action_required: no`, and do not ask for a second approval for Brownfield Analysis.
|
|
69
|
+
7. Ask exactly one question that names the selected `run_id` and `current_gate`.
|
|
70
|
+
8. Offer options in stable order: exact `Approval: <GateName>`, localized revise and localized decline. Add explicit cancel only where supported after decline; otherwise host dismissal maps to cancel. Never preselect, skip, auto-submit or reorder an option.
|
|
71
|
+
9. Use the surface adapter declared in the canonical plugin definition only when it can wait for deliberate input without auto-resolution; otherwise request the same exact approval in concise text.
|
|
72
|
+
10. Re-run gate evaluation for the same run and expected gate after the response and immediately before persistence.
|
|
73
|
+
11. Reject a missing artefact, ambiguous or wrong run, wrong gate, stale expected gate, timeout/default, hook-supplied answer, agent message, technical permission outcome or plan approval.
|
|
74
|
+
12. Persist accepted input only through the existing control-state workflow.
|
|
75
|
+
|
|
76
|
+
Before composing the question, resolve the configured chat locale from `.agdf/control/config.json` through `../agdf-interaction-locales.json`: exact complete pack, language subtag, then English fallback. German and English are initial packs, not a closed language list. Keep `Approval: <GateName>` exactly unchanged in every language, and do not mix presentation languages within one interaction. Labels and descriptions use the same resolved locale; host-owned UI chrome remains host-owned and may use a different language.
|
|
77
|
+
|
|
78
|
+
For the transition card, use the complete resolved locale pack. The initial German pack includes `Bereit für deine Entscheidung`, `Jetzt freigeben` and `Danach`; the initial English pack includes `Ready for your decision`, `Approve now` and `Next`. Keep each card in one locale. Use a localized human-readable gate title rather than an internal status label, while leaving the exact gate identifier and approval value unchanged. Do not render a Markdown table, dashboard rows, raw control-state keys, diagnostic codes, evidence lists, a duplicated gate question or a false user gate in the approval-time card.
|
|
79
|
+
|
|
80
|
+
The primary option remains exactly `Approval: SD`; only explanatory copy and non-authoritative outcome labels are localized. Concrete localized copy belongs to the user-facing interaction layer or the approved delivery artefact, not to English runtime rules.
|
|
71
81
|
|
|
72
82
|
Make exactly one native-attempt for the ready gate. If the host does not render,
|
|
73
83
|
apply or safely return the native question on that attempt, switch immediately
|
|
@@ -81,7 +91,11 @@ Surface behavior:
|
|
|
81
91
|
- OpenCode: use built-in `question` when permitted. Preserve explicit `permission.question` denial and use exact text in that case. `once`, `always`, `reject` and auto mode never become gate input.
|
|
82
92
|
- Other, unavailable or non-interactive surfaces: use exact textual approval and wait for a new explicit user response.
|
|
83
93
|
|
|
84
|
-
|
|
94
|
+
Localized labels such as `Überarbeiten`/`Revise`, `Ablehnen`/`Decline` and `Abbrechen`/`Cancel` are presentation mappings to stable non-approval outcomes only. A label, description, option position or recommendation never authorizes a gate. Host-provided free-text or `Überspringen`/`Skip` actions never advance an AGDF gate.
|
|
95
|
+
|
|
96
|
+
A free-form response must still exactly match the current gate's approval formula after revalidation. Keep `decline`, `cancel`, `no_response`, `timeout`, `empty`, `invalid` and `stale` distinct; none advances the gate. Native presentation, host permission and plan approval are inputs or separate authority domains, never durable AGDF authority.
|
|
97
|
+
|
|
98
|
+
Every primary chat card shows the selected run's `UR`, `PRD`, `SD` and `TP` in that order. Render an existing canonical path as a readable link and a missing artefact as localized non-link text; never guess paths. Resolve the human run title from current artefact heading, approved UR heading, Objective, then normalized `run_id`. Status, blocked, clarification and internal-step interactions use the same locale and artefact projection but do not show approval buttons. Keep raw process keys and machine status values in JSON or audit detail.
|
|
85
99
|
|
|
86
100
|
## Rules
|
|
87
101
|
1. Fail closed when a required approval or artefact status is missing.
|
|
@@ -170,6 +184,11 @@ Keep the result short and operational. Render the Runtime Contract's compact hum
|
|
|
170
184
|
|
|
171
185
|
When an approval is missing, also include `Next gate after approval` and `Allowed after approval` exactly as constrained by the Runtime Contract. Keep forbidden outputs, evidence and next-skill detail in the concise surrounding text when relevant; they are not extra status-card rows.
|
|
172
186
|
|
|
187
|
+
This operational status table is for status reporting. When the same response
|
|
188
|
+
immediately requests a ready gate approval, replace the table in the visible
|
|
189
|
+
approval experience with the Gate Transition Card defined above, then invoke
|
|
190
|
+
the native question or exact-text fallback. Do not show both cards.
|
|
191
|
+
|
|
173
192
|
If this skill creates or updates control artefacts, do not paste full file bodies into the chat.
|
|
174
193
|
List paths, summarize the decision, name the blocker or approval needed, and keep the durable content in the files.
|
|
175
194
|
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"fallbackLocale": "en",
|
|
4
|
+
"optionOrder": ["approve", "revise", "decline", "cancel"],
|
|
5
|
+
"lengthBudgets": {
|
|
6
|
+
"label": 40,
|
|
7
|
+
"description": 160,
|
|
8
|
+
"title": 100
|
|
9
|
+
},
|
|
10
|
+
"locales": {
|
|
11
|
+
"en": {
|
|
12
|
+
"statusCard": {
|
|
13
|
+
"title": "AGDF status-card",
|
|
14
|
+
"run": "Selected run",
|
|
15
|
+
"humanTitle": "Run title",
|
|
16
|
+
"gate": "Current gate",
|
|
17
|
+
"blocked": "Blocked by",
|
|
18
|
+
"missing": "Missing approval",
|
|
19
|
+
"outcome": "Outcome after approval",
|
|
20
|
+
"internal": "Internal next step",
|
|
21
|
+
"userGate": "Next user gate",
|
|
22
|
+
"userAction": "User action required",
|
|
23
|
+
"nextGate": "Next gate after approval",
|
|
24
|
+
"allowedAfter": "Allowed after approval",
|
|
25
|
+
"skill": "Next skill",
|
|
26
|
+
"step": "Next step",
|
|
27
|
+
"quality": "Quality outlook",
|
|
28
|
+
"allowed": "Allowed now",
|
|
29
|
+
"forbidden": "Forbidden now",
|
|
30
|
+
"artefacts": "Artefacts"
|
|
31
|
+
},
|
|
32
|
+
"gateTitles": {
|
|
33
|
+
"UR": "User requirements",
|
|
34
|
+
"PRD": "Product requirements",
|
|
35
|
+
"SD": "Solution design",
|
|
36
|
+
"TP": "Task and test plan",
|
|
37
|
+
"QA": "Quality assurance",
|
|
38
|
+
"UAT": "User acceptance",
|
|
39
|
+
"Brownfield Review": "Brownfield review",
|
|
40
|
+
"Mode/Slice Decision": "Delivery scope decision",
|
|
41
|
+
"Brownfield Analysis": "Implementation preparation",
|
|
42
|
+
"CD+Tests": "Implementation and tests",
|
|
43
|
+
"CR": "Code review",
|
|
44
|
+
"OR": "Delivery report"
|
|
45
|
+
},
|
|
46
|
+
"interaction": {
|
|
47
|
+
"ready": "Ready for your decision",
|
|
48
|
+
"approveHeading": "Approve now",
|
|
49
|
+
"nextHeading": "Next",
|
|
50
|
+
"approveDescription": "Approve this gate with the exact authorization value.",
|
|
51
|
+
"reviseLabel": "Revise",
|
|
52
|
+
"reviseDescription": "Keep the gate open and request changes.",
|
|
53
|
+
"declineLabel": "Decline",
|
|
54
|
+
"declineDescription": "Reject this gate deliberately; authority remains unchanged.",
|
|
55
|
+
"cancelLabel": "Cancel",
|
|
56
|
+
"cancelDescription": "Close this decision without approving or declining it."
|
|
57
|
+
},
|
|
58
|
+
"artefacts": {
|
|
59
|
+
"notYetCreated": "not yet created"
|
|
60
|
+
},
|
|
61
|
+
"primary": {
|
|
62
|
+
"status": {
|
|
63
|
+
"open": "open",
|
|
64
|
+
"blocked": "blocked",
|
|
65
|
+
"pass": "passed",
|
|
66
|
+
"warn": "attention needed",
|
|
67
|
+
"revise": "revision needed",
|
|
68
|
+
"in_progress": "in progress"
|
|
69
|
+
},
|
|
70
|
+
"none": "none",
|
|
71
|
+
"blocked": "current gate prerequisites",
|
|
72
|
+
"quality": "Keep the presentation contract, evidence and gate authority aligned.",
|
|
73
|
+
"actions": {
|
|
74
|
+
"UR": "Clarify and approve the user requirements.",
|
|
75
|
+
"Brownfield Review": "Review existing owners and choose the smallest safe delivery path.",
|
|
76
|
+
"Mode/Slice Decision": "Decide the proportionate delivery scope from repository evidence.",
|
|
77
|
+
"PRD": "Define and approve the product behavior.",
|
|
78
|
+
"SD": "Define and approve the solution design.",
|
|
79
|
+
"TP": "Define and approve the task and test plan.",
|
|
80
|
+
"Brownfield Analysis": "Verify owners, reuse and regression coverage before implementation.",
|
|
81
|
+
"CD+Tests": "Implement the approved plan and collect test evidence.",
|
|
82
|
+
"CR": "Review the implementation and resolve blocking findings.",
|
|
83
|
+
"QA": "Evaluate quality evidence and make the QA decision.",
|
|
84
|
+
"UAT": "Make the deliberate user-acceptance decision.",
|
|
85
|
+
"OR": "Prepare the auditable delivery report."
|
|
86
|
+
},
|
|
87
|
+
"afterApproval": {
|
|
88
|
+
"UR": "Review existing owners and choose the proportionate delivery path; implementation remains blocked.",
|
|
89
|
+
"PRD": "Draft the solution design; implementation remains blocked.",
|
|
90
|
+
"SD": "Draft the task and test plan; implementation remains blocked.",
|
|
91
|
+
"TP": "Run pre-implementation Brownfield Analysis; implementation starts only if it passes.",
|
|
92
|
+
"QA": "Prepare the user-acceptance decision; release remains blocked.",
|
|
93
|
+
"UAT": "Prepare the delivery report; version-control and release actions still require explicit instruction."
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
"de": {
|
|
98
|
+
"statusCard": {
|
|
99
|
+
"title": "AGDF-Statuskarte",
|
|
100
|
+
"run": "Ausgewählter Run",
|
|
101
|
+
"humanTitle": "Run-Titel",
|
|
102
|
+
"gate": "Aktuelles Gate",
|
|
103
|
+
"blocked": "Blockiert durch",
|
|
104
|
+
"missing": "Fehlende Freigabe",
|
|
105
|
+
"outcome": "Ergebnis nach Freigabe",
|
|
106
|
+
"internal": "Interner nächster Schritt",
|
|
107
|
+
"userGate": "Nächstes User-Gate",
|
|
108
|
+
"userAction": "Nutzeraktion erforderlich",
|
|
109
|
+
"nextGate": "Nächstes Gate nach Freigabe",
|
|
110
|
+
"allowedAfter": "Nach Freigabe erlaubt",
|
|
111
|
+
"skill": "Nächster Skill",
|
|
112
|
+
"step": "Nächster Schritt",
|
|
113
|
+
"quality": "Qualitätsausblick",
|
|
114
|
+
"allowed": "Jetzt erlaubt",
|
|
115
|
+
"forbidden": "Aktuell verboten",
|
|
116
|
+
"artefacts": "Artefakte"
|
|
117
|
+
},
|
|
118
|
+
"gateTitles": {
|
|
119
|
+
"UR": "Nutzeranforderungen",
|
|
120
|
+
"PRD": "Produktanforderungen",
|
|
121
|
+
"SD": "Lösungsdesign",
|
|
122
|
+
"TP": "Aufgaben- und Testplan",
|
|
123
|
+
"QA": "Qualitätssicherung",
|
|
124
|
+
"UAT": "Nutzerabnahme",
|
|
125
|
+
"Brownfield Review": "Brownfield-Prüfung",
|
|
126
|
+
"Mode/Slice Decision": "Entscheidung zum Lieferumfang",
|
|
127
|
+
"Brownfield Analysis": "Implementierungsvorbereitung",
|
|
128
|
+
"CD+Tests": "Implementierung und Tests",
|
|
129
|
+
"CR": "Code-Review",
|
|
130
|
+
"OR": "Lieferbericht"
|
|
131
|
+
},
|
|
132
|
+
"interaction": {
|
|
133
|
+
"ready": "Bereit für deine Entscheidung",
|
|
134
|
+
"approveHeading": "Jetzt freigeben",
|
|
135
|
+
"nextHeading": "Danach",
|
|
136
|
+
"approveDescription": "Dieses Gate mit dem exakten Freigabewert autorisieren.",
|
|
137
|
+
"reviseLabel": "Überarbeiten",
|
|
138
|
+
"reviseDescription": "Das Gate offen lassen und Änderungen anfordern.",
|
|
139
|
+
"declineLabel": "Ablehnen",
|
|
140
|
+
"declineDescription": "Dieses Gate bewusst ablehnen; die Berechtigung bleibt unverändert.",
|
|
141
|
+
"cancelLabel": "Abbrechen",
|
|
142
|
+
"cancelDescription": "Diese Entscheidung ohne Freigabe oder Ablehnung schließen."
|
|
143
|
+
},
|
|
144
|
+
"artefacts": {
|
|
145
|
+
"notYetCreated": "noch nicht erstellt"
|
|
146
|
+
},
|
|
147
|
+
"primary": {
|
|
148
|
+
"status": {
|
|
149
|
+
"open": "offen",
|
|
150
|
+
"blocked": "blockiert",
|
|
151
|
+
"pass": "bestanden",
|
|
152
|
+
"warn": "Prüfung erforderlich",
|
|
153
|
+
"revise": "Überarbeitung erforderlich",
|
|
154
|
+
"in_progress": "in Arbeit"
|
|
155
|
+
},
|
|
156
|
+
"none": "keine",
|
|
157
|
+
"blocked": "Voraussetzungen des aktuellen Gates",
|
|
158
|
+
"quality": "Präsentationsvertrag, Nachweise und Gate-Berechtigung konsistent halten.",
|
|
159
|
+
"actions": {
|
|
160
|
+
"UR": "Nutzeranforderungen klären und freigeben.",
|
|
161
|
+
"Brownfield Review": "Bestehende Owner prüfen und den kleinsten sicheren Lieferweg wählen.",
|
|
162
|
+
"Mode/Slice Decision": "Den angemessenen Lieferumfang anhand der Repository-Nachweise festlegen.",
|
|
163
|
+
"PRD": "Produktverhalten definieren und freigeben.",
|
|
164
|
+
"SD": "Lösungsdesign definieren und freigeben.",
|
|
165
|
+
"TP": "Aufgaben- und Testplan definieren und freigeben.",
|
|
166
|
+
"Brownfield Analysis": "Owner, Wiederverwendung und Regressionstests vor der Implementierung prüfen.",
|
|
167
|
+
"CD+Tests": "Den freigegebenen Plan implementieren und Testnachweise sammeln.",
|
|
168
|
+
"CR": "Implementierung prüfen und blockierende Befunde beheben.",
|
|
169
|
+
"QA": "Qualitätsnachweise bewerten und die QA-Entscheidung treffen.",
|
|
170
|
+
"UAT": "Die bewusste Nutzerabnahme entscheiden.",
|
|
171
|
+
"OR": "Den auditierbaren Lieferbericht erstellen."
|
|
172
|
+
},
|
|
173
|
+
"afterApproval": {
|
|
174
|
+
"UR": "Bestehende Owner prüfen und den angemessenen Lieferweg wählen; die Implementierung bleibt gesperrt.",
|
|
175
|
+
"PRD": "Das Lösungsdesign entwerfen; die Implementierung bleibt gesperrt.",
|
|
176
|
+
"SD": "Den Aufgaben- und Testplan entwerfen; die Implementierung bleibt gesperrt.",
|
|
177
|
+
"TP": "Die Brownfield-Analyse vor der Implementierung durchführen; die Implementierung startet nur nach bestandenem Ergebnis.",
|
|
178
|
+
"QA": "Die Nutzerabnahme vorbereiten; die Veröffentlichung bleibt gesperrt.",
|
|
179
|
+
"UAT": "Den Lieferbericht vorbereiten; Versionskontroll- und Veröffentlichungsaktionen benötigen weiterhin eine ausdrückliche Anweisung."
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|