@momentiq/dark-factory-cli 2.1.0 → 2.2.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/dist/adapters/static-schema-lint.js +1 -1
- package/dist/cli.js +3 -3
- package/dist/cli.js.map +1 -1
- package/dist/commands/onboard.d.ts +64 -1
- package/dist/commands/onboard.d.ts.map +1 -1
- package/dist/commands/onboard.js +265 -53
- package/dist/commands/onboard.js.map +1 -1
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +20 -0
- package/dist/doctor.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +2 -0
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools/onboard.d.ts +6 -0
- package/dist/mcp/tools/onboard.d.ts.map +1 -0
- package/dist/mcp/tools/onboard.js +115 -0
- package/dist/mcp/tools/onboard.js.map +1 -0
- package/dist/onboard/apply-plan.d.ts +29 -0
- package/dist/onboard/apply-plan.d.ts.map +1 -0
- package/dist/onboard/apply-plan.js +80 -0
- package/dist/onboard/apply-plan.js.map +1 -0
- package/dist/onboard/auto-profile.d.ts +3 -0
- package/dist/onboard/auto-profile.d.ts.map +1 -0
- package/dist/onboard/auto-profile.js +20 -0
- package/dist/onboard/auto-profile.js.map +1 -0
- package/dist/onboard/generate-plan.d.ts +18 -0
- package/dist/onboard/generate-plan.d.ts.map +1 -0
- package/dist/onboard/generate-plan.js +68 -0
- package/dist/onboard/generate-plan.js.map +1 -0
- package/dist/onboard/llm-client.d.ts +45 -0
- package/dist/onboard/llm-client.d.ts.map +1 -0
- package/dist/onboard/llm-client.js +84 -0
- package/dist/onboard/llm-client.js.map +1 -0
- package/dist/onboard/prompts/scaffold.md +93 -0
- package/dist/onboard/prompts.d.ts +13 -0
- package/dist/onboard/prompts.d.ts.map +1 -0
- package/dist/onboard/prompts.js +54 -0
- package/dist/onboard/prompts.js.map +1 -0
- package/dist/onboard/scaffold-schema.d.ts +194 -0
- package/dist/onboard/scaffold-schema.d.ts.map +1 -0
- package/dist/onboard/scaffold-schema.js +73 -0
- package/dist/onboard/scaffold-schema.js.map +1 -0
- package/dist/onboard/schema.d.ts.map +1 -1
- package/dist/onboard/schema.js +7 -1
- package/dist/onboard/schema.js.map +1 -1
- package/dist/onboard/seeders/adr.d.ts +3 -0
- package/dist/onboard/seeders/adr.d.ts.map +1 -0
- package/dist/onboard/seeders/adr.js +212 -0
- package/dist/onboard/seeders/adr.js.map +1 -0
- package/dist/onboard/seeders/agent-review-config/cloud.canonical.json +22 -0
- package/dist/onboard/seeders/agent-review-config/local.canonical.json +21 -0
- package/dist/onboard/seeders/agent-review-config.d.ts +3 -0
- package/dist/onboard/seeders/agent-review-config.d.ts.map +1 -0
- package/dist/onboard/seeders/agent-review-config.js +38 -0
- package/dist/onboard/seeders/agent-review-config.js.map +1 -0
- package/dist/onboard/seeders/cycle1-bootstrap.d.ts +3 -0
- package/dist/onboard/seeders/cycle1-bootstrap.d.ts.map +1 -0
- package/dist/onboard/seeders/cycle1-bootstrap.js +76 -0
- package/dist/onboard/seeders/cycle1-bootstrap.js.map +1 -0
- package/dist/onboard/seeders/index.d.ts +47 -0
- package/dist/onboard/seeders/index.d.ts.map +1 -0
- package/dist/onboard/seeders/index.js +37 -0
- package/dist/onboard/seeders/index.js.map +1 -0
- package/dist/onboard/seeders/runbook.d.ts +13 -0
- package/dist/onboard/seeders/runbook.d.ts.map +1 -0
- package/dist/onboard/seeders/runbook.js +85 -0
- package/dist/onboard/seeders/runbook.js.map +1 -0
- package/dist/onboard/seeders/templates/adr.md.tmpl +26 -0
- package/dist/onboard/seeders/templates/cycle1-bootstrap.md.tmpl +64 -0
- package/dist/onboard/seeders/templates/runbook.md.tmpl +26 -0
- package/dist/onboard/template-loader.d.ts +20 -0
- package/dist/onboard/template-loader.d.ts.map +1 -0
- package/dist/onboard/template-loader.js +143 -0
- package/dist/onboard/template-loader.js.map +1 -0
- package/dist/onboard/template-ref.d.ts +15 -0
- package/dist/onboard/template-ref.d.ts.map +1 -0
- package/dist/onboard/template-ref.js +45 -0
- package/dist/onboard/template-ref.js.map +1 -0
- package/dist/onboard/validate.d.ts +19 -0
- package/dist/onboard/validate.d.ts.map +1 -0
- package/dist/onboard/validate.js +127 -0
- package/dist/onboard/validate.js.map +1 -0
- package/dist/onboard/writers/dry-run-renderer.d.ts +6 -0
- package/dist/onboard/writers/dry-run-renderer.d.ts.map +1 -0
- package/dist/onboard/writers/dry-run-renderer.js +88 -0
- package/dist/onboard/writers/dry-run-renderer.js.map +1 -0
- package/dist/onboard/writers/emit.d.ts +6 -0
- package/dist/onboard/writers/emit.d.ts.map +1 -0
- package/dist/onboard/writers/emit.js +29 -0
- package/dist/onboard/writers/emit.js.map +1 -0
- package/dist/onboard/writers/merge.d.ts +16 -0
- package/dist/onboard/writers/merge.d.ts.map +1 -0
- package/dist/onboard/writers/merge.js +142 -0
- package/dist/onboard/writers/merge.js.map +1 -0
- package/dist/onboard/writers/pr-writer.d.ts +44 -0
- package/dist/onboard/writers/pr-writer.d.ts.map +1 -0
- package/dist/onboard/writers/pr-writer.js +104 -0
- package/dist/onboard/writers/pr-writer.js.map +1 -0
- package/dist/onboard/writers/skip.d.ts +9 -0
- package/dist/onboard/writers/skip.d.ts.map +1 -0
- package/dist/onboard/writers/skip.js +9 -0
- package/dist/onboard/writers/skip.js.map +1 -0
- package/package.json +4 -1
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
// packages/cli/src/onboard/template-loader.ts
|
|
2
|
+
//
|
|
3
|
+
// Template loader for `df onboard`'s Stage B input.
|
|
4
|
+
// Resolves a templateRef (gh:<owner>/<repo>@<ref> | file://<abs>@<ref>) to a
|
|
5
|
+
// content-addressed cache directory, then walks the directory and returns
|
|
6
|
+
// the file set (subject to the Phase B filter rules: no .git/node_modules,
|
|
7
|
+
// ≤ 64 KB per file, no binary, ≤ 200 entries total).
|
|
8
|
+
//
|
|
9
|
+
// Cache key is the resolved sha — so `latest` and the sha it resolves to
|
|
10
|
+
// share one entry, no churn on re-runs.
|
|
11
|
+
//
|
|
12
|
+
// Ref parsing is delegated to template-ref.ts (Task 1's co-located foundation
|
|
13
|
+
// file) — this loader consumes parseTemplateRef + the parsed-ref types from
|
|
14
|
+
// there. Round-4 restructure-completion: keeping the parser in the foundation
|
|
15
|
+
// file means schema (Task 1) and loader (Task 3) cannot drift on the semantic
|
|
16
|
+
// check, AND no circular import is possible (template-ref.ts imports nothing
|
|
17
|
+
// from schema or loader, so the loader can import ScaffoldPlanSchema in the
|
|
18
|
+
// future if it ever needs to).
|
|
19
|
+
import { execFile } from "node:child_process";
|
|
20
|
+
import { promisify } from "node:util";
|
|
21
|
+
import { mkdir, readdir, readFile, rename, rm, stat, cp } from "node:fs/promises";
|
|
22
|
+
import { homedir } from "node:os";
|
|
23
|
+
import { join, relative } from "node:path";
|
|
24
|
+
import { parseTemplateRef, } from "./template-ref.js";
|
|
25
|
+
export { parseTemplateRef };
|
|
26
|
+
const ex = promisify(execFile);
|
|
27
|
+
export const MAX_TEMPLATE_FILES = 200;
|
|
28
|
+
export const MAX_TEMPLATE_FILE_SIZE = 65_536;
|
|
29
|
+
const SKIP_DIRS = new Set([".git", "node_modules", "dist", "build"]);
|
|
30
|
+
const FORTY_HEX = /^[0-9a-f]{40}$/i;
|
|
31
|
+
async function resolveSha(parsed) {
|
|
32
|
+
if (parsed.kind === "file") {
|
|
33
|
+
return parsed.ref;
|
|
34
|
+
}
|
|
35
|
+
if (FORTY_HEX.test(parsed.ref)) {
|
|
36
|
+
return parsed.ref.toLowerCase();
|
|
37
|
+
}
|
|
38
|
+
const url = `https://github.com/${parsed.owner}/${parsed.repo}.git`;
|
|
39
|
+
const refArg = parsed.ref === "latest" ? "HEAD" :
|
|
40
|
+
parsed.ref.startsWith("refs/") ? parsed.ref :
|
|
41
|
+
parsed.ref;
|
|
42
|
+
const { stdout } = await ex("git", ["ls-remote", url, refArg]);
|
|
43
|
+
const sha = stdout.split(/\s/)[0];
|
|
44
|
+
if (!sha || !FORTY_HEX.test(sha)) {
|
|
45
|
+
throw new Error(`df onboard: could not resolve ref "${parsed.ref}" against ${url}. ` +
|
|
46
|
+
"Verify the ref exists and the repo is publicly readable.");
|
|
47
|
+
}
|
|
48
|
+
return sha.toLowerCase();
|
|
49
|
+
}
|
|
50
|
+
function cacheDirFor(parsed, sha, cacheRoot) {
|
|
51
|
+
if (parsed.kind === "gh") {
|
|
52
|
+
return join(cacheRoot, `${parsed.owner}__${parsed.repo}__${sha}`);
|
|
53
|
+
}
|
|
54
|
+
const tag = parsed.path.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
55
|
+
return join(cacheRoot, `file__${tag}__${sha}`);
|
|
56
|
+
}
|
|
57
|
+
async function populateCache(parsed, sha, cacheDir) {
|
|
58
|
+
const tmp = `${cacheDir}.tmp-${process.pid}-${Date.now()}`;
|
|
59
|
+
await rm(tmp, { recursive: true, force: true });
|
|
60
|
+
if (parsed.kind === "file") {
|
|
61
|
+
await cp(parsed.path, tmp, { recursive: true });
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
const url = `https://github.com/${parsed.owner}/${parsed.repo}.git`;
|
|
65
|
+
await mkdir(tmp, { recursive: true });
|
|
66
|
+
await ex("git", ["init", "-q"], { cwd: tmp });
|
|
67
|
+
await ex("git", ["fetch", "--depth", "1", "-q", url, sha], { cwd: tmp });
|
|
68
|
+
await ex("git", ["checkout", "-q", "FETCH_HEAD"], { cwd: tmp });
|
|
69
|
+
await rm(join(tmp, ".git"), { recursive: true, force: true });
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
await rename(tmp, cacheDir);
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
await rm(tmp, { recursive: true, force: true });
|
|
76
|
+
try {
|
|
77
|
+
await stat(cacheDir);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
throw err;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
async function isBinary(filepath) {
|
|
85
|
+
const head = Buffer.alloc(8192);
|
|
86
|
+
const fh = await import("node:fs/promises").then((m) => m.open(filepath, "r"));
|
|
87
|
+
try {
|
|
88
|
+
const { bytesRead } = await fh.read(head, 0, head.length, 0);
|
|
89
|
+
for (let i = 0; i < bytesRead; i++)
|
|
90
|
+
if (head[i] === 0)
|
|
91
|
+
return true;
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
await fh.close();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
async function walkTemplate(rootDir) {
|
|
99
|
+
const out = [];
|
|
100
|
+
async function recur(dir) {
|
|
101
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
102
|
+
for (const e of entries) {
|
|
103
|
+
const abs = join(dir, e.name);
|
|
104
|
+
if (e.isDirectory()) {
|
|
105
|
+
if (SKIP_DIRS.has(e.name))
|
|
106
|
+
continue;
|
|
107
|
+
await recur(abs);
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (!e.isFile())
|
|
111
|
+
continue;
|
|
112
|
+
const st = await stat(abs);
|
|
113
|
+
if (st.size > MAX_TEMPLATE_FILE_SIZE)
|
|
114
|
+
continue;
|
|
115
|
+
if (await isBinary(abs))
|
|
116
|
+
continue;
|
|
117
|
+
const rel = relative(rootDir, abs);
|
|
118
|
+
out.push({ path: rel, content: await readFile(abs, "utf8") });
|
|
119
|
+
if (out.length > MAX_TEMPLATE_FILES) {
|
|
120
|
+
throw new Error(`df onboard: template file count exceeds ${MAX_TEMPLATE_FILES}. ` +
|
|
121
|
+
"Reduce the template surface or raise MAX_TEMPLATE_FILES (cycle 15 Phase B / B-D4).");
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
await recur(rootDir);
|
|
126
|
+
return out;
|
|
127
|
+
}
|
|
128
|
+
export async function loadTemplate(canonicalRef, opts = {}) {
|
|
129
|
+
const parsed = parseTemplateRef(canonicalRef);
|
|
130
|
+
const cacheRoot = opts.cacheRoot ?? join(homedir(), ".df", "cache", "templates");
|
|
131
|
+
await mkdir(cacheRoot, { recursive: true });
|
|
132
|
+
const sha = await resolveSha(parsed);
|
|
133
|
+
const cacheDir = cacheDirFor(parsed, sha, cacheRoot);
|
|
134
|
+
try {
|
|
135
|
+
await stat(cacheDir);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
await populateCache(parsed, sha, cacheDir);
|
|
139
|
+
}
|
|
140
|
+
const files = await walkTemplate(cacheDir);
|
|
141
|
+
return { canonicalRef, resolvedSha: sha, cacheDir, files };
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=template-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template-loader.js","sourceRoot":"","sources":["../../src/onboard/template-loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const TEMPLATE_REF_SHAPE_RE: RegExp;
|
|
2
|
+
export interface GhTemplateRef {
|
|
3
|
+
kind: "gh";
|
|
4
|
+
owner: string;
|
|
5
|
+
repo: string;
|
|
6
|
+
ref: string;
|
|
7
|
+
}
|
|
8
|
+
export interface FileTemplateRef {
|
|
9
|
+
kind: "file";
|
|
10
|
+
path: string;
|
|
11
|
+
ref: string;
|
|
12
|
+
}
|
|
13
|
+
export type ParsedTemplateRef = GhTemplateRef | FileTemplateRef;
|
|
14
|
+
export declare function parseTemplateRef(input: string): ParsedTemplateRef;
|
|
15
|
+
//# sourceMappingURL=template-ref.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template-ref.d.ts","sourceRoot":"","sources":["../../src/onboard/template-ref.ts"],"names":[],"mappings":"AAwBA,eAAO,MAAM,qBAAqB,QAA+C,CAAC;AAElF,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,IAAI,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,MAAM,iBAAiB,GAAG,aAAa,GAAG,eAAe,CAAC;AAEhE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,iBAAiB,CAyBjE"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// packages/cli/src/onboard/template-ref.ts
|
|
2
|
+
//
|
|
3
|
+
// Template-ref foundation (round-4 advisor restructure-completion).
|
|
4
|
+
//
|
|
5
|
+
// Co-located foundation file: both `scaffold-schema.ts` (Task 1) and
|
|
6
|
+
// `template-loader.ts` (Task 3) import `parseTemplateRef` from here so
|
|
7
|
+
// the predicate has a single source of truth (schema and loader cannot
|
|
8
|
+
// drift on the semantic ref check) AND there's no circular import (the
|
|
9
|
+
// loader can also import ScaffoldPlanSchema if it ever needs to without
|
|
10
|
+
// creating a cycle, because template-ref.ts imports from neither).
|
|
11
|
+
//
|
|
12
|
+
// History — round-3 W3 advisor restructure. Rounds 1+2 tried to encode
|
|
13
|
+
// the NEGATIVE constraint ("not a 7–39 hex string") as a POSITIVE
|
|
14
|
+
// character class inside a single regex. Each round's tweak introduced
|
|
15
|
+
// a new false-positive or false-negative: round 1 ([A-Za-z._/-]) silently
|
|
16
|
+
// accepted short hex; round 2 ([g-zG-Z._/-]) rejected valid pure-digit
|
|
17
|
+
// refs like `123456` / `20260603`; gemini's prescribed round-3 lookahead
|
|
18
|
+
// fix STILL rejected `20260603` (an 8-digit ref is a subset of
|
|
19
|
+
// [0-9a-fA-F]). The negative constraint cannot compose cleanly with a
|
|
20
|
+
// positive class. The restructure: narrow the regex to SHAPE, delegate
|
|
21
|
+
// semantics to this parser. See commit log + plan §B-D3 for the
|
|
22
|
+
// iteration arc (round-1 → round-2 → round-3 regex iteration; round-4
|
|
23
|
+
// shared-module extraction).
|
|
24
|
+
export const TEMPLATE_REF_SHAPE_RE = /^(gh:[^/]+\/[^@]+|file:\/\/\/[^@]+)@[^@]+$/;
|
|
25
|
+
export function parseTemplateRef(input) {
|
|
26
|
+
const fileMatch = input.match(/^file:\/\/(\/[^@]+)@([A-Za-z0-9._/-]+)$/);
|
|
27
|
+
if (fileMatch) {
|
|
28
|
+
return { kind: "file", path: fileMatch[1], ref: fileMatch[2] };
|
|
29
|
+
}
|
|
30
|
+
const ghMatch = input.match(/^gh:([^/]+)\/([^@]+)@([A-Za-z0-9._/-]+)$/);
|
|
31
|
+
if (ghMatch) {
|
|
32
|
+
const [, owner, repo, ref] = ghMatch;
|
|
33
|
+
if (ref.length >= 7 &&
|
|
34
|
+
ref.length < 40 &&
|
|
35
|
+
/^[0-9a-fA-F]+$/.test(ref) &&
|
|
36
|
+
/[a-fA-F]/.test(ref)) {
|
|
37
|
+
throw new Error(`df onboard: short sha "${ref}" is not supported as a template ref. ` +
|
|
38
|
+
"Use the full 40-character sha, or a tag/branch name.");
|
|
39
|
+
}
|
|
40
|
+
return { kind: "gh", owner: owner, repo: repo, ref: ref };
|
|
41
|
+
}
|
|
42
|
+
throw new Error(`df onboard: malformed templateRef "${input}". ` +
|
|
43
|
+
"Expected gh:<owner>/<repo>@<ref> or file:///<abs-path>@<ref>.");
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=template-ref.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template-ref.js","sourceRoot":"","sources":["../../src/onboard/template-ref.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,EAAE;AACF,oEAAoE;AACpE,EAAE;AACF,qEAAqE;AACrE,uEAAuE;AACvE,uEAAuE;AACvE,uEAAuE;AACvE,wEAAwE;AACxE,mEAAmE;AACnE,EAAE;AACF,uEAAuE;AACvE,kEAAkE;AAClE,uEAAuE;AACvE,0EAA0E;AAC1E,uEAAuE;AACvE,yEAAyE;AACzE,+DAA+D;AAC/D,sEAAsE;AACtE,uEAAuE;AACvE,gEAAgE;AAChE,sEAAsE;AACtE,6BAA6B;AAE7B,MAAM,CAAC,MAAM,qBAAqB,GAAG,4CAA4C,CAAC;AAiBlF,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;IACzE,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAE,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC,CAAE,EAAE,CAAC;IACnE,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;IACxE,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC;QACrC,IACE,GAAI,CAAC,MAAM,IAAI,CAAC;YAChB,GAAI,CAAC,MAAM,GAAG,EAAE;YAChB,gBAAgB,CAAC,IAAI,CAAC,GAAI,CAAC;YAC3B,UAAU,CAAC,IAAI,CAAC,GAAI,CAAC,EACrB,CAAC;YACD,MAAM,IAAI,KAAK,CACb,0BAA0B,GAAG,wCAAwC;gBACnE,sDAAsD,CACzD,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAM,EAAE,IAAI,EAAE,IAAK,EAAE,GAAG,EAAE,GAAI,EAAE,CAAC;IAC/D,CAAC;IACD,MAAM,IAAI,KAAK,CACb,sCAAsC,KAAK,KAAK;QAC9C,+DAA+D,CAClE,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { DoctorCheck } from "@momentiq/dark-factory-schemas";
|
|
2
|
+
export interface CheckAgentContextSetOptions {
|
|
3
|
+
repoRoot: string;
|
|
4
|
+
/**
|
|
5
|
+
* The value of `loaded.config.context?.guidanceFiles` from the loaded
|
|
6
|
+
* AgentReviewConfig. The required-files walk (CLAUDE.md, AGENTS.md, etc.)
|
|
7
|
+
* runs UNCONDITIONALLY regardless of this value (per Decision #7 round-1
|
|
8
|
+
* revision — the cycle 15 D3 required-files set is the floor, not gated
|
|
9
|
+
* by the opt-in guidanceFiles field).
|
|
10
|
+
*
|
|
11
|
+
* - `undefined` or `[]` → guidance-file walk skipped; single
|
|
12
|
+
* `agent_context.guidance_not_configured` informational marker emitted.
|
|
13
|
+
* - Non-empty array → each path additionally checked; failures emit
|
|
14
|
+
* `agent_context.guidance_<i>` per Decision #7.
|
|
15
|
+
*/
|
|
16
|
+
guidanceFiles: readonly string[] | undefined;
|
|
17
|
+
}
|
|
18
|
+
export declare function checkAgentContextSet(opts: CheckAgentContextSetOptions): Promise<DoctorCheck[]>;
|
|
19
|
+
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/onboard/validate.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAElE,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;;;;;;OAWG;IACH,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;CAC9C;AA2DD,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,2BAA2B,GAChC,OAAO,CAAC,WAAW,EAAE,CAAC,CA+DxB"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// Cycle 15 Phase C — `checkAgentContextSet()` for `df doctor`.
|
|
2
|
+
//
|
|
3
|
+
// Walks the cycle-15 D3 required-files set (CLAUDE.md, AGENTS.md,
|
|
4
|
+
// .claude/settings.json, docs/PRINCIPLES.md, docs/roadmap/cycles/cycle1-*.md,
|
|
5
|
+
// .agent-review/config.json) UNCONDITIONALLY, then optionally validates each
|
|
6
|
+
// path in `context.guidanceFiles` (from the loaded AgentReviewConfig) resolves
|
|
7
|
+
// to a real file under `repoRoot`.
|
|
8
|
+
//
|
|
9
|
+
// Per Decision #7 (round-1 revision): the required-files walk runs regardless
|
|
10
|
+
// of whether `context.guidanceFiles` is configured — the D3 set is the floor.
|
|
11
|
+
// The guidance-file walk is opt-in: when `guidanceFiles` is undefined OR `[]`,
|
|
12
|
+
// a single `agent_context.guidance_not_configured` informational marker is
|
|
13
|
+
// emitted (passed: true, optional: true) so operators see the field was
|
|
14
|
+
// skipped rather than silently absent.
|
|
15
|
+
//
|
|
16
|
+
// Cycle 15 exit-criterion lines 297–303: "the post-apply check fails loudly
|
|
17
|
+
// when any of [list] are missing or unwired (`context.guidanceFiles` does not
|
|
18
|
+
// point at real files). All current repos must pass `df doctor` after this
|
|
19
|
+
// lands."
|
|
20
|
+
import { access, readdir } from "node:fs/promises";
|
|
21
|
+
import { constants } from "node:fs";
|
|
22
|
+
import { resolve } from "node:path";
|
|
23
|
+
const REQUIRED_FILES = [
|
|
24
|
+
{ key: "claude_md", name: "CLAUDE.md", path: "CLAUDE.md", isGlob: false },
|
|
25
|
+
{ key: "agents_md", name: "AGENTS.md", path: "AGENTS.md", isGlob: false },
|
|
26
|
+
{
|
|
27
|
+
key: "claude_settings",
|
|
28
|
+
name: ".claude/settings.json",
|
|
29
|
+
path: ".claude/settings.json",
|
|
30
|
+
isGlob: false,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
key: "principles",
|
|
34
|
+
name: "docs/PRINCIPLES.md",
|
|
35
|
+
path: "docs/PRINCIPLES.md",
|
|
36
|
+
isGlob: false,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
key: "cycle1_bootstrap",
|
|
40
|
+
name: "docs/roadmap/cycles/cycle1-*.md",
|
|
41
|
+
path: "docs/roadmap/cycles",
|
|
42
|
+
isGlob: true,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
key: "config",
|
|
46
|
+
name: ".agent-review/config.json",
|
|
47
|
+
path: ".agent-review/config.json",
|
|
48
|
+
isGlob: false,
|
|
49
|
+
},
|
|
50
|
+
];
|
|
51
|
+
async function fileExists(path) {
|
|
52
|
+
try {
|
|
53
|
+
await access(path, constants.F_OK);
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async function cycle1GlobMatches(dir) {
|
|
61
|
+
try {
|
|
62
|
+
const entries = await readdir(dir);
|
|
63
|
+
return entries.some((name) => /^cycle1-.*\.md$/.test(name));
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const REMEDIATION = "run `df onboard --apply` to generate the missing agent-context files, or restore the file from version control";
|
|
70
|
+
export async function checkAgentContextSet(opts) {
|
|
71
|
+
const out = [];
|
|
72
|
+
// Required-file walk — runs UNCONDITIONALLY per Decision #7 (round-1
|
|
73
|
+
// revision). The cycle 15 exit-criterion lines 297–303 say "fails loudly
|
|
74
|
+
// when any of [list] are missing OR unwired"; a repo without a
|
|
75
|
+
// `context.guidanceFiles` block in .agent-review/config.json should still
|
|
76
|
+
// fail when CLAUDE.md is missing.
|
|
77
|
+
for (const req of REQUIRED_FILES) {
|
|
78
|
+
const fullPath = resolve(opts.repoRoot, req.path);
|
|
79
|
+
const exists = req.isGlob
|
|
80
|
+
? await cycle1GlobMatches(fullPath)
|
|
81
|
+
: await fileExists(fullPath);
|
|
82
|
+
out.push(exists
|
|
83
|
+
? {
|
|
84
|
+
name: `agent_context.${req.key}`,
|
|
85
|
+
passed: true,
|
|
86
|
+
detail: `${req.name} present at ${fullPath}`,
|
|
87
|
+
}
|
|
88
|
+
: {
|
|
89
|
+
name: `agent_context.${req.key}`,
|
|
90
|
+
passed: false,
|
|
91
|
+
detail: `${req.name} missing at ${fullPath}`,
|
|
92
|
+
remediation: REMEDIATION,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
// Guidance-file walk — additional check, runs only when the guidanceFiles
|
|
96
|
+
// field is non-empty. The field is opt-in (NOT a gate for the required-
|
|
97
|
+
// files set above).
|
|
98
|
+
if (opts.guidanceFiles === undefined || opts.guidanceFiles.length === 0) {
|
|
99
|
+
out.push({
|
|
100
|
+
name: "agent_context.guidance_not_configured",
|
|
101
|
+
passed: true,
|
|
102
|
+
optional: true,
|
|
103
|
+
detail: ".agent-review/config.json has no `context.guidanceFiles` block — additional per-path validation skipped (the required-files walk above still ran).",
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
for (let i = 0; i < opts.guidanceFiles.length; i++) {
|
|
108
|
+
const rel = opts.guidanceFiles[i];
|
|
109
|
+
const full = resolve(opts.repoRoot, rel);
|
|
110
|
+
const exists = await fileExists(full);
|
|
111
|
+
out.push(exists
|
|
112
|
+
? {
|
|
113
|
+
name: `agent_context.guidance_${i}`,
|
|
114
|
+
passed: true,
|
|
115
|
+
detail: `guidanceFiles[${i}] (${rel}) resolves to ${full}`,
|
|
116
|
+
}
|
|
117
|
+
: {
|
|
118
|
+
name: `agent_context.guidance_${i}`,
|
|
119
|
+
passed: false,
|
|
120
|
+
detail: `guidanceFiles[${i}] (${rel}) does not resolve to a real file under ${opts.repoRoot}`,
|
|
121
|
+
remediation: `fix the path in .agent-review/config.json's context.guidanceFiles[${i}] or create the file`,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return out;
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/onboard/validate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ScaffoldPlan } from "../scaffold-schema.js";
|
|
2
|
+
export interface DryRunOptions {
|
|
3
|
+
color?: boolean;
|
|
4
|
+
}
|
|
5
|
+
export declare function renderDryRun(rootDir: string, plan: ScaffoldPlan, opts?: DryRunOptions): Promise<string>;
|
|
6
|
+
//# sourceMappingURL=dry-run-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dry-run-renderer.d.ts","sourceRoot":"","sources":["../../../src/onboard/writers/dry-run-renderer.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,YAAY,EAAY,MAAM,uBAAuB,CAAC;AAEpE,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AA4DD,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,YAAY,EAClB,IAAI,GAAE,aAAkB,GACvB,OAAO,CAAC,MAAM,CAAC,CAkBjB"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// packages/cli/src/onboard/writers/dry-run-renderer.ts
|
|
2
|
+
//
|
|
3
|
+
// Render a human-readable preview of a ScaffoldPlan against a target dir.
|
|
4
|
+
// Shows per-file actions: emit (new or overwrite-diff), merge (additive
|
|
5
|
+
// append preview), skip (no-op). Colorized by default; honors NO_COLOR.
|
|
6
|
+
import { readFile } from "node:fs/promises";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { createPatch } from "diff";
|
|
9
|
+
const C = {
|
|
10
|
+
reset: "\x1b[0m",
|
|
11
|
+
bold: "\x1b[1m",
|
|
12
|
+
red: "\x1b[31m",
|
|
13
|
+
green: "\x1b[32m",
|
|
14
|
+
yellow: "\x1b[33m",
|
|
15
|
+
cyan: "\x1b[36m",
|
|
16
|
+
dim: "\x1b[2m",
|
|
17
|
+
};
|
|
18
|
+
function colored(s, code, on) {
|
|
19
|
+
return on ? `${code}${s}${C.reset}` : s;
|
|
20
|
+
}
|
|
21
|
+
async function readIfExists(p) {
|
|
22
|
+
try {
|
|
23
|
+
return await readFile(p, "utf8");
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function diffBlock(path, existing, proposed, color) {
|
|
30
|
+
const patch = createPatch(path, existing, proposed, "existing", "proposed");
|
|
31
|
+
if (!color)
|
|
32
|
+
return patch;
|
|
33
|
+
// Colorize +/- lines.
|
|
34
|
+
return patch.split("\n").map((line) => {
|
|
35
|
+
if (line.startsWith("+++") || line.startsWith("---"))
|
|
36
|
+
return colored(line, C.bold, true);
|
|
37
|
+
if (line.startsWith("+"))
|
|
38
|
+
return colored(line, C.green, true);
|
|
39
|
+
if (line.startsWith("-"))
|
|
40
|
+
return colored(line, C.red, true);
|
|
41
|
+
if (line.startsWith("@@"))
|
|
42
|
+
return colored(line, C.cyan, true);
|
|
43
|
+
return line;
|
|
44
|
+
}).join("\n");
|
|
45
|
+
}
|
|
46
|
+
async function renderFile(rootDir, file, color) {
|
|
47
|
+
const path = file.path;
|
|
48
|
+
if (file.action === "skip") {
|
|
49
|
+
return colored(`skip ${path}`, C.yellow, color) +
|
|
50
|
+
colored(` — ${file.rationale}`, C.dim, color) + "\n";
|
|
51
|
+
}
|
|
52
|
+
if (file.action === "emit") {
|
|
53
|
+
const existing = await readIfExists(join(rootDir, path));
|
|
54
|
+
if (existing === null) {
|
|
55
|
+
const header = colored(`emit ${path} (new file)`, C.green, color) + "\n";
|
|
56
|
+
const body = file.tailored_content.split("\n").map((l) => `+ ${l}`).join("\n");
|
|
57
|
+
return header + (color ? colored(body, C.green, true) : body) + "\n";
|
|
58
|
+
}
|
|
59
|
+
const header = colored(`emit ${path} (overwrite — diff below)`, C.bold, color) + "\n";
|
|
60
|
+
return header + diffBlock(path, existing, file.tailored_content, color) + "\n";
|
|
61
|
+
}
|
|
62
|
+
// merge
|
|
63
|
+
const existing = await readIfExists(join(rootDir, path));
|
|
64
|
+
if (existing === null) {
|
|
65
|
+
const header = colored(`merge ${path} (target absent — falling back to emit)`, C.yellow, color) + "\n";
|
|
66
|
+
return header + (color ? colored(file.tailored_content, C.green, true) : file.tailored_content) + "\n";
|
|
67
|
+
}
|
|
68
|
+
const header = colored(`merge ${path} (additive append)`, C.bold, color) + "\n";
|
|
69
|
+
const body = file.tailored_content.split("\n").map((l) => `+ ${l}`).join("\n");
|
|
70
|
+
return header + (color ? colored(body, C.green, true) : body) + "\n";
|
|
71
|
+
}
|
|
72
|
+
export async function renderDryRun(rootDir, plan, opts = {}) {
|
|
73
|
+
const color = opts.color ?? (process.env["NO_COLOR"] === undefined || process.env["NO_COLOR"] === "");
|
|
74
|
+
const lines = [];
|
|
75
|
+
lines.push(colored(`# df onboard — dry-run preview`, C.bold, color));
|
|
76
|
+
lines.push(`# template: ${plan.templateRef}`);
|
|
77
|
+
lines.push(`# generated: ${plan.generatedAtIso}`);
|
|
78
|
+
lines.push(`# files: ${plan.files.length}`);
|
|
79
|
+
lines.push("");
|
|
80
|
+
for (const file of plan.files) {
|
|
81
|
+
lines.push(await renderFile(rootDir, file, color));
|
|
82
|
+
}
|
|
83
|
+
lines.push("");
|
|
84
|
+
lines.push(colored("Summary: ", C.bold, color) + plan.summary);
|
|
85
|
+
lines.push(colored("Dry-run only — pass --apply to write, --pr to open a PR.", C.dim, color));
|
|
86
|
+
return lines.join("\n") + "\n";
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=dry-run-renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dry-run-renderer.js","sourceRoot":"","sources":["../../../src/onboard/writers/dry-run-renderer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../../../src/onboard/writers/emit.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAcD,wBAAsB,SAAS,CAC7B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,YAAY,EAClB,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC,IAAI,CAAC,CAWf"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// packages/cli/src/onboard/writers/emit.ts
|
|
2
|
+
import { mkdir, writeFile, stat } from "node:fs/promises";
|
|
3
|
+
import { dirname, isAbsolute, relative, resolve } from "node:path";
|
|
4
|
+
function safeResolve(root, p) {
|
|
5
|
+
if (isAbsolute(p)) {
|
|
6
|
+
throw new Error(`df onboard: refuses to emit to absolute path "${p}" (outside the target root).`);
|
|
7
|
+
}
|
|
8
|
+
const resolved = resolve(root, p);
|
|
9
|
+
const rel = relative(root, resolved);
|
|
10
|
+
if (rel.startsWith("..") || isAbsolute(rel)) {
|
|
11
|
+
throw new Error(`df onboard: path traversal blocked — "${p}" resolves outside the target root.`);
|
|
12
|
+
}
|
|
13
|
+
return resolved;
|
|
14
|
+
}
|
|
15
|
+
export async function writeEmit(rootDir, plan, opts = {}) {
|
|
16
|
+
const abs = safeResolve(rootDir, plan.path);
|
|
17
|
+
let exists = false;
|
|
18
|
+
try {
|
|
19
|
+
await stat(abs);
|
|
20
|
+
exists = true;
|
|
21
|
+
}
|
|
22
|
+
catch { }
|
|
23
|
+
if (exists && !opts.force) {
|
|
24
|
+
throw new Error(`df onboard: refuses to overwrite existing file "${plan.path}" (pass force=true to override).`);
|
|
25
|
+
}
|
|
26
|
+
await mkdir(dirname(abs), { recursive: true });
|
|
27
|
+
await writeFile(abs, plan.tailored_content, "utf8");
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=emit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit.js","sourceRoot":"","sources":["../../../src/onboard/writers/emit.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,UAAU,EAAQ,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQzE,SAAS,WAAW,CAAC,IAAY,EAAE,CAAS;IAC1C,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,8BAA8B,CAAC,CAAC;IACpG,CAAC;IACD,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAClC,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACrC,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,qCAAqC,CAAC,CAAC;IACnG,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,OAAe,EACf,IAAkB,EAClB,OAAoB,EAAE;IAEtB,MAAM,GAAG,GAAG,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5C,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,IAAI,CAAC;QAAC,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC;QAAC,MAAM,GAAG,IAAI,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IAChD,IAAI,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CACb,mDAAmD,IAAI,CAAC,IAAI,kCAAkC,CAC/F,CAAC;IACJ,CAAC;IACD,MAAM,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/C,MAAM,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC;AACtD,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { MergeFilePlan } from "../scaffold-schema.js";
|
|
2
|
+
export declare const BEGIN_MARKER = "<!-- df onboard: inserted-by-cycle-15 BEGIN -->";
|
|
3
|
+
export declare const END_MARKER = "<!-- df onboard: inserted-by-cycle-15 END -->";
|
|
4
|
+
export interface MergeOptions {
|
|
5
|
+
stderr?: (s: string) => void;
|
|
6
|
+
}
|
|
7
|
+
export interface MergeResult {
|
|
8
|
+
path: string;
|
|
9
|
+
action: "merge";
|
|
10
|
+
wrote: boolean;
|
|
11
|
+
skipped: boolean;
|
|
12
|
+
reason?: string;
|
|
13
|
+
fellBackToEmit?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare function writeMerge(rootDir: string, plan: MergeFilePlan, opts?: MergeOptions): Promise<MergeResult>;
|
|
16
|
+
//# sourceMappingURL=merge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge.d.ts","sourceRoot":"","sources":["../../../src/onboard/writers/merge.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,eAAO,MAAM,YAAY,oDAAoD,CAAC;AAC9E,eAAO,MAAM,UAAU,kDAAkD,CAAC;AAG1E,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AA4ED,wBAAsB,UAAU,CAC9B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,aAAa,EACnB,IAAI,GAAE,YAAiB,GACtB,OAAO,CAAC,WAAW,CAAC,CA6CtB"}
|