create-agdf 0.8.0 → 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.
@@ -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,24 @@ import {
25
25
  parseControlState,
26
26
  verifyLegacyProjection,
27
27
  } from "../lib/control-state/index.js";
28
+ import {
29
+ buildArtefactRefs,
30
+ buildRunCandidates,
31
+ canonicalizeLanguageTag,
32
+ formatArtefactRefs,
33
+ gateTitle,
34
+ localePack,
35
+ resolveHumanRunTitle,
36
+ resolvePresentationLocale,
37
+ } from "../lib/interaction-presentation.js";
28
38
 
29
39
  const __dirname = dirname(fileURLToPath(import.meta.url));
30
40
  const packageRoot = resolve(__dirname, "..");
31
41
  const generatedRoot = join(packageRoot, "generated");
32
42
  const pluginDefinitionPath = join(generatedRoot, "plugins", "agdf", "meta", "agdf-plugin.definition.json");
33
43
  const pluginDefinition = JSON.parse(readFileSync(pluginDefinitionPath, "utf8"));
44
+ const interactionLocalesPath = join(generatedRoot, "plugins", "agdf", "meta", "agdf-interaction-locales.json");
45
+ const interactionLocales = JSON.parse(readFileSync(interactionLocalesPath, "utf8"));
34
46
  const pluginInstallCommand = "npx --yes @agdf/cli@latest claude";
35
47
  const testNpmCliPath = process.env.NODE_ENV === "test" ? process.env.AGDF_TEST_NPM_CLI_PATH || "" : "";
36
48
  const npmCommand = testNpmCliPath
@@ -221,9 +233,9 @@ Backward-compatible create-agdf usage:
221
233
  Options:
222
234
  --dir <path> Write files into a specific directory. With opencode, use this as the OpenCode config directory.
223
235
  --force Overwrite existing generated files
224
- --language <de|en>
236
+ --language <tag>
225
237
  Set AGDF chat and artefact language. Defaults to detected system locale.
226
- --lang <de|en> Alias for --language
238
+ --lang <tag> Alias for --language
227
239
  --json Print machine-readable command output as JSON
228
240
  --status-card Print compact gate-check status-card output for interactive use
229
241
  --run <run_id> Select one canonical run
@@ -246,11 +258,17 @@ Options:
246
258
  }
247
259
 
248
260
  function normalizeLanguage(value) {
249
- const normalized = String(value ?? "").trim().toLowerCase().replace("_", "-");
261
+ return canonicalizeLanguageTag(value);
262
+ }
263
+
264
+ function configuredLanguage(value) {
265
+ const normalized = normalizeLanguage(value);
250
266
  if (!normalized) return "";
251
- if (normalized.startsWith("de")) return "de";
252
- if (normalized.startsWith("en")) return "en";
253
- return "";
267
+ const language = normalized.split("-")[0];
268
+ if (interactionLocales.locales[normalized] || interactionLocales.locales[language]) {
269
+ return resolvePresentationLocale(interactionLocales, normalized);
270
+ }
271
+ return normalized;
254
272
  }
255
273
 
