create-agdf 0.8.4 → 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 +22 -9
- package/generated/.github/skills/agdf-interaction-locales.json +74 -4
- package/generated/.github/skills/agdf-release-or/SKILL.md +4 -3
- package/generated/.github/skills/agdf-runtime-contract.md +79 -8
- package/generated/.opencode/agdf-interaction-locales.json +74 -4
- package/generated/.opencode/agdf-runtime-contract.md +79 -8
- package/generated/.opencode/skills/agdf-brownfield-analysis/SKILL.md +3 -3
- package/generated/.opencode/skills/agdf-gate-check/SKILL.md +22 -9
- 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 +74 -4
- package/generated/plugins/agdf/meta/agdf-plugin.definition.json +13 -1
- package/generated/plugins/agdf/meta/agdf-runtime-contract.md +79 -8
- package/generated/plugins/agdf/skills/brownfield-analysis/SKILL.md +3 -3
- package/generated/plugins/agdf/skills/gate-check/SKILL.md +22 -9
- 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 +118 -4
- package/package.json +1 -1
|
@@ -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,13 +64,14 @@ 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}`);
|
|
70
71
|
}
|
|
71
72
|
for (const key of REQUIRED_GATES) {
|
|
72
73
|
if (typeof pack.gateTitles?.[key] !== "string" || !pack.gateTitles[key].trim()) errors.push(`missing_gate_title:${locale}:${key}`);
|
|
74
|
+
if (typeof pack.gateActionTitles?.[key] !== "string" || !pack.gateActionTitles[key].trim()) errors.push(`missing_gate_action_title:${locale}:${key}`);
|
|
73
75
|
}
|
|
74
76
|
}
|
|
75
77
|
if (JSON.stringify(registry?.optionOrder) !== JSON.stringify(["approve", "revise", "decline", "cancel"])) errors.push("option_order");
|
|
@@ -179,8 +181,31 @@ export function reconcileRunScope({ requestText = "", scopeKey = "", runs = [] }
|
|
|
179
181
|
return Object.freeze({ outcome: matches[0].lifecycle === "active" ? "active_match" : "completed_match", matches, reason: "exact_match" });
|
|
180
182
|
}
|
|
181
183
|
|
|
182
|
-
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 } = {}) {
|
|
183
200
|
if (!ready) return Object.freeze({ attempted: false, outcome: "unavailable_before_invocation", reason: "gate_not_ready", authorizes: false });
|
|
201
|
+
const preflight = validateApprovalOrientationSnapshot(orientationSnapshot);
|
|
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
|
+
}
|
|
184
209
|
if (typeof invokeNative !== "function") return Object.freeze({ attempted: false, outcome: "unavailable_before_invocation", reason: "adapter_unavailable", authorizes: false });
|
|
185
210
|
let adapterResult;
|
|
186
211
|
try {
|
|
@@ -280,6 +305,7 @@ export function buildApprovalOrientationSnapshot({
|
|
|
280
305
|
const pack = localePack(registry, locale);
|
|
281
306
|
const runTitle = String(humanPresentation.runTitle ?? "").trim() || normalizedRunTitle(runId);
|
|
282
307
|
const currentGateTitle = String(humanPresentation.gateTitle ?? "").trim() || gateTitle(registry, locale, gate);
|
|
308
|
+
const primaryHeading = String(pack.gateActionTitles?.[gate] ?? "").trim();
|
|
283
309
|
const artefactRefs = Object.freeze([...(humanPresentation.artefactRefs ?? [])].map((ref) => Object.freeze({ ...ref })));
|
|
284
310
|
const statusFields = Object.freeze([
|
|
285
311
|
Object.freeze({ id: "selected_run", label: pack.statusCard.run, value: `${runTitle} · ${runId}` }),
|
|
@@ -298,8 +324,15 @@ export function buildApprovalOrientationSnapshot({
|
|
|
298
324
|
current_gate: gate,
|
|
299
325
|
presentation_language: locale,
|
|
300
326
|
sequence: APPROVAL_SEQUENCE,
|
|
301
|
-
compact_status_card: Object.freeze({
|
|
327
|
+
compact_status_card: Object.freeze({
|
|
328
|
+
semantic_block: "run_status_card",
|
|
329
|
+
title: primaryHeading,
|
|
330
|
+
primary_heading: primaryHeading,
|
|
331
|
+
primary_heading_level: 2,
|
|
332
|
+
fields: statusFields,
|
|
333
|
+
}),
|
|
302
334
|
gate_transition_card: Object.freeze({
|
|
335
|
+
semantic_block: "gate_transition_card",
|
|
303
336
|
title: `${currentGateTitle} · ${runTitle} · ${runId}`,
|
|
304
337
|
artefact_refs: artefactRefs,
|
|
305
338
|
ready: pack.interaction.ready,
|
|
@@ -309,11 +342,32 @@ export function buildApprovalOrientationSnapshot({
|
|
|
309
342
|
next_heading: pack.interaction.nextHeading,
|
|
310
343
|
next_gate: String(statusCard.next_gate_after_approval ?? "none"),
|
|
311
344
|
}),
|
|
312
|
-
approval_interaction: Object.freeze({ expected_approval: expectedApproval, options, authorizes: false }),
|
|
345
|
+
approval_interaction: Object.freeze({ semantic_block: "approval_interaction", expected_approval: expectedApproval, options, authorizes: false }),
|
|
313
346
|
authorizes: false,
|
|
314
347
|
});
|
|
315
348
|
}
|
|
316
349
|
|
|
350
|
+
export function validateApprovalOrientationSnapshot(snapshot) {
|
|
351
|
+
const errors = [];
|
|
352
|
+
if (!plainObject(snapshot)) return Object.freeze({ valid: false, errors: Object.freeze(["snapshot_missing"]) });
|
|
353
|
+
if (JSON.stringify(snapshot.sequence) !== JSON.stringify(APPROVAL_SEQUENCE)) errors.push("sequence");
|
|
354
|
+
if (snapshot.compact_status_card?.semantic_block !== "run_status_card") errors.push("run_status_card");
|
|
355
|
+
if (snapshot.gate_transition_card?.semantic_block !== "gate_transition_card") errors.push("gate_transition_card");
|
|
356
|
+
if (snapshot.approval_interaction?.semantic_block !== "approval_interaction") errors.push("approval_interaction");
|
|
357
|
+
const heading = String(snapshot.compact_status_card?.primary_heading ?? "").trim();
|
|
358
|
+
if (!heading || snapshot.compact_status_card?.primary_heading_level !== 2) errors.push("primary_heading");
|
|
359
|
+
if (String(snapshot.compact_status_card?.title ?? "").trim() !== heading) errors.push("primary_heading_owner");
|
|
360
|
+
if (/^(?:(?:agdf[- ]?status(?: card|karte)?|run status card|gate transition card)(?:\b|\s*[-:—·])|(?:UR|PRD|SD|TP|QA|UAT)(?:\s*[-:—·]|$))/i.test(heading)) errors.push("generic_primary_heading");
|
|
361
|
+
const fieldIds = snapshot.compact_status_card?.fields?.map((field) => field?.id);
|
|
362
|
+
if (JSON.stringify(fieldIds) !== JSON.stringify(["selected_run", "readiness_status", "current_gate", "missing_approval", "next_action", "quality_outlook"])) errors.push("status_fields");
|
|
363
|
+
const expectedApproval = `Approval: ${String(snapshot.current_gate ?? "").trim()}`;
|
|
364
|
+
if (!REQUIRED_GATES.includes(snapshot.current_gate)
|
|
365
|
+
|| snapshot.gate_transition_card?.exact_approval !== expectedApproval
|
|
366
|
+
|| snapshot.approval_interaction?.expected_approval !== expectedApproval
|
|
367
|
+
|| snapshot.approval_interaction?.options?.[0]?.value !== expectedApproval) errors.push("canonical_approval");
|
|
368
|
+
return Object.freeze({ valid: errors.length === 0, errors: Object.freeze(errors) });
|
|
369
|
+
}
|
|
370
|
+
|
|
317
371
|
export function attachApprovalOrientationSnapshot(statusCard, options = {}) {
|
|
318
372
|
if (!plainObject(statusCard)) throw new Error("approval orientation status card missing");
|
|
319
373
|
const snapshot = buildApprovalOrientationSnapshot({ ...options, statusCard });
|
|
@@ -363,6 +417,66 @@ export function buildQualityReadiness({
|
|
|
363
417
|
});
|
|
364
418
|
}
|
|
365
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
|
+
|
|
366
480
|
export const interactionPresentationConstants = Object.freeze({
|
|
367
481
|
artefactOrder: Object.freeze([...ARTEFACT_ORDER]),
|
|
368
482
|
outcomes: Object.freeze([...OUTCOMES]),
|
package/package.json
CHANGED