create-agdf 0.6.9 → 0.7.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/bin/create-agdf.js +136 -58
- package/generated/.agdf/control/templates/RUN_STATE.md +21 -0
- package/generated/.github/skills/agdf-runtime-contract.md +5 -0
- package/generated/.opencode/agdf-runtime-contract.md +5 -0
- package/generated/plugins/agdf/.codex-plugin/plugin.json +1 -1
- package/generated/plugins/agdf/control/templates/RUN_STATE.md +21 -0
- package/generated/plugins/agdf/meta/agdf-plugin.definition.json +1 -1
- package/generated/plugins/agdf/meta/agdf-runtime-contract.md +5 -0
- package/lib/control-state/run-state-parser.js +7 -3
- package/package.json +1 -1
package/bin/create-agdf.js
CHANGED
|
@@ -32,14 +32,23 @@ const generatedRoot = join(packageRoot, "generated");
|
|
|
32
32
|
const pluginDefinitionPath = join(generatedRoot, "plugins", "agdf", "meta", "agdf-plugin.definition.json");
|
|
33
33
|
const pluginDefinition = JSON.parse(readFileSync(pluginDefinitionPath, "utf8"));
|
|
34
34
|
const pluginInstallCommand = "npx --yes @agdf/cli@latest claude";
|
|
35
|
-
const
|
|
36
|
-
const
|
|
35
|
+
const testNpmCliPath = process.env.NODE_ENV === "test" ? process.env.AGDF_TEST_NPM_CLI_PATH || "" : "";
|
|
36
|
+
const npmCommand = testNpmCliPath
|
|
37
|
+
? process.execPath
|
|
38
|
+
: process.platform === "win32"
|
|
39
|
+
? process.execPath
|
|
40
|
+
: "npm";
|
|
41
|
+
const npmPrefixArgs = testNpmCliPath
|
|
42
|
+
? [testNpmCliPath]
|
|
43
|
+
: process.platform === "win32"
|
|
44
|
+
? [join(dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js")]
|
|
45
|
+
: [];
|
|
37
46
|
const allowedTargets = new Set(["codex", "codex-repo", "claude", "copilot", "opencode", "opencode-status", "opencode-repo", "both", "init", "config", "doctor", "gate-check", "delivery-map", "delivery-path-search", "run-create", "run-migrate", "run-render-legacy"]);
|
|
38
47
|
const agdfFragmentPath = "AGENTS.agdf.md";
|
|
39
48
|
const openCodeConfigFragmentPath = "opencode.agdf.json";
|
|
40
49
|
const userGateOrder = ["UR", "PRD", "SD", "TP", "QA", "UAT"];
|
|
41
50
|
const durableGateArtefacts = new Set(["UR", "PRD", "SD", "TP", "QA"]);
|
|
42
|
-
const internalStepArtefacts = new Set(["Brownfield Review"]);
|
|
51
|
+
const internalStepArtefacts = new Set(["Brownfield Review", "Brownfield Analysis", "CD+Tests", "CR"]);
|
|
43
52
|
const deliveryRelationships = [
|
|
44
53
|
{ from: "UR", relationship: "approved_by", to: "Approval: UR", requiredBy: "UR" },
|
|
45
54
|
{ from: "PRD", relationship: "derived_from", to: "UR", requiredBy: "PRD" },
|
|
@@ -62,21 +71,6 @@ const nextSkillByGate = {
|
|
|
62
71
|
UAT: "delivery-closeout",
|
|
63
72
|
OR: "release-or",
|
|
64
73
|
};
|
|
65
|
-
const gateProgressOrder = [
|
|
66
|
-
"UR",
|
|
67
|
-
"Brownfield Review",
|
|
68
|
-
"Mode/Slice Decision",
|
|
69
|
-
"Quick Task Execution",
|
|
70
|
-
"PRD",
|
|
71
|
-
"SD",
|
|
72
|
-
"TP",
|
|
73
|
-
"Brownfield Analysis",
|
|
74
|
-
"CD+Tests",
|
|
75
|
-
"CR",
|
|
76
|
-
"QA",
|
|
77
|
-
"UAT",
|
|
78
|
-
"OR",
|
|
79
|
-
];
|
|
80
74
|
const codexSkillNames = pluginDefinition.skillSet.map((skill) => `${pluginDefinition.codex.skillPrefix}${skill.slug}`);
|
|
81
75
|
const copilotSkillNames = pluginDefinition.skillSet.map((skill) => `${pluginDefinition.copilot.skillPrefix}${skill.slug}`);
|
|
82
76
|
const openCodeSkillNames = pluginDefinition.skillSet.map((skill) => `${pluginDefinition.opencode.skillPrefix}${skill.slug}`);
|
|
@@ -481,6 +475,7 @@ function defaultOpenCodeConfigDir() {
|
|
|
481
475
|
|
|
482
476
|
function installOpenCodeGlobalPlugin(configDir) {
|
|
483
477
|
assertGlobalOpenCodeSurfaceWritable(configDir);
|
|
478
|
+
const previousPackage = resolveOpenCodePackage(configDir);
|
|
484
479
|
const configPath = join(configDir, "opencode.json");
|
|
485
480
|
let config = {};
|
|
486
481
|
|
|
@@ -528,15 +523,21 @@ function installOpenCodeGlobalPlugin(configDir) {
|
|
|
528
523
|
|
|
529
524
|
mkdirSync(configDir, { recursive: true });
|
|
530
525
|
try {
|
|
531
|
-
|
|
526
|
+
const packageSpecifier = `${pluginDefinition.opencode.npmPackage}@${pluginDefinition.version}`;
|
|
527
|
+
execFileSync(npmCommand, [...npmPrefixArgs, "install", "--silent", "--save-prod", "--save-exact", packageSpecifier], {
|
|
528
|
+
cwd: configDir,
|
|
529
|
+
stdio: "pipe",
|
|
530
|
+
});
|
|
532
531
|
} catch (error) {
|
|
533
532
|
throw new Error(`Failed to install ${pluginDefinition.opencode.npmPackage} into the OpenCode config directory: ${(error.stderr || error.message).toString().trim()}`);
|
|
534
533
|
}
|
|
535
534
|
writeFileSync(configPath, `${JSON.stringify(nextConfig, null, 2)}\n`, "utf8");
|
|
535
|
+
const installedPackage = resolveOpenCodePackage(configDir);
|
|
536
536
|
|
|
537
537
|
return {
|
|
538
538
|
configPath,
|
|
539
539
|
added: !alreadyInstalled,
|
|
540
|
+
transition: openCodePackageTransition(previousPackage, installedPackage),
|
|
540
541
|
};
|
|
541
542
|
}
|
|
542
543
|
|
|
@@ -661,24 +662,64 @@ function isOpenCodeRepositorySurfacePresent(targetDir) {
|
|
|
661
662
|
function resolveOpenCodePackage(configDir) {
|
|
662
663
|
const packageName = pluginDefinition.opencode.npmPackage;
|
|
663
664
|
try {
|
|
665
|
+
const resolvedPath = execFileSync(process.execPath, ["-e", `process.stdout.write(require.resolve(${JSON.stringify(packageName)}))`], {
|
|
666
|
+
cwd: configDir,
|
|
667
|
+
encoding: "utf8",
|
|
668
|
+
stdio: "pipe",
|
|
669
|
+
});
|
|
670
|
+
let installedVersion = "";
|
|
671
|
+
try {
|
|
672
|
+
const packageManifest = JSON.parse(readFileSync(join(dirname(resolvedPath), "package.json"), "utf8"));
|
|
673
|
+
installedVersion = typeof packageManifest.version === "string" && packageManifest.version.trim() ? packageManifest.version.trim() : "";
|
|
674
|
+
} catch {
|
|
675
|
+
installedVersion = "";
|
|
676
|
+
}
|
|
664
677
|
return {
|
|
665
678
|
loadable: true,
|
|
666
|
-
path:
|
|
667
|
-
|
|
668
|
-
encoding: "utf8",
|
|
669
|
-
stdio: "pipe",
|
|
670
|
-
}),
|
|
679
|
+
path: resolvedPath,
|
|
680
|
+
installed_version: installedVersion,
|
|
671
681
|
error: "",
|
|
672
682
|
};
|
|
673
683
|
} catch (error) {
|
|
674
684
|
return {
|
|
675
685
|
loadable: false,
|
|
676
686
|
path: "",
|
|
687
|
+
installed_version: "",
|
|
677
688
|
error: (error.stderr || error.message || "package not resolvable").toString().trim(),
|
|
678
689
|
};
|
|
679
690
|
}
|
|
680
691
|
}
|
|
681
692
|
|
|
693
|
+
function openCodePackageVersionStatus(packageState) {
|
|
694
|
+
if (!packageState.loadable) return "unloadable";
|
|
695
|
+
if (!packageState.installed_version) return "unknown";
|
|
696
|
+
return packageState.installed_version === pluginDefinition.version ? "current" : "outdated";
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
function openCodePackageTransition(previousPackage, installedPackage) {
|
|
700
|
+
const previousVersion = previousPackage.loadable ? previousPackage.installed_version : "";
|
|
701
|
+
const installedVersion = installedPackage.loadable ? installedPackage.installed_version : "";
|
|
702
|
+
if (!installedVersion || (previousPackage.loadable && !previousVersion)) {
|
|
703
|
+
return {
|
|
704
|
+
previous_version: previousVersion,
|
|
705
|
+
installed_version: installedVersion,
|
|
706
|
+
status: "unknown",
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
if (!previousPackage.loadable) {
|
|
710
|
+
return {
|
|
711
|
+
previous_version: "",
|
|
712
|
+
installed_version: installedVersion,
|
|
713
|
+
status: "installed",
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
return {
|
|
717
|
+
previous_version: previousVersion,
|
|
718
|
+
installed_version: installedVersion,
|
|
719
|
+
status: previousVersion === installedVersion ? "unchanged" : "updated",
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
|
|
682
723
|
function evaluateGlobalOpenCodeSurface(configDir) {
|
|
683
724
|
const paths = globalOpenCodeConfigPaths(configDir);
|
|
684
725
|
const skillCount = globalOpenCodeSkillNames.filter((skillName) => existsSync(join(paths.skills, skillName, "SKILL.md"))).length;
|
|
@@ -693,12 +734,13 @@ function evaluateGlobalOpenCodeSurface(configDir) {
|
|
|
693
734
|
};
|
|
694
735
|
}
|
|
695
736
|
|
|
696
|
-
function evaluateOpenCodeStatus(targetDir, configDir = defaultOpenCodeConfigDir()) {
|
|
737
|
+
function evaluateOpenCodeStatus(targetDir, configDir = defaultOpenCodeConfigDir(), transition = null) {
|
|
697
738
|
const configPath = join(configDir, "opencode.json");
|
|
698
739
|
const configState = readOpenCodeConfig(configPath);
|
|
699
740
|
const plugins = Array.isArray(configState.config.plugin) ? configState.config.plugin : [];
|
|
700
741
|
const globalConfigured = plugins.includes(pluginDefinition.opencode.npmPackage);
|
|
701
742
|
const packageState = resolveOpenCodePackage(configDir);
|
|
743
|
+
const packageVersionStatus = openCodePackageVersionStatus(packageState);
|
|
702
744
|
const globalNativeSurface = evaluateGlobalOpenCodeSurface(configDir);
|
|
703
745
|
const sessionSignals = {
|
|
704
746
|
active: process.env.AGDF_PLUGIN_ACTIVE === "1",
|
|
@@ -714,6 +756,8 @@ function evaluateOpenCodeStatus(targetDir, configDir = defaultOpenCodeConfigDir(
|
|
|
714
756
|
if (configState.parseError) findings.push(`OpenCode global config is not valid JSON: ${configState.parseError}`);
|
|
715
757
|
if (!globalConfigured) findings.push(`OpenCode global config does not include ${pluginDefinition.opencode.npmPackage}.`);
|
|
716
758
|
if (!packageState.loadable) findings.push(`${pluginDefinition.opencode.npmPackage} is not loadable from the OpenCode config directory.`);
|
|
759
|
+
if (packageVersionStatus === "outdated") findings.push(`${pluginDefinition.opencode.npmPackage} version ${packageState.installed_version} is outdated; expected ${pluginDefinition.version}.`);
|
|
760
|
+
if (packageVersionStatus === "unknown" && packageState.loadable) findings.push(`${pluginDefinition.opencode.npmPackage} is loadable but its installed version is unknown.`);
|
|
717
761
|
if (!globalNativeSurface.complete) findings.push(`Global OpenCode native skill surface is incomplete (${globalNativeSurface.skill_count}/${globalNativeSurface.expected_skill_count} skills).`);
|
|
718
762
|
if (!sessionSignals.active) findings.push("No active AGDF OpenCode session signal is visible in this process.");
|
|
719
763
|
if (!repositorySurface) findings.push("Current repository does not contain the AGDF OpenCode surface.");
|
|
@@ -731,6 +775,10 @@ function evaluateOpenCodeStatus(targetDir, configDir = defaultOpenCodeConfigDir(
|
|
|
731
775
|
name: pluginDefinition.opencode.npmPackage,
|
|
732
776
|
loadable: packageState.loadable,
|
|
733
777
|
resolved_path: packageState.path,
|
|
778
|
+
installed_version: packageState.installed_version || null,
|
|
779
|
+
expected_version: pluginDefinition.version,
|
|
780
|
+
version_status: packageVersionStatus,
|
|
781
|
+
...(transition ? { transition } : {}),
|
|
734
782
|
error: packageState.error,
|
|
735
783
|
},
|
|
736
784
|
global_native_surface: globalNativeSurface,
|
|
@@ -744,7 +792,9 @@ function evaluateOpenCodeStatus(targetDir, configDir = defaultOpenCodeConfigDir(
|
|
|
744
792
|
},
|
|
745
793
|
visible_entrypoint: repositorySurface ? `${pluginDefinition.opencode.skillPrefix}gate-check (native skill)` : "none until opencode-repo is installed for this repository",
|
|
746
794
|
findings,
|
|
747
|
-
next_step:
|
|
795
|
+
next_step: packageVersionStatus !== "current"
|
|
796
|
+
? "Run npx --yes @agdf/cli@latest opencode to install or repair the OpenCode package version."
|
|
797
|
+
: !globalNativeSurface.complete
|
|
748
798
|
? "Run npx --yes @agdf/cli@latest opencode to install or repair the global native OpenCode skill surface."
|
|
749
799
|
: repositorySurface
|
|
750
800
|
? `Restart OpenCode if needed, then load ${pluginDefinition.opencode.skillPrefix}gate-check through the native skill tool for new build/change intent.`
|
|
@@ -764,6 +814,18 @@ function printOpenCodeStatus(report, json) {
|
|
|
764
814
|
if (report.global_config.parse_error) console.log(`Config parse error: ${report.global_config.parse_error}`);
|
|
765
815
|
console.log(`Package loadable: ${report.package.loadable ? "yes" : "no"}`);
|
|
766
816
|
if (report.package.resolved_path) console.log(`Package path: ${report.package.resolved_path}`);
|
|
817
|
+
console.log(`Package version: ${report.package.installed_version || "unknown"}`);
|
|
818
|
+
console.log(`Expected version: ${report.package.expected_version}`);
|
|
819
|
+
console.log(`Version status: ${report.package.version_status}`);
|
|
820
|
+
if (report.package.transition?.status === "updated") {
|
|
821
|
+
console.log(`Version transition: ${report.package.transition.previous_version} -> ${report.package.transition.installed_version}`);
|
|
822
|
+
} else if (report.package.transition?.status === "installed") {
|
|
823
|
+
console.log(`Version transition: new install (${report.package.transition.installed_version || "unknown"})`);
|
|
824
|
+
} else if (report.package.transition?.status === "unchanged") {
|
|
825
|
+
console.log(`Version transition: unchanged (${report.package.transition.installed_version})`);
|
|
826
|
+
} else if (report.package.transition?.status === "unknown") {
|
|
827
|
+
console.log("Version transition: unknown");
|
|
828
|
+
}
|
|
767
829
|
console.log(`Global native skills: ${report.global_native_surface.complete ? "complete" : "incomplete"} (${report.global_native_surface.skill_count}/${report.global_native_surface.expected_skill_count})`);
|
|
768
830
|
console.log(`Global skill path: ${report.global_native_surface.path}`);
|
|
769
831
|
console.log(`Session active signal: ${report.session.active ? "yes" : "no"}`);
|
|
@@ -1753,20 +1815,6 @@ function readRunState(targetDir, selection = {}) {
|
|
|
1753
1815
|
};
|
|
1754
1816
|
}
|
|
1755
1817
|
|
|
1756
|
-
function firstUnapprovedGate(approvals) {
|
|
1757
|
-
for (const gate of userGateOrder) {
|
|
1758
|
-
const status = approvals.get(gate)?.status ?? "";
|
|
1759
|
-
if (status !== "approved" && status !== "not_applicable") return gate;
|
|
1760
|
-
}
|
|
1761
|
-
return "OR";
|
|
1762
|
-
}
|
|
1763
|
-
|
|
1764
|
-
function normalizeCurrentGate(value, fallbackGate) {
|
|
1765
|
-
if (isPlaceholderValue(value)) return fallbackGate;
|
|
1766
|
-
const normalized = value.replace(/`/g, "").trim();
|
|
1767
|
-
return normalized || fallbackGate;
|
|
1768
|
-
}
|
|
1769
|
-
|
|
1770
1818
|
function gateApprovalStatus(runState, gate) {
|
|
1771
1819
|
if (!userGateOrder.includes(gate)) return "not_applicable";
|
|
1772
1820
|
return runState.approvals.get(gate)?.status ?? "";
|
|
@@ -1820,7 +1868,9 @@ function analyzeDurableGateArtefactConsistency(runState) {
|
|
|
1820
1868
|
function isInternalStepSatisfied(runState, step) {
|
|
1821
1869
|
const artefact = runState.artefacts.get(step);
|
|
1822
1870
|
if (!artefact) return false;
|
|
1823
|
-
|
|
1871
|
+
if (artefact.status === "done") return true;
|
|
1872
|
+
return artefact.status === "not_applicable"
|
|
1873
|
+
&& (step === "Brownfield Review" || step === "Brownfield Analysis");
|
|
1824
1874
|
}
|
|
1825
1875
|
|
|
1826
1876
|
function modeSliceDecision(runState) {
|
|
@@ -2039,15 +2089,6 @@ function buildStatusCard({
|
|
|
2039
2089
|
};
|
|
2040
2090
|
}
|
|
2041
2091
|
|
|
2042
|
-
function effectiveCurrentGate(runState, transitionDecision) {
|
|
2043
|
-
if (transitionDecision.status !== "open") return transitionDecision.current_gate;
|
|
2044
|
-
const explicitGate = normalizeCurrentGate(runState.current_gate, "");
|
|
2045
|
-
const explicitIndex = gateProgressOrder.indexOf(explicitGate);
|
|
2046
|
-
const fallbackIndex = gateProgressOrder.indexOf(transitionDecision.current_gate);
|
|
2047
|
-
if (explicitIndex === -1 || fallbackIndex === -1) return transitionDecision.current_gate;
|
|
2048
|
-
return explicitIndex > fallbackIndex ? explicitGate : transitionDecision.current_gate;
|
|
2049
|
-
}
|
|
2050
|
-
|
|
2051
2092
|
function durableArtefactBlock(gate, nextGate) {
|
|
2052
2093
|
const label = gate === "QA" ? "QA report" : `${gate} artefact`;
|
|
2053
2094
|
const stablePath = gate === "QA" ? ".agdf/control/artefacts/<key>/QA_REPORT.md" : `.agdf/control/artefacts/<key>/${gate}.md`;
|
|
@@ -2192,6 +2233,43 @@ function transitionDecisionForRunState(runState) {
|
|
|
2192
2233
|
};
|
|
2193
2234
|
}
|
|
2194
2235
|
|
|
2236
|
+
const implementationStepsRequired = gateApprovalStatus(runState, "TP") === "approved";
|
|
2237
|
+
if (implementationStepsRequired && !isInternalStepSatisfied(runState, "Brownfield Analysis")) {
|
|
2238
|
+
return {
|
|
2239
|
+
status: "open",
|
|
2240
|
+
current_gate: "Brownfield Analysis",
|
|
2241
|
+
blocking_reason: "none",
|
|
2242
|
+
missing_approval: "none",
|
|
2243
|
+
allowed: ["run Brownfield Analysis for the approved TP scope", "verify existing owners, reuse paths and regression risks"],
|
|
2244
|
+
forbidden: ["implement before Brownfield evidence supports the approved TP path", "claim QA or release readiness"],
|
|
2245
|
+
next_allowed_action: "Run Brownfield Analysis for the approved TP scope before CD+Tests.",
|
|
2246
|
+
};
|
|
2247
|
+
}
|
|
2248
|
+
|
|
2249
|
+
if (implementationStepsRequired && !isInternalStepSatisfied(runState, "CD+Tests")) {
|
|
2250
|
+
return {
|
|
2251
|
+
status: "open",
|
|
2252
|
+
current_gate: "CD+Tests",
|
|
2253
|
+
blocking_reason: "none",
|
|
2254
|
+
missing_approval: "none",
|
|
2255
|
+
allowed: ["implement the approved TP tasks", "run the approved test plan", "record implementation and test evidence"],
|
|
2256
|
+
forbidden: ["claim QA pass", "request UAT approval", "release"],
|
|
2257
|
+
next_allowed_action: "Implement the approved TP scope, run its tests, and record CD+Tests evidence before CR.",
|
|
2258
|
+
};
|
|
2259
|
+
}
|
|
2260
|
+
|
|
2261
|
+
if (implementationStepsRequired && !isInternalStepSatisfied(runState, "CR")) {
|
|
2262
|
+
return {
|
|
2263
|
+
status: "open",
|
|
2264
|
+
current_gate: "CR",
|
|
2265
|
+
blocking_reason: "none",
|
|
2266
|
+
missing_approval: "none",
|
|
2267
|
+
allowed: ["run mandatory code review", "record correctness, regression, security and maintainability findings", "fix blocking review findings"],
|
|
2268
|
+
forbidden: ["claim QA pass", "request UAT approval", "release"],
|
|
2269
|
+
next_allowed_action: "Run Code Review for the implemented TP scope and resolve blocking findings before QA.",
|
|
2270
|
+
};
|
|
2271
|
+
}
|
|
2272
|
+
|
|
2195
2273
|
if (gateApprovalStatus(runState, "QA") === "approved" && !isGateSatisfied(runState, "QA")) return durableArtefactBlock("QA", "UAT");
|
|
2196
2274
|
|
|
2197
2275
|
if (isGateSatisfied(runState, "QA") && !isGateSatisfied(runState, "UAT")) {
|
|
@@ -2220,12 +2298,12 @@ function transitionDecisionForRunState(runState) {
|
|
|
2220
2298
|
|
|
2221
2299
|
return {
|
|
2222
2300
|
status: "open",
|
|
2223
|
-
current_gate: "
|
|
2301
|
+
current_gate: "QA",
|
|
2224
2302
|
blocking_reason: "none",
|
|
2225
|
-
missing_approval: "
|
|
2226
|
-
allowed: ["run
|
|
2227
|
-
forbidden: ["
|
|
2228
|
-
next_allowed_action: "Run
|
|
2303
|
+
missing_approval: "Approval: QA",
|
|
2304
|
+
allowed: ["run QA gate", "persist or refine the QA report", "request exact QA approval"],
|
|
2305
|
+
forbidden: ["request UAT approval", "release", "claim delivery readiness before QA approval and report evidence"],
|
|
2306
|
+
next_allowed_action: "Run the QA gate, persist the QA report, and request exact approval: Approval: QA",
|
|
2229
2307
|
};
|
|
2230
2308
|
}
|
|
2231
2309
|
|
|
@@ -2238,7 +2316,7 @@ function evaluateGateCheck(targetDir, selection = {}) {
|
|
|
2238
2316
|
const doctorRevise = doctorReport.findings.find((finding) => finding.severity === "revise");
|
|
2239
2317
|
|
|
2240
2318
|
let status = transitionDecision.status;
|
|
2241
|
-
let currentGate =
|
|
2319
|
+
let currentGate = transitionDecision.current_gate;
|
|
2242
2320
|
let blockingReason = transitionDecision.blocking_reason;
|
|
2243
2321
|
let missingApproval = transitionDecision.missing_approval;
|
|
2244
2322
|
let allowed = transitionDecision.allowed;
|
|
@@ -2413,7 +2491,7 @@ function evaluateDeliveryMap(targetDir, selection = {}) {
|
|
|
2413
2491
|
const runState = readRunState(targetDir, selection);
|
|
2414
2492
|
const map = analyzeDeliveryMap(runState);
|
|
2415
2493
|
const gateDecision = transitionDecisionForRunState(runState);
|
|
2416
|
-
const currentGate =
|
|
2494
|
+
const currentGate = gateDecision.current_gate;
|
|
2417
2495
|
|
|
2418
2496
|
const severityRank = { block: 3, revise: 2, warn: 1 };
|
|
2419
2497
|
const deliverySeverity = map.findings.reduce((max, finding) => Math.max(max, severityRank[finding.severity] ?? 0), 0);
|
|
@@ -2647,7 +2725,7 @@ async function main() {
|
|
|
2647
2725
|
const result = installOpenCodeGlobalPlugin(configDir);
|
|
2648
2726
|
installOpenCodeGlobalSurface(configDir);
|
|
2649
2727
|
console.log(`AGDF OpenCode global plugin ${result.added ? "installed" : "already present"}: ${result.configPath}`);
|
|
2650
|
-
const report = evaluateOpenCodeStatus(options.dir, configDir);
|
|
2728
|
+
const report = evaluateOpenCodeStatus(options.dir, configDir, result.transition);
|
|
2651
2729
|
printOpenCodeStatus(report, false);
|
|
2652
2730
|
console.log("Restart OpenCode so it loads the updated global plugin config.");
|
|
2653
2731
|
} catch (error) {
|
|
@@ -37,6 +37,27 @@ Describe the trustworthy outcome.
|
|
|
37
37
|
| QA | missing | |
|
|
38
38
|
| UAT | missing | |
|
|
39
39
|
|
|
40
|
+
## Artefacts
|
|
41
|
+
|
|
42
|
+
| Type | Path | Status | Notes |
|
|
43
|
+
|---|---|---|---|
|
|
44
|
+
| UR | | draft | |
|
|
45
|
+
| Brownfield Review | | missing | |
|
|
46
|
+
| PRD | | missing | |
|
|
47
|
+
| SD | | missing | |
|
|
48
|
+
| TP | | missing | |
|
|
49
|
+
| Brownfield Analysis | | missing | |
|
|
50
|
+
| CD+Tests | | missing | |
|
|
51
|
+
| CR | | missing | |
|
|
52
|
+
| QA | | missing | |
|
|
53
|
+
|
|
54
|
+
## Mode/Slice Decision
|
|
55
|
+
|
|
56
|
+
- decision:
|
|
57
|
+
- required_next_gate:
|
|
58
|
+
- scope_reason:
|
|
59
|
+
- evidence:
|
|
60
|
+
|
|
40
61
|
## Evidence
|
|
41
62
|
|
|
42
63
|
| Evidence | Source | Covers | Strength |
|
|
@@ -233,6 +233,7 @@ section or any other existing line.
|
|
|
233
233
|
|
|
234
234
|
- User gates: `UR -> PRD -> SD -> TP -> QA -> UAT`
|
|
235
235
|
- Internal mandatory steps: `Brownfield Review -> Mode/Slice Decision -> Brownfield Analysis -> CD+Tests -> CR -> OR`
|
|
236
|
+
- On the approved-TP path, `CD+Tests` and `CR` are satisfied only by `done`; `not_applicable` may satisfy Brownfield Review or Brownfield Analysis, but it must not bypass implementation/test evidence or mandatory Code Review.
|
|
236
237
|
- Exact approval formula: `Approval: <GateName>`
|
|
237
238
|
- Legacy alias: `Freigabe: <GateName>` may be accepted when reviewing older German runs, but all new outputs must use `Approval: <GateName>`.
|
|
238
239
|
- Implicit consent is not approval. Phrases such as "ok", "go ahead", "do it", "approved", "continue", "leg los" or "looks good" are work intent, not gate approval.
|
|
@@ -293,7 +294,11 @@ This table is the canonical transition model. Skills may reference it, but must
|
|
|
293
294
|
| `SD` approved and SD artefact persisted or linked, TP missing or draft | `TP` | draft/refine Task/Test Plan, task IDs, evidence plan, persist/link TP, request `Approval: TP` | implementation, QA, release | `Approval: TP` |
|
|
294
295
|
| `TP` approved and TP artefact persisted or linked, Brownfield Analysis missing | `Brownfield Analysis` | run Brownfield Analysis for approved TP scope | implementation, QA, release | none |
|
|
295
296
|
| Brownfield Analysis passed for approved TP | `CD+Tests` | implement approved TP tasks and run tests | QA pass, UAT, release | none |
|
|
297
|
+
| `CD+Tests` done for approved TP, CR missing | `CR` | run mandatory Code Review and resolve blocking findings | QA pass, UAT, release | none |
|
|
298
|
+
| `CR` done, QA not approved | `QA` | run QA gate, persist/refine QA report, request `Approval: QA` | UAT, release | `Approval: QA` |
|
|
296
299
|
| `QA` approved but QA report missing or not pass | `QA` | persist/link QA report with `pass` decision or revise/block evidence | UAT, release | none |
|
|
300
|
+
| QA approved and QA report is `pass` or `passed`, UAT not approved | `UAT` | request `Approval: UAT`, prepare non-operative delivery summary | release and automatic VCS actions | `Approval: UAT` |
|
|
301
|
+
| UAT approved | `OR` | produce OR or delivery closeout; prepare VCS handoff only when requested | automatic commit, push, PR or release | none |
|
|
297
302
|
|
|
298
303
|
## Brownfield Modes
|
|
299
304
|
|
|
@@ -233,6 +233,7 @@ section or any other existing line.
|
|
|
233
233
|
|
|
234
234
|
- User gates: `UR -> PRD -> SD -> TP -> QA -> UAT`
|
|
235
235
|
- Internal mandatory steps: `Brownfield Review -> Mode/Slice Decision -> Brownfield Analysis -> CD+Tests -> CR -> OR`
|
|
236
|
+
- On the approved-TP path, `CD+Tests` and `CR` are satisfied only by `done`; `not_applicable` may satisfy Brownfield Review or Brownfield Analysis, but it must not bypass implementation/test evidence or mandatory Code Review.
|
|
236
237
|
- Exact approval formula: `Approval: <GateName>`
|
|
237
238
|
- Legacy alias: `Freigabe: <GateName>` may be accepted when reviewing older German runs, but all new outputs must use `Approval: <GateName>`.
|
|
238
239
|
- Implicit consent is not approval. Phrases such as "ok", "go ahead", "do it", "approved", "continue", "leg los" or "looks good" are work intent, not gate approval.
|
|
@@ -293,7 +294,11 @@ This table is the canonical transition model. Skills may reference it, but must
|
|
|
293
294
|
| `SD` approved and SD artefact persisted or linked, TP missing or draft | `TP` | draft/refine Task/Test Plan, task IDs, evidence plan, persist/link TP, request `Approval: TP` | implementation, QA, release | `Approval: TP` |
|
|
294
295
|
| `TP` approved and TP artefact persisted or linked, Brownfield Analysis missing | `Brownfield Analysis` | run Brownfield Analysis for approved TP scope | implementation, QA, release | none |
|
|
295
296
|
| Brownfield Analysis passed for approved TP | `CD+Tests` | implement approved TP tasks and run tests | QA pass, UAT, release | none |
|
|
297
|
+
| `CD+Tests` done for approved TP, CR missing | `CR` | run mandatory Code Review and resolve blocking findings | QA pass, UAT, release | none |
|
|
298
|
+
| `CR` done, QA not approved | `QA` | run QA gate, persist/refine QA report, request `Approval: QA` | UAT, release | `Approval: QA` |
|
|
296
299
|
| `QA` approved but QA report missing or not pass | `QA` | persist/link QA report with `pass` decision or revise/block evidence | UAT, release | none |
|
|
300
|
+
| QA approved and QA report is `pass` or `passed`, UAT not approved | `UAT` | request `Approval: UAT`, prepare non-operative delivery summary | release and automatic VCS actions | `Approval: UAT` |
|
|
301
|
+
| UAT approved | `OR` | produce OR or delivery closeout; prepare VCS handoff only when requested | automatic commit, push, PR or release | none |
|
|
297
302
|
|
|
298
303
|
## Brownfield Modes
|
|
299
304
|
|
|
@@ -37,6 +37,27 @@ Describe the trustworthy outcome.
|
|
|
37
37
|
| QA | missing | |
|
|
38
38
|
| UAT | missing | |
|
|
39
39
|
|
|
40
|
+
## Artefacts
|
|
41
|
+
|
|
42
|
+
| Type | Path | Status | Notes |
|
|
43
|
+
|---|---|---|---|
|
|
44
|
+
| UR | | draft | |
|
|
45
|
+
| Brownfield Review | | missing | |
|
|
46
|
+
| PRD | | missing | |
|
|
47
|
+
| SD | | missing | |
|
|
48
|
+
| TP | | missing | |
|
|
49
|
+
| Brownfield Analysis | | missing | |
|
|
50
|
+
| CD+Tests | | missing | |
|
|
51
|
+
| CR | | missing | |
|
|
52
|
+
| QA | | missing | |
|
|
53
|
+
|
|
54
|
+
## Mode/Slice Decision
|
|
55
|
+
|
|
56
|
+
- decision:
|
|
57
|
+
- required_next_gate:
|
|
58
|
+
- scope_reason:
|
|
59
|
+
- evidence:
|
|
60
|
+
|
|
40
61
|
## Evidence
|
|
41
62
|
|
|
42
63
|
| Evidence | Source | Covers | Strength |
|
|
@@ -233,6 +233,7 @@ section or any other existing line.
|
|
|
233
233
|
|
|
234
234
|
- User gates: `UR -> PRD -> SD -> TP -> QA -> UAT`
|
|
235
235
|
- Internal mandatory steps: `Brownfield Review -> Mode/Slice Decision -> Brownfield Analysis -> CD+Tests -> CR -> OR`
|
|
236
|
+
- On the approved-TP path, `CD+Tests` and `CR` are satisfied only by `done`; `not_applicable` may satisfy Brownfield Review or Brownfield Analysis, but it must not bypass implementation/test evidence or mandatory Code Review.
|
|
236
237
|
- Exact approval formula: `Approval: <GateName>`
|
|
237
238
|
- Legacy alias: `Freigabe: <GateName>` may be accepted when reviewing older German runs, but all new outputs must use `Approval: <GateName>`.
|
|
238
239
|
- Implicit consent is not approval. Phrases such as "ok", "go ahead", "do it", "approved", "continue", "leg los" or "looks good" are work intent, not gate approval.
|
|
@@ -293,7 +294,11 @@ This table is the canonical transition model. Skills may reference it, but must
|
|
|
293
294
|
| `SD` approved and SD artefact persisted or linked, TP missing or draft | `TP` | draft/refine Task/Test Plan, task IDs, evidence plan, persist/link TP, request `Approval: TP` | implementation, QA, release | `Approval: TP` |
|
|
294
295
|
| `TP` approved and TP artefact persisted or linked, Brownfield Analysis missing | `Brownfield Analysis` | run Brownfield Analysis for approved TP scope | implementation, QA, release | none |
|
|
295
296
|
| Brownfield Analysis passed for approved TP | `CD+Tests` | implement approved TP tasks and run tests | QA pass, UAT, release | none |
|
|
297
|
+
| `CD+Tests` done for approved TP, CR missing | `CR` | run mandatory Code Review and resolve blocking findings | QA pass, UAT, release | none |
|
|
298
|
+
| `CR` done, QA not approved | `QA` | run QA gate, persist/refine QA report, request `Approval: QA` | UAT, release | `Approval: QA` |
|
|
296
299
|
| `QA` approved but QA report missing or not pass | `QA` | persist/link QA report with `pass` decision or revise/block evidence | UAT, release | none |
|
|
300
|
+
| QA approved and QA report is `pass` or `passed`, UAT not approved | `UAT` | request `Approval: UAT`, prepare non-operative delivery summary | release and automatic VCS actions | `Approval: UAT` |
|
|
301
|
+
| UAT approved | `OR` | produce OR or delivery closeout; prepare VCS handoff only when requested | automatic commit, push, PR or release | none |
|
|
297
302
|
|
|
298
303
|
## Brownfield Modes
|
|
299
304
|
|
|
@@ -101,11 +101,13 @@ export function parseControlState(
|
|
|
101
101
|
const approvals = new Map();
|
|
102
102
|
for (const h of ["Approvals", "Gate Checklist"])
|
|
103
103
|
for (const [g, s, e] of rows(section(content, h))) {
|
|
104
|
-
if (userGates.includes(g))
|
|
104
|
+
if (userGates.includes(g)) {
|
|
105
|
+
const status = clean(s);
|
|
105
106
|
approvals.set(g, {
|
|
106
|
-
status:
|
|
107
|
+
status: g === "QA" && (status === "pass" || status === "passed") ? "approved" : status,
|
|
107
108
|
evidence: e ?? "",
|
|
108
109
|
});
|
|
110
|
+
}
|
|
109
111
|
}
|
|
110
112
|
const artefacts = new Map();
|
|
111
113
|
for (const [t, p, s, n] of rows(section(content, "Artefacts"))) {
|
|
@@ -113,7 +115,9 @@ export function parseControlState(
|
|
|
113
115
|
artefacts.set(t, { path: p ?? "", status: clean(s), notes: n ?? "" });
|
|
114
116
|
}
|
|
115
117
|
const mapRows = (h, header, fn) => dataRows(content, h, header).map(fn);
|
|
116
|
-
const mode = "Mode
|
|
118
|
+
const mode = section(content, "Mode/Slice Decision").trim()
|
|
119
|
+
? "Mode/Slice Decision"
|
|
120
|
+
: "Mode / Slice Decision",
|
|
117
121
|
source = "Source And Scope State",
|
|
118
122
|
memory = "Knowledge Persistence Decision";
|
|
119
123
|
return {
|
package/package.json
CHANGED