create-agdf 0.8.3 → 0.8.4
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 +9 -0
- package/generated/.github/skills/agdf-gate-check/SKILL.md +6 -0
- package/generated/.github/skills/agdf-interaction-locales.json +16 -0
- package/generated/.github/skills/agdf-runtime-contract.md +7 -0
- package/generated/.opencode/agdf-interaction-locales.json +16 -0
- package/generated/.opencode/agdf-runtime-contract.md +7 -0
- package/generated/.opencode/skills/agdf-gate-check/SKILL.md +6 -0
- package/generated/plugins/agdf/.codex-plugin/plugin.json +1 -1
- package/generated/plugins/agdf/meta/agdf-interaction-locales.json +16 -0
- package/generated/plugins/agdf/meta/agdf-plugin.definition.json +1 -1
- package/generated/plugins/agdf/meta/agdf-runtime-contract.md +7 -0
- package/generated/plugins/agdf/skills/gate-check/SKILL.md +6 -0
- package/lib/interaction-presentation.js +51 -0
- package/package.json +1 -1
package/bin/create-agdf.js
CHANGED
|
@@ -2259,10 +2259,14 @@ function buildStatusCard({
|
|
|
2259
2259
|
const qualityOutlook = deriveQualityOutlook(runState, findings);
|
|
2260
2260
|
const postApproval = postApprovalTransition(missingApproval);
|
|
2261
2261
|
const isUserGateApproval = missingApproval !== "none";
|
|
2262
|
+
const lifecycle = extractField(runState.content ?? "", "lifecycle") || "unknown";
|
|
2263
|
+
const nativeAttemptRequired = status === "open" && isUserGateApproval;
|
|
2262
2264
|
return {
|
|
2263
2265
|
run_id: extractField(runState.content ?? "", "run_id") || "unknown",
|
|
2264
2266
|
presentation_language: chatLanguage,
|
|
2265
2267
|
mode: extractField(runState.content ?? "", "mode") || "unknown",
|
|
2268
|
+
lifecycle,
|
|
2269
|
+
delivery_state: lifecycle === "completed" && currentGate === "OR" ? "completed_closeout_pending" : lifecycle,
|
|
2266
2270
|
status,
|
|
2267
2271
|
current_gate: currentGate,
|
|
2268
2272
|
mode_slice_decision: runState.mode_slice_decision?.decision || "undecided",
|
|
@@ -2280,6 +2284,8 @@ function buildStatusCard({
|
|
|
2280
2284
|
next_skill: nextSkillByGate[currentGate] ?? "gate-check",
|
|
2281
2285
|
next_step: nextAllowedAction,
|
|
2282
2286
|
quality_outlook: qualityOutlook,
|
|
2287
|
+
interaction_kind: nativeAttemptRequired ? "gate_approval" : status === "blocked" ? "blocked" : "status",
|
|
2288
|
+
native_attempt_required: nativeAttemptRequired,
|
|
2283
2289
|
};
|
|
2284
2290
|
}
|
|
2285
2291
|
|
|
@@ -2736,6 +2742,8 @@ function evaluateGateCheck(targetDir, selection = {}) {
|
|
|
2736
2742
|
doctor_summary: doctorReport.summary,
|
|
2737
2743
|
evidence_refs: runState.evidence_refs,
|
|
2738
2744
|
quality_outlook: deriveQualityOutlook(runState, deliveryMap.findings),
|
|
2745
|
+
interaction_kind: statusCard.interaction_kind,
|
|
2746
|
+
native_attempt_required: statusCard.native_attempt_required,
|
|
2739
2747
|
candidate_runs: runState.candidate_runs ?? [],
|
|
2740
2748
|
status_card: statusCard,
|
|
2741
2749
|
delivery_map: {
|
|
@@ -2764,6 +2772,7 @@ function printGateCheckStatusCard(report) {
|
|
|
2764
2772
|
console.log(`${labels.run}: ${card.run_id}`);
|
|
2765
2773
|
console.log(`${labels.humanTitle}: ${presentation.runTitle}`);
|
|
2766
2774
|
console.log(`${labels.gate}: ${card.current_gate} — ${presentation.gateTitle}`);
|
|
2775
|
+
console.log(`${labels.lifecycle}: ${primary.lifecycle[card.delivery_state] ?? primary.lifecycle.unknown}`);
|
|
2767
2776
|
console.log(`${labels.artefacts}: ${formatArtefactRefs(presentation.artefactRefs)}`);
|
|
2768
2777
|
console.log(`${labels.blocked}: ${card.blocking_condition === "none" ? primary.none : primary.blocked}`);
|
|
2769
2778
|
console.log(`${labels.missing}: ${card.missing_approval === "none" ? primary.none : card.missing_approval}`);
|
|
@@ -75,6 +75,12 @@ 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
|
+
The ready-gate projection must expose `native_attempt_required: true`. Treat this as a mandatory
|
|
79
|
+
orchestration instruction: after rendering the two cards, invoke the configured native question
|
|
80
|
+
adapter exactly once before using the exact-text fallback. A hook, permission result or session
|
|
81
|
+
context message cannot replace that attempt or supply its answer. For every non-ready interaction,
|
|
82
|
+
the signal is absent or false and no approval control may be shown.
|
|
83
|
+
|
|
78
84
|
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.
|
|
79
85
|
|
|
80
86
|
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.
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"skill": "Next skill",
|
|
26
26
|
"step": "Next step",
|
|
27
27
|
"quality": "Quality outlook",
|
|
28
|
+
"lifecycle": "Delivery status",
|
|
28
29
|
"allowed": "Allowed now",
|
|
29
30
|
"forbidden": "Forbidden now",
|
|
30
31
|
"artefacts": "Artefacts"
|
|
@@ -91,6 +92,13 @@
|
|
|
91
92
|
"none": "none",
|
|
92
93
|
"blocked": "current gate prerequisites",
|
|
93
94
|
"quality": "Keep the presentation contract, evidence and gate authority aligned.",
|
|
95
|
+
"lifecycle": {
|
|
96
|
+
"active": "in progress",
|
|
97
|
+
"completed_closeout_pending": "completed — delivery closeout pending",
|
|
98
|
+
"completed": "completed",
|
|
99
|
+
"blocked": "blocked",
|
|
100
|
+
"unknown": "status not available"
|
|
101
|
+
},
|
|
94
102
|
"actions": {
|
|
95
103
|
"UR": "Clarify and approve the user requirements.",
|
|
96
104
|
"Brownfield Review": "Review existing owners and choose the smallest safe delivery path.",
|
|
@@ -132,6 +140,7 @@
|
|
|
132
140
|
"skill": "Nächster Skill",
|
|
133
141
|
"step": "Nächster Schritt",
|
|
134
142
|
"quality": "Qualitätsausblick",
|
|
143
|
+
"lifecycle": "Lieferstatus",
|
|
135
144
|
"allowed": "Jetzt erlaubt",
|
|
136
145
|
"forbidden": "Aktuell verboten",
|
|
137
146
|
"artefacts": "Artefakte"
|
|
@@ -198,6 +207,13 @@
|
|
|
198
207
|
"none": "keine",
|
|
199
208
|
"blocked": "Voraussetzungen des aktuellen Gates",
|
|
200
209
|
"quality": "Präsentationsvertrag, Nachweise und Gate-Berechtigung konsistent halten.",
|
|
210
|
+
"lifecycle": {
|
|
211
|
+
"active": "in Arbeit",
|
|
212
|
+
"completed_closeout_pending": "abgeschlossen — Abschluss offen",
|
|
213
|
+
"completed": "abgeschlossen",
|
|
214
|
+
"blocked": "blockiert",
|
|
215
|
+
"unknown": "Status nicht verfügbar"
|
|
216
|
+
},
|
|
201
217
|
"actions": {
|
|
202
218
|
"UR": "Nutzeranforderungen klären und freigeben.",
|
|
203
219
|
"Brownfield Review": "Bestehende Owner prüfen und den kleinsten sicheren Lieferweg wählen.",
|
|
@@ -390,6 +390,7 @@ interaction_kind: clarification | tool_permission | gate_approval | blocked | st
|
|
|
390
390
|
surface: codex | claude | opencode | fallback
|
|
391
391
|
run_id: required for gate_approval
|
|
392
392
|
current_gate: required for gate_approval
|
|
393
|
+
native_attempt_required: true only for an eligible gate_approval before the first adapter attempt
|
|
393
394
|
prompt: required
|
|
394
395
|
options: required for a structured question
|
|
395
396
|
effects: required when the interaction can cause side effects
|
|
@@ -420,6 +421,12 @@ Before presenting `gate_approval`, the agent must:
|
|
|
420
421
|
6. reject missing evidence, ambiguous or wrong run, wrong gate, stale state and any response that is no longer valid;
|
|
421
422
|
7. persist an accepted approval only through the existing control-state workflow.
|
|
422
423
|
|
|
424
|
+
For an eligible `gate_approval`, `native_attempt_required` is a mandatory orchestration signal. The
|
|
425
|
+
agent must make exactly one configured native adapter attempt after the two orientation cards and
|
|
426
|
+
before any exact-text fallback. Hooks may prepare context but must not answer, approve or replace
|
|
427
|
+
the adapter attempt. The signal is absent or false for clarification, blocked, status-only,
|
|
428
|
+
internal-step and non-ready interactions.
|
|
429
|
+
|
|
423
430
|
The first eligible native-attempt has a single bounded outcome: the declared
|
|
424
431
|
host control is presented, or the agent immediately uses the exact-text
|
|
425
432
|
fallback. A host that does not apply the control does not trigger a second
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"skill": "Next skill",
|
|
26
26
|
"step": "Next step",
|
|
27
27
|
"quality": "Quality outlook",
|
|
28
|
+
"lifecycle": "Delivery status",
|
|
28
29
|
"allowed": "Allowed now",
|
|
29
30
|
"forbidden": "Forbidden now",
|
|
30
31
|
"artefacts": "Artefacts"
|
|
@@ -91,6 +92,13 @@
|
|
|
91
92
|
"none": "none",
|
|
92
93
|
"blocked": "current gate prerequisites",
|
|
93
94
|
"quality": "Keep the presentation contract, evidence and gate authority aligned.",
|
|
95
|
+
"lifecycle": {
|
|
96
|
+
"active": "in progress",
|
|
97
|
+
"completed_closeout_pending": "completed — delivery closeout pending",
|
|
98
|
+
"completed": "completed",
|
|
99
|
+
"blocked": "blocked",
|
|
100
|
+
"unknown": "status not available"
|
|
101
|
+
},
|
|
94
102
|
"actions": {
|
|
95
103
|
"UR": "Clarify and approve the user requirements.",
|
|
96
104
|
"Brownfield Review": "Review existing owners and choose the smallest safe delivery path.",
|
|
@@ -132,6 +140,7 @@
|
|
|
132
140
|
"skill": "Nächster Skill",
|
|
133
141
|
"step": "Nächster Schritt",
|
|
134
142
|
"quality": "Qualitätsausblick",
|
|
143
|
+
"lifecycle": "Lieferstatus",
|
|
135
144
|
"allowed": "Jetzt erlaubt",
|
|
136
145
|
"forbidden": "Aktuell verboten",
|
|
137
146
|
"artefacts": "Artefakte"
|
|
@@ -198,6 +207,13 @@
|
|
|
198
207
|
"none": "keine",
|
|
199
208
|
"blocked": "Voraussetzungen des aktuellen Gates",
|
|
200
209
|
"quality": "Präsentationsvertrag, Nachweise und Gate-Berechtigung konsistent halten.",
|
|
210
|
+
"lifecycle": {
|
|
211
|
+
"active": "in Arbeit",
|
|
212
|
+
"completed_closeout_pending": "abgeschlossen — Abschluss offen",
|
|
213
|
+
"completed": "abgeschlossen",
|
|
214
|
+
"blocked": "blockiert",
|
|
215
|
+
"unknown": "Status nicht verfügbar"
|
|
216
|
+
},
|
|
201
217
|
"actions": {
|
|
202
218
|
"UR": "Nutzeranforderungen klären und freigeben.",
|
|
203
219
|
"Brownfield Review": "Bestehende Owner prüfen und den kleinsten sicheren Lieferweg wählen.",
|
|
@@ -390,6 +390,7 @@ interaction_kind: clarification | tool_permission | gate_approval | blocked | st
|
|
|
390
390
|
surface: codex | claude | opencode | fallback
|
|
391
391
|
run_id: required for gate_approval
|
|
392
392
|
current_gate: required for gate_approval
|
|
393
|
+
native_attempt_required: true only for an eligible gate_approval before the first adapter attempt
|
|
393
394
|
prompt: required
|
|
394
395
|
options: required for a structured question
|
|
395
396
|
effects: required when the interaction can cause side effects
|
|
@@ -420,6 +421,12 @@ Before presenting `gate_approval`, the agent must:
|
|
|
420
421
|
6. reject missing evidence, ambiguous or wrong run, wrong gate, stale state and any response that is no longer valid;
|
|
421
422
|
7. persist an accepted approval only through the existing control-state workflow.
|
|
422
423
|
|
|
424
|
+
For an eligible `gate_approval`, `native_attempt_required` is a mandatory orchestration signal. The
|
|
425
|
+
agent must make exactly one configured native adapter attempt after the two orientation cards and
|
|
426
|
+
before any exact-text fallback. Hooks may prepare context but must not answer, approve or replace
|
|
427
|
+
the adapter attempt. The signal is absent or false for clarification, blocked, status-only,
|
|
428
|
+
internal-step and non-ready interactions.
|
|
429
|
+
|
|
423
430
|
The first eligible native-attempt has a single bounded outcome: the declared
|
|
424
431
|
host control is presented, or the agent immediately uses the exact-text
|
|
425
432
|
fallback. A host that does not apply the control does not trigger a second
|
|
@@ -75,6 +75,12 @@ 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
|
+
The ready-gate projection must expose `native_attempt_required: true`. Treat this as a mandatory
|
|
79
|
+
orchestration instruction: after rendering the two cards, invoke the configured native question
|
|
80
|
+
adapter exactly once before using the exact-text fallback. A hook, permission result or session
|
|
81
|
+
context message cannot replace that attempt or supply its answer. For every non-ready interaction,
|
|
82
|
+
the signal is absent or false and no approval control may be shown.
|
|
83
|
+
|
|
78
84
|
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.
|
|
79
85
|
|
|
80
86
|
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.
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"skill": "Next skill",
|
|
26
26
|
"step": "Next step",
|
|
27
27
|
"quality": "Quality outlook",
|
|
28
|
+
"lifecycle": "Delivery status",
|
|
28
29
|
"allowed": "Allowed now",
|
|
29
30
|
"forbidden": "Forbidden now",
|
|
30
31
|
"artefacts": "Artefacts"
|
|
@@ -91,6 +92,13 @@
|
|
|
91
92
|
"none": "none",
|
|
92
93
|
"blocked": "current gate prerequisites",
|
|
93
94
|
"quality": "Keep the presentation contract, evidence and gate authority aligned.",
|
|
95
|
+
"lifecycle": {
|
|
96
|
+
"active": "in progress",
|
|
97
|
+
"completed_closeout_pending": "completed — delivery closeout pending",
|
|
98
|
+
"completed": "completed",
|
|
99
|
+
"blocked": "blocked",
|
|
100
|
+
"unknown": "status not available"
|
|
101
|
+
},
|
|
94
102
|
"actions": {
|
|
95
103
|
"UR": "Clarify and approve the user requirements.",
|
|
96
104
|
"Brownfield Review": "Review existing owners and choose the smallest safe delivery path.",
|
|
@@ -132,6 +140,7 @@
|
|
|
132
140
|
"skill": "Nächster Skill",
|
|
133
141
|
"step": "Nächster Schritt",
|
|
134
142
|
"quality": "Qualitätsausblick",
|
|
143
|
+
"lifecycle": "Lieferstatus",
|
|
135
144
|
"allowed": "Jetzt erlaubt",
|
|
136
145
|
"forbidden": "Aktuell verboten",
|
|
137
146
|
"artefacts": "Artefakte"
|
|
@@ -198,6 +207,13 @@
|
|
|
198
207
|
"none": "keine",
|
|
199
208
|
"blocked": "Voraussetzungen des aktuellen Gates",
|
|
200
209
|
"quality": "Präsentationsvertrag, Nachweise und Gate-Berechtigung konsistent halten.",
|
|
210
|
+
"lifecycle": {
|
|
211
|
+
"active": "in Arbeit",
|
|
212
|
+
"completed_closeout_pending": "abgeschlossen — Abschluss offen",
|
|
213
|
+
"completed": "abgeschlossen",
|
|
214
|
+
"blocked": "blockiert",
|
|
215
|
+
"unknown": "Status nicht verfügbar"
|
|
216
|
+
},
|
|
201
217
|
"actions": {
|
|
202
218
|
"UR": "Nutzeranforderungen klären und freigeben.",
|
|
203
219
|
"Brownfield Review": "Bestehende Owner prüfen und den kleinsten sicheren Lieferweg wählen.",
|
|
@@ -390,6 +390,7 @@ interaction_kind: clarification | tool_permission | gate_approval | blocked | st
|
|
|
390
390
|
surface: codex | claude | opencode | fallback
|
|
391
391
|
run_id: required for gate_approval
|
|
392
392
|
current_gate: required for gate_approval
|
|
393
|
+
native_attempt_required: true only for an eligible gate_approval before the first adapter attempt
|
|
393
394
|
prompt: required
|
|
394
395
|
options: required for a structured question
|
|
395
396
|
effects: required when the interaction can cause side effects
|
|
@@ -420,6 +421,12 @@ Before presenting `gate_approval`, the agent must:
|
|
|
420
421
|
6. reject missing evidence, ambiguous or wrong run, wrong gate, stale state and any response that is no longer valid;
|
|
421
422
|
7. persist an accepted approval only through the existing control-state workflow.
|
|
422
423
|
|
|
424
|
+
For an eligible `gate_approval`, `native_attempt_required` is a mandatory orchestration signal. The
|
|
425
|
+
agent must make exactly one configured native adapter attempt after the two orientation cards and
|
|
426
|
+
before any exact-text fallback. Hooks may prepare context but must not answer, approve or replace
|
|
427
|
+
the adapter attempt. The signal is absent or false for clarification, blocked, status-only,
|
|
428
|
+
internal-step and non-ready interactions.
|
|
429
|
+
|
|
423
430
|
The first eligible native-attempt has a single bounded outcome: the declared
|
|
424
431
|
host control is presented, or the agent immediately uses the exact-text
|
|
425
432
|
fallback. A host that does not apply the control does not trigger a second
|
|
@@ -75,6 +75,12 @@ 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
|
+
The ready-gate projection must expose `native_attempt_required: true`. Treat this as a mandatory
|
|
79
|
+
orchestration instruction: after rendering the two cards, invoke the configured native question
|
|
80
|
+
adapter exactly once before using the exact-text fallback. A hook, permission result or session
|
|
81
|
+
context message cannot replace that attempt or supply its answer. For every non-ready interaction,
|
|
82
|
+
the signal is absent or false and no approval control may be shown.
|
|
83
|
+
|
|
78
84
|
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.
|
|
79
85
|
|
|
80
86
|
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.
|
|
@@ -147,6 +147,57 @@ export function buildRunCandidates(runs) {
|
|
|
147
147
|
.sort((left, right) => left.display_title.localeCompare(right.display_title) || left.run_id.localeCompare(right.run_id));
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
export function normalizeReconciliationText(value) {
|
|
151
|
+
return String(value ?? "")
|
|
152
|
+
.normalize("NFKC")
|
|
153
|
+
.toLowerCase()
|
|
154
|
+
.replace(/[._:/\\-]+/g, " ")
|
|
155
|
+
.replace(/[^\p{L}\p{N}\s]+/gu, " ")
|
|
156
|
+
.replace(/\s+/g, " ")
|
|
157
|
+
.trim();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function reconcileRunScope({ requestText = "", scopeKey = "", runs = [] } = {}) {
|
|
161
|
+
const requested = normalizeReconciliationText(scopeKey || requestText);
|
|
162
|
+
if (!requested) return Object.freeze({ outcome: "match_uncertain", matches: [], reason: "scope_input_missing" });
|
|
163
|
+
const matches = [...(runs ?? [])]
|
|
164
|
+
.filter((run) => run?.valid && ["active", "completed"].includes(run?.meta?.lifecycle) && typeof run.run_id === "string")
|
|
165
|
+
.filter((run) => {
|
|
166
|
+
const keys = [run.scope_key, run.display_title, run.current_artefact_heading, run.ur_heading]
|
|
167
|
+
.map(normalizeReconciliationText)
|
|
168
|
+
.filter(Boolean);
|
|
169
|
+
return keys.includes(requested);
|
|
170
|
+
})
|
|
171
|
+
.map((run) => Object.freeze({
|
|
172
|
+
run_id: run.run_id,
|
|
173
|
+
lifecycle: run.meta.lifecycle,
|
|
174
|
+
display_title: displaySafeTitle(run.display_title || run.ur_heading || run.run_id, normalizedRunTitle(run.run_id)),
|
|
175
|
+
current_gate: run.control_state?.current_gate || run.meta?.current_gate || "unknown",
|
|
176
|
+
}))
|
|
177
|
+
.sort((left, right) => left.run_id.localeCompare(right.run_id));
|
|
178
|
+
if (matches.length !== 1) return Object.freeze({ outcome: matches.length ? "match_uncertain" : "no_match", matches, reason: matches.length > 1 ? "multiple_exact_matches" : "no_exact_match" });
|
|
179
|
+
return Object.freeze({ outcome: matches[0].lifecycle === "active" ? "active_match" : "completed_match", matches, reason: "exact_match" });
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export function executeNativeApprovalAttempt({ ready = false, invokeNative, fallback } = {}) {
|
|
183
|
+
if (!ready) return Object.freeze({ attempted: false, outcome: "unavailable_before_invocation", reason: "gate_not_ready", authorizes: false });
|
|
184
|
+
if (typeof invokeNative !== "function") return Object.freeze({ attempted: false, outcome: "unavailable_before_invocation", reason: "adapter_unavailable", authorizes: false });
|
|
185
|
+
let adapterResult;
|
|
186
|
+
try {
|
|
187
|
+
adapterResult = invokeNative();
|
|
188
|
+
} catch (error) {
|
|
189
|
+
adapterResult = { outcome: "attempted_not_applied", reason: String(error?.message || "adapter_error") };
|
|
190
|
+
}
|
|
191
|
+
const outcome = ATTEMPT_OUTCOMES.has(adapterResult?.outcome)
|
|
192
|
+
? adapterResult.outcome
|
|
193
|
+
: adapterResult?.presented === true || adapterResult?.applied === true
|
|
194
|
+
? "presented"
|
|
195
|
+
: "attempted_not_applied";
|
|
196
|
+
const reason = String(adapterResult?.reason || "").trim();
|
|
197
|
+
if (outcome !== "presented" && typeof fallback === "function") fallback({ outcome, reason });
|
|
198
|
+
return Object.freeze({ attempted: true, outcome, reason, authorizes: false });
|
|
199
|
+
}
|
|
200
|
+
|
|
150
201
|
export function buildInteractionAttempt({ interactionId, runId, currentGate, surface, attemptOutcome, expectedApproval, fallbackReason = "" }) {
|
|
151
202
|
if (!ATTEMPT_OUTCOMES.has(attemptOutcome)) throw new Error("invalid interaction attempt outcome");
|
|
152
203
|
if (!String(interactionId ?? "").trim() || !String(runId ?? "").trim() || !String(currentGate ?? "").trim())
|
package/package.json
CHANGED