@momentiq/dark-factory-cli 1.1.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +86 -2
- package/dist/adapters/critic-result-schema.d.ts +14 -14
- package/dist/adapters/index.d.ts +1 -0
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +7 -0
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/static-schema-lint.d.ts +68 -0
- package/dist/adapters/static-schema-lint.d.ts.map +1 -0
- package/dist/adapters/static-schema-lint.js +813 -0
- package/dist/adapters/static-schema-lint.js.map +1 -0
- package/dist/cli.d.ts +17 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +313 -41
- package/dist/cli.js.map +1 -1
- package/dist/commands/findings.d.ts +6 -0
- package/dist/commands/findings.d.ts.map +1 -0
- package/dist/commands/findings.js +196 -0
- package/dist/commands/findings.js.map +1 -0
- package/dist/commands/onboard.d.ts +6 -0
- package/dist/commands/onboard.d.ts.map +1 -0
- package/dist/commands/onboard.js +111 -0
- package/dist/commands/onboard.js.map +1 -0
- package/dist/commands/skills.d.ts +6 -0
- package/dist/commands/skills.d.ts.map +1 -0
- package/dist/commands/skills.js +248 -0
- package/dist/commands/skills.js.map +1 -0
- package/dist/cycle-doc-validator/validate_cycle_doc.py +131 -60
- package/dist/doctor.d.ts +17 -0
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +107 -0
- package/dist/doctor.js.map +1 -1
- package/dist/evidence/docker-build.d.ts +6 -0
- package/dist/evidence/docker-build.d.ts.map +1 -0
- package/dist/evidence/docker-build.js +199 -0
- package/dist/evidence/docker-build.js.map +1 -0
- package/dist/evidence/index.d.ts +1 -0
- package/dist/evidence/index.d.ts.map +1 -1
- package/dist/evidence/index.js +6 -0
- package/dist/evidence/index.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.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/doctor.d.ts.map +1 -1
- package/dist/mcp/tools/doctor.js +5 -0
- package/dist/mcp/tools/doctor.js.map +1 -1
- package/dist/mcp/tools/review-bypass.d.ts.map +1 -1
- package/dist/mcp/tools/review-bypass.js +21 -0
- package/dist/mcp/tools/review-bypass.js.map +1 -1
- package/dist/mcp/tools/skills-install.d.ts +6 -0
- package/dist/mcp/tools/skills-install.d.ts.map +1 -0
- package/dist/mcp/tools/skills-install.js +260 -0
- package/dist/mcp/tools/skills-install.js.map +1 -0
- package/dist/mcp/tools/stats-gate.d.ts.map +1 -1
- package/dist/mcp/tools/stats-gate.js +63 -15
- package/dist/mcp/tools/stats-gate.js.map +1 -1
- 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/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/schema.d.ts +545 -0
- package/dist/onboard/schema.d.ts.map +1 -0
- package/dist/onboard/schema.js +142 -0
- package/dist/onboard/schema.js.map +1 -0
- package/dist/policy/gate.d.ts +1 -1
- package/dist/policy/gate.d.ts.map +1 -1
- package/dist/policy/gate.js +96 -12
- package/dist/policy/gate.js.map +1 -1
- package/dist/prompt.d.ts +1 -0
- package/dist/prompt.d.ts.map +1 -1
- package/dist/prompt.js +105 -1
- package/dist/prompt.js.map +1 -1
- package/dist/report.d.ts +106 -3
- package/dist/report.d.ts.map +1 -1
- package/dist/report.js +282 -10
- package/dist/report.js.map +1 -1
- package/dist/runner.d.ts +2 -0
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +86 -2
- package/dist/runner.js.map +1 -1
- package/dist/self-consistency.d.ts +144 -0
- package/dist/self-consistency.d.ts.map +1 -0
- package/dist/self-consistency.js +368 -0
- package/dist/self-consistency.js.map +1 -0
- package/dist/skills/config.d.ts +176 -0
- package/dist/skills/config.d.ts.map +1 -0
- package/dist/skills/config.js +251 -0
- package/dist/skills/config.js.map +1 -0
- package/dist/skills/index.d.ts +4 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +8 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/skills/install.d.ts +62 -0
- package/dist/skills/install.d.ts.map +1 -0
- package/dist/skills/install.js +315 -0
- package/dist/skills/install.js.map +1 -0
- package/dist/skills/template.d.ts +42 -0
- package/dist/skills/template.d.ts.map +1 -0
- package/dist/skills/template.js +95 -0
- package/dist/skills/template.js.map +1 -0
- package/dist/trusted-surface/rebind.d.ts.map +1 -1
- package/dist/trusted-surface/rebind.js +14 -1
- package/dist/trusted-surface/rebind.js.map +1 -1
- package/package.json +36 -2
- package/skills/README.md +89 -0
- package/skills/chief-engineer-blitz/SKILL.md.tmpl +443 -0
- package/skills/chief-engineer-blitz/skill.json +53 -0
- package/skills/chief-engineer-review/SKILL.md.tmpl +184 -0
- package/skills/chief-engineer-review/references/review-examples.md.tmpl +130 -0
- package/skills/chief-engineer-review/skill.json +67 -0
- package/skills/chief-engineer-review/templates/code-review-prompt.md.tmpl +111 -0
- package/skills/chief-engineer-review/templates/escalation-prompt.md.tmpl +56 -0
- package/skills/chief-engineer-review/templates/plan-review-prompt.md.tmpl +74 -0
- package/skills/skill-schema.json +73 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { readdir } from "node:fs/promises";
|
|
2
|
+
import { extname, join } from "node:path";
|
|
3
|
+
const SKIP_DIR_NAMES = new Set([
|
|
4
|
+
"node_modules",
|
|
5
|
+
"dist",
|
|
6
|
+
"build",
|
|
7
|
+
"target",
|
|
8
|
+
".next",
|
|
9
|
+
".venv",
|
|
10
|
+
"__pycache__",
|
|
11
|
+
".gradle",
|
|
12
|
+
]);
|
|
13
|
+
const DIR_CATEGORY = {
|
|
14
|
+
services: "services",
|
|
15
|
+
apps: "services",
|
|
16
|
+
packages: "packages",
|
|
17
|
+
src: "src",
|
|
18
|
+
lib: "src",
|
|
19
|
+
tests: "tests",
|
|
20
|
+
test: "tests",
|
|
21
|
+
__tests__: "tests",
|
|
22
|
+
docs: "docs",
|
|
23
|
+
documentation: "docs",
|
|
24
|
+
infra: "infra",
|
|
25
|
+
terraform: "infra",
|
|
26
|
+
deploy: "infra",
|
|
27
|
+
scripts: "scripts",
|
|
28
|
+
bin: "scripts",
|
|
29
|
+
tools: "scripts",
|
|
30
|
+
};
|
|
31
|
+
const EXT_LANG = {
|
|
32
|
+
".ts": "typescript",
|
|
33
|
+
".tsx": "typescript",
|
|
34
|
+
".js": "javascript",
|
|
35
|
+
".jsx": "javascript",
|
|
36
|
+
".mjs": "javascript",
|
|
37
|
+
".cjs": "javascript",
|
|
38
|
+
".py": "python",
|
|
39
|
+
".go": "go",
|
|
40
|
+
".rs": "rust",
|
|
41
|
+
".rb": "ruby",
|
|
42
|
+
".ex": "elixir",
|
|
43
|
+
".exs": "elixir",
|
|
44
|
+
".java": "java",
|
|
45
|
+
".kt": "kotlin",
|
|
46
|
+
".kts": "kotlin",
|
|
47
|
+
".cs": "csharp",
|
|
48
|
+
".swift": "swift",
|
|
49
|
+
".md": "markdown",
|
|
50
|
+
".yaml": "yaml",
|
|
51
|
+
".yml": "yaml",
|
|
52
|
+
".json": "json",
|
|
53
|
+
};
|
|
54
|
+
const TEST_DIR_NAMES = new Set(["tests", "test", "__tests__", "spec"]);
|
|
55
|
+
const MAX_DEPTH = 4;
|
|
56
|
+
const MAX_FILES = 50_000;
|
|
57
|
+
const MAX_TOP_LEVEL_DIRS = 30;
|
|
58
|
+
const MAX_TEST_DIRS = 20;
|
|
59
|
+
const MAX_SERVICES = 30;
|
|
60
|
+
class FileCapExceededError extends Error {
|
|
61
|
+
constructor() {
|
|
62
|
+
super(`tree analyzer exceeded ${MAX_FILES.toLocaleString()} file cap`);
|
|
63
|
+
this.name = "FileCapExceededError";
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function shouldSkipEntry(name) {
|
|
67
|
+
// Skip every hidden entry (`.git`, `.github`, `.vscode`, dotfiles…) and
|
|
68
|
+
// every well-known build-artifact directory.
|
|
69
|
+
if (name.startsWith("."))
|
|
70
|
+
return true;
|
|
71
|
+
if (SKIP_DIR_NAMES.has(name))
|
|
72
|
+
return true;
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
async function walk(absPath, relPath, depth, topLevelName, state) {
|
|
76
|
+
if (depth > MAX_DEPTH)
|
|
77
|
+
return;
|
|
78
|
+
let entries;
|
|
79
|
+
try {
|
|
80
|
+
entries = await readdir(absPath, { withFileTypes: true });
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// Permission denied or transient — treat as empty so the analyzer
|
|
84
|
+
// doesn't bomb the whole onboarding pass over one unreadable subtree.
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
for (const entry of entries) {
|
|
88
|
+
if (shouldSkipEntry(entry.name))
|
|
89
|
+
continue;
|
|
90
|
+
const childRel = relPath === "" ? entry.name : `${relPath}/${entry.name}`;
|
|
91
|
+
const childAbs = join(absPath, entry.name);
|
|
92
|
+
if (entry.isDirectory()) {
|
|
93
|
+
// testDirs: any directory whose basename matches tests/test/__tests__/spec
|
|
94
|
+
// at depth ≤ 3 (the directory itself sits at depth+1 from root).
|
|
95
|
+
const dirDepth = depth + 1;
|
|
96
|
+
if (dirDepth <= 3 &&
|
|
97
|
+
TEST_DIR_NAMES.has(entry.name) &&
|
|
98
|
+
state.testDirs.length < MAX_TEST_DIRS &&
|
|
99
|
+
!state.testDirs.includes(childRel)) {
|
|
100
|
+
state.testDirs.push(childRel);
|
|
101
|
+
}
|
|
102
|
+
await walk(childAbs, childRel, depth + 1, topLevelName ?? entry.name, state);
|
|
103
|
+
}
|
|
104
|
+
else if (entry.isFile()) {
|
|
105
|
+
state.fileCount += 1;
|
|
106
|
+
if (state.fileCount > MAX_FILES)
|
|
107
|
+
throw new FileCapExceededError();
|
|
108
|
+
const ext = extname(entry.name).toLowerCase();
|
|
109
|
+
const bucket = EXT_LANG[ext] ?? "other";
|
|
110
|
+
state.languageBreakdown[bucket] =
|
|
111
|
+
(state.languageBreakdown[bucket] ?? 0) + 1;
|
|
112
|
+
if (topLevelName !== null) {
|
|
113
|
+
state.topLevelFileCounts.set(topLevelName, (state.topLevelFileCounts.get(topLevelName) ?? 0) + 1);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Symlinks and other types are ignored — we only follow concrete files
|
|
117
|
+
// and directories, which matches the manifest analyzer's posture.
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function classify(name) {
|
|
121
|
+
return DIR_CATEGORY[name] ?? "other";
|
|
122
|
+
}
|
|
123
|
+
async function listImmediateDirs(absPath) {
|
|
124
|
+
try {
|
|
125
|
+
const entries = await readdir(absPath, { withFileTypes: true });
|
|
126
|
+
return entries
|
|
127
|
+
.filter((e) => e.isDirectory() && !shouldSkipEntry(e.name))
|
|
128
|
+
.map((e) => e.name);
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return [];
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
export const treeAnalyzer = {
|
|
135
|
+
name: "tree",
|
|
136
|
+
async detect(rootDir) {
|
|
137
|
+
const state = {
|
|
138
|
+
fileCount: 0,
|
|
139
|
+
languageBreakdown: {},
|
|
140
|
+
testDirs: [],
|
|
141
|
+
topLevelFileCounts: new Map(),
|
|
142
|
+
};
|
|
143
|
+
// Enumerate top-level entries first so we can populate `topLevelDirs`
|
|
144
|
+
// independent of how many files each subtree contains.
|
|
145
|
+
let rootEntries;
|
|
146
|
+
try {
|
|
147
|
+
rootEntries = await readdir(rootDir, { withFileTypes: true });
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
rootEntries = [];
|
|
151
|
+
}
|
|
152
|
+
const topLevelDirNames = [];
|
|
153
|
+
for (const entry of rootEntries) {
|
|
154
|
+
if (entry.isDirectory() && !shouldSkipEntry(entry.name)) {
|
|
155
|
+
topLevelDirNames.push(entry.name);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
await walk(rootDir, "", 0, null, state);
|
|
159
|
+
const topLevelDirs = topLevelDirNames
|
|
160
|
+
.slice(0, MAX_TOP_LEVEL_DIRS)
|
|
161
|
+
.map((name) => ({
|
|
162
|
+
name,
|
|
163
|
+
category: classify(name),
|
|
164
|
+
fileCount: state.topLevelFileCounts.get(name) ?? 0,
|
|
165
|
+
}));
|
|
166
|
+
// Services discovery: immediate children of every top-level dir of
|
|
167
|
+
// category `services` (literally `services/` or `apps/`).
|
|
168
|
+
const services = [];
|
|
169
|
+
for (const top of topLevelDirNames) {
|
|
170
|
+
if (classify(top) !== "services")
|
|
171
|
+
continue;
|
|
172
|
+
const children = await listImmediateDirs(join(rootDir, top));
|
|
173
|
+
for (const child of children) {
|
|
174
|
+
if (services.length >= MAX_SERVICES)
|
|
175
|
+
break;
|
|
176
|
+
services.push({
|
|
177
|
+
name: child,
|
|
178
|
+
path: `${top}/${child}`,
|
|
179
|
+
stack: null,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
if (services.length >= MAX_SERVICES)
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
tree: {
|
|
187
|
+
topLevelDirs,
|
|
188
|
+
languageBreakdown: state.languageBreakdown,
|
|
189
|
+
testDirs: state.testDirs.slice(0, MAX_TEST_DIRS),
|
|
190
|
+
fileCount: state.fileCount,
|
|
191
|
+
},
|
|
192
|
+
services,
|
|
193
|
+
};
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
//# sourceMappingURL=tree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree.js","sourceRoot":"","sources":["../../../src/onboard/analyzers/tree.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface GitHistoryFixture {
|
|
2
|
+
canonical: string;
|
|
3
|
+
defaultBranch: string;
|
|
4
|
+
remote: string;
|
|
5
|
+
subjects: string[];
|
|
6
|
+
}
|
|
7
|
+
export declare function parseGitHistory(body: string): GitHistoryFixture;
|
|
8
|
+
/**
|
|
9
|
+
* Initialize `<repoDir>` as a real git repo with the fixture's remote and
|
|
10
|
+
* default-branch metadata, then replay the subjects as empty commits over
|
|
11
|
+
* an initial commit that captures whatever files already exist in repoDir.
|
|
12
|
+
*
|
|
13
|
+
* After this returns the git analyzer will see:
|
|
14
|
+
* - a real .git dir
|
|
15
|
+
* - an origin remote (so canonicalName parses)
|
|
16
|
+
* - the right default branch
|
|
17
|
+
* - up to 200 subjects via `git log --pretty=%s` (oldest → newest)
|
|
18
|
+
*/
|
|
19
|
+
export declare function replayGitHistory(repoDir: string, fixture: GitHistoryFixture): Promise<void>;
|
|
20
|
+
//# sourceMappingURL=replay-git-history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replay-git-history.d.ts","sourceRoot":"","sources":["../../../src/onboard/fixtures/replay-git-history.ts"],"names":[],"mappings":"AAyBA,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CA0B/D;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,IAAI,CAAC,CAkCf"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// Replay a fixture's compact git-history.txt into a real synthetic git
|
|
2
|
+
// repo — used by the fixture builder (Task 11) AND the integration test
|
|
3
|
+
// (Task 12). Shipped from src/ (not tests/) so the build script and the
|
|
4
|
+
// integration test always agree on the replay semantics.
|
|
5
|
+
//
|
|
6
|
+
// Format (line-oriented, deterministic; ≤ 5 KB per fixture):
|
|
7
|
+
//
|
|
8
|
+
// # comment lines start with '#'
|
|
9
|
+
// canonical: <owner>/<name>
|
|
10
|
+
// defaultBranch: <branch>
|
|
11
|
+
// remote: https://github.com/<owner>/<name>.git
|
|
12
|
+
//
|
|
13
|
+
// subjects:
|
|
14
|
+
// <subject 1>
|
|
15
|
+
// <subject 2>
|
|
16
|
+
// ...
|
|
17
|
+
//
|
|
18
|
+
// Authors / dates / SHAs are NOT preserved — only the canonical remote,
|
|
19
|
+
// default branch, and subject stream that drives recentCommitConventions
|
|
20
|
+
// detection.
|
|
21
|
+
import { execFile } from "node:child_process";
|
|
22
|
+
import { promisify } from "node:util";
|
|
23
|
+
const ex = promisify(execFile);
|
|
24
|
+
export function parseGitHistory(body) {
|
|
25
|
+
const lines = body.split(/\r?\n/);
|
|
26
|
+
let canonical = "";
|
|
27
|
+
let defaultBranch = "main";
|
|
28
|
+
let remote = "";
|
|
29
|
+
const subjects = [];
|
|
30
|
+
let mode = "meta";
|
|
31
|
+
for (const raw of lines) {
|
|
32
|
+
const line = raw.trimEnd();
|
|
33
|
+
if (mode === "meta") {
|
|
34
|
+
if (line.startsWith("#") || line === "")
|
|
35
|
+
continue;
|
|
36
|
+
if (line.startsWith("canonical:")) {
|
|
37
|
+
canonical = line.slice("canonical:".length).trim();
|
|
38
|
+
}
|
|
39
|
+
else if (line.startsWith("defaultBranch:")) {
|
|
40
|
+
defaultBranch = line.slice("defaultBranch:".length).trim();
|
|
41
|
+
}
|
|
42
|
+
else if (line.startsWith("remote:")) {
|
|
43
|
+
remote = line.slice("remote:".length).trim();
|
|
44
|
+
}
|
|
45
|
+
else if (line === "subjects:") {
|
|
46
|
+
mode = "subjects";
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
if (line === "" || line.startsWith("#"))
|
|
51
|
+
continue;
|
|
52
|
+
subjects.push(line);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return { canonical, defaultBranch, remote, subjects: subjects.slice(0, 200) };
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Initialize `<repoDir>` as a real git repo with the fixture's remote and
|
|
59
|
+
* default-branch metadata, then replay the subjects as empty commits over
|
|
60
|
+
* an initial commit that captures whatever files already exist in repoDir.
|
|
61
|
+
*
|
|
62
|
+
* After this returns the git analyzer will see:
|
|
63
|
+
* - a real .git dir
|
|
64
|
+
* - an origin remote (so canonicalName parses)
|
|
65
|
+
* - the right default branch
|
|
66
|
+
* - up to 200 subjects via `git log --pretty=%s` (oldest → newest)
|
|
67
|
+
*/
|
|
68
|
+
export async function replayGitHistory(repoDir, fixture) {
|
|
69
|
+
await ex("git", ["init", "-b", fixture.defaultBranch], { cwd: repoDir });
|
|
70
|
+
await ex("git", ["config", "user.email", "fixture@test"], { cwd: repoDir });
|
|
71
|
+
await ex("git", ["config", "user.name", "Fixture"], { cwd: repoDir });
|
|
72
|
+
await ex("git", ["config", "commit.gpgsign", "false"], { cwd: repoDir });
|
|
73
|
+
if (fixture.remote) {
|
|
74
|
+
await ex("git", ["remote", "add", "origin", fixture.remote], { cwd: repoDir });
|
|
75
|
+
// The git analyzer reads origin/HEAD via symbolic-ref to derive the
|
|
76
|
+
// default branch. Without an actual remote fetch we set it manually
|
|
77
|
+
// so the fixture's defaultBranch survives the round-trip.
|
|
78
|
+
await ex("git", [
|
|
79
|
+
"symbolic-ref",
|
|
80
|
+
"refs/remotes/origin/HEAD",
|
|
81
|
+
`refs/remotes/origin/${fixture.defaultBranch}`,
|
|
82
|
+
], { cwd: repoDir });
|
|
83
|
+
}
|
|
84
|
+
const firstSubject = fixture.subjects[0] ?? "chore: initial fixture commit";
|
|
85
|
+
await ex("git", ["add", "-A"], { cwd: repoDir });
|
|
86
|
+
await ex("git", ["commit", "--allow-empty", "-m", firstSubject], { cwd: repoDir });
|
|
87
|
+
for (const subject of fixture.subjects.slice(1)) {
|
|
88
|
+
await ex("git", ["commit", "--allow-empty", "-m", subject], { cwd: repoDir });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=replay-git-history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replay-git-history.js","sourceRoot":"","sources":["../../../src/onboard/fixtures/replay-git-history.ts"],"names":[],"mappings":"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"}
|