create-agdf 0.8.5 → 0.8.6
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 +141 -10
- package/generated/.agdf/control/templates/artefacts/VERIFIED_CHANGE.md +10 -0
- package/generated/.github/skills/agdf-brownfield-analysis/SKILL.md +3 -3
- package/generated/.github/skills/agdf-gate-check/SKILL.md +20 -7
- package/generated/.github/skills/agdf-interaction-locales.json +58 -4
- package/generated/.github/skills/agdf-release-or/SKILL.md +4 -3
- package/generated/.github/skills/agdf-runtime-contract.md +71 -8
- package/generated/.opencode/agdf-interaction-locales.json +58 -4
- package/generated/.opencode/agdf-runtime-contract.md +71 -8
- package/generated/.opencode/skills/agdf-brownfield-analysis/SKILL.md +3 -3
- package/generated/.opencode/skills/agdf-gate-check/SKILL.md +20 -7
- package/generated/.opencode/skills/agdf-release-or/SKILL.md +4 -3
- package/generated/plugins/agdf/.codex-plugin/plugin.json +1 -1
- package/generated/plugins/agdf/control/templates/artefacts/VERIFIED_CHANGE.md +10 -0
- package/generated/plugins/agdf/meta/agdf-interaction-locales.json +58 -4
- package/generated/plugins/agdf/meta/agdf-plugin.definition.json +9 -5
- package/generated/plugins/agdf/meta/agdf-runtime-contract.md +71 -8
- package/generated/plugins/agdf/skills/brownfield-analysis/SKILL.md +3 -3
- package/generated/plugins/agdf/skills/gate-check/SKILL.md +20 -7
- package/generated/plugins/agdf/skills/release-or/SKILL.md +4 -3
- package/lib/control-state/run-state-parser.js +30 -3
- package/lib/interaction-presentation.js +84 -2
- package/package.json +1 -1
|
@@ -26,14 +26,14 @@ When `.agdf/control/` is present, persist or link `post_ur_review` output under
|
|
|
26
26
|
|
|
27
27
|
## Modes
|
|
28
28
|
|
|
29
|
-
- `post_ur_review`: use after approved durable UR to size and route the work. Output must decide `quick_task`, `structured_slice`, `structured_delivery`, or `block` with scope reason and evidence.
|
|
29
|
+
- `post_ur_review`: use after approved durable UR to size and route the work. Output must decide `quick_task`, `verified_change`, `structured_slice`, `structured_delivery`, or `block` with scope reason and evidence.
|
|
30
30
|
- `pre_implementation_analysis`: use after approved durable TP to verify the implementation path before `CD+Tests`. Output must focus on reuse path, owners, regression risk, test impact and minimal clean implementation.
|
|
31
31
|
|
|
32
32
|
Do not mix both modes silently. Name the active mode in the output.
|
|
33
33
|
|
|
34
34
|
## Rules
|
|
35
35
|
1. Brownfield first: understand the existing codebase before PRD/SD decisions when existing-system impact is possible, and again before implementation.
|
|
36
|
-
2. Brownfield Review after `Approval: UR` is a sizing and routing step. It must visibly decide `quick_task`, `structured_slice`, `structured_delivery`, or `block` before PRD depth or implementation is chosen.
|
|
36
|
+
2. Brownfield Review after `Approval: UR` is a sizing and routing step. It must visibly decide `quick_task`, `verified_change`, `structured_slice`, `structured_delivery`, or `block` before PRD depth or implementation is chosen.
|
|
37
37
|
3. Reuse-before-create: prefer existing modules, services, components, tables, endpoints, tests, and configuration.
|
|
38
38
|
4. Minimal clean slice: choose the smallest durable intervention, not merely the smallest technical diff.
|
|
39
39
|
5. No silent parallel structures.
|
|
@@ -106,7 +106,7 @@ Use a concise structure:
|
|
|
106
106
|
## Brownfield Analysis
|
|
107
107
|
- mode: post_ur_review | pre_implementation_analysis
|
|
108
108
|
- decision: pass | revise | block | not_applicable
|
|
109
|
-
- mode_slice_decision: quick_task | structured_slice | structured_delivery | block
|
|
109
|
+
- mode_slice_decision: quick_task | verified_change | structured_slice | structured_delivery | block
|
|
110
110
|
- required_next_gate: none | PRD | SD | TP | Brownfield Analysis
|
|
111
111
|
- artefact: .agdf/control/artefacts/<key>/BROWNFIELD_REVIEW.md | none
|
|
112
112
|
- scope:
|
|
@@ -75,17 +75,18 @@ For a ready `gate_approval`:
|
|
|
75
75
|
13. 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.
|
|
76
76
|
14. Persist accepted input only through the existing control-state workflow.
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
78
|
+
Before projecting a ready gate, evaluate adapter callability, deliberate wait safety and canonical
|
|
79
|
+
approval-value transport. Expose `native_attempt_required: true` only when that preflight proves
|
|
80
|
+
`exact_option_value` or `separate_label_and_value` transport with safe deliberate waiting. Decorated-only,
|
|
81
|
+
missing, conflicting or unknown capability exposes false and `unavailable_before_invocation`; unsafe
|
|
82
|
+
waiting exposes false and `unsafe_to_wait`. In both cases use exact text without invoking the adapter.
|
|
83
|
+
A hook, permission result or session context message cannot replace an eligible attempt or supply its answer.
|
|
83
84
|
|
|
84
85
|
Before composing the question, resolve the configured chat locale from `.agdf/control/config.json` through `plugin/meta/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.
|
|
85
86
|
|
|
86
87
|
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.
|
|
87
88
|
|
|
88
|
-
The primary option
|
|
89
|
+
The primary option is derived exactly as `Approval: <GateName>` from the evaluated current gate; 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.
|
|
89
90
|
|
|
90
91
|
Make exactly one native-attempt for the ready gate. If the host does not render,
|
|
91
92
|
apply or safely return the native question on that attempt, switch immediately
|
|
@@ -112,6 +113,18 @@ A free-form response must still exactly match the current gate's approval formul
|
|
|
112
113
|
|
|
113
114
|
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.
|
|
114
115
|
|
|
116
|
+
### Breadcrumb Rendering
|
|
117
|
+
|
|
118
|
+
The compact human Run Status Card includes a single-line path-derived breadcrumb showing the user's position in the delivery journey. Derive it from the Mode/Slice Decision and the Approvals table — not a fixed template. Use `✓` for fulfilled, `●` for current, `○` for open, separated by ` · `. Non-applicable gates are absent. See the Runtime Contract §Breadcrumb for the path templates and the derived `breadcrumb` array.
|
|
119
|
+
|
|
120
|
+
### Post-Acceptance Transition Narration
|
|
121
|
+
|
|
122
|
+
After each accepted gate approval is persisted, emit exactly one narration line using the template `<what was satisfied> → <what the agent does next internally> → <user action: yes/no>`. This generalizes the existing TP pattern (step 7 above) to every gate advancement. The narration is post-acceptance only: it never appears in the same message as the Gate Transition Card, never contains the `Approval:` value, and never repeats the decision's effect. For internal steps (Brownfield Review, Brownfield Analysis), state what the agent does next and that no user action is required, without exposing `next_user_gate: none` or asking for a second approval. See the Runtime Contract §Post-Acceptance Transition Narration for the full contract.
|
|
123
|
+
|
|
124
|
+
### Internal-State Collapse in the Human Card
|
|
125
|
+
|
|
126
|
+
When rendering the compact human Run Status Card, collapse internal sub-states (`verified_change` sub-states, `context_graph_required_action`, `multi_scope_state`) to stable human labels. `escalated`, `open_gap` and `blocked` remain explicitly visible. The full machine/audit projection retains all raw values unchanged. See the Runtime Contract §Internal-State Collapse for the complete mapping table.
|
|
127
|
+
|
|
115
128
|
## Rules
|
|
116
129
|
1. Fail closed when a required approval or artefact status is missing.
|
|
117
130
|
2. The earliest blocking gate wins.
|
|
@@ -125,7 +138,7 @@ Every primary chat card shows the selected run's `UR`, `PRD`, `SD` and `TP` in t
|
|
|
125
138
|
10. Approval of one user gate permits work on the next allowed gate artefact or required internal step only; it never skips directly to implementation.
|
|
126
139
|
11. New product semantics, functional change or user-visible behaviour change requires a durable UR in `.agdf/control/` or a linked authoritative repository SoT before Brownfield Review, PRD, SD, TP, Brownfield Analysis or implementation.
|
|
127
140
|
12. Approval text and durable artefact presence are separate requirements for UR, PRD, SD, TP and QA report decisions. Approval text without the corresponding persisted or linked artefact keeps the current gate at that gate.
|
|
128
|
-
13. After Brownfield Review, decide the process size before drafting PRD or implementing: `quick_task | structured_slice | structured_delivery | block`.
|
|
141
|
+
13. After Brownfield Review, decide the process size before drafting PRD or implementing: `quick_task | verified_change | structured_slice | structured_delivery | block`.
|
|
129
142
|
14. The Mode/Slice Decision must be visible and evidenced before any Quick Task execution, PRD shortcut or implementation. A decision value without scope reason and evidence is still missing.
|
|
130
143
|
15. Missing or incomplete control state must not push setup work back to the user. For a fresh request, draft the current minimal artefact in the response and request the exact approval. Initialize or write `.agdf/control/` only when durable control state is explicitly requested, already live for the repository, or required for a deterministic CLI/CI setup path. Implementation remains forbidden.
|
|
131
144
|
16. Branch names, uncommitted diffs, generated summaries and chat history are not sufficient scope proof when durable artefacts or approvals are missing or conflicting.
|
|
@@ -43,9 +43,10 @@ Use the Runtime Contract definition of `Relevant Run` to decide whether OR is ma
|
|
|
43
43
|
9. End with the immediately permissible next step.
|
|
44
44
|
10. `CD+Tests` is not completion.
|
|
45
45
|
11. When moving a backlog item to Completed or Superseded, use the canonical human-readable table and link the final OR with a document-relative Markdown link.
|
|
46
|
-
12.
|
|
47
|
-
13.
|
|
48
|
-
14.
|
|
46
|
+
12. For an executed `verified_change`, a lifecycle-consistent complete Mini-Closeout in the linked `VERIFIED_CHANGE.md` is the compact OR target; do not require a separate `OR.md` by ritual.
|
|
47
|
+
13. Keep machine status normalization in the CLI; do not write internal snake_case status values into the human-facing backlog.
|
|
48
|
+
14. Reconcile Context Graph impact before clean closeout: report `context_graph_reconciliation: resolved | not_applicable | open_gap`.
|
|
49
|
+
15. If Context Graph work remains unresolved, report it as an explicit open gap and do not describe the run as cleanly handoff-ready.
|
|
49
50
|
15. After writing or updating `MASTER_BACKLOG.md`, run `doctor --json` (or the locally available equivalent) and resolve any `AGDF_BACKLOG_STATUS_UNKNOWN` or `AGDF_BACKLOG_ARTEFACT_LABEL_UNKNOWN` finding before closeout. See the AGDF control scaffold's `MASTER_BACKLOG.md` template Rules section for the canonical status/artefact label vocabulary.
|
|
50
51
|
|
|
51
52
|
## When To Use
|
|
@@ -76,6 +76,24 @@ function rows(s) {
|
|
|
76
76
|
function clean(v = "") {
|
|
77
77
|
return v.replace(/^`|`$/g, "").trim();
|
|
78
78
|
}
|
|
79
|
+
export function parseArtefactPathCell(value = "") {
|
|
80
|
+
const raw = String(value).trim();
|
|
81
|
+
if (!raw) return { raw, path: "", format: "plain", reason: "empty" };
|
|
82
|
+
const ticks = [...raw].filter((character) => character === "`").length;
|
|
83
|
+
if (ticks === 0) return { raw, path: raw, format: "plain", reason: "none" };
|
|
84
|
+
if (ticks === 2 && raw.startsWith("`") && raw.endsWith("`")) {
|
|
85
|
+
const path = raw.slice(1, -1).trim();
|
|
86
|
+
if (path && !path.includes("`")) return { raw, path, format: "code_span", reason: "none" };
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
raw,
|
|
90
|
+
path: "",
|
|
91
|
+
format: "invalid",
|
|
92
|
+
reason: ticks === 1 || raw.startsWith("`") !== raw.endsWith("`")
|
|
93
|
+
? "unmatched_delimiter"
|
|
94
|
+
: "embedded_delimiter",
|
|
95
|
+
};
|
|
96
|
+
}
|
|
79
97
|
function meaningful(v = "") {
|
|
80
98
|
return Boolean(v && !(v.startsWith("`") && v.includes("|")));
|
|
81
99
|
}
|
|
@@ -96,7 +114,7 @@ function dataRows(c, h, header) {
|
|
|
96
114
|
}
|
|
97
115
|
export function parseControlState(
|
|
98
116
|
content,
|
|
99
|
-
{ userGates = [], internalSteps = [] } = {},
|
|
117
|
+
{ userGates = [], internalSteps = [], closeoutArtefacts = [] } = {},
|
|
100
118
|
) {
|
|
101
119
|
const approvals = new Map();
|
|
102
120
|
for (const h of ["Approvals", "Gate Checklist"])
|
|
@@ -111,8 +129,17 @@ export function parseControlState(
|
|
|
111
129
|
}
|
|
112
130
|
const artefacts = new Map();
|
|
113
131
|
for (const [t, p, s, n] of rows(section(content, "Artefacts"))) {
|
|
114
|
-
if (userGates.includes(t) || internalSteps.includes(t))
|
|
115
|
-
|
|
132
|
+
if (userGates.includes(t) || internalSteps.includes(t) || closeoutArtefacts.includes(t)) {
|
|
133
|
+
const parsedPath = parseArtefactPathCell(p ?? "");
|
|
134
|
+
artefacts.set(t, {
|
|
135
|
+
path: parsedPath.path,
|
|
136
|
+
status: clean(s),
|
|
137
|
+
notes: n ?? "",
|
|
138
|
+
raw_path: parsedPath.raw,
|
|
139
|
+
path_format: parsedPath.format,
|
|
140
|
+
path_reason: parsedPath.reason,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
116
143
|
}
|
|
117
144
|
const mapRows = (h, header, fn) => dataRows(content, h, header).map(fn);
|
|
118
145
|
const mode = section(content, "Mode/Slice Decision").trim()
|
|
@@ -2,6 +2,7 @@ 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
4
|
const ATTEMPT_OUTCOMES = new Set(["presented", "unavailable_before_invocation", "attempted_not_applied", "unsafe_to_wait"]);
|
|
5
|
+
const APPROVAL_VALUE_TRANSPORTS = new Set(["exact_option_value", "separate_label_and_value", "decorated_label_only", "unknown"]);
|
|
5
6
|
const APPROVAL_SEQUENCE = Object.freeze(["run_status_card", "gate_transition_card", "approval_interaction"]);
|
|
6
7
|
const QUALITY_STATUS_RANK = { pass: 0, warn: 1, revise: 2, block: 3 };
|
|
7
8
|
const QUALITY_DIMENSIONS = Object.freeze([
|
|
@@ -63,7 +64,7 @@ export function validateLocaleRegistry(registry) {
|
|
|
63
64
|
for (const [key, value] of visibleStrings(pack)) {
|
|
64
65
|
if (!value.trim()) errors.push(`empty_copy:${locale}:${key}`);
|
|
65
66
|
const budget = key.startsWith("gateTitles.") ? budgets.title
|
|
66
|
-
: key.includes("Description") || key.includes("fallbackReasons") || key.startsWith("primary.actions.") || key.startsWith("primary.afterApproval.") || key === "primary.quality"
|
|
67
|
+
: key.includes("Description") || key.includes("fallbackReasons") || key.startsWith("primary.actions.") || key.startsWith("primary.afterApproval.") || key.startsWith("primary.narration.") || key === "primary.quality"
|
|
67
68
|
? budgets.description
|
|
68
69
|
: budgets.label;
|
|
69
70
|
if (Number.isInteger(budget) && value.length > budget) errors.push(`length_budget:${locale}:${key}`);
|
|
@@ -180,10 +181,31 @@ export function reconcileRunScope({ requestText = "", scopeKey = "", runs = [] }
|
|
|
180
181
|
return Object.freeze({ outcome: matches[0].lifecycle === "active" ? "active_match" : "completed_match", matches, reason: "exact_match" });
|
|
181
182
|
}
|
|
182
183
|
|
|
183
|
-
export function
|
|
184
|
+
export function evaluateNativeApprovalCapability({ staticCapability, runtimeCapability } = {}) {
|
|
185
|
+
const staticValue = staticCapability?.approvalValueTransport;
|
|
186
|
+
const runtimeValue = runtimeCapability?.approvalValueTransport;
|
|
187
|
+
if (runtimeCapability && staticCapability && (runtimeValue !== staticValue || runtimeCapability.waitSafety !== staticCapability.waitSafety)) {
|
|
188
|
+
return Object.freeze({ eligible: false, native_attempt_required: false, preflight_outcome: "unavailable_before_invocation", reason: "capability_conflict", evidence_source: "runtime" });
|
|
189
|
+
}
|
|
190
|
+
const capability = runtimeCapability ?? staticCapability;
|
|
191
|
+
const evidenceSource = runtimeCapability ? "runtime" : staticCapability ? "static" : "none";
|
|
192
|
+
if (!capability || !APPROVAL_VALUE_TRANSPORTS.has(capability.approvalValueTransport)) return Object.freeze({ eligible: false, native_attempt_required: false, preflight_outcome: "unavailable_before_invocation", reason: "capability_missing", evidence_source: evidenceSource });
|
|
193
|
+
if (capability.waitSafety === "unsafe") return Object.freeze({ eligible: false, native_attempt_required: false, preflight_outcome: "unsafe_to_wait", reason: "unsafe_wait", evidence_source: evidenceSource });
|
|
194
|
+
if (capability.waitSafety !== "deliberate_no_auto_resolution") return Object.freeze({ eligible: false, native_attempt_required: false, preflight_outcome: "unavailable_before_invocation", reason: "capability_missing", evidence_source: evidenceSource });
|
|
195
|
+
if (!new Set(["exact_option_value", "separate_label_and_value"]).has(capability.approvalValueTransport)) return Object.freeze({ eligible: false, native_attempt_required: false, preflight_outcome: "unavailable_before_invocation", reason: capability.approvalValueTransport === "decorated_label_only" ? "decorated_only" : "capability_missing", evidence_source: evidenceSource });
|
|
196
|
+
return Object.freeze({ eligible: true, native_attempt_required: true, preflight_outcome: "eligible_for_invocation", reason: capability.approvalValueTransport === "exact_option_value" ? "exact_transport" : "separate_value_transport", evidence_source: evidenceSource });
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export function executeNativeApprovalAttempt({ ready = false, orientationSnapshot, capabilityPreflight, invokeNative, fallback } = {}) {
|
|
184
200
|
if (!ready) return Object.freeze({ attempted: false, outcome: "unavailable_before_invocation", reason: "gate_not_ready", authorizes: false });
|
|
185
201
|
const preflight = validateApprovalOrientationSnapshot(orientationSnapshot);
|
|
186
202
|
if (!preflight.valid) return Object.freeze({ attempted: false, outcome: "unavailable_before_invocation", reason: "orientation_preflight_failed", authorizes: false });
|
|
203
|
+
if (!capabilityPreflight?.eligible) {
|
|
204
|
+
const outcome = capabilityPreflight?.preflight_outcome === "unsafe_to_wait" ? "unsafe_to_wait" : "unavailable_before_invocation";
|
|
205
|
+
const reason = capabilityPreflight?.reason || "capability_missing";
|
|
206
|
+
if (typeof fallback === "function") fallback({ outcome, reason });
|
|
207
|
+
return Object.freeze({ attempted: false, outcome, reason, authorizes: false });
|
|
208
|
+
}
|
|
187
209
|
if (typeof invokeNative !== "function") return Object.freeze({ attempted: false, outcome: "unavailable_before_invocation", reason: "adapter_unavailable", authorizes: false });
|
|
188
210
|
let adapterResult;
|
|
189
211
|
try {
|
|
@@ -395,6 +417,66 @@ export function buildQualityReadiness({
|
|
|
395
417
|
});
|
|
396
418
|
}
|
|
397
419
|
|
|
420
|
+
export function collapseInternalState(
|
|
421
|
+
{ modeSliceDecision = "", verifiedChangeState = "", contextGraphRequiredAction = "", multiScopeState = "" } = {},
|
|
422
|
+
registry,
|
|
423
|
+
requestedLocale,
|
|
424
|
+
) {
|
|
425
|
+
const pack = localePack(registry, requestedLocale);
|
|
426
|
+
const labels = pack.internalStateLabels || {};
|
|
427
|
+
const result = {};
|
|
428
|
+
if (modeSliceDecision === "verified_change") {
|
|
429
|
+
if (verifiedChangeState === "escalated") {
|
|
430
|
+
result.verified_change = labels.verifiedChangeEscalated || "Escalated to structured delivery";
|
|
431
|
+
} else if (["missing", "draft", "invalid", "eligible", "executed"].includes(verifiedChangeState)) {
|
|
432
|
+
result.verified_change = labels.verifiedChange || "Compact change under review";
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
if (contextGraphRequiredAction === "open_gap") {
|
|
436
|
+
result.context_graph = labels.contextGraphOpenGap || "Graph gap open";
|
|
437
|
+
} else if (["link", "update", "create", "resolve_drift"].includes(contextGraphRequiredAction)) {
|
|
438
|
+
result.context_graph = labels.contextGraphMaintained || "Project memory maintained";
|
|
439
|
+
}
|
|
440
|
+
if (multiScopeState === "blocked") {
|
|
441
|
+
result.multi_scope = labels.multiScopeBlocked || "Ambiguous scope, clarification needed";
|
|
442
|
+
}
|
|
443
|
+
return result;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
export function buildBreadcrumb(breadcrumb, registry, requestedLocale) {
|
|
447
|
+
if (!Array.isArray(breadcrumb)) return "";
|
|
448
|
+
const pack = localePack(registry, requestedLocale);
|
|
449
|
+
const cardLabels = pack.statusCard || {};
|
|
450
|
+
const titles = pack.gateTitles || {};
|
|
451
|
+
const sep = cardLabels.breadcrumbSeparator || " \u00b7 ";
|
|
452
|
+
const symbols = {
|
|
453
|
+
fulfilled: cardLabels.breadcrumbFulfilled || "\u2713",
|
|
454
|
+
current: cardLabels.breadcrumbCurrent || "\u25cf",
|
|
455
|
+
open: cardLabels.breadcrumbOpen || "\u25cb",
|
|
456
|
+
};
|
|
457
|
+
return breadcrumb
|
|
458
|
+
.map((entry) => {
|
|
459
|
+
const title = titles[entry.gate] || entry.gate;
|
|
460
|
+
const symbol = symbols[entry.status] || symbols.open;
|
|
461
|
+
return `${title} ${symbol}`;
|
|
462
|
+
})
|
|
463
|
+
.join(sep);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
export function buildTransitionNarration(gate, registry, requestedLocale) {
|
|
467
|
+
const pack = localePack(registry, requestedLocale);
|
|
468
|
+
const narration = pack.primary?.narration || {};
|
|
469
|
+
const gateTitles = pack.gateTitles || {};
|
|
470
|
+
const gateTitle = gateTitles[gate] || gate;
|
|
471
|
+
const gateConfig = narration.gates?.[gate] || {};
|
|
472
|
+
const agentNext = gateConfig.agentNext || "";
|
|
473
|
+
const userAction = gateConfig.userAction || narration.noAction || "no user action required now";
|
|
474
|
+
if (!agentNext) return "";
|
|
475
|
+
const gateSatisfiedTemplate = narration.gateSatisfied || "{gate} approved";
|
|
476
|
+
const gateSatisfied = gateSatisfiedTemplate.replace("{gate}", gateTitle);
|
|
477
|
+
return `${gateSatisfied} \u2192 ${agentNext} \u2192 ${userAction}`;
|
|
478
|
+
}
|
|
479
|
+
|
|
398
480
|
export const interactionPresentationConstants = Object.freeze({
|
|
399
481
|
artefactOrder: Object.freeze([...ARTEFACT_ORDER]),
|
|
400
482
|
outcomes: Object.freeze([...OUTCOMES]),
|
package/package.json
CHANGED