@momentiq/dark-factory-cli 2.0.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.d.ts.map +1 -1
- package/dist/cli.js +18 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/onboard.d.ts +69 -0
- package/dist/commands/onboard.d.ts.map +1 -0
- package/dist/commands/onboard.js +323 -0
- package/dist/commands/onboard.js.map +1 -0
- package/dist/cycle-doc-validator/validate_cycle_doc.py +131 -60
- 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/analyze.d.ts +7 -0
- package/dist/onboard/analyze.d.ts.map +1 -0
- package/dist/onboard/analyze.js +86 -0
- package/dist/onboard/analyze.js.map +1 -0
- package/dist/onboard/analyzer.d.ts +15 -0
- package/dist/onboard/analyzer.d.ts.map +1 -0
- package/dist/onboard/analyzer.js +52 -0
- package/dist/onboard/analyzer.js.map +1 -0
- package/dist/onboard/analyzers/ci.d.ts +3 -0
- package/dist/onboard/analyzers/ci.d.ts.map +1 -0
- package/dist/onboard/analyzers/ci.js +112 -0
- package/dist/onboard/analyzers/ci.js.map +1 -0
- package/dist/onboard/analyzers/docs.d.ts +3 -0
- package/dist/onboard/analyzers/docs.d.ts.map +1 -0
- package/dist/onboard/analyzers/docs.js +151 -0
- package/dist/onboard/analyzers/docs.js.map +1 -0
- package/dist/onboard/analyzers/git.d.ts +3 -0
- package/dist/onboard/analyzers/git.d.ts.map +1 -0
- package/dist/onboard/analyzers/git.js +87 -0
- package/dist/onboard/analyzers/git.js.map +1 -0
- package/dist/onboard/analyzers/lockfile.d.ts +3 -0
- package/dist/onboard/analyzers/lockfile.d.ts.map +1 -0
- package/dist/onboard/analyzers/lockfile.js +285 -0
- package/dist/onboard/analyzers/lockfile.js.map +1 -0
- package/dist/onboard/analyzers/manifest.d.ts +3 -0
- package/dist/onboard/analyzers/manifest.d.ts.map +1 -0
- package/dist/onboard/analyzers/manifest.js +228 -0
- package/dist/onboard/analyzers/manifest.js.map +1 -0
- package/dist/onboard/analyzers/tree.d.ts +3 -0
- package/dist/onboard/analyzers/tree.d.ts.map +1 -0
- package/dist/onboard/analyzers/tree.js +196 -0
- package/dist/onboard/analyzers/tree.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/fixtures/replay-git-history.d.ts +20 -0
- package/dist/onboard/fixtures/replay-git-history.d.ts.map +1 -0
- package/dist/onboard/fixtures/replay-git-history.js +91 -0
- package/dist/onboard/fixtures/replay-git-history.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 +545 -0
- package/dist/onboard/schema.d.ts.map +1 -0
- package/dist/onboard/schema.js +148 -0
- package/dist/onboard/schema.js.map +1 -0
- 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 +8 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runbook.js","sourceRoot":"","sources":["../../../src/onboard/seeders/runbook.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# ADR {year}-{nn} — {title}
|
|
2
|
+
|
|
3
|
+
- **Status:** Proposed
|
|
4
|
+
- **Date:** {date}
|
|
5
|
+
- **Deciders:** {deciders}
|
|
6
|
+
- **Scope:** {scope}
|
|
7
|
+
|
|
8
|
+
## Context
|
|
9
|
+
|
|
10
|
+
This decision was surfaced from the deterministic Stage A analysis of the repo at {repo_root}.
|
|
11
|
+
The relevant evidence:
|
|
12
|
+
|
|
13
|
+
{evidence_bullets}
|
|
14
|
+
|
|
15
|
+
## Decision
|
|
16
|
+
|
|
17
|
+
{rationale}
|
|
18
|
+
|
|
19
|
+
## Consequences
|
|
20
|
+
|
|
21
|
+
{consequences}
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
Generated by `df onboard` (cycle 15 Phase C). The maintainer should expand each
|
|
26
|
+
section with repo-specific nuance the deterministic analysis could not produce.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Cycle 1 — {repo_name} bootstrap"
|
|
3
|
+
status: "draft"
|
|
4
|
+
owner: "@{owner}-maintainers"
|
|
5
|
+
started: "{date}"
|
|
6
|
+
target: null
|
|
7
|
+
closed: null
|
|
8
|
+
related_issues: []
|
|
9
|
+
related_repos:
|
|
10
|
+
- "{canonical_name}"
|
|
11
|
+
tags:
|
|
12
|
+
- bootstrap
|
|
13
|
+
- cycle1
|
|
14
|
+
- agent-context
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# Cycle 1 — {repo_name} bootstrap
|
|
18
|
+
|
|
19
|
+
> Generated by `df onboard` (cycle 15 Phase C) from the deterministic Stage A
|
|
20
|
+
> analysis of this repo. The maintainer should expand each section with the
|
|
21
|
+
> nuance the analyzer could not produce.
|
|
22
|
+
|
|
23
|
+
## Scope
|
|
24
|
+
|
|
25
|
+
Bootstrap the agent-context set for `{canonical_name}` so AI-driven development
|
|
26
|
+
(Claude Code, Cursor, Codex, Gemini) operates with the same architectural
|
|
27
|
+
context as a human maintainer. This cycle delivers the initial `CLAUDE.md`,
|
|
28
|
+
`AGENTS.md`, `docs/` skeleton, and the first ADRs surfaced from the repo's
|
|
29
|
+
existing decisions.
|
|
30
|
+
|
|
31
|
+
## Stack
|
|
32
|
+
|
|
33
|
+
{stack_bullets}
|
|
34
|
+
|
|
35
|
+
## Services
|
|
36
|
+
|
|
37
|
+
{services_bullets}
|
|
38
|
+
|
|
39
|
+
## Deploy story
|
|
40
|
+
|
|
41
|
+
{deploy_story_body}
|
|
42
|
+
|
|
43
|
+
## Dark Factory gate posture
|
|
44
|
+
|
|
45
|
+
{df_presence_body}
|
|
46
|
+
|
|
47
|
+
## Agent context set
|
|
48
|
+
|
|
49
|
+
{agent_context_body}
|
|
50
|
+
|
|
51
|
+
## Exit criteria
|
|
52
|
+
|
|
53
|
+
- [ ] `CLAUDE.md` lists every section relevant to this repo's actual stack + services.
|
|
54
|
+
- [ ] `AGENTS.md` documents the per-vendor critic posture this repo runs.
|
|
55
|
+
- [ ] `docs/PRINCIPLES.md` exists with the project's engineering principles.
|
|
56
|
+
- [ ] `docs/roadmap/` directory exists; this doc is its first entry.
|
|
57
|
+
- [ ] At least 3 ADRs under `docs/ADR/` (seeded from this repo's surfaced decisions).
|
|
58
|
+
- [ ] `df doctor` against this repo passes `agent_context_*` checks.
|
|
59
|
+
|
|
60
|
+
## Open questions
|
|
61
|
+
|
|
62
|
+
- Which on-call rotation owns this repo's deploy story?
|
|
63
|
+
- Are there security boundaries beyond the standard DF gate posture above?
|
|
64
|
+
- Does this repo need a separate runbook beyond the seeded deploy runbook?
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{{!-- packages/cli/src/onboard/seeders/runbook.md.tmpl --}}
|
|
2
|
+
# Runbook: {workflow_name}
|
|
3
|
+
|
|
4
|
+
> Generated by `df onboard` (cycle 15 Phase C) from the analysis of
|
|
5
|
+
> `{workflow_path}`. The maintainer should expand each section with the
|
|
6
|
+
> nuance the analyzer could not produce.
|
|
7
|
+
|
|
8
|
+
**Workflow:** [`{workflow_path}`]({workflow_path}){workflow_triggers_note}
|
|
9
|
+
|
|
10
|
+
## Triggering
|
|
11
|
+
|
|
12
|
+
{triggering_body}
|
|
13
|
+
|
|
14
|
+
## Verifying success
|
|
15
|
+
|
|
16
|
+
{verifying_body}
|
|
17
|
+
|
|
18
|
+
## Rollback
|
|
19
|
+
|
|
20
|
+
{rollback_body}
|
|
21
|
+
|
|
22
|
+
## On-call
|
|
23
|
+
|
|
24
|
+
- Who is paged when this workflow fails? (TODO: name the rotation)
|
|
25
|
+
- Where do alerts surface? (TODO: link the alert source)
|
|
26
|
+
- What is the SLO this workflow is meant to satisfy? (TODO)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { parseTemplateRef, type ParsedTemplateRef, type GhTemplateRef, type FileTemplateRef } from "./template-ref.js";
|
|
2
|
+
export { parseTemplateRef };
|
|
3
|
+
export type { ParsedTemplateRef, GhTemplateRef, FileTemplateRef };
|
|
4
|
+
export declare const MAX_TEMPLATE_FILES = 200;
|
|
5
|
+
export declare const MAX_TEMPLATE_FILE_SIZE = 65536;
|
|
6
|
+
export interface TemplateFile {
|
|
7
|
+
path: string;
|
|
8
|
+
content: string;
|
|
9
|
+
}
|
|
10
|
+
export interface Template {
|
|
11
|
+
canonicalRef: string;
|
|
12
|
+
resolvedSha: string;
|
|
13
|
+
cacheDir: string;
|
|
14
|
+
files: TemplateFile[];
|
|
15
|
+
}
|
|
16
|
+
export interface LoadOptions {
|
|
17
|
+
cacheRoot?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function loadTemplate(canonicalRef: string, opts?: LoadOptions): Promise<Template>;
|
|
20
|
+
//# sourceMappingURL=template-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template-loader.d.ts","sourceRoot":"","sources":["../../src/onboard/template-loader.ts"],"names":[],"mappings":"AAwBA,OAAO,EACL,gBAAgB,EAChB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,eAAe,EACrB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,gBAAgB,EAAE,CAAC;AAC5B,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,eAAe,EAAE,CAAC;AAIlE,eAAO,MAAM,kBAAkB,MAAM,CAAC;AACtC,eAAO,MAAM,sBAAsB,QAAS,CAAC;AAG7C,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,YAAY,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAiGD,wBAAsB,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAalG"}
|
|
@@ -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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"}
|