create-agdf 0.1.7 → 0.1.8
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 +25 -2
- package/bin/create-agdf.js +310 -3
- package/generated/.agdf/control/README.md +20 -5
- package/generated/plugins/agdf/.codex-plugin/plugin.json +1 -1
- package/generated/plugins/agdf/control/README.md +20 -5
- package/generated/plugins/agdf/meta/agdf-plugin.definition.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,6 +8,8 @@ Bootstrap AGDF repository instructions for one repository.
|
|
|
8
8
|
npm create agdf@latest codex
|
|
9
9
|
npm create agdf@latest copilot
|
|
10
10
|
npm create agdf@latest both
|
|
11
|
+
npm create agdf@latest init
|
|
12
|
+
npm create agdf@latest doctor
|
|
11
13
|
```
|
|
12
14
|
|
|
13
15
|
Optional flags:
|
|
@@ -29,7 +31,7 @@ After `npm create agdf@latest codex`, restart Codex in that repository, open `/p
|
|
|
29
31
|
|
|
30
32
|
## Control scaffold
|
|
31
33
|
|
|
32
|
-
The generated `.agdf/control/templates/` files are starting points for durable AGDF state:
|
|
34
|
+
The generated `.agdf/control/templates/` files are reusable starting points for durable AGDF state:
|
|
33
35
|
|
|
34
36
|
- `AGDF_RUN.md` for the current run dashboard
|
|
35
37
|
- `MASTER_BACKLOG.md` for active delivery pointers
|
|
@@ -37,7 +39,28 @@ The generated `.agdf/control/templates/` files are starting points for durable A
|
|
|
37
39
|
- `CONTEXT_GRAPH.md` for durable Brownfield findings, decisions, risks, evidence and exit criteria
|
|
38
40
|
- `AGENT_QUALITY_CONTRACTS.json` for reusable block, revise and warning conditions
|
|
39
41
|
|
|
40
|
-
|
|
42
|
+
Use `init` to promote those templates into live control files:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npm create agdf@latest init
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
This writes:
|
|
49
|
+
|
|
50
|
+
- `.agdf/control/AGDF_RUN.md`
|
|
51
|
+
- `.agdf/control/MASTER_BACKLOG.md`
|
|
52
|
+
- `.agdf/control/SOT_REGISTRY.md`
|
|
53
|
+
- `.agdf/control/CONTEXT_GRAPH.md`
|
|
54
|
+
- `.agdf/control/AGENT_QUALITY_CONTRACTS.json`
|
|
55
|
+
|
|
56
|
+
Use `doctor` to check whether the live control state is actionable:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npm create agdf@latest doctor
|
|
60
|
+
npm create agdf@latest doctor --json
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The doctor reports missing live control files, missing current gate, missing next allowed action, empty evidence, empty backlog pointer, empty source-of-truth registry, duplicate active SoT rows and invalid quality contracts. It exits non-zero only for blocking control failures.
|
|
41
64
|
|
|
42
65
|
## Single source of truth
|
|
43
66
|
|
package/bin/create-agdf.js
CHANGED
|
@@ -11,7 +11,7 @@ const generatedRoot = join(packageRoot, "generated");
|
|
|
11
11
|
const pluginDefinitionPath = join(generatedRoot, "plugins", "agdf", "meta", "agdf-plugin.definition.json");
|
|
12
12
|
const pluginDefinition = JSON.parse(readFileSync(pluginDefinitionPath, "utf8"));
|
|
13
13
|
const pluginInstallCommand = "claude plugin add arndtgold/ai-native-governance-delivery-framework";
|
|
14
|
-
const allowedTargets = new Set(["codex", "copilot", "both"]);
|
|
14
|
+
const allowedTargets = new Set(["codex", "copilot", "both", "init", "doctor"]);
|
|
15
15
|
const agdfFragmentPath = "AGENTS.agdf.md";
|
|
16
16
|
const codexSkillNames = pluginDefinition.skillSet.map((skill) => `${pluginDefinition.codex.skillPrefix}${skill.slug}`);
|
|
17
17
|
const copilotSkillNames = pluginDefinition.skillSet.map((skill) => `${pluginDefinition.copilot.skillPrefix}${skill.slug}`);
|
|
@@ -41,6 +41,35 @@ const controlFiles = [
|
|
|
41
41
|
join(".agdf", "control", "templates", "CONTEXT_GRAPH.md"),
|
|
42
42
|
join(".agdf", "control", "templates", "AGENT_QUALITY_CONTRACTS.json"),
|
|
43
43
|
];
|
|
44
|
+
const liveControlFiles = [
|
|
45
|
+
{
|
|
46
|
+
path: join(".agdf", "control", "AGDF_RUN.md"),
|
|
47
|
+
source: join(".agdf", "control", "templates", "AGDF_RUN.md"),
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
path: join(".agdf", "control", "MASTER_BACKLOG.md"),
|
|
51
|
+
source: join(".agdf", "control", "templates", "MASTER_BACKLOG.md"),
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
path: join(".agdf", "control", "SOT_REGISTRY.md"),
|
|
55
|
+
source: join(".agdf", "control", "templates", "SOT_REGISTRY.md"),
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
path: join(".agdf", "control", "CONTEXT_GRAPH.md"),
|
|
59
|
+
source: join(".agdf", "control", "templates", "CONTEXT_GRAPH.md"),
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
path: join(".agdf", "control", "AGENT_QUALITY_CONTRACTS.json"),
|
|
63
|
+
source: join(".agdf", "control", "templates", "AGENT_QUALITY_CONTRACTS.json"),
|
|
64
|
+
},
|
|
65
|
+
];
|
|
66
|
+
const doctorRequiredFiles = [
|
|
67
|
+
join(".agdf", "control", "AGDF_RUN.md"),
|
|
68
|
+
join(".agdf", "control", "MASTER_BACKLOG.md"),
|
|
69
|
+
join(".agdf", "control", "SOT_REGISTRY.md"),
|
|
70
|
+
join(".agdf", "control", "CONTEXT_GRAPH.md"),
|
|
71
|
+
join(".agdf", "control", "AGENT_QUALITY_CONTRACTS.json"),
|
|
72
|
+
];
|
|
44
73
|
const copilotInstructionFiles = [
|
|
45
74
|
join(".github", "copilot-instructions.md"),
|
|
46
75
|
join(".github", "instructions", "agdf-governance.instructions.md"),
|
|
@@ -58,10 +87,13 @@ Usage:
|
|
|
58
87
|
npm create agdf@latest codex
|
|
59
88
|
npm create agdf@latest copilot
|
|
60
89
|
npm create agdf@latest both
|
|
90
|
+
npm create agdf@latest init
|
|
91
|
+
npm create agdf@latest doctor
|
|
61
92
|
|
|
62
93
|
Options:
|
|
63
94
|
--dir <path> Write files into a specific directory
|
|
64
95
|
--force Overwrite existing generated files
|
|
96
|
+
--json Print doctor output as JSON
|
|
65
97
|
--help Show this help
|
|
66
98
|
`);
|
|
67
99
|
}
|
|
@@ -71,6 +103,7 @@ function parseArgs(argv) {
|
|
|
71
103
|
let target;
|
|
72
104
|
let dir = ".";
|
|
73
105
|
let force = false;
|
|
106
|
+
let json = false;
|
|
74
107
|
|
|
75
108
|
for (let i = 0; i < args.length; i += 1) {
|
|
76
109
|
const arg = args[i];
|
|
@@ -86,6 +119,11 @@ function parseArgs(argv) {
|
|
|
86
119
|
continue;
|
|
87
120
|
}
|
|
88
121
|
|
|
122
|
+
if (arg === "--json") {
|
|
123
|
+
json = true;
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
|
|
89
127
|
if (arg === "--dir") {
|
|
90
128
|
const next = args[i + 1];
|
|
91
129
|
if (!next) {
|
|
@@ -118,7 +156,7 @@ function parseArgs(argv) {
|
|
|
118
156
|
}
|
|
119
157
|
|
|
120
158
|
if (!target || !allowedTargets.has(target)) {
|
|
121
|
-
console.error("Please choose one target: codex, copilot or
|
|
159
|
+
console.error("Please choose one target: codex, copilot, both, init or doctor.");
|
|
122
160
|
printUsage();
|
|
123
161
|
process.exit(1);
|
|
124
162
|
}
|
|
@@ -127,6 +165,7 @@ function parseArgs(argv) {
|
|
|
127
165
|
target,
|
|
128
166
|
dir: resolve(process.cwd(), dir),
|
|
129
167
|
force,
|
|
168
|
+
json,
|
|
130
169
|
};
|
|
131
170
|
}
|
|
132
171
|
|
|
@@ -148,6 +187,22 @@ function writeGeneratedFile(targetDir, relativePath, content, force) {
|
|
|
148
187
|
function generatedFilesForTarget(target, targetDir, force) {
|
|
149
188
|
const files = [];
|
|
150
189
|
|
|
190
|
+
if (target === "init") {
|
|
191
|
+
files.push({
|
|
192
|
+
path: join(".agdf", "control", "README.md"),
|
|
193
|
+
content: loadAsset(join(".agdf", "control", "README.md")),
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
for (const controlPath of liveControlFiles) {
|
|
197
|
+
files.push({
|
|
198
|
+
path: controlPath.path,
|
|
199
|
+
content: loadAsset(controlPath.source),
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return files;
|
|
204
|
+
}
|
|
205
|
+
|
|
151
206
|
if (target === "codex" || target === "both") {
|
|
152
207
|
for (const codexPath of codexPluginFiles) {
|
|
153
208
|
files.push({
|
|
@@ -200,6 +255,12 @@ function printNextSteps(target, destination, files, wroteAgentsFragment) {
|
|
|
200
255
|
|
|
201
256
|
console.log("");
|
|
202
257
|
console.log("Next steps:");
|
|
258
|
+
if (target === "init") {
|
|
259
|
+
console.log("- Fill .agdf/control/AGDF_RUN.md with the current gate, evidence and next allowed action.");
|
|
260
|
+
console.log("- Run npm create agdf@latest doctor to check the control state before the next agent run.");
|
|
261
|
+
console.log("- Commit the live control files once they represent the repository's current delivery state.");
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
203
264
|
if (wroteAgentsFragment) {
|
|
204
265
|
console.log(`- Existing AGENTS.md detected. Merge ${agdfFragmentPath} into your current AGENTS.md before using Copilot with AGDF.`);
|
|
205
266
|
}
|
|
@@ -212,13 +273,259 @@ function printNextSteps(target, destination, files, wroteAgentsFragment) {
|
|
|
212
273
|
}
|
|
213
274
|
if (target === "copilot" || target === "both") {
|
|
214
275
|
console.log("- In GitHub Copilot CLI, run /instructions after the AGENTS.md step is complete to confirm that AGDF instructions and the repository skills are visible.");
|
|
215
|
-
console.log("-
|
|
276
|
+
console.log("- Run npm create agdf@latest init when the repository needs live AGDF control files.");
|
|
216
277
|
}
|
|
217
278
|
console.log("- Commit the generated files so the repository becomes the source of truth.");
|
|
218
279
|
}
|
|
219
280
|
|
|
281
|
+
function readTargetFile(targetDir, relativePath) {
|
|
282
|
+
return readFileSync(join(targetDir, relativePath), "utf8");
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function addFinding(findings, severity, code, message, path, nextStep) {
|
|
286
|
+
findings.push({
|
|
287
|
+
severity,
|
|
288
|
+
code,
|
|
289
|
+
message,
|
|
290
|
+
path,
|
|
291
|
+
next_step: nextStep,
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function nonEmptyTableRows(content) {
|
|
296
|
+
return content
|
|
297
|
+
.split("\n")
|
|
298
|
+
.filter((line) => line.trim().startsWith("|"))
|
|
299
|
+
.filter((line) => !line.includes("---"))
|
|
300
|
+
.map((line) => line.split("|").map((cell) => cell.trim()).filter(Boolean))
|
|
301
|
+
.filter((cells) => cells.some((cell) => cell && !cell.startsWith("`")));
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function tableRows(content) {
|
|
305
|
+
return content
|
|
306
|
+
.split("\n")
|
|
307
|
+
.filter((line) => line.trim().startsWith("|"))
|
|
308
|
+
.filter((line) => !line.includes("---"))
|
|
309
|
+
.map((line) => {
|
|
310
|
+
const cells = line.split("|").map((cell) => cell.trim());
|
|
311
|
+
if (cells[0] === "") cells.shift();
|
|
312
|
+
if (cells.at(-1) === "") cells.pop();
|
|
313
|
+
return cells;
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function hasFilledTableRow(content, firstCellPattern) {
|
|
318
|
+
return tableRows(content)
|
|
319
|
+
.filter((cells) => firstCellPattern.test(cells[0] ?? ""))
|
|
320
|
+
.some((cells) => cells.slice(1).some((cell) => cell && !cell.startsWith("`")));
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function isPlaceholderValue(value) {
|
|
324
|
+
return !value || (value.startsWith("`") && value.includes("|"));
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function hasFilledEvidenceRow(content) {
|
|
328
|
+
const evidenceSection = content.match(/## Evidence([\s\S]*?)(?:\n## |\n# |$)/)?.[1] ?? "";
|
|
329
|
+
return tableRows(evidenceSection)
|
|
330
|
+
.filter((cells) => cells[0] !== "Evidence")
|
|
331
|
+
.some((cells) => {
|
|
332
|
+
const [evidence, source, covers] = cells;
|
|
333
|
+
return Boolean(evidence || source || covers);
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function parseQualityContracts(content) {
|
|
338
|
+
const parsed = JSON.parse(content);
|
|
339
|
+
if (!Array.isArray(parsed.contracts) || parsed.contracts.length === 0) {
|
|
340
|
+
throw new Error("contracts must be a non-empty array");
|
|
341
|
+
}
|
|
342
|
+
for (const contract of parsed.contracts) {
|
|
343
|
+
if (!contract.code || !contract.impact || !contract.required_evidence) {
|
|
344
|
+
throw new Error(`contract ${contract.code ?? "<unknown>"} is missing code, impact or required_evidence`);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return parsed;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function evaluateDoctor(targetDir) {
|
|
351
|
+
const findings = [];
|
|
352
|
+
const missing = doctorRequiredFiles.filter((relativePath) => !existsSync(join(targetDir, relativePath)));
|
|
353
|
+
|
|
354
|
+
for (const relativePath of missing) {
|
|
355
|
+
const templatePath = join(dirname(relativePath), "templates", relativePath.split("/").at(-1));
|
|
356
|
+
const hasTemplate = existsSync(join(targetDir, templatePath));
|
|
357
|
+
addFinding(
|
|
358
|
+
findings,
|
|
359
|
+
"block",
|
|
360
|
+
"AGDF_CONTROL_FILE_MISSING",
|
|
361
|
+
hasTemplate
|
|
362
|
+
? "Live control file is missing; only the template exists."
|
|
363
|
+
: "Required live control file is missing.",
|
|
364
|
+
relativePath,
|
|
365
|
+
"Run npm create agdf@latest init, then fill the live control files with the current repository state.",
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
if (missing.length === 0) {
|
|
370
|
+
const runPath = join(".agdf", "control", "AGDF_RUN.md");
|
|
371
|
+
const run = readTargetFile(targetDir, runPath);
|
|
372
|
+
const currentGateLine = run.match(/^- current_gate:[^\S\r\n]*(.*)$/m)?.[1]?.trim() ?? "";
|
|
373
|
+
const nextActionLine = run.match(/^- next_allowed_action:[^\S\r\n]*(.*)$/m)?.[1]?.trim() ?? "";
|
|
374
|
+
const hasEvidence = hasFilledEvidenceRow(run);
|
|
375
|
+
|
|
376
|
+
if (isPlaceholderValue(currentGateLine)) {
|
|
377
|
+
addFinding(
|
|
378
|
+
findings,
|
|
379
|
+
"revise",
|
|
380
|
+
"AGDF_CURRENT_GATE_MISSING",
|
|
381
|
+
"AGDF_RUN.md does not name the current gate.",
|
|
382
|
+
runPath,
|
|
383
|
+
"Set current_gate to the current delivery gate or none.",
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
if (isPlaceholderValue(nextActionLine)) {
|
|
388
|
+
addFinding(
|
|
389
|
+
findings,
|
|
390
|
+
"revise",
|
|
391
|
+
"AGDF_NEXT_ALLOWED_ACTION_MISSING",
|
|
392
|
+
"AGDF_RUN.md does not state the next allowed action.",
|
|
393
|
+
runPath,
|
|
394
|
+
"Fill the next allowed action before asking an agent to continue delivery work.",
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
if (!hasEvidence) {
|
|
399
|
+
addFinding(
|
|
400
|
+
findings,
|
|
401
|
+
"warn",
|
|
402
|
+
"AGDF_EVIDENCE_EMPTY",
|
|
403
|
+
"AGDF_RUN.md has no visible evidence row yet.",
|
|
404
|
+
runPath,
|
|
405
|
+
"Add at least one evidence row or explicitly document that no evidence exists yet.",
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const backlogPath = join(".agdf", "control", "MASTER_BACKLOG.md");
|
|
410
|
+
const backlog = readTargetFile(targetDir, backlogPath);
|
|
411
|
+
if (!hasFilledTableRow(backlog, /^P[0-9]/)) {
|
|
412
|
+
addFinding(
|
|
413
|
+
findings,
|
|
414
|
+
"warn",
|
|
415
|
+
"AGDF_BACKLOG_POINTER_EMPTY",
|
|
416
|
+
"MASTER_BACKLOG.md does not contain an active or planned work pointer.",
|
|
417
|
+
backlogPath,
|
|
418
|
+
"Add the active item or document that no governed delivery item is active.",
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const sotPath = join(".agdf", "control", "SOT_REGISTRY.md");
|
|
423
|
+
const sot = readTargetFile(targetDir, sotPath);
|
|
424
|
+
if (!hasFilledTableRow(sot, /Product intent|Architecture|Runtime contracts|UX \/ user flows|Operations \/ release/)) {
|
|
425
|
+
addFinding(
|
|
426
|
+
findings,
|
|
427
|
+
"warn",
|
|
428
|
+
"AGDF_SOT_REGISTRY_EMPTY",
|
|
429
|
+
"SOT_REGISTRY.md has no filled primary source-of-truth row.",
|
|
430
|
+
sotPath,
|
|
431
|
+
"Assign one primary source of truth for at least the domains relevant to the next run.",
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const activeDomains = new Map();
|
|
436
|
+
for (const cells of nonEmptyTableRows(sot)) {
|
|
437
|
+
const [domain, document, status] = cells;
|
|
438
|
+
if (!domain || !document || status !== "active") continue;
|
|
439
|
+
activeDomains.set(domain, (activeDomains.get(domain) ?? 0) + 1);
|
|
440
|
+
}
|
|
441
|
+
for (const [domain, count] of activeDomains.entries()) {
|
|
442
|
+
if (count > 1) {
|
|
443
|
+
addFinding(
|
|
444
|
+
findings,
|
|
445
|
+
"block",
|
|
446
|
+
"AGDF_PARALLEL_SOT",
|
|
447
|
+
`Domain has ${count} active source-of-truth rows: ${domain}.`,
|
|
448
|
+
sotPath,
|
|
449
|
+
"Keep exactly one active primary source of truth for this domain.",
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
const contextPath = join(".agdf", "control", "CONTEXT_GRAPH.md");
|
|
455
|
+
const contextGraph = readTargetFile(targetDir, contextPath);
|
|
456
|
+
if (contextGraph.includes("### CG-001 Example")) {
|
|
457
|
+
addFinding(
|
|
458
|
+
findings,
|
|
459
|
+
"warn",
|
|
460
|
+
"AGDF_CONTEXT_GRAPH_TEMPLATE_NODE",
|
|
461
|
+
"CONTEXT_GRAPH.md still contains the example node.",
|
|
462
|
+
contextPath,
|
|
463
|
+
"Remove the example or replace it with an evidenced node that has an exit criterion.",
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
const contractsPath = join(".agdf", "control", "AGENT_QUALITY_CONTRACTS.json");
|
|
468
|
+
try {
|
|
469
|
+
parseQualityContracts(readTargetFile(targetDir, contractsPath));
|
|
470
|
+
} catch (error) {
|
|
471
|
+
addFinding(
|
|
472
|
+
findings,
|
|
473
|
+
"block",
|
|
474
|
+
"AGDF_QUALITY_CONTRACTS_INVALID",
|
|
475
|
+
`AGENT_QUALITY_CONTRACTS.json is invalid: ${error.message}`,
|
|
476
|
+
contractsPath,
|
|
477
|
+
"Restore the generated contracts or fix the JSON contract schema.",
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
const severityRank = { block: 3, revise: 2, warn: 1 };
|
|
483
|
+
const maxSeverity = findings.reduce((max, finding) => Math.max(max, severityRank[finding.severity] ?? 0), 0);
|
|
484
|
+
const status = maxSeverity >= 3 ? "block" : maxSeverity === 2 ? "revise" : maxSeverity === 1 ? "warn" : "pass";
|
|
485
|
+
|
|
486
|
+
return {
|
|
487
|
+
schema_version: "1",
|
|
488
|
+
status,
|
|
489
|
+
checked_at: new Date().toISOString(),
|
|
490
|
+
target_dir: targetDir,
|
|
491
|
+
summary: {
|
|
492
|
+
findings: findings.length,
|
|
493
|
+
block: findings.filter((finding) => finding.severity === "block").length,
|
|
494
|
+
revise: findings.filter((finding) => finding.severity === "revise").length,
|
|
495
|
+
warn: findings.filter((finding) => finding.severity === "warn").length,
|
|
496
|
+
},
|
|
497
|
+
findings,
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function printDoctorReport(report, json) {
|
|
502
|
+
if (json) {
|
|
503
|
+
console.log(JSON.stringify(report, null, 2));
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
console.log(`AGDF doctor: ${report.status}`);
|
|
508
|
+
console.log(`Checked: ${report.target_dir}`);
|
|
509
|
+
console.log(`Findings: ${report.summary.findings} (${report.summary.block} block, ${report.summary.revise} revise, ${report.summary.warn} warn)`);
|
|
510
|
+
|
|
511
|
+
for (const finding of report.findings) {
|
|
512
|
+
console.log("");
|
|
513
|
+
console.log(`[${finding.severity}] ${finding.code}`);
|
|
514
|
+
console.log(`Path: ${finding.path}`);
|
|
515
|
+
console.log(finding.message);
|
|
516
|
+
console.log(`Next step: ${finding.next_step}`);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
220
520
|
function main() {
|
|
221
521
|
const options = parseArgs(process.argv.slice(2));
|
|
522
|
+
|
|
523
|
+
if (options.target === "doctor") {
|
|
524
|
+
const report = evaluateDoctor(options.dir);
|
|
525
|
+
printDoctorReport(report, options.json);
|
|
526
|
+
process.exit(report.status === "block" ? 2 : 0);
|
|
527
|
+
}
|
|
528
|
+
|
|
222
529
|
const files = generatedFilesForTarget(options.target, options.dir, options.force);
|
|
223
530
|
const wroteAgentsFragment = files.some(file => file.path === agdfFragmentPath);
|
|
224
531
|
|
|
@@ -8,11 +8,11 @@ Use this scaffold when a target repository should keep AGDF state outside chat h
|
|
|
8
8
|
|
|
9
9
|
| File | Purpose |
|
|
10
10
|
|---|---|
|
|
11
|
-
| `templates/AGDF_RUN.md` |
|
|
12
|
-
| `templates/MASTER_BACKLOG.md` |
|
|
13
|
-
| `templates/SOT_REGISTRY.md` |
|
|
14
|
-
| `templates/CONTEXT_GRAPH.md` |
|
|
15
|
-
| `templates/AGENT_QUALITY_CONTRACTS.json` |
|
|
11
|
+
| `templates/AGDF_RUN.md` | Template for current run state: mode, gate, approvals, evidence, risks, next allowed action |
|
|
12
|
+
| `templates/MASTER_BACKLOG.md` | Template for the living backlog pointer: active initiatives and current UR/PRD/SD/TP artefacts |
|
|
13
|
+
| `templates/SOT_REGISTRY.md` | Template for the source-of-truth registry: one primary owner per domain |
|
|
14
|
+
| `templates/CONTEXT_GRAPH.md` | Template for project memory: durable decisions, Brownfield findings, risks, evidence and exit criteria |
|
|
15
|
+
| `templates/AGENT_QUALITY_CONTRACTS.json` | Template for machine-readable warning, revise and block contracts for review and QA |
|
|
16
16
|
|
|
17
17
|
## Recommended Target Layout
|
|
18
18
|
|
|
@@ -28,6 +28,21 @@ Use this scaffold when a target repository should keep AGDF state outside chat h
|
|
|
28
28
|
|
|
29
29
|
Keep these files small and reviewable. They are control artefacts, not a second documentation site.
|
|
30
30
|
|
|
31
|
+
Create the live files with:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm create agdf@latest init
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Then check whether the live state is actionable:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm create agdf@latest doctor
|
|
41
|
+
npm create agdf@latest doctor --json
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`doctor` does not replace agent judgment. It catches basic control failures: missing live files, missing current gate, missing next allowed action, empty evidence, empty backlog pointer, empty source-of-truth registry, duplicate active SoT rows and invalid quality contracts.
|
|
45
|
+
|
|
31
46
|
## Operating Rules
|
|
32
47
|
|
|
33
48
|
- `AGDF_RUN.md` is the current run dashboard.
|
|
@@ -8,11 +8,11 @@ Use this scaffold when a target repository should keep AGDF state outside chat h
|
|
|
8
8
|
|
|
9
9
|
| File | Purpose |
|
|
10
10
|
|---|---|
|
|
11
|
-
| `templates/AGDF_RUN.md` |
|
|
12
|
-
| `templates/MASTER_BACKLOG.md` |
|
|
13
|
-
| `templates/SOT_REGISTRY.md` |
|
|
14
|
-
| `templates/CONTEXT_GRAPH.md` |
|
|
15
|
-
| `templates/AGENT_QUALITY_CONTRACTS.json` |
|
|
11
|
+
| `templates/AGDF_RUN.md` | Template for current run state: mode, gate, approvals, evidence, risks, next allowed action |
|
|
12
|
+
| `templates/MASTER_BACKLOG.md` | Template for the living backlog pointer: active initiatives and current UR/PRD/SD/TP artefacts |
|
|
13
|
+
| `templates/SOT_REGISTRY.md` | Template for the source-of-truth registry: one primary owner per domain |
|
|
14
|
+
| `templates/CONTEXT_GRAPH.md` | Template for project memory: durable decisions, Brownfield findings, risks, evidence and exit criteria |
|
|
15
|
+
| `templates/AGENT_QUALITY_CONTRACTS.json` | Template for machine-readable warning, revise and block contracts for review and QA |
|
|
16
16
|
|
|
17
17
|
## Recommended Target Layout
|
|
18
18
|
|
|
@@ -28,6 +28,21 @@ Use this scaffold when a target repository should keep AGDF state outside chat h
|
|
|
28
28
|
|
|
29
29
|
Keep these files small and reviewable. They are control artefacts, not a second documentation site.
|
|
30
30
|
|
|
31
|
+
Create the live files with:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm create agdf@latest init
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Then check whether the live state is actionable:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm create agdf@latest doctor
|
|
41
|
+
npm create agdf@latest doctor --json
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`doctor` does not replace agent judgment. It catches basic control failures: missing live files, missing current gate, missing next allowed action, empty evidence, empty backlog pointer, empty source-of-truth registry, duplicate active SoT rows and invalid quality contracts.
|
|
45
|
+
|
|
31
46
|
## Operating Rules
|
|
32
47
|
|
|
33
48
|
- `AGDF_RUN.md` is the current run dashboard.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"id": "agdf",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.8",
|
|
5
5
|
"displayName": "AI Governance & Delivery Framework",
|
|
6
6
|
"developerName": "AI-native Governance & Delivery Framework",
|
|
7
7
|
"description": "Codex-first workflow skills for gated, auditable AI-assisted software delivery.",
|