@haiyangbg/buildbeat 2.0.2 → 3.0.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/CHANGELOG.md +18 -301
- package/README.en.md +6 -19
- package/README.md +6 -19
- package/SKILL.md +168 -219
- package/bin/buildbeat.js +14 -2
- package/docs/CAPABILITY-MATRIX.md +13 -55
- package/docs/README.md +12 -14
- package/docs/RELEASING.md +8 -9
- package/docs/v2/RFC-0001-product-definition.md +2 -0
- package/docs/v2/RFC-0003-workflow-policy.md +2 -0
- package/docs/v2/guide/00-how-to-talk.md +3 -3
- package/docs/v2/guide/01-quickstart.md +12 -12
- package/docs/v2/guide/03-policy-guide.md +1 -1
- package/docs/v2/guide/06-evidence-guide.md +3 -3
- package/docs/v2/guide/07-approval-guide.md +10 -10
- package/docs/v2/guide/10-recovery.md +6 -6
- package/docs/v2/guide/11-session-handoff.en.md +2 -2
- package/docs/v2/guide/11-session-handoff.md +2 -2
- package/docs/v2/guide/README.md +0 -6
- package/lessons.md +52 -71
- package/package.json +3 -8
- package/src/v2/cli/run.js +33 -23
- package/src/v2/engine/risk-preset.js +1 -1
- package/src/v2/runtime/notify.js +5 -5
- package/src/v2/runtime/overview.js +7 -7
- package/templates/ARCHITECTURE.md +1 -1
- package/templates/contracts/PROTOCOL.md +2 -10
- package/templates/gitignore.template +0 -3
- package/templates/pm/adr/README.md +1 -1
- package/templates/pm/decisions.md +4 -5
- package/templates/standards/CODE.md +1 -1
- package/templates/standards/DESIGN.md +1 -1
- package/templates/standards/REVIEW.md +2 -2
- package/templates/standards/STACK.md +2 -8
- package/templates/v2/AGENTS.md +18 -18
- package/templates/v2/BUILDBEAT.md +2 -3
- package/templates/v2/CLAUDE.md +1 -1
- package/templates/v2/run-config.example.yaml +1 -1
- package/templates/v2//346/214/207/346/214/245/345/217/260.md +6 -6
- package/bin/buildbeat-v2.js +0 -18
- package/bin/solobaton.js +0 -6
- package/docs/CHECKS.md +0 -326
- package/docs/CLI.md +0 -245
- package/docs/LEGACY-V1.16-MIGRATION.md +0 -54
- package/docs/v2/guide/08-migration-v1.md +0 -72
- package/example/.buildbeat/manifest.json +0 -45
- package/example/AGENTS.md +0 -19
- package/example/ARCHITECTURE.md +0 -39
- package/example/BUILDBEAT.md +0 -17
- package/example/CLAUDE.md +0 -7
- package/example/README.md +0 -75
- package/example/contracts/PROTOCOL.md +0 -38
- package/example/pm/NOW.md +0 -22
- package/example/pm/adr/ADR-0001-local-first-sqlite.md +0 -25
- package/example/pm/adr/README.md +0 -7
- package/example/pm/archive//344/270/200/346/234/237/evidence/gate1.md +0 -5
- package/example/pm/archive//344/270/200/346/234/237/evidence/gate2.md +0 -5
- package/example/pm/archive//344/270/200/346/234/237/evidence/gate3.md +0 -5
- package/example/pm/archive//344/270/200/346/234/237/evidence/gate4.md +0 -5
- package/example/pm/archive//344/270/200/346/234/237/evidence/implementation.md +0 -5
- package/example/pm/decisions.md +0 -20
- package/example/pm/status//344/272/247/345/223/201.md +0 -20
- package/example/pm/status//345/205/250/346/240/210.md +0 -15
- package/example/pm/status//346/265/213/350/257/225.md +0 -15
- package/example/pm//344/270/200/346/234/237-/347/234/213/346/235/277.md +0 -97
- package/example/standards/CODE.md +0 -18
- package/example/standards/DESIGN.md +0 -34
- package/example/standards/REVIEW.md +0 -16
- package/example/standards/STACK.md +0 -31
- package/src/cli.js +0 -323
- package/src/constants.js +0 -202
- package/src/doctor.js +0 -267
- package/src/planner.js +0 -251
- package/src/project.js +0 -844
- package/src/upgrader.js +0 -1249
- package/src/v2/presets/risk/legacy-four-gates.yaml +0 -44
- package/src/writer.js +0 -534
- package/templates/.claude/agents/reviewer.md +0 -62
- package/templates/AGENTS.md +0 -85
- package/templates/BUILDBEAT.md +0 -13
- package/templates/CLAUDE.md +0 -7
- package/templates/pm/NOW.md +0 -26
- package/templates/pm/changes/README.md +0 -44
- package/templates/pm/status/README.md +0 -32
- package/templates/pm//345/275/223/346/234/237/347/234/213/346/235/277.md +0 -62
- package/templates/scripts/bus-check.sh +0 -1875
- package/templates/scripts/design-preview.sh +0 -44
- package/templates/scripts/drift-check.sh +0 -112
- package/templates/scripts/pre-commit.sh +0 -74
- package/templates/scripts/verify-status.sh +0 -105
- package/templates//346/214/207/346/214/245/345/217/260.md +0 -58
package/src/cli.js
DELETED
|
@@ -1,323 +0,0 @@
|
|
|
1
|
-
import { createInterface } from "node:readline/promises";
|
|
2
|
-
|
|
3
|
-
import { CLI_VERSION, OUTPUT_SCHEMA_VERSION } from "./constants.js";
|
|
4
|
-
import { formatDoctor, runDoctor } from "./doctor.js";
|
|
5
|
-
import { buildPlan, formatPlan } from "./planner.js";
|
|
6
|
-
import { applyUpgrade, buildUpgradePlan, formatUpgradePlan } from "./upgrader.js";
|
|
7
|
-
import { applyScaffold, WriteError } from "./writer.js";
|
|
8
|
-
|
|
9
|
-
const HELP = `BuildBeat CLI v${CLI_VERSION} (Wave 2 source candidate)
|
|
10
|
-
|
|
11
|
-
Usage:
|
|
12
|
-
buildbeat doctor [path] [--json]
|
|
13
|
-
buildbeat init [path] [--dry-run] [--layout default|compact] [--json] [--yes]
|
|
14
|
-
buildbeat adopt [path] [--dry-run] [--layout default|compact] [--json] [--yes]
|
|
15
|
-
buildbeat upgrade [path] [--dry-run] [--json] [--force] [--major]
|
|
16
|
-
buildbeat version
|
|
17
|
-
|
|
18
|
-
init/adopt write only after a blocker-free plan and confirmation; --yes skips
|
|
19
|
-
only that prompt. upgrade is schema-2-only and requires a clean target-root Git
|
|
20
|
-
worktree. diff and uninstall remain unavailable.
|
|
21
|
-
|
|
22
|
-
Legacy compatibility: the published npm package and solobaton executable alias
|
|
23
|
-
remain available during the BuildBeat namespace migration.`;
|
|
24
|
-
|
|
25
|
-
class UsageError extends Error {
|
|
26
|
-
constructor(message) {
|
|
27
|
-
super(message);
|
|
28
|
-
this.name = "UsageError";
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function parse(args) {
|
|
33
|
-
if (args.length === 0) {
|
|
34
|
-
return {
|
|
35
|
-
command: "help",
|
|
36
|
-
target: ".",
|
|
37
|
-
json: false,
|
|
38
|
-
dryRun: false,
|
|
39
|
-
layout: null,
|
|
40
|
-
yes: false,
|
|
41
|
-
force: false,
|
|
42
|
-
major: false,
|
|
43
|
-
targetProvided: false,
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
const options = {
|
|
47
|
-
command: args[0],
|
|
48
|
-
target: ".",
|
|
49
|
-
json: false,
|
|
50
|
-
dryRun: false,
|
|
51
|
-
yes: false,
|
|
52
|
-
force: false,
|
|
53
|
-
major: false,
|
|
54
|
-
layout: null,
|
|
55
|
-
help: false,
|
|
56
|
-
targetProvided: false,
|
|
57
|
-
};
|
|
58
|
-
let targetSeen = false;
|
|
59
|
-
for (let index = 1; index < args.length; index += 1) {
|
|
60
|
-
const token = args[index];
|
|
61
|
-
if (token === "--json") {
|
|
62
|
-
options.json = true;
|
|
63
|
-
} else if (token === "--dry-run") {
|
|
64
|
-
options.dryRun = true;
|
|
65
|
-
} else if (token === "--yes") {
|
|
66
|
-
options.yes = true;
|
|
67
|
-
} else if (token === "--force") {
|
|
68
|
-
options.force = true;
|
|
69
|
-
} else if (token === "--major") {
|
|
70
|
-
options.major = true;
|
|
71
|
-
} else if (token === "--help" || token === "-h") {
|
|
72
|
-
options.help = true;
|
|
73
|
-
} else if (token === "--layout") {
|
|
74
|
-
index += 1;
|
|
75
|
-
if (index >= args.length) {
|
|
76
|
-
throw new UsageError("--layout requires default or compact.");
|
|
77
|
-
}
|
|
78
|
-
options.layout = args[index];
|
|
79
|
-
} else if (token.startsWith("--layout=")) {
|
|
80
|
-
options.layout = token.slice("--layout=".length);
|
|
81
|
-
} else if (token.startsWith("-")) {
|
|
82
|
-
throw new UsageError(`Unknown option: ${token}`);
|
|
83
|
-
} else if (!targetSeen) {
|
|
84
|
-
options.target = token;
|
|
85
|
-
targetSeen = true;
|
|
86
|
-
options.targetProvided = true;
|
|
87
|
-
} else {
|
|
88
|
-
throw new UsageError(`Unexpected argument: ${token}`);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
if (options.layout && !["default", "compact"].includes(options.layout)) {
|
|
92
|
-
throw new UsageError("--layout must be default or compact.");
|
|
93
|
-
}
|
|
94
|
-
return options;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
async function confirmPlan(io, plan) {
|
|
98
|
-
if (typeof io.confirm === "function") {
|
|
99
|
-
return Boolean(await io.confirm(plan));
|
|
100
|
-
}
|
|
101
|
-
if (!io.stdin?.isTTY || !io.stderr) {
|
|
102
|
-
return null;
|
|
103
|
-
}
|
|
104
|
-
const readline = createInterface({ input: io.stdin, output: io.stderr });
|
|
105
|
-
try {
|
|
106
|
-
const answer = await readline.question("Apply this BuildBeat plan? [y/N] ");
|
|
107
|
-
return /^(?:y|yes)$/i.test(answer.trim());
|
|
108
|
-
} finally {
|
|
109
|
-
readline.close();
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function outputJson(io, value) {
|
|
114
|
-
io.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function commandLabel(value) {
|
|
118
|
-
if (typeof value !== "string" || value.length === 0) {
|
|
119
|
-
return null;
|
|
120
|
-
}
|
|
121
|
-
return value
|
|
122
|
-
.replace(/[\u0000-\u001f\u007f]+/g, " ")
|
|
123
|
-
.replace(/\s+/g, " ")
|
|
124
|
-
.trim()
|
|
125
|
-
.slice(0, 80) || null;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function writeError(io, message, { json = false, code = "usage", command = null } = {}) {
|
|
129
|
-
if (json) {
|
|
130
|
-
outputJson(io, {
|
|
131
|
-
schemaVersion: OUTPUT_SCHEMA_VERSION,
|
|
132
|
-
command: commandLabel(command),
|
|
133
|
-
cliVersion: CLI_VERSION,
|
|
134
|
-
ok: false,
|
|
135
|
-
error: { code, message },
|
|
136
|
-
});
|
|
137
|
-
} else {
|
|
138
|
-
io.stderr.write(`Error: ${message}\n`);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export async function run(
|
|
143
|
-
args,
|
|
144
|
-
io = { stdin: process.stdin, stdout: process.stdout, stderr: process.stderr },
|
|
145
|
-
) {
|
|
146
|
-
let options;
|
|
147
|
-
try {
|
|
148
|
-
options = parse(args);
|
|
149
|
-
} catch (error) {
|
|
150
|
-
writeError(io, error.message, {
|
|
151
|
-
json: args.includes("--json"),
|
|
152
|
-
command: args[0] || null,
|
|
153
|
-
});
|
|
154
|
-
return 2;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
if (options.help || options.command === "help" || options.command === "--help") {
|
|
158
|
-
io.stdout.write(`${HELP}\n`);
|
|
159
|
-
return 0;
|
|
160
|
-
}
|
|
161
|
-
if (options.command === "version" || options.command === "--version" || options.command === "-v") {
|
|
162
|
-
if (
|
|
163
|
-
options.targetProvided ||
|
|
164
|
-
options.json ||
|
|
165
|
-
options.dryRun ||
|
|
166
|
-
options.yes ||
|
|
167
|
-
options.force ||
|
|
168
|
-
options.major ||
|
|
169
|
-
options.layout
|
|
170
|
-
) {
|
|
171
|
-
writeError(io, "version does not accept a path or options.", {
|
|
172
|
-
json: options.json,
|
|
173
|
-
command: options.command,
|
|
174
|
-
});
|
|
175
|
-
return 2;
|
|
176
|
-
}
|
|
177
|
-
io.stdout.write(`${CLI_VERSION}\n`);
|
|
178
|
-
return 0;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
try {
|
|
182
|
-
if (options.command === "doctor") {
|
|
183
|
-
if (options.layout || options.dryRun || options.yes || options.force || options.major) {
|
|
184
|
-
throw new UsageError("doctor accepts only [path] and --json.");
|
|
185
|
-
}
|
|
186
|
-
const report = runDoctor(options.target);
|
|
187
|
-
if (options.json) {
|
|
188
|
-
outputJson(io, report);
|
|
189
|
-
} else {
|
|
190
|
-
io.stdout.write(`${formatDoctor(report)}\n`);
|
|
191
|
-
}
|
|
192
|
-
return report.ok ? 0 : 1;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
if (options.command === "init" || options.command === "adopt") {
|
|
196
|
-
if (options.force || options.major) {
|
|
197
|
-
throw new UsageError(`${options.command} does not accept --force or --major.`);
|
|
198
|
-
}
|
|
199
|
-
if (options.dryRun && options.yes) {
|
|
200
|
-
throw new UsageError("--yes cannot be combined with --dry-run.");
|
|
201
|
-
}
|
|
202
|
-
const layout = options.layout || (options.command === "adopt" ? "compact" : "default");
|
|
203
|
-
const now = new Date();
|
|
204
|
-
const plan = buildPlan({
|
|
205
|
-
mode: options.command,
|
|
206
|
-
target: options.target,
|
|
207
|
-
layout,
|
|
208
|
-
preview: options.dryRun,
|
|
209
|
-
now,
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
if (options.dryRun || !plan.ready) {
|
|
213
|
-
if (options.json) {
|
|
214
|
-
outputJson(io, plan);
|
|
215
|
-
} else {
|
|
216
|
-
io.stdout.write(`${formatPlan(plan)}\n`);
|
|
217
|
-
}
|
|
218
|
-
return plan.ready ? 0 : 1;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
if (!options.json) {
|
|
222
|
-
io.stdout.write(`${formatPlan(plan)}\n`);
|
|
223
|
-
} else if (options.yes || io.stdin?.isTTY) {
|
|
224
|
-
io.stderr.write(`${formatPlan(plan)}\n`);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
if (!options.yes) {
|
|
228
|
-
const confirmed = await confirmPlan(io, plan);
|
|
229
|
-
if (confirmed === null) {
|
|
230
|
-
writeError(
|
|
231
|
-
io,
|
|
232
|
-
"Interactive confirmation is unavailable. Re-run with --yes only after reviewing --dry-run output.",
|
|
233
|
-
{
|
|
234
|
-
json: options.json,
|
|
235
|
-
code: "confirmation_required",
|
|
236
|
-
command: options.command,
|
|
237
|
-
},
|
|
238
|
-
);
|
|
239
|
-
return 2;
|
|
240
|
-
}
|
|
241
|
-
if (!confirmed) {
|
|
242
|
-
if (options.json) {
|
|
243
|
-
outputJson(io, { ...plan, cancelled: true });
|
|
244
|
-
} else {
|
|
245
|
-
io.stdout.write("\nCancelled. No files changed.\n");
|
|
246
|
-
}
|
|
247
|
-
return 0;
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const result = applyScaffold(plan, { now });
|
|
252
|
-
if (options.json) {
|
|
253
|
-
outputJson(io, result);
|
|
254
|
-
} else {
|
|
255
|
-
io.stdout.write(`\n${formatPlan(result)}\n`);
|
|
256
|
-
}
|
|
257
|
-
return 0;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
if (options.command === "upgrade") {
|
|
261
|
-
if (options.layout || options.yes) {
|
|
262
|
-
throw new UsageError("upgrade accepts only [path], --dry-run, --json, --force, and --major.");
|
|
263
|
-
}
|
|
264
|
-
const now = new Date();
|
|
265
|
-
const plan = buildUpgradePlan({
|
|
266
|
-
target: options.target,
|
|
267
|
-
preview: options.dryRun,
|
|
268
|
-
force: options.force,
|
|
269
|
-
major: options.major,
|
|
270
|
-
now,
|
|
271
|
-
});
|
|
272
|
-
if (options.dryRun || !plan.ready || plan.upToDate) {
|
|
273
|
-
if (options.json) {
|
|
274
|
-
outputJson(io, plan);
|
|
275
|
-
} else {
|
|
276
|
-
io.stdout.write(`${formatUpgradePlan(plan)}\n`);
|
|
277
|
-
}
|
|
278
|
-
return plan.ready ? 0 : 1;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
if (options.json) {
|
|
282
|
-
io.stderr.write(`${formatUpgradePlan(plan)}\n`);
|
|
283
|
-
} else {
|
|
284
|
-
io.stdout.write(`${formatUpgradePlan(plan)}\n`);
|
|
285
|
-
}
|
|
286
|
-
const result = applyUpgrade(plan, { now });
|
|
287
|
-
if (options.json) {
|
|
288
|
-
outputJson(io, result);
|
|
289
|
-
} else {
|
|
290
|
-
io.stdout.write(`\n${formatUpgradePlan(result)}\n`);
|
|
291
|
-
}
|
|
292
|
-
return result.doctor?.ok === false ? 1 : 0;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
if (["uninstall", "diff"].includes(options.command)) {
|
|
296
|
-
writeError(
|
|
297
|
-
io,
|
|
298
|
-
`${options.command} is reserved by the lifecycle contract but is not enabled in this CLI build.`,
|
|
299
|
-
{
|
|
300
|
-
json: options.json,
|
|
301
|
-
code: "command_not_available",
|
|
302
|
-
command: options.command,
|
|
303
|
-
},
|
|
304
|
-
);
|
|
305
|
-
return 2;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
throw new UsageError(`Unknown command: ${options.command}`);
|
|
309
|
-
} catch (error) {
|
|
310
|
-
if (error instanceof UsageError) {
|
|
311
|
-
writeError(io, error.message, { json: options.json, command: options.command });
|
|
312
|
-
return 2;
|
|
313
|
-
}
|
|
314
|
-
writeError(io, error.message, {
|
|
315
|
-
json: options.json,
|
|
316
|
-
code: error instanceof WriteError ? error.code : "runtime_error",
|
|
317
|
-
command: options.command,
|
|
318
|
-
});
|
|
319
|
-
return 1;
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
export { HELP };
|
package/src/constants.js
DELETED
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
|
|
3
|
-
const packageJson = JSON.parse(
|
|
4
|
-
readFileSync(new URL("../package.json", import.meta.url), "utf8"),
|
|
5
|
-
);
|
|
6
|
-
|
|
7
|
-
export const CLI_VERSION = packageJson.version;
|
|
8
|
-
// The v1 scaffold surface is frozen at v1.21 while the package version moves
|
|
9
|
-
// to v2 (kernel + runtime). scaffoldVersion tracks the scaffold content
|
|
10
|
-
// bundle, not the CLI, so existing installs see no fictitious major upgrade.
|
|
11
|
-
export const SCAFFOLD_VERSION = "v1.21";
|
|
12
|
-
export const OUTPUT_SCHEMA_VERSION = 2;
|
|
13
|
-
export const PRODUCT_NAME = "BuildBeat";
|
|
14
|
-
export const LEGACY_PRODUCT_NAME = "Solobaton";
|
|
15
|
-
export const MARKER_FILE = "BUILDBEAT.md";
|
|
16
|
-
export const LEGACY_MARKER_FILE = "SOLOBATON.md";
|
|
17
|
-
export const MANIFEST_PATH = ".buildbeat/manifest.json";
|
|
18
|
-
export const LEGACY_MANIFEST_PATH = ".solobaton/manifest.json";
|
|
19
|
-
export const MANIFEST_PATHS = [MANIFEST_PATH, LEGACY_MANIFEST_PATH];
|
|
20
|
-
export const MANIFEST_SCHEMA_VERSION = 2;
|
|
21
|
-
export const SUPPORTED_MANIFEST_SCHEMA_VERSIONS = [1, 2];
|
|
22
|
-
|
|
23
|
-
export const GITIGNORE_BEGIN_MARKER = "# >>> buildbeat managed >>>";
|
|
24
|
-
export const GITIGNORE_END_MARKER = "# <<< buildbeat managed <<<";
|
|
25
|
-
export const LEGACY_GITIGNORE_BEGIN_MARKER = "# >>> solobaton managed >>>";
|
|
26
|
-
export const LEGACY_GITIGNORE_END_MARKER = "# <<< solobaton managed <<<";
|
|
27
|
-
export const GITIGNORE_MARKER_PAIRS = [
|
|
28
|
-
[GITIGNORE_BEGIN_MARKER, GITIGNORE_END_MARKER],
|
|
29
|
-
[LEGACY_GITIGNORE_BEGIN_MARKER, LEGACY_GITIGNORE_END_MARKER],
|
|
30
|
-
];
|
|
31
|
-
|
|
32
|
-
export const SCRIPT_NAMES = [
|
|
33
|
-
"bus-check.sh",
|
|
34
|
-
"design-preview.sh",
|
|
35
|
-
"drift-check.sh",
|
|
36
|
-
"pre-commit.sh",
|
|
37
|
-
"verify-status.sh",
|
|
38
|
-
];
|
|
39
|
-
|
|
40
|
-
export const COMMON_REQUIRED_FILES = [
|
|
41
|
-
".claude/agents/reviewer.md",
|
|
42
|
-
"AGENTS.md",
|
|
43
|
-
"ARCHITECTURE.md",
|
|
44
|
-
"CLAUDE.md",
|
|
45
|
-
"contracts/PROTOCOL.md",
|
|
46
|
-
"pm/NOW.md",
|
|
47
|
-
"pm/changes/README.md",
|
|
48
|
-
"pm/decisions.md",
|
|
49
|
-
"pm/status/README.md",
|
|
50
|
-
];
|
|
51
|
-
|
|
52
|
-
// Optional, project-owned template libraries. They ship in the package so an
|
|
53
|
-
// AI session can use them on demand, but they are never part of the default
|
|
54
|
-
// init/adopt plan or the required scaffold surface.
|
|
55
|
-
export const OPTIONAL_TEMPLATE_PREFIXES = ["standards/", "pm/adr/"];
|
|
56
|
-
|
|
57
|
-
export const IGNORED_SCAN_DIRECTORIES = new Set([
|
|
58
|
-
".claude",
|
|
59
|
-
".codex",
|
|
60
|
-
".git",
|
|
61
|
-
".buildbeat",
|
|
62
|
-
".solobaton",
|
|
63
|
-
".next",
|
|
64
|
-
".nuxt",
|
|
65
|
-
".output",
|
|
66
|
-
"build",
|
|
67
|
-
"coverage",
|
|
68
|
-
"dist",
|
|
69
|
-
"node_modules",
|
|
70
|
-
"target",
|
|
71
|
-
"vendor",
|
|
72
|
-
]);
|
|
73
|
-
|
|
74
|
-
export const RENDER_REQUIRED_PLACEHOLDERS = {
|
|
75
|
-
".claude/agents/reviewer.md": ["<项目名>"],
|
|
76
|
-
"AGENTS.md": [
|
|
77
|
-
"<项目名>",
|
|
78
|
-
"<N>",
|
|
79
|
-
"<代码仓1>",
|
|
80
|
-
"<代码仓2>",
|
|
81
|
-
"<被测仓>",
|
|
82
|
-
"<PreStop/drain 机制>",
|
|
83
|
-
],
|
|
84
|
-
"ARCHITECTURE.md": [
|
|
85
|
-
"<项目名>",
|
|
86
|
-
"<项目是什么、给谁用、核心取舍>",
|
|
87
|
-
"<用户入口>",
|
|
88
|
-
"<前端/客户端>",
|
|
89
|
-
"<仓名>",
|
|
90
|
-
"<部署单元>",
|
|
91
|
-
"<网关/服务A>",
|
|
92
|
-
"<审计/可观测>",
|
|
93
|
-
"<服务B>",
|
|
94
|
-
"<服务C>",
|
|
95
|
-
"<项目根>",
|
|
96
|
-
"<代码仓1>",
|
|
97
|
-
"<代码仓2>",
|
|
98
|
-
"<说明>",
|
|
99
|
-
"<部署平台/区域>",
|
|
100
|
-
"<应用/服务清单:名称+ID+实例>",
|
|
101
|
-
"<入口/域名/LB>",
|
|
102
|
-
"<数据库/缓存>",
|
|
103
|
-
"<服务A 凭据>",
|
|
104
|
-
"<路径/获取命令>",
|
|
105
|
-
"<运行时 env 实查>",
|
|
106
|
-
"<平台 CLI 命令>",
|
|
107
|
-
],
|
|
108
|
-
"BUILDBEAT.md": ["<X.Y>", "<yyyy-mm-dd>", "<默认|紧凑>"],
|
|
109
|
-
"contracts/PROTOCOL.md": [
|
|
110
|
-
"<项目名>",
|
|
111
|
-
"<vX.Y.Z>",
|
|
112
|
-
"<上线日期>",
|
|
113
|
-
"<代码子仓1>",
|
|
114
|
-
"<bus-baseline.json app 名或 n/a>",
|
|
115
|
-
"<边界A:服务X ↔ 服务Y>",
|
|
116
|
-
"<对齐点>",
|
|
117
|
-
"<怎么核的:实测命令/代码行/配置查询>",
|
|
118
|
-
],
|
|
119
|
-
"gitignore.template": ["<代码仓1>", "<代码仓2>"],
|
|
120
|
-
"pm/NOW.md": ["<期名>", "<一句话状态>", "<快轨|标准轨|重轨>", "<期>", "<域>"],
|
|
121
|
-
"pm/decisions.md": [
|
|
122
|
-
"<yyyy-mm-dd>",
|
|
123
|
-
"<谁>",
|
|
124
|
-
"<包ID>",
|
|
125
|
-
"<默认 2–5 个真实取舍的收敛结论;单项决定直接写一句>",
|
|
126
|
-
"<文件/落点>",
|
|
127
|
-
],
|
|
128
|
-
"pm/当期看板.md": [
|
|
129
|
-
"<期名>",
|
|
130
|
-
"<工作包名>",
|
|
131
|
-
"<这轮最终要交付什么结果,不用文件名代替>",
|
|
132
|
-
"<产品 / 全栈 / 测试;按需调用,各自仍只写自己的边界>",
|
|
133
|
-
"<为达成结果可自动继续的关联任务/AI视角/文件边界>",
|
|
134
|
-
"<带证据完成 / 必须由人处理的真实阻塞 / 用户明确的检查点>",
|
|
135
|
-
"<完成时填一条可核验的仓库相对路径 / candidate hash;未完成留空>",
|
|
136
|
-
"<N>",
|
|
137
|
-
"<Gate>",
|
|
138
|
-
"<需求1>",
|
|
139
|
-
"<跨边界接口/字段/机制 约定;契约口径落 `contracts/PROTOCOL.md`>",
|
|
140
|
-
"<对照需求清单 + 设计稿逐屏;上线前必过的清单>",
|
|
141
|
-
],
|
|
142
|
-
"pm/adr/ADR-0000-template.md": [
|
|
143
|
-
"<标题>",
|
|
144
|
-
"<yyyy-mm-dd>",
|
|
145
|
-
"<为什么现在必须做这个长期技术决定>",
|
|
146
|
-
"<最终选择及其边界>",
|
|
147
|
-
"<正向、负向与回滚影响>",
|
|
148
|
-
"<方案 A / B / C 及未选原因>",
|
|
149
|
-
"<工作包 / 契约 / evidence 路径或 n/a>",
|
|
150
|
-
],
|
|
151
|
-
"scripts/drift-check.sh": ["<应用1>", "<应用2>", "<代码子仓1>"],
|
|
152
|
-
"scripts/verify-status.sh": ["<套件1>", "<套件2>", "<代码子仓1>", "<代码子仓2>"],
|
|
153
|
-
"standards/STACK.md": [
|
|
154
|
-
"<项目名>",
|
|
155
|
-
"<运行时及版本约束>",
|
|
156
|
-
"<包管理器及 lockfile>",
|
|
157
|
-
"<主要语言与框架>",
|
|
158
|
-
"<数据库 / 缓存 / 消息设施>",
|
|
159
|
-
"<部署平台 / 容器基线>",
|
|
160
|
-
"<CI 与测试命令>",
|
|
161
|
-
"<许可证 / 供应链约束>",
|
|
162
|
-
"<.nvmrc / engines.node 的精确值;多值重复本行;无则 n/a>",
|
|
163
|
-
"<lockfile 文件名;多类重复本行;无则 n/a>",
|
|
164
|
-
"<Dockerfile FROM 镜像;多值重复本行;无则 n/a>",
|
|
165
|
-
],
|
|
166
|
-
"standards/CODE.md": ["<项目名>", "<代码组织与命名约定>", "<项目特有禁止事项>"],
|
|
167
|
-
"standards/REVIEW.md": ["<项目名>", "<项目特有 Review 条件>"],
|
|
168
|
-
"standards/DESIGN.md": [
|
|
169
|
-
"<项目名>",
|
|
170
|
-
"<设计原则>",
|
|
171
|
-
"<排版 / 色彩 / 间距 token 来源>",
|
|
172
|
-
"<核心组件与复用边界>",
|
|
173
|
-
"<项目特有例外>",
|
|
174
|
-
],
|
|
175
|
-
"指挥台.md": ["<被测仓>"],
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
export const FILE_POLICIES = {
|
|
179
|
-
REPLACE_IF_UNMODIFIED: "replace-if-unmodified",
|
|
180
|
-
// Schema 1 compatibility only. New plans and schema 2 manifests never emit
|
|
181
|
-
// this historical policy.
|
|
182
|
-
THREE_WAY_ONLY: "three-way-only",
|
|
183
|
-
PROJECT_OWNED: "project-owned",
|
|
184
|
-
MERGE_ONLY: "merge-only",
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
export function filePolicy(templatePath) {
|
|
188
|
-
if (templatePath === "gitignore.template") {
|
|
189
|
-
return FILE_POLICIES.MERGE_ONLY;
|
|
190
|
-
}
|
|
191
|
-
if (
|
|
192
|
-
templatePath === "CLAUDE.md" ||
|
|
193
|
-
templatePath === ".claude/agents/reviewer.md" ||
|
|
194
|
-
templatePath === "AGENTS.md" ||
|
|
195
|
-
templatePath === "BUILDBEAT.md" ||
|
|
196
|
-
templatePath === "指挥台.md" ||
|
|
197
|
-
(/^scripts\//.test(templatePath) && templatePath !== "scripts/verify-status.sh")
|
|
198
|
-
) {
|
|
199
|
-
return FILE_POLICIES.REPLACE_IF_UNMODIFIED;
|
|
200
|
-
}
|
|
201
|
-
return FILE_POLICIES.PROJECT_OWNED;
|
|
202
|
-
}
|