256
274
  function detectSystemLocale() {
@@ -264,7 +282,7 @@ function detectSystemLocale() {
264
282
  }
265
283
 
266
284
  function resolveLanguagePreference(explicitLanguage) {
267
- const explicit = normalizeLanguage(explicitLanguage);
285
+ const explicit = configuredLanguage(explicitLanguage);
268
286
  if (explicit) {
269
287
  return {
270
288
  artifact_language: explicit,
@@ -276,7 +294,7 @@ function resolveLanguagePreference(explicitLanguage) {
276
294
  }
277
295
 
278
296
  const detectedLocale = detectSystemLocale();
279
- const detected = normalizeLanguage(detectedLocale) || "en";
297
+ const detected = configuredLanguage(detectedLocale) || interactionLocales.fallbackLocale;
280
298
  return {
281
299
  artifact_language: detected,
282
300
  chat_language: detected,
@@ -288,12 +306,12 @@ function resolveLanguagePreference(explicitLanguage) {
288
306
 
289
307
  function resolveConfiguredChatLanguage(targetDir) {
290
308
  const configPath = join(targetDir, ".agdf", "control", "config.json");
291
- if (!existsSync(configPath)) return "en";
309
+ if (!existsSync(configPath)) return interactionLocales.fallbackLocale;
292
310
  try {
293
311
  const config = JSON.parse(readFileSync(configPath, "utf8"));
294
- return normalizeLanguage(config.chat_language) || "en";
312
+ return resolvePresentationLocale(interactionLocales, config.chat_language);
295
313
  } catch {
296
- return "en";
314
+ return interactionLocales.fallbackLocale;
297
315
  }
298
316
  }
299
317
 
@@ -414,9 +432,9 @@ function parseArgs(argv) {
414
432
  console.error(`Missing value for ${arg}`);
415
433
  process.exit(1);
416
434
  }
417
- const normalized = normalizeLanguage(next);
435
+ const normalized = configuredLanguage(next);
418
436
  if (!normalized) {
419
- console.error("Unsupported language. Use --language de or --language en.");
437
+ console.error("Invalid language tag. Use a BCP 47 tag such as de, en or fr-CA.");
420
438
  process.exit(1);
421
439
  }
422
440
  language = normalized;
@@ -1899,6 +1917,7 @@ function readRunState(targetDir, selection = {}) {
1899
1917
  let runPath = join(".agdf", "control", "AGDF_RUN.md");
1900
1918
  const canonicalRoot = join(targetDir, ".agdf", "control", "runs");
1901
1919
  let resolutionError;
1920
+ let candidateRuns = [];
1902
1921
  if (existsSync(canonicalRoot)) {
1903
1922
  try {
1904
1923
  const selected = resolveRuns(targetDir, {
@@ -1910,6 +1929,21 @@ function readRunState(targetDir, selection = {}) {
1910
1929
  : selected.run.path;
1911
1930
  } catch (error) {
1912
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
+ }
1913
1947
  }
1914
1948
  }
1915
1949
  if (resolutionError || !existsSync(join(targetDir, runPath))) {
@@ -1929,6 +1963,7 @@ function readRunState(targetDir, selection = {}) {
1929
1963
  quality_outlook: "",
1930
1964
  source_scope: {},
1931
1965
  memory: {},
1966
+ candidate_runs: candidateRuns,
1932
1967
  resolution_error: resolutionError,
1933
1968
  };
1934
1969
  }
@@ -2246,6 +2281,48 @@ function buildStatusCard({
2246
2281
  };
2247
2282
  }
2248
2283
 
2284
+ function resolvedArtefactFile(targetDir, rawPath) {
2285
+ const normalizedPath = String(rawPath ?? "").replace(/^`|`$/g, "").trim();
2286
+ if (!normalizedPath || isAbsolute(normalizedPath) || normalizedPath.includes("<") || normalizedPath.includes(">")) return "";
2287
+ const absolutePath = resolve(targetDir, normalizedPath);
2288
+ if (relative(targetDir, absolutePath).startsWith("..") || !existsSync(absolutePath)) return "";
2289
+ try {
2290
+ const realPath = realpathSync(absolutePath);
2291
+ return relative(realpathSync(targetDir), realPath).startsWith("..") || !statSync(realPath).isFile() ? "" : realPath;
2292
+ } catch {
2293
+ return "";
2294
+ }
2295
+ }
2296
+
2297
+ function readArtefactHeading(targetDir, artefact) {
2298
+ const artefactPath = resolvedArtefactFile(targetDir, artefact?.path);
2299
+ if (!artefactPath) return "";
2300
+ try {
2301
+ return readFileSync(artefactPath, "utf8").match(/^#\s+(.+)$/m)?.[1]?.trim() ?? "";
2302
+ } catch {
2303
+ return "";
2304
+ }
2305
+ }
2306
+
2307
+ function buildHumanPresentation(targetDir, runState, currentGate, presentationLocale) {
2308
+ const currentArtefactHeading = readArtefactHeading(targetDir, runState.artefacts.get(currentGate));
2309
+ const urHeading = readArtefactHeading(targetDir, runState.artefacts.get("UR"));
2310
+ return {
2311
+ runTitle: resolveHumanRunTitle({
2312
+ currentArtefactHeading,
2313
+ urHeading,
2314
+ runContent: runState.content,
2315
+ runId: extractField(runState.content ?? "", "run_id") || "unknown",
2316
+ }),
2317
+ gateTitle: gateTitle(interactionLocales, presentationLocale, currentGate),
2318
+ artefactRefs: buildArtefactRefs(runState.artefacts, interactionLocales, presentationLocale, {
2319
+ pathExists(path) {
2320
+ return Boolean(resolvedArtefactFile(targetDir, path));
2321
+ },
2322
+ }),
2323
+ };
2324
+ }
2325
+
2249
2326
  function durableArtefactBlock(gate, nextGate) {
2250
2327
  const label = gate === "QA" ? "QA report" : `${gate} artefact`;
2251
2328
  const stablePath = gate === "QA" ? ".agdf/control/artefacts/<key>/QA_REPORT.md" : `.agdf/control/artefacts/<key>/${gate}.md`;
@@ -2274,6 +2351,10 @@ function isGateSatisfied(runState, gate) {
2274
2351
  return isDurableGateArtefactSatisfied(runState, gate);
2275
2352
  }
2276
2353
 
2354
+ function qaRevisionRequired(runState) {
2355
+ return gateArtefactStatus(runState, "QA").status === "revise";
2356
+ }
2357
+
2277
2358
  function transitionDecisionForRunState(runState, verifiedChange = null) {
2278
2359
  if (gateApprovalStatus(runState, "UR") === "approved" && !isGateSatisfied(runState, "UR")) return durableArtefactBlock("UR", "PRD");
2279
2360
 
@@ -2474,6 +2555,18 @@ function transitionDecisionForRunState(runState, verifiedChange = null) {
2474
2555
  };
2475
2556
  }
2476
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
+
2477
2570
  if (gateApprovalStatus(runState, "QA") === "approved" && !isGateSatisfied(runState, "QA")) return durableArtefactBlock("QA", "UAT");
2478
2571
 
2479
2572
  if (isGateSatisfied(runState, "QA") && !isGateSatisfied(runState, "UAT")) {
@@ -2566,6 +2659,23 @@ function evaluateGateCheck(targetDir, selection = {}) {
2566
2659
  }
2567
2660
 
2568
2661
  const postApproval = postApprovalTransition(missingApproval);
2662
+ const presentationLocale = resolveConfiguredChatLanguage(targetDir);
2663
+ const statusCard = buildStatusCard({
2664
+ status,
2665
+ currentGate,
2666
+ allowed,
2667
+ forbidden,
2668
+ blockingReason,
2669
+ missingApproval,
2670
+ nextAllowedAction,
2671
+ runState,
2672
+ chatLanguage: presentationLocale,
2673
+ findings: deliveryMap.findings,
2674
+ });
2675
+ Object.defineProperty(statusCard, "humanPresentation", {
2676
+ value: buildHumanPresentation(targetDir, runState, currentGate, presentationLocale),
2677
+ enumerable: false,
2678
+ });
2569
2679
 
2570
2680
  return {
2571
2681
  schema_version: "1",
@@ -2582,18 +2692,8 @@ function evaluateGateCheck(targetDir, selection = {}) {
2582
2692
  doctor_summary: doctorReport.summary,
2583
2693
  evidence_refs: runState.evidence_refs,
2584
2694
  quality_outlook: deriveQualityOutlook(runState, deliveryMap.findings),
2585
- status_card: buildStatusCard({
2586
- status,
2587
- currentGate,
2588
- allowed,
2589
- forbidden,
2590
- blockingReason,
2591
- missingApproval,
2592
- nextAllowedAction,
2593
- runState,
2594
- chatLanguage: resolveConfiguredChatLanguage(targetDir),
2595
- findings: deliveryMap.findings,
2596
- }),
2695
+ candidate_runs: runState.candidate_runs ?? [],
2696
+ status_card: statusCard,
2597
2697
  delivery_map: {
2598
2698
  relationships: deliveryMap.relationships,
2599
2699
  mode_slice_decision: runState.mode_slice_decision,
@@ -2609,58 +2709,27 @@ function evaluateGateCheck(targetDir, selection = {}) {
2609
2709
 
2610
2710
  function printGateCheckStatusCard(report) {
2611
2711
  const card = report.status_card;
2612
- const de = card.presentation_language === "de";
2613
- const labels = de ? {
2614
- title: "AGDF-Statuskarte",
2615
- run: "Ausgewählter Run",
2616
- gate: "Aktuelles Gate",
2617
- blocked: "Blockiert durch",
2618
- missing: "Fehlende Freigabe",
2619
- outcome: "Ergebnis nach Freigabe",
2620
- internal: "Interner nächster Schritt",
2621
- userGate: "Nächstes User-Gate",
2622
- userAction: "Nutzeraktion erforderlich",
2623
- nextGate: "Nächstes Gate nach Freigabe",
2624
- allowedAfter: "Nach Freigabe erlaubt",
2625
- skill: "Nächster Skill",
2626
- step: "Nächster Schritt",
2627
- quality: "Qualitätsausblick",
2628
- allowed: "Jetzt erlaubt",
2629
- forbidden: "Aktuell verboten",
2630
- } : {
2631
- title: "AGDF status-card",
2632
- run: "Selected run",
2633
- gate: "Current gate",
2634
- blocked: "Blocked by",
2635
- missing: "Missing approval",
2636
- outcome: "User-visible outcome after approval",
2637
- internal: "Internal next step",
2638
- userGate: "Next user gate",
2639
- userAction: "User action required",
2640
- nextGate: "Next gate after approval",
2641
- allowedAfter: "Allowed after approval",
2642
- skill: "Next skill",
2643
- step: "Next step",
2644
- quality: "Quality outlook",
2645
- allowed: "Allowed now",
2646
- forbidden: "Forbidden now",
2712
+ const labels = localePack(interactionLocales, card.presentation_language).statusCard;
2713
+ const primary = localePack(interactionLocales, card.presentation_language).primary;
2714
+ const presentation = card.humanPresentation ?? {
2715
+ runTitle: card.run_id,
2716
+ gateTitle: gateTitle(interactionLocales, card.presentation_language, card.current_gate),
2717
+ artefactRefs: buildArtefactRefs({}, interactionLocales, card.presentation_language),
2647
2718
  };
2648
- console.log(`${labels.title}: ${card.status}`);
2719
+ console.log(`${labels.title}: ${primary.status[card.status] ?? card.status}`);
2649
2720
  console.log(`${labels.run}: ${card.run_id}`);
2650
- console.log(`${labels.gate}: ${card.current_gate}`);
2651
- console.log(`${labels.blocked}: ${card.blocking_condition}`);
2652
- console.log(`${labels.missing}: ${card.missing_approval}`);
2653
- console.log(`${labels.outcome}: ${card.user_visible_outcome_after_approval}`);
2654
- console.log(`${labels.internal}: ${card.internal_next_step}`);
2655
- console.log(`${labels.userGate}: ${card.next_user_gate}`);
2656
- console.log(`${labels.userAction}: ${card.user_action_required}`);
2657
- if (card.next_gate_after_approval !== "none") console.log(`${labels.nextGate}: ${card.next_gate_after_approval}`);
2658
- if (card.allowed_after_approval !== "none") console.log(`${labels.allowedAfter}: ${card.allowed_after_approval}`);
2659
- console.log(`${labels.skill}: ${card.next_skill}`);
2660
- console.log(`${labels.step}: ${card.next_step}`);
2661
- console.log(`${labels.quality}: ${card.quality_outlook}`);
2662
- if (card.allowed_now.length > 0) console.log(`${labels.allowed}: ${card.allowed_now.join("; ")}`);
2663
- if (card.forbidden_now.length > 0) console.log(`${labels.forbidden}: ${card.forbidden_now.join("; ")}`);
2721
+ console.log(`${labels.humanTitle}: ${presentation.runTitle}`);
2722
+ console.log(`${labels.gate}: ${card.current_gate} — ${presentation.gateTitle}`);
2723
+ console.log(`${labels.artefacts}: ${formatArtefactRefs(presentation.artefactRefs)}`);
2724
+ console.log(`${labels.blocked}: ${card.blocking_condition === "none" ? primary.none : primary.blocked}`);
2725
+ console.log(`${labels.missing}: ${card.missing_approval === "none" ? primary.none : card.missing_approval}`);
2726
+ if (card.next_gate_after_approval !== "none") {
2727
+ console.log(`${labels.nextGate}: ${card.next_gate_after_approval} — ${gateTitle(interactionLocales, card.presentation_language, card.next_gate_after_approval)}`);
2728
+ console.log(`${labels.allowedAfter}: ${primary.afterApproval[card.current_gate] ?? primary.actions[card.current_gate]}`);
2729
+ }
2730
+ console.log(`${labels.allowed}: ${primary.actions[card.current_gate] ?? primary.none}`);
2731
+ console.log(`${labels.step}: ${primary.actions[card.current_gate] ?? primary.none}`);
2732
+ console.log(`${labels.quality}: ${primary.quality}`);
2664
2733
  }
2665
2734
 
2666
2735
  function printGateCheckReport(report, json, statusCard = false) {
@@ -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 `gate_approval` before selecting a host control.
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,20 +62,20 @@ 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. Render a separate localized Gate Transition Card immediately before any native question or exact-text fallback. Never put the card only into the question, button description or hidden tool context.
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
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
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
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
69
  7. Ask exactly one question that names the selected `run_id` and `current_gate`.
70
- 8. Offer the exact approving option `Approval: <GateName>` plus bounded revise and cancel/decline outcomes.
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
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
72
  10. Re-run gate evaluation for the same run and expected gate after the response and immediately before persistence.
73
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
74
  12. Persist accepted input only through the existing control-state workflow.
75
75
 
76
- Before composing the question, resolve the configured chat locale from `.agdf/control/config.json`. Use German presentation text for `chat_language: de`; use English for `chat_language: en` or as the deterministic fallback for an absent or unsupported locale. Keep `Approval: <GateName>` exactly unchanged in every language, and do not mix presentation languages within one question.
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
77
 
78
- For the transition card, German uses `Bereit für deine Entscheidung`, `Jetzt freigeben` and `Danach`; English uses `Ready for your decision`, `Approve now` and `Next`. Keep each card in one locale. Use a human-readable gate title rather than an internal status label. 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.
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
79
 
80
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.
81
81
 
@@ -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.
@@ -91,9 +98,11 @@ Surface behavior:
91
98
  - 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.
92
99
  - Other, unavailable or non-interactive surfaces: use exact textual approval and wait for a new explicit user response.
93
100
 
94
- Localized labels such as `Überarbeiten`/`Revise`, `Ablehnen`/`Decline` and `Abbrechen`/`Cancel` are presentation mappings to stable non-approval outcomes only. Host-provided free-text or `Überspringen`/`Skip` actions never advance an AGDF gate.
101
+ 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.
102
+
103
+ 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.
95
104
 
96
- A free-form response must still exactly match the current gate's approval formula after revalidation. Revise, decline and cancel never advance the gate. Native presentation, host permission and plan approval are inputs or separate authority domains, never durable AGDF authority.
105
+ 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.
97
106
 
98
107
  ## Rules
99
108
  1. Fail closed when a required approval or artefact status is missing.
@@ -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
+ }