create-agdf 0.9.8 → 0.10.0
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/README.md +11 -1
- package/generated/.github/copilot-instructions.md +1 -1
- package/generated/.github/skills/agdf-gate-check/SKILL.md +13 -7
- package/generated/.github/skills/agdf-interaction-locales.json +42 -12
- package/generated/.github/skills/contracts/control-scaffold.md +1 -1
- package/generated/.github/skills/contracts/interaction.md +43 -9
- package/generated/.opencode/README.md +1 -1
- package/generated/.opencode/agdf-interaction-locales.json +42 -12
- package/generated/.opencode/contracts/control-scaffold.md +1 -1
- package/generated/.opencode/contracts/interaction.md +43 -9
- package/generated/.opencode/skills/agdf-gate-check/SKILL.md +13 -7
- package/generated/plugins/agdf/.codex-plugin/plugin.json +1 -1
- package/generated/plugins/agdf/meta/agdf-interaction-locales.json +42 -12
- package/generated/plugins/agdf/meta/agdf-plugin.definition.json +1 -1
- package/generated/plugins/agdf/meta/contracts/control-scaffold.md +1 -1
- package/generated/plugins/agdf/meta/contracts/interaction.md +43 -9
- package/generated/plugins/agdf/skills/gate-check/SKILL.md +13 -7
- package/lib/cli/application.js +8 -0
- package/lib/cli/command-registry.js +19 -1
- package/lib/cli/parse-args.js +3 -0
- package/lib/control-evaluation/gate-check.js +58 -3
- package/lib/interaction-presentation.js +114 -14
- package/package.json +1 -1
|
@@ -63,8 +63,8 @@ export function validateLocaleRegistry(registry) {
|
|
|
63
63
|
if (JSON.stringify(keys) !== JSON.stringify(baseline)) errors.push(`incomplete_locale:${locale}`);
|
|
64
64
|
for (const [key, value] of visibleStrings(pack)) {
|
|
65
65
|
if (!value.trim()) errors.push(`empty_copy:${locale}:${key}`);
|
|
66
|
-
const budget = key.startsWith("gateTitles.") ? budgets.title
|
|
67
|
-
: key.includes("Description") || key.includes("fallbackReasons") || key.startsWith("primary.actions.") || key.startsWith("primary.afterApproval.") || key.startsWith("primary.narration.") || key.startsWith("gateRationale.") || key.startsWith("interaction.why.") ||
|
|
66
|
+
const budget = key.startsWith("gateTitles.") || key.startsWith("gateActionTitles.") ? budgets.title
|
|
67
|
+
: key.includes("Description") || key.includes("fallbackReasons") || key.startsWith("gateRequiredDecisions.") || key.startsWith("primary.actions.") || key.startsWith("primary.afterApproval.") || key.startsWith("primary.narration.") || key.startsWith("gateRationale.") || key.startsWith("interaction.why.") || ["interaction.decisionInstruction", "interaction.decisionPrompt", "interaction.exactTextRequest", "interaction.decisionFollows", "interaction.presentationFailure", "interaction.nonReadyDecision", "primary.quality"].includes(key)
|
|
68
68
|
? budgets.description
|
|
69
69
|
: budgets.label;
|
|
70
70
|
if (Number.isInteger(budget) && value.length > budget) errors.push(`length_budget:${locale}:${key}`);
|
|
@@ -72,6 +72,7 @@ export function validateLocaleRegistry(registry) {
|
|
|
72
72
|
for (const key of REQUIRED_GATES) {
|
|
73
73
|
if (typeof pack.gateTitles?.[key] !== "string" || !pack.gateTitles[key].trim()) errors.push(`missing_gate_title:${locale}:${key}`);
|
|
74
74
|
if (typeof pack.gateActionTitles?.[key] !== "string" || !pack.gateActionTitles[key].trim()) errors.push(`missing_gate_action_title:${locale}:${key}`);
|
|
75
|
+
if (typeof pack.gateRequiredDecisions?.[key] !== "string" || !pack.gateRequiredDecisions[key].trim()) errors.push(`missing_gate_required_decision:${locale}:${key}`);
|
|
75
76
|
}
|
|
76
77
|
}
|
|
77
78
|
if (JSON.stringify(registry?.optionOrder) !== JSON.stringify(["approve", "revise", "decline", "cancel"])) errors.push("option_order");
|
|
@@ -303,21 +304,24 @@ export function buildApprovalOrientationSnapshot({
|
|
|
303
304
|
const gate = String(statusCard.current_gate ?? "").trim();
|
|
304
305
|
const runId = String(statusCard.run_id ?? "").trim();
|
|
305
306
|
const expectedApproval = `Approval: ${gate}`;
|
|
306
|
-
if (!REQUIRED_GATES.includes(gate) ||
|
|
307
|
+
if (!REQUIRED_GATES.includes(gate) || !/^[A-Za-z0-9._-]+$/.test(runId) || statusCard.status !== "open" || statusCard.missing_approval !== expectedApproval) return null;
|
|
307
308
|
|
|
308
309
|
const locale = resolvePresentationLocale(registry, requestedLocale);
|
|
309
310
|
const pack = localePack(registry, locale);
|
|
310
|
-
const runTitle =
|
|
311
|
+
const runTitle = displaySafeTitle(humanPresentation.runTitle, normalizedRunTitle(runId));
|
|
311
312
|
const currentGateTitle = String(humanPresentation.gateTitle ?? "").trim() || gateTitle(registry, locale, gate);
|
|
312
313
|
const primaryHeading = String(pack.gateActionTitles?.[gate] ?? "").trim();
|
|
313
314
|
const artefactRefs = Object.freeze([...(humanPresentation.artefactRefs ?? [])].map((ref) => Object.freeze({ ...ref })));
|
|
315
|
+
const nextGate = String(statusCard.next_gate_after_approval ?? "none");
|
|
316
|
+
const narration = pack.primary.narration.gates[gate] ?? {};
|
|
317
|
+
const nextDecision = narration.userAction
|
|
318
|
+
|| (nextGate === "none" ? pack.primary.narration.noAction : `${pack.gateTitles[nextGate] ?? nextGate} ${pack.interaction.decisionFollows}`);
|
|
314
319
|
const statusFields = Object.freeze([
|
|
315
|
-
Object.freeze({ id: "selected_run", label: pack.statusCard.run, value: `${runTitle} ·
|
|
320
|
+
Object.freeze({ id: "selected_run", label: pack.statusCard.run, value: `${runTitle} · \`${runId}\`` }),
|
|
316
321
|
Object.freeze({ id: "readiness_status", label: pack.statusCard.title, value: pack.interaction.ready }),
|
|
317
|
-
Object.freeze({ id: "current_gate", label: pack.statusCard.gate, value: `${
|
|
318
|
-
Object.freeze({ id: "
|
|
319
|
-
Object.freeze({ id: "next_action", label: pack.statusCard.step, value: pack.
|
|
320
|
-
Object.freeze({ id: "quality_outlook", label: pack.statusCard.quality, value: pack.primary.quality }),
|
|
322
|
+
Object.freeze({ id: "current_gate", label: pack.statusCard.gate, value: `${currentGateTitle} (\`${gate}\`)` }),
|
|
323
|
+
Object.freeze({ id: "required_decision", label: pack.statusCard.requiredDecision, value: pack.gateRequiredDecisions[gate] }),
|
|
324
|
+
Object.freeze({ id: "next_action", label: pack.statusCard.step, value: pack.interaction.decisionInstruction }),
|
|
321
325
|
]);
|
|
322
326
|
const options = Object.freeze(gateOptions(registry, locale, gate).map((option) => Object.freeze({ ...option })));
|
|
323
327
|
|
|
@@ -337,21 +341,29 @@ export function buildApprovalOrientationSnapshot({
|
|
|
337
341
|
}),
|
|
338
342
|
gate_transition_card: Object.freeze({
|
|
339
343
|
semantic_block: "gate_transition_card",
|
|
340
|
-
title: `${currentGateTitle} · ${runTitle} ·
|
|
344
|
+
title: `${currentGateTitle} · ${runTitle} · \`${runId}\``,
|
|
341
345
|
artefact_refs: artefactRefs,
|
|
342
346
|
ready: pack.interaction.ready,
|
|
343
347
|
approve_heading: pack.interaction.approveHeading,
|
|
344
348
|
exact_approval: expectedApproval,
|
|
345
349
|
approval_effect: pack.primary.afterApproval[gate] ?? pack.primary.actions[gate] ?? "",
|
|
346
350
|
next_heading: pack.interaction.nextHeading,
|
|
347
|
-
next_gate:
|
|
351
|
+
next_gate: nextGate,
|
|
352
|
+
next_transition: `${narration.agentNext ?? pack.primary.actions[gate] ?? ""}. ${nextDecision}.`,
|
|
353
|
+
}),
|
|
354
|
+
approval_interaction: Object.freeze({
|
|
355
|
+
semantic_block: "approval_interaction",
|
|
356
|
+
prompt: pack.interaction.decisionPrompt.replace("{gate}", currentGateTitle).replace("{run_id}", runId),
|
|
357
|
+
expected_approval: expectedApproval,
|
|
358
|
+
options,
|
|
359
|
+
exact_text_fallback: pack.interaction.exactTextRequest.replace("{approval}", expectedApproval),
|
|
360
|
+
authorizes: false,
|
|
348
361
|
}),
|
|
349
|
-
approval_interaction: Object.freeze({ semantic_block: "approval_interaction", expected_approval: expectedApproval, options, authorizes: false }),
|
|
350
362
|
authorizes: false,
|
|
351
363
|
});
|
|
352
364
|
}
|
|
353
365
|
|
|
354
|
-
export function validateApprovalOrientationSnapshot(snapshot) {
|
|
366
|
+
export function validateApprovalOrientationSnapshot(snapshot, { registry, expectedIdentity } = {}) {
|
|
355
367
|
const errors = [];
|
|
356
368
|
if (!plainObject(snapshot)) return Object.freeze({ valid: false, errors: Object.freeze(["snapshot_missing"]) });
|
|
357
369
|
if (JSON.stringify(snapshot.sequence) !== JSON.stringify(APPROVAL_SEQUENCE)) errors.push("sequence");
|
|
@@ -362,16 +374,104 @@ export function validateApprovalOrientationSnapshot(snapshot) {
|
|
|
362
374
|
if (!heading || snapshot.compact_status_card?.primary_heading_level !== 2) errors.push("primary_heading");
|
|
363
375
|
if (String(snapshot.compact_status_card?.title ?? "").trim() !== heading) errors.push("primary_heading_owner");
|
|
364
376
|
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");
|
|
377
|
+
if (/^(?:approve|accept|authorize|freigeben|genehmigen|abnehmen)\b|(?:freigeben|genehmigen|abnehmen)$/i.test(heading)) errors.push("approval_biased_heading");
|
|
365
378
|
const fieldIds = snapshot.compact_status_card?.fields?.map((field) => field?.id);
|
|
366
|
-
if (JSON.stringify(fieldIds) !== JSON.stringify(["selected_run", "readiness_status", "current_gate", "
|
|
379
|
+
if (JSON.stringify(fieldIds) !== JSON.stringify(["selected_run", "readiness_status", "current_gate", "required_decision", "next_action"])) errors.push("status_fields");
|
|
380
|
+
if (!String(snapshot.revision_id ?? "").trim()) errors.push("revision_identity");
|
|
381
|
+
const runIdentitySuffix = ` · \`${String(snapshot.run_id ?? "")}\``;
|
|
382
|
+
if (!String(snapshot.compact_status_card?.fields?.[0]?.value ?? "").endsWith(runIdentitySuffix)
|
|
383
|
+
|| !String(snapshot.gate_transition_card?.title ?? "").endsWith(runIdentitySuffix)) errors.push("identity_projection");
|
|
367
384
|
const expectedApproval = `Approval: ${String(snapshot.current_gate ?? "").trim()}`;
|
|
385
|
+
const inCardApprovalCount = JSON.stringify({
|
|
386
|
+
compact_status_card: snapshot.compact_status_card,
|
|
387
|
+
gate_transition_card: snapshot.gate_transition_card,
|
|
388
|
+
}).split(expectedApproval).length - 1;
|
|
389
|
+
if (inCardApprovalCount !== 1) errors.push("approval_card_occurrence");
|
|
390
|
+
const artefactOrder = snapshot.gate_transition_card?.artefact_refs?.map((ref) => ref?.type);
|
|
391
|
+
if (JSON.stringify(artefactOrder) !== JSON.stringify(ARTEFACT_ORDER)) errors.push("artefact_order");
|
|
392
|
+
if (snapshot.gate_transition_card?.artefact_refs?.some((ref) => ref?.exists && safeArtefactPath(ref.path) !== ref.path)) errors.push("unsafe_artefact_ref");
|
|
393
|
+
if (!String(snapshot.gate_transition_card?.approval_effect ?? "").trim() || !String(snapshot.gate_transition_card?.next_transition ?? "").trim()) errors.push("transition_content");
|
|
394
|
+
if (!String(snapshot.approval_interaction?.prompt ?? "").trim() || !String(snapshot.approval_interaction?.exact_text_fallback ?? "").includes(expectedApproval)) errors.push("approval_interaction_copy");
|
|
395
|
+
if (JSON.stringify(snapshot.approval_interaction?.options?.map((option) => option?.outcome)) !== JSON.stringify(["approve", "revise", "decline"])) errors.push("option_order");
|
|
368
396
|
if (!REQUIRED_GATES.includes(snapshot.current_gate)
|
|
369
397
|
|| snapshot.gate_transition_card?.exact_approval !== expectedApproval
|
|
370
398
|
|| snapshot.approval_interaction?.expected_approval !== expectedApproval
|
|
371
399
|
|| snapshot.approval_interaction?.options?.[0]?.value !== expectedApproval) errors.push("canonical_approval");
|
|
400
|
+
if (plainObject(expectedIdentity)) {
|
|
401
|
+
if (["run_id", "revision_id", "current_gate", "presentation_language"]
|
|
402
|
+
.some((key) => String(snapshot[key] ?? "") !== String(expectedIdentity[key] ?? ""))) errors.push("stale_identity");
|
|
403
|
+
}
|
|
404
|
+
if (plainObject(registry) && REQUIRED_GATES.includes(snapshot.current_gate)) {
|
|
405
|
+
const locale = String(snapshot.presentation_language ?? "");
|
|
406
|
+
const pack = localePack(registry, locale);
|
|
407
|
+
const gate = snapshot.current_gate;
|
|
408
|
+
const fields = snapshot.compact_status_card?.fields ?? [];
|
|
409
|
+
const localizedOptions = gateOptions(registry, locale, gate);
|
|
410
|
+
const localizedGateTitle = gateTitle(registry, locale, gate);
|
|
411
|
+
const nextGate = String(snapshot.gate_transition_card?.next_gate ?? "none");
|
|
412
|
+
const narration = pack.primary.narration.gates[gate] ?? {};
|
|
413
|
+
const nextDecision = narration.userAction
|
|
414
|
+
|| (nextGate === "none" ? pack.primary.narration.noAction : `${pack.gateTitles[nextGate] ?? nextGate} ${pack.interaction.decisionFollows}`);
|
|
415
|
+
const nextTransition = `${narration.agentNext ?? pack.primary.actions[gate] ?? ""}. ${nextDecision}.`;
|
|
416
|
+
const localeConsistent = resolvePresentationLocale(registry, locale) === locale
|
|
417
|
+
&& heading === pack.gateActionTitles?.[gate]
|
|
418
|
+
&& fields[0]?.label === pack.statusCard.run
|
|
419
|
+
&& fields[1]?.label === pack.statusCard.title
|
|
420
|
+
&& fields[1]?.value === pack.interaction.ready
|
|
421
|
+
&& fields[2]?.label === pack.statusCard.gate
|
|
422
|
+
&& fields[2]?.value === `${localizedGateTitle} (\`${gate}\`)`
|
|
423
|
+
&& fields[3]?.label === pack.statusCard.requiredDecision
|
|
424
|
+
&& fields[3]?.value === pack.gateRequiredDecisions?.[gate]
|
|
425
|
+
&& fields[4]?.label === pack.statusCard.step
|
|
426
|
+
&& fields[4]?.value === pack.interaction.decisionInstruction
|
|
427
|
+
&& String(snapshot.gate_transition_card?.title ?? "").startsWith(`${localizedGateTitle} · `)
|
|
428
|
+
&& snapshot.gate_transition_card?.ready === pack.interaction.ready
|
|
429
|
+
&& snapshot.gate_transition_card?.approve_heading === pack.interaction.approveHeading
|
|
430
|
+
&& snapshot.gate_transition_card?.approval_effect === (pack.primary.afterApproval?.[gate] ?? pack.primary.actions?.[gate] ?? "")
|
|
431
|
+
&& snapshot.gate_transition_card?.next_heading === pack.interaction.nextHeading
|
|
432
|
+
&& snapshot.gate_transition_card?.next_transition === nextTransition
|
|
433
|
+
&& snapshot.approval_interaction?.prompt === pack.interaction.decisionPrompt.replace("{gate}", localizedGateTitle).replace("{run_id}", snapshot.run_id)
|
|
434
|
+
&& snapshot.approval_interaction?.exact_text_fallback === pack.interaction.exactTextRequest.replace("{approval}", expectedApproval)
|
|
435
|
+
&& JSON.stringify(snapshot.approval_interaction?.options) === JSON.stringify(localizedOptions);
|
|
436
|
+
if (!localeConsistent) errors.push("locale_consistency");
|
|
437
|
+
}
|
|
372
438
|
return Object.freeze({ valid: errors.length === 0, errors: Object.freeze(errors) });
|
|
373
439
|
}
|
|
374
440
|
|
|
441
|
+
export function renderApprovalOrientationSnapshot(snapshot, validation = {}) {
|
|
442
|
+
if (!validateApprovalOrientationSnapshot(snapshot, validation).valid) return null;
|
|
443
|
+
const statusMarkdown = [
|
|
444
|
+
`## ${snapshot.compact_status_card.primary_heading}`,
|
|
445
|
+
...snapshot.compact_status_card.fields.map((field) => `${field.label}: ${field.value}`),
|
|
446
|
+
].join("\n");
|
|
447
|
+
const transition = snapshot.gate_transition_card;
|
|
448
|
+
const transitionMarkdown = [
|
|
449
|
+
transition.title,
|
|
450
|
+
formatArtefactRefs(transition.artefact_refs),
|
|
451
|
+
transition.ready,
|
|
452
|
+
"",
|
|
453
|
+
transition.approve_heading,
|
|
454
|
+
`\`${transition.exact_approval}\` ${transition.approval_effect}`,
|
|
455
|
+
"",
|
|
456
|
+
transition.next_heading,
|
|
457
|
+
transition.next_transition,
|
|
458
|
+
].join("\n");
|
|
459
|
+
return Object.freeze({
|
|
460
|
+
schema_version: "1",
|
|
461
|
+
run_id: snapshot.run_id,
|
|
462
|
+
revision_id: snapshot.revision_id,
|
|
463
|
+
current_gate: snapshot.current_gate,
|
|
464
|
+
presentation_language: snapshot.presentation_language,
|
|
465
|
+
sequence: snapshot.sequence,
|
|
466
|
+
blocks: Object.freeze({
|
|
467
|
+
run_status_card: Object.freeze({ markdown: statusMarkdown }),
|
|
468
|
+
gate_transition_card: Object.freeze({ markdown: transitionMarkdown }),
|
|
469
|
+
}),
|
|
470
|
+
approval_interaction: snapshot.approval_interaction,
|
|
471
|
+
authorizes: false,
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
|
|
375
475
|
export function attachApprovalOrientationSnapshot(statusCard, options = {}) {
|
|
376
476
|
if (!plainObject(statusCard)) throw new Error("approval orientation status card missing");
|
|
377
477
|
const snapshot = buildApprovalOrientationSnapshot({ ...options, statusCard });
|
package/package.json
CHANGED