specdo 1.0.2
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 +139 -0
- package/README.md +308 -0
- package/README.zh-CN.md +306 -0
- package/bin/specdo.js +3 -0
- package/dist/cli/index.d.ts +15 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +297 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/commands/_shared.d.ts +45 -0
- package/dist/commands/_shared.d.ts.map +1 -0
- package/dist/commands/_shared.js +124 -0
- package/dist/commands/_shared.js.map +1 -0
- package/dist/commands/apply.d.ts +30 -0
- package/dist/commands/apply.d.ts.map +1 -0
- package/dist/commands/apply.js +393 -0
- package/dist/commands/apply.js.map +1 -0
- package/dist/commands/archive.d.ts +25 -0
- package/dist/commands/archive.d.ts.map +1 -0
- package/dist/commands/archive.js +362 -0
- package/dist/commands/archive.js.map +1 -0
- package/dist/commands/doctor.d.ts +21 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +180 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/domains.d.ts +14 -0
- package/dist/commands/domains.d.ts.map +1 -0
- package/dist/commands/domains.js +107 -0
- package/dist/commands/domains.js.map +1 -0
- package/dist/commands/explore.d.ts +48 -0
- package/dist/commands/explore.d.ts.map +1 -0
- package/dist/commands/explore.js +378 -0
- package/dist/commands/explore.js.map +1 -0
- package/dist/commands/init.d.ts +45 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +243 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.d.ts +23 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +135 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/propose.d.ts +22 -0
- package/dist/commands/propose.d.ts.map +1 -0
- package/dist/commands/propose.js +316 -0
- package/dist/commands/propose.js.map +1 -0
- package/dist/commands/show.d.ts +15 -0
- package/dist/commands/show.d.ts.map +1 -0
- package/dist/commands/show.js +214 -0
- package/dist/commands/show.js.map +1 -0
- package/dist/commands/status.d.ts +17 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +146 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/sync.d.ts +21 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +113 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/validate.d.ts +117 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +446 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/core/apply-brief-renderer.d.ts +35 -0
- package/dist/core/apply-brief-renderer.d.ts.map +1 -0
- package/dist/core/apply-brief-renderer.js +242 -0
- package/dist/core/apply-brief-renderer.js.map +1 -0
- package/dist/core/config-store.d.ts +190 -0
- package/dist/core/config-store.d.ts.map +1 -0
- package/dist/core/config-store.js +280 -0
- package/dist/core/config-store.js.map +1 -0
- package/dist/core/context-store.d.ts +96 -0
- package/dist/core/context-store.d.ts.map +1 -0
- package/dist/core/context-store.js +426 -0
- package/dist/core/context-store.js.map +1 -0
- package/dist/core/json-schemas.d.ts +349 -0
- package/dist/core/json-schemas.d.ts.map +1 -0
- package/dist/core/json-schemas.js +125 -0
- package/dist/core/json-schemas.js.map +1 -0
- package/dist/core/skill-content/cross-domain.d.ts +12 -0
- package/dist/core/skill-content/cross-domain.d.ts.map +1 -0
- package/dist/core/skill-content/cross-domain.js +291 -0
- package/dist/core/skill-content/cross-domain.js.map +1 -0
- package/dist/core/skill-content/protocol-examples.d.ts +13 -0
- package/dist/core/skill-content/protocol-examples.d.ts.map +1 -0
- package/dist/core/skill-content/protocol-examples.js +190 -0
- package/dist/core/skill-content/protocol-examples.js.map +1 -0
- package/dist/core/skill-content/workflow-content.d.ts +25 -0
- package/dist/core/skill-content/workflow-content.d.ts.map +1 -0
- package/dist/core/skill-content/workflow-content.js +1572 -0
- package/dist/core/skill-content/workflow-content.js.map +1 -0
- package/dist/core/skill-exporter.d.ts +186 -0
- package/dist/core/skill-exporter.d.ts.map +1 -0
- package/dist/core/skill-exporter.js +922 -0
- package/dist/core/skill-exporter.js.map +1 -0
- package/dist/core/spec-sync.d.ts +65 -0
- package/dist/core/spec-sync.d.ts.map +1 -0
- package/dist/core/spec-sync.js +226 -0
- package/dist/core/spec-sync.js.map +1 -0
- package/dist/core/task-parser.d.ts +58 -0
- package/dist/core/task-parser.d.ts.map +1 -0
- package/dist/core/task-parser.js +244 -0
- package/dist/core/task-parser.js.map +1 -0
- package/dist/core/template-renderer.d.ts +51 -0
- package/dist/core/template-renderer.d.ts.map +1 -0
- package/dist/core/template-renderer.js +362 -0
- package/dist/core/template-renderer.js.map +1 -0
- package/dist/domains/architecture.d.ts +34 -0
- package/dist/domains/architecture.d.ts.map +1 -0
- package/dist/domains/architecture.js +341 -0
- package/dist/domains/architecture.js.map +1 -0
- package/dist/domains/backend.d.ts +35 -0
- package/dist/domains/backend.d.ts.map +1 -0
- package/dist/domains/backend.js +367 -0
- package/dist/domains/backend.js.map +1 -0
- package/dist/domains/frontend.d.ts +36 -0
- package/dist/domains/frontend.d.ts.map +1 -0
- package/dist/domains/frontend.js +373 -0
- package/dist/domains/frontend.js.map +1 -0
- package/dist/domains/index.d.ts +49 -0
- package/dist/domains/index.d.ts.map +1 -0
- package/dist/domains/index.js +255 -0
- package/dist/domains/index.js.map +1 -0
- package/dist/domains/operations.d.ts +37 -0
- package/dist/domains/operations.d.ts.map +1 -0
- package/dist/domains/operations.js +344 -0
- package/dist/domains/operations.js.map +1 -0
- package/dist/domains/pool-ranking.d.ts +43 -0
- package/dist/domains/pool-ranking.d.ts.map +1 -0
- package/dist/domains/pool-ranking.js +153 -0
- package/dist/domains/pool-ranking.js.map +1 -0
- package/dist/domains/quality.d.ts +45 -0
- package/dist/domains/quality.d.ts.map +1 -0
- package/dist/domains/quality.js +368 -0
- package/dist/domains/quality.js.map +1 -0
- package/dist/domains/security.d.ts +19 -0
- package/dist/domains/security.d.ts.map +1 -0
- package/dist/domains/security.js +364 -0
- package/dist/domains/security.js.map +1 -0
- package/dist/domains/signal-match.d.ts +25 -0
- package/dist/domains/signal-match.d.ts.map +1 -0
- package/dist/domains/signal-match.js +67 -0
- package/dist/domains/signal-match.js.map +1 -0
- package/dist/domains/types.d.ts +354 -0
- package/dist/domains/types.d.ts.map +1 -0
- package/dist/domains/types.js +12 -0
- package/dist/domains/types.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/protocols/index.d.ts +36 -0
- package/dist/protocols/index.d.ts.map +1 -0
- package/dist/protocols/index.js +85 -0
- package/dist/protocols/index.js.map +1 -0
- package/dist/protocols/review-to-solid.d.ts +32 -0
- package/dist/protocols/review-to-solid.d.ts.map +1 -0
- package/dist/protocols/review-to-solid.js +309 -0
- package/dist/protocols/review-to-solid.js.map +1 -0
- package/dist/utils/prompt.d.ts +37 -0
- package/dist/utils/prompt.d.ts.map +1 -0
- package/dist/utils/prompt.js +81 -0
- package/dist/utils/prompt.js.map +1 -0
- package/package.json +80 -0
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* specdo archive [--change <name>] [--skip-sync-check]
|
|
3
|
+
*
|
|
4
|
+
* 行为:
|
|
5
|
+
* 1. 必须 init;--change 必需
|
|
6
|
+
* 2. 检查 tasks 全部完成 + 每个完成任务有 evidence
|
|
7
|
+
* 3. 实时只读检查当前 changes/<name>/specs 与 specdo/specs 的同步状态
|
|
8
|
+
* - 只要存在 added / conflict → 始终失败(即使 --skip-sync-check)
|
|
9
|
+
* - sync 未运行 → 失败(除非 --skip-sync-check)
|
|
10
|
+
* - sync.completedAt = null → 失败(除非 --skip-sync-check)
|
|
11
|
+
* 4. same-filesystem rename: changes/<name>/ → archive/<name>/
|
|
12
|
+
* 5. 在 archive 目录内写 archive-summary.md 与 context.archive 元数据
|
|
13
|
+
* - rename 失败 EXDEV → exit 3
|
|
14
|
+
* - 目标已存在 → exit 1
|
|
15
|
+
* - 元数据写入失败 → 尝试回滚 rename,避免 active change 脏状态
|
|
16
|
+
*/
|
|
17
|
+
import * as fs from 'node:fs';
|
|
18
|
+
import * as path from 'node:path';
|
|
19
|
+
import { ContextStore } from '../core/context-store.js';
|
|
20
|
+
import { planSync, SyncError } from '../core/spec-sync.js';
|
|
21
|
+
import { parseTasks } from '../core/task-parser.js';
|
|
22
|
+
import { loadConfig, resolveDomains } from '../core/config-store.js';
|
|
23
|
+
import { validateChange } from './validate.js';
|
|
24
|
+
import { fail, findSpecdoConfig, getArchiveDir, getChangeDir, isValidChangeName, safeExists, safeIsDir, failOnInvalidConfig, } from './_shared.js';
|
|
25
|
+
export async function handleArchive(options) {
|
|
26
|
+
const { cwd } = options;
|
|
27
|
+
if (!findSpecdoConfig(cwd)) {
|
|
28
|
+
return fail(1, ["Not initialized. Run 'specdo init' first."]);
|
|
29
|
+
}
|
|
30
|
+
if (!options.change) {
|
|
31
|
+
return fail(1, ['archive requires --change <name>.']);
|
|
32
|
+
}
|
|
33
|
+
if (!isValidChangeName(options.change)) {
|
|
34
|
+
return fail(1, [`Invalid --change name: "${options.change}".`]);
|
|
35
|
+
}
|
|
36
|
+
const changeName = options.change;
|
|
37
|
+
const changeDir = getChangeDir(cwd, changeName);
|
|
38
|
+
if (!safeIsDir(changeDir)) {
|
|
39
|
+
return fail(1, [`Change directory not found: ${changeDir}.`]);
|
|
40
|
+
}
|
|
41
|
+
const archiveDir = getArchiveDir(cwd, changeName);
|
|
42
|
+
if (safeExists(archiveDir)) {
|
|
43
|
+
return fail(1, [
|
|
44
|
+
`Archive target already exists: ${archiveDir}.`,
|
|
45
|
+
`Remove or rename the existing archive entry before re-archiving.`,
|
|
46
|
+
]);
|
|
47
|
+
}
|
|
48
|
+
const tasksPath = path.join(changeDir, 'tasks.md');
|
|
49
|
+
if (!safeExists(tasksPath)) {
|
|
50
|
+
return fail(1, [`tasks.md not found at ${tasksPath}; cannot validate completion.`]);
|
|
51
|
+
}
|
|
52
|
+
const now = options.now ?? (() => new Date().toISOString());
|
|
53
|
+
const configResult = loadConfig(cwd);
|
|
54
|
+
const configFailure = failOnInvalidConfig(configResult);
|
|
55
|
+
if (configFailure)
|
|
56
|
+
return configFailure;
|
|
57
|
+
const validation = validateChange(cwd, changeName);
|
|
58
|
+
const validationErrors = validation.issues.filter((issue) => issue.level === 'error');
|
|
59
|
+
if (validationErrors.length > 0) {
|
|
60
|
+
return fail(1, renderValidationIssues(changeName, validationErrors));
|
|
61
|
+
}
|
|
62
|
+
const store = new ContextStore({ changeDir, now });
|
|
63
|
+
const ctx = store.read();
|
|
64
|
+
const resolvedDomains = resolveDomains(configResult.config).map((r) => r.domain);
|
|
65
|
+
const sourceSpecsDir = path.join(changeDir, 'specs');
|
|
66
|
+
const specsDir = path.join(cwd, 'specdo/specs');
|
|
67
|
+
// ─── 1. tasks 检查 ───
|
|
68
|
+
let parsed;
|
|
69
|
+
try {
|
|
70
|
+
parsed = parseTasks(fs.readFileSync(tasksPath, 'utf-8'));
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
return fail(1, [`tasks.md parse failed: ${err.message}`]);
|
|
74
|
+
}
|
|
75
|
+
if (parsed.tasks.length === 0) {
|
|
76
|
+
return fail(1, ['tasks.md has no tasks; nothing to archive.']);
|
|
77
|
+
}
|
|
78
|
+
const incomplete = parsed.tasks.filter((t) => !t.completed);
|
|
79
|
+
if (incomplete.length > 0) {
|
|
80
|
+
return fail(1, [
|
|
81
|
+
`Cannot archive: ${incomplete.length} task(s) still incomplete:`,
|
|
82
|
+
...incomplete.map((t) => ` - ${t.number}. ${t.title}`),
|
|
83
|
+
]);
|
|
84
|
+
}
|
|
85
|
+
const missingEvidence = parsed.tasks.filter((t) => t.completed && (!t.evidence || t.evidence.trim().length === 0));
|
|
86
|
+
if (missingEvidence.length > 0) {
|
|
87
|
+
return fail(1, [
|
|
88
|
+
`Cannot archive: ${missingEvidence.length} completed task(s) missing evidence:`,
|
|
89
|
+
...missingEvidence.map((t) => ` - ${t.number}. ${t.title}`),
|
|
90
|
+
]);
|
|
91
|
+
}
|
|
92
|
+
// ─── 2. apply.tasksCompleted vs tasksTotal ───
|
|
93
|
+
if (!validation.context?.apply) {
|
|
94
|
+
return fail(1, [
|
|
95
|
+
'Cannot archive: context.apply is missing.',
|
|
96
|
+
`Run 'specdo apply --change ${changeName}' to rebuild apply state before archiving.`,
|
|
97
|
+
]);
|
|
98
|
+
}
|
|
99
|
+
if (validation.context.apply.tasksCompleted !== validation.context.apply.tasksTotal ||
|
|
100
|
+
validation.context.apply.tasksTotal !== parsed.tasks.length) {
|
|
101
|
+
return fail(1, [
|
|
102
|
+
`context.apply is out of sync with tasks.md (parsed ${parsed.tasks.length} tasks, ` +
|
|
103
|
+
`context says ${validation.context.apply.tasksCompleted}/${validation.context.apply.tasksTotal}).`,
|
|
104
|
+
`Run 'specdo apply --change ${changeName}' to refresh state.`,
|
|
105
|
+
]);
|
|
106
|
+
}
|
|
107
|
+
// ─── 3. sync 检查(实时只读比对 + 历史 completedAt 审计) ───
|
|
108
|
+
let liveSync;
|
|
109
|
+
try {
|
|
110
|
+
liveSync = inspectLiveSync({ changeName, sourceSpecsDir, specsDir });
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
if (err instanceof ArchivePreconditionError) {
|
|
114
|
+
return fail(err.exitCode, err.lines);
|
|
115
|
+
}
|
|
116
|
+
return fail(3, [`Failed to inspect current sync state: ${err.message}`]);
|
|
117
|
+
}
|
|
118
|
+
if (liveSync.unsyncedAdded.length > 0 || liveSync.unsyncedConflicts.length > 0) {
|
|
119
|
+
return fail(1, [
|
|
120
|
+
`Cannot archive: change specs are not fully synced into specdo/specs.`,
|
|
121
|
+
...liveSync.unsyncedAdded.map((rel) => ` + pending add: ${rel}`),
|
|
122
|
+
...liveSync.unsyncedConflicts.map((rel) => ` ! pending conflict: ${rel}`),
|
|
123
|
+
`Re-run 'specdo sync --change ${changeName}' before archiving.`,
|
|
124
|
+
]);
|
|
125
|
+
}
|
|
126
|
+
const syncSnapshot = {
|
|
127
|
+
completedAt: ctx.sync?.completedAt ?? null,
|
|
128
|
+
unresolvedConflicts: liveSync.unsyncedConflicts,
|
|
129
|
+
forcedConflicts: ctx.sync?.forcedConflicts ?? [],
|
|
130
|
+
};
|
|
131
|
+
// 显式校验 context.json 中的 conflicts 字段
|
|
132
|
+
if (ctx.sync?.conflicts && ctx.sync.conflicts.length > 0) {
|
|
133
|
+
return fail(1, [
|
|
134
|
+
`Cannot archive: ${ctx.sync.conflicts.length} unresolved sync conflict(s) recorded in context.json.`,
|
|
135
|
+
...ctx.sync.conflicts.map((c) => ` - ${c}`),
|
|
136
|
+
`Run 'specdo sync --change ${changeName} --force' to overwrite, or hand-merge and re-sync.`,
|
|
137
|
+
]);
|
|
138
|
+
}
|
|
139
|
+
const riskNotes = [];
|
|
140
|
+
let skippedSyncCheck = false;
|
|
141
|
+
let skipSyncReason;
|
|
142
|
+
if (!ctx.sync) {
|
|
143
|
+
if (!options.skipSyncCheck) {
|
|
144
|
+
return fail(1, [
|
|
145
|
+
`Cannot archive: sync has not been executed. ` +
|
|
146
|
+
`Run 'specdo sync --change ${changeName}' first, or pass --skip-sync-check (record-only).`,
|
|
147
|
+
]);
|
|
148
|
+
}
|
|
149
|
+
skippedSyncCheck = true;
|
|
150
|
+
skipSyncReason = 'Sync was never executed';
|
|
151
|
+
riskNotes.push('Sync was never executed');
|
|
152
|
+
}
|
|
153
|
+
else if (ctx.sync.completedAt === null) {
|
|
154
|
+
if (!options.skipSyncCheck) {
|
|
155
|
+
return fail(1, [
|
|
156
|
+
`Cannot archive: sync is incomplete (completedAt = null).`,
|
|
157
|
+
`Re-run 'specdo sync --change ${changeName}' or pass --skip-sync-check (record-only).`,
|
|
158
|
+
]);
|
|
159
|
+
}
|
|
160
|
+
skippedSyncCheck = true;
|
|
161
|
+
skipSyncReason = 'Sync started but never completed';
|
|
162
|
+
riskNotes.push('Sync started but never completed');
|
|
163
|
+
}
|
|
164
|
+
// ─── 4. rename 到 archive/ ───
|
|
165
|
+
fs.mkdirSync(path.dirname(archiveDir), { recursive: true });
|
|
166
|
+
try {
|
|
167
|
+
fs.renameSync(changeDir, archiveDir);
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
const code = err.code;
|
|
171
|
+
if (code === 'EXDEV') {
|
|
172
|
+
return fail(3, [
|
|
173
|
+
`specdo/changes/ and specdo/archive/ must reside on the same filesystem. ` +
|
|
174
|
+
`Symlinks across mount points are not supported. ` +
|
|
175
|
+
`(${err.message})`,
|
|
176
|
+
]);
|
|
177
|
+
}
|
|
178
|
+
if (code === 'ENOTEMPTY' || code === 'EEXIST') {
|
|
179
|
+
return fail(1, [`Archive target already exists: ${archiveDir}.`]);
|
|
180
|
+
}
|
|
181
|
+
return fail(3, [`Failed to rename change directory to archive: ${err.message}`]);
|
|
182
|
+
}
|
|
183
|
+
// ─── 5. 在 archive 目录内写 summary + context.archive;失败时回滚 rename ───
|
|
184
|
+
const summaryRelPath = 'archive-summary.md';
|
|
185
|
+
const summaryAbsPath = path.join(archiveDir, summaryRelPath);
|
|
186
|
+
const archivedAt = now();
|
|
187
|
+
const summary = renderArchiveSummary({
|
|
188
|
+
changeName,
|
|
189
|
+
tasksCount: parsed.tasks.length,
|
|
190
|
+
domainsUsed: ctx.propose?.domainsUsed ?? [],
|
|
191
|
+
syncSnapshot,
|
|
192
|
+
skippedSyncCheck,
|
|
193
|
+
skipSyncReason,
|
|
194
|
+
riskNotes,
|
|
195
|
+
archivedAt,
|
|
196
|
+
});
|
|
197
|
+
const archiveStore = new ContextStore({ changeDir: archiveDir, now });
|
|
198
|
+
try {
|
|
199
|
+
fs.writeFileSync(summaryAbsPath, summary, 'utf-8');
|
|
200
|
+
archiveStore.writeDeep({
|
|
201
|
+
archive: {
|
|
202
|
+
archivedAt,
|
|
203
|
+
archivePath: path.relative(cwd, archiveDir),
|
|
204
|
+
summaryPath: summaryRelPath,
|
|
205
|
+
skippedSyncCheck: skippedSyncCheck ? true : undefined,
|
|
206
|
+
skipSyncReason,
|
|
207
|
+
syncSnapshot,
|
|
208
|
+
riskNotes: riskNotes.length > 0 ? riskNotes : undefined,
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
catch (err) {
|
|
213
|
+
return rollbackArchivedChange({
|
|
214
|
+
cwd,
|
|
215
|
+
changeDir,
|
|
216
|
+
archiveDir,
|
|
217
|
+
summaryAbsPath,
|
|
218
|
+
message: `Failed to finalize archive metadata: ${err.message}`,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
// ─── 6. 注入领域 verify checklist 作为 stdout 提示 ───
|
|
222
|
+
const stdout = [];
|
|
223
|
+
stdout.push(`✓ Archived '${changeName}' → ${path.relative(cwd, archiveDir)}/.`);
|
|
224
|
+
stdout.push(`Summary: ${path.relative(cwd, path.join(archiveDir, summaryRelPath))}`);
|
|
225
|
+
stdout.push('');
|
|
226
|
+
if (riskNotes.length > 0) {
|
|
227
|
+
stdout.push('Risk notes:');
|
|
228
|
+
for (const r of riskNotes) {
|
|
229
|
+
stdout.push(` ! ${r}`);
|
|
230
|
+
}
|
|
231
|
+
stdout.push('');
|
|
232
|
+
}
|
|
233
|
+
const verifyChecklist = collectVerifyChecklist(resolvedDomains, ctx.propose?.domainsUsed ?? []);
|
|
234
|
+
if (verifyChecklist.length > 0) {
|
|
235
|
+
stdout.push('Pre-archive verify checklist (cross-check before announcing the change):');
|
|
236
|
+
for (const item of verifyChecklist) {
|
|
237
|
+
stdout.push(` - [ ] ${item}`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return { exitCode: 0, stdout, stderr: [] };
|
|
241
|
+
}
|
|
242
|
+
function renderArchiveSummary(input) {
|
|
243
|
+
const lines = [];
|
|
244
|
+
lines.push(`# Archive Summary: ${input.changeName}`);
|
|
245
|
+
lines.push('');
|
|
246
|
+
lines.push(`<!-- generatedBy: specdo archive at ${input.archivedAt} -->`);
|
|
247
|
+
lines.push('');
|
|
248
|
+
lines.push('## Outcome');
|
|
249
|
+
lines.push('');
|
|
250
|
+
lines.push(`- Tasks completed: ${input.tasksCount}`);
|
|
251
|
+
lines.push(`- Domains used: ${input.domainsUsed.length > 0 ? input.domainsUsed.join(', ') : '(none)'}`);
|
|
252
|
+
lines.push('');
|
|
253
|
+
lines.push('## Sync Snapshot');
|
|
254
|
+
lines.push('');
|
|
255
|
+
lines.push(`- completedAt: ${input.syncSnapshot.completedAt ?? '(none)'}`);
|
|
256
|
+
lines.push(`- unresolvedConflicts: ${input.syncSnapshot.unresolvedConflicts.length}`);
|
|
257
|
+
lines.push(`- forcedConflicts: ${input.syncSnapshot.forcedConflicts.length}`);
|
|
258
|
+
if (input.syncSnapshot.forcedConflicts.length > 0) {
|
|
259
|
+
for (const f of input.syncSnapshot.forcedConflicts) {
|
|
260
|
+
lines.push(` - ${f}`);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
lines.push('');
|
|
264
|
+
if (input.skippedSyncCheck) {
|
|
265
|
+
lines.push('## Skipped Sync Check');
|
|
266
|
+
lines.push('');
|
|
267
|
+
lines.push(`- reason: ${input.skipSyncReason ?? 'unspecified'}`);
|
|
268
|
+
lines.push('');
|
|
269
|
+
}
|
|
270
|
+
if (input.riskNotes.length > 0) {
|
|
271
|
+
lines.push('## Risk Notes');
|
|
272
|
+
lines.push('');
|
|
273
|
+
for (const r of input.riskNotes) {
|
|
274
|
+
lines.push(`- ⚠️ ${r}`);
|
|
275
|
+
}
|
|
276
|
+
lines.push('');
|
|
277
|
+
}
|
|
278
|
+
return lines.join('\n');
|
|
279
|
+
}
|
|
280
|
+
function inspectLiveSync(input) {
|
|
281
|
+
let entries;
|
|
282
|
+
try {
|
|
283
|
+
entries = planSync({
|
|
284
|
+
changesSpecsDir: input.sourceSpecsDir,
|
|
285
|
+
specsDir: input.specsDir,
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
catch (err) {
|
|
289
|
+
if (err instanceof SyncError && err.exitCode === 1) {
|
|
290
|
+
throw new ArchivePreconditionError([
|
|
291
|
+
`Cannot archive: source specs directory not found for change '${input.changeName}'.`,
|
|
292
|
+
`Run 'specdo propose --change ${input.changeName}' first.`,
|
|
293
|
+
]);
|
|
294
|
+
}
|
|
295
|
+
throw err;
|
|
296
|
+
}
|
|
297
|
+
return {
|
|
298
|
+
unsyncedAdded: entries.filter((entry) => entry.status === 'added').map((entry) => entry.relativePath),
|
|
299
|
+
unsyncedConflicts: entries.filter((entry) => entry.status === 'conflict').map((entry) => entry.relativePath),
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
function rollbackArchivedChange(input) {
|
|
303
|
+
const rollbackErrors = [];
|
|
304
|
+
try {
|
|
305
|
+
if (fs.existsSync(input.summaryAbsPath)) {
|
|
306
|
+
fs.rmSync(input.summaryAbsPath, { force: true });
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
catch (err) {
|
|
310
|
+
rollbackErrors.push(`remove summary: ${err.message}`);
|
|
311
|
+
}
|
|
312
|
+
try {
|
|
313
|
+
if (!safeExists(input.changeDir) && safeExists(input.archiveDir)) {
|
|
314
|
+
fs.renameSync(input.archiveDir, input.changeDir);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
catch (err) {
|
|
318
|
+
rollbackErrors.push(`rename rollback: ${err.message}`);
|
|
319
|
+
}
|
|
320
|
+
if (rollbackErrors.length > 0) {
|
|
321
|
+
return fail(3, [
|
|
322
|
+
input.message,
|
|
323
|
+
`Rollback failed: ${rollbackErrors.join('; ')}`,
|
|
324
|
+
`Inspect ${path.relative(input.cwd, input.archiveDir)} manually before retrying archive.`,
|
|
325
|
+
]);
|
|
326
|
+
}
|
|
327
|
+
return fail(3, [input.message, 'Archive directory was rolled back to the active change.']);
|
|
328
|
+
}
|
|
329
|
+
class ArchivePreconditionError extends Error {
|
|
330
|
+
lines;
|
|
331
|
+
exitCode = 1;
|
|
332
|
+
constructor(lines) {
|
|
333
|
+
super(lines.join('\n'));
|
|
334
|
+
this.lines = lines;
|
|
335
|
+
this.name = 'ArchivePreconditionError';
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
function collectVerifyChecklist(resolvedDomains, domainNames) {
|
|
339
|
+
const out = [];
|
|
340
|
+
const seen = new Set();
|
|
341
|
+
const byName = new Map(resolvedDomains.map((domain) => [domain.name, domain]));
|
|
342
|
+
for (const name of domainNames) {
|
|
343
|
+
const domain = byName.get(name);
|
|
344
|
+
if (!domain)
|
|
345
|
+
continue;
|
|
346
|
+
for (const item of domain.verify?.checklist ?? []) {
|
|
347
|
+
if (seen.has(item))
|
|
348
|
+
continue;
|
|
349
|
+
seen.add(item);
|
|
350
|
+
out.push(`(${name}) ${item}`);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return out;
|
|
354
|
+
}
|
|
355
|
+
function renderValidationIssues(changeName, issues) {
|
|
356
|
+
return [
|
|
357
|
+
`Cannot archive: validation failed for change '${changeName}'.`,
|
|
358
|
+
...issues.map((issue) => ` - ${issue.path}: ${issue.message}`),
|
|
359
|
+
`Run 'specdo validate --change ${changeName}' to inspect the full report.`,
|
|
360
|
+
];
|
|
361
|
+
}
|
|
362
|
+
//# sourceMappingURL=archive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"archive.js","sourceRoot":"","sources":["../../src/commands/archive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,cAAc,EAAwB,MAAM,eAAe,CAAC;AACrE,OAAO,EAEL,IAAI,EACJ,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,UAAU,EACV,SAAS,EACT,mBAAmB,GACpB,MAAM,cAAc,CAAC;AAStB,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAuB;IACzD,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;IAExB,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC,CAAC,EAAE,CAAC,2CAA2C,CAAC,CAAC,CAAC;IAChE,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC,CAAC,EAAE,CAAC,mCAAmC,CAAC,CAAC,CAAC;IACxD,CAAC;IACD,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACvC,OAAO,IAAI,CAAC,CAAC,EAAE,CAAC,2BAA2B,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;IAClE,CAAC;IACD,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC;IAClC,MAAM,SAAS,GAAG,YAAY,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;IAChD,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC,CAAC,EAAE,CAAC,+BAA+B,SAAS,GAAG,CAAC,CAAC,CAAC;IAChE,CAAC;IAED,MAAM,UAAU,GAAG,aAAa,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;IAClD,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC,CAAC,EAAE;YACb,kCAAkC,UAAU,GAAG;YAC/C,kEAAkE;SACnE,CAAC,CAAC;IACL,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IACnD,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC,CAAC,EAAE,CAAC,yBAAyB,SAAS,+BAA+B,CAAC,CAAC,CAAC;IACtF,CAAC;IAED,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5D,MAAM,YAAY,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IACrC,MAAM,aAAa,GAAG,mBAAmB,CAAC,YAAY,CAAC,CAAC;IACxD,IAAI,aAAa;QAAE,OAAO,aAAa,CAAC;IACxC,MAAM,UAAU,GAAG,cAAc,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;IACnD,MAAM,gBAAgB,GAAG,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC;IACtF,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,OAAO,IAAI,CAAC,CAAC,EAAE,sBAAsB,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAC,CAAC;IACvE,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,YAAY,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;IACnD,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IACzB,MAAM,eAAe,GAAG,cAAc,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IACjF,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IAEhD,sBAAsB;IACtB,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACH,MAAM,GAAG,UAAU,CAAC,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;IAC3D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,IAAI,CAAC,CAAC,EAAE,CAAC,0BAA2B,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACvE,CAAC;IACD,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC,CAAC,EAAE,CAAC,4CAA4C,CAAC,CAAC,CAAC;IACjE,CAAC;IACD,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAC5D,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC,CAAC,EAAE;YACb,mBAAmB,UAAU,CAAC,MAAM,4BAA4B;YAChE,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC;SACxD,CAAC,CAAC;IACL,CAAC;IACD,MAAM,eAAe,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;IACnH,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC,CAAC,EAAE;YACb,mBAAmB,eAAe,CAAC,MAAM,sCAAsC;YAC/E,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC;SAC7D,CAAC,CAAC;IACL,CAAC;IAED,gDAAgD;IAChD,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC,CAAC,EAAE;YACb,2CAA2C;YAC3C,8BAA8B,UAAU,4CAA4C;SACrF,CAAC,CAAC;IACL,CAAC;IACD,IACE,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,cAAc,KAAK,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU;QAC/E,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,KAAK,MAAM,CAAC,KAAK,CAAC,MAAM,EAC3D,CAAC;QACD,OAAO,IAAI,CAAC,CAAC,EAAE;YACb,sDAAsD,MAAM,CAAC,KAAK,CAAC,MAAM,UAAU;gBACjF,gBAAgB,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,cAAc,IAAI,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,IAAI;YACpG,8BAA8B,UAAU,qBAAqB;SAC9D,CAAC,CAAC;IACL,CAAC;IAED,iDAAiD;IACjD,IAAI,QAAQ,CAAC;IACb,IAAI,CAAC;QACH,QAAQ,GAAG,eAAe,CAAC,EAAE,UAAU,EAAE,cAAc,EAAE,QAAQ,EAAE,CAAC,CAAC;IACvE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,wBAAwB,EAAE,CAAC;YAC5C,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;QACvC,CAAC;QACD,OAAO,IAAI,CAAC,CAAC,EAAE,CAAC,yCAA0C,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACtF,CAAC;IACD,IAAI,QAAQ,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/E,OAAO,IAAI,CAAC,CAAC,EAAE;YACb,sEAAsE;YACtE,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,oBAAoB,GAAG,EAAE,CAAC;YACjE,GAAG,QAAQ,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,yBAAyB,GAAG,EAAE,CAAC;YAC1E,gCAAgC,UAAU,qBAAqB;SAChE,CAAC,CAAC;IACL,CAAC;IAED,MAAM,YAAY,GAAG;QACnB,WAAW,EAAE,GAAG,CAAC,IAAI,EAAE,WAAW,IAAI,IAAI;QAC1C,mBAAmB,EAAE,QAAQ,CAAC,iBAAiB;QAC/C,eAAe,EAAE,GAAG,CAAC,IAAI,EAAE,eAAe,IAAI,EAAE;KACjD,CAAC;IAEF,oCAAoC;IACpC,IAAI,GAAG,CAAC,IAAI,EAAE,SAAS,IAAI,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzD,OAAO,IAAI,CAAC,CAAC,EAAE;YACb,mBAAmB,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,wDAAwD;YACpG,GAAG,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5C,6BAA6B,UAAU,oDAAoD;SAC5F,CAAC,CAAC;IACL,CAAC;IAED,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,IAAI,gBAAgB,GAAG,KAAK,CAAC;IAC7B,IAAI,cAAkC,CAAC;IAEvC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACd,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;YAC3B,OAAO,IAAI,CAAC,CAAC,EAAE;gBACb,8CAA8C;oBAC5C,6BAA6B,UAAU,mDAAmD;aAC7F,CAAC,CAAC;QACL,CAAC;QACD,gBAAgB,GAAG,IAAI,CAAC;QACxB,cAAc,GAAG,yBAAyB,CAAC;QAC3C,SAAS,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IAC5C,CAAC;SAAM,IAAI,GAAG,CAAC,IAAI,CAAC,WAAW,KAAK,IAAI,EAAE,CAAC;QACzC,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;YAC3B,OAAO,IAAI,CAAC,CAAC,EAAE;gBACb,0DAA0D;gBAC1D,gCAAgC,UAAU,4CAA4C;aACvF,CAAC,CAAC;QACL,CAAC;QACD,gBAAgB,GAAG,IAAI,CAAC;QACxB,cAAc,GAAG,kCAAkC,CAAC;QACpD,SAAS,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;IACrD,CAAC;IAED,+BAA+B;IAC/B,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,IAAI,CAAC;QACH,EAAE,CAAC,UAAU,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IACvC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,GAAI,GAA6B,CAAC,IAAI,CAAC;QACjD,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;YACrB,OAAO,IAAI,CAAC,CAAC,EAAE;gBACb,0EAA0E;oBACxE,kDAAkD;oBAClD,IAAK,GAAa,CAAC,OAAO,GAAG;aAChC,CAAC,CAAC;QACL,CAAC;QACD,IAAI,IAAI,KAAK,WAAW,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC9C,OAAO,IAAI,CAAC,CAAC,EAAE,CAAC,kCAAkC,UAAU,GAAG,CAAC,CAAC,CAAC;QACpE,CAAC;QACD,OAAO,IAAI,CAAC,CAAC,EAAE,CAAC,iDAAkD,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAC9F,CAAC;IAED,mEAAmE;IACnE,MAAM,cAAc,GAAG,oBAAoB,CAAC;IAC5C,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;IAC7D,MAAM,UAAU,GAAG,GAAG,EAAE,CAAC;IACzB,MAAM,OAAO,GAAG,oBAAoB,CAAC;QACnC,UAAU;QACV,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM;QAC/B,WAAW,EAAE,GAAG,CAAC,OAAO,EAAE,WAAW,IAAI,EAAE;QAC3C,YAAY;QACZ,gBAAgB;QAChB,cAAc;QACd,SAAS;QACT,UAAU;KACX,CAAC,CAAC;IACH,MAAM,YAAY,GAAG,IAAI,YAAY,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC;IACtE,IAAI,CAAC;QACH,EAAE,CAAC,aAAa,CAAC,cAAc,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QACnD,YAAY,CAAC,SAAS,CAAC;YACrB,OAAO,EAAE;gBACP,UAAU;gBACV,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC;gBAC3C,WAAW,EAAE,cAAc;gBAC3B,gBAAgB,EAAE,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;gBACrD,cAAc;gBACd,YAAY;gBACZ,SAAS,EAAE,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;aACxD;SACF,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,sBAAsB,CAAC;YAC5B,GAAG;YACH,SAAS;YACT,UAAU;YACV,cAAc;YACd,OAAO,EAAE,wCAAyC,GAAa,CAAC,OAAO,EAAE;SAC1E,CAAC,CAAC;IACL,CAAC;IAED,gDAAgD;IAChD,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,CAAC,IAAI,CAAC,eAAe,UAAU,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC;IAChF,MAAM,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC;IACrF,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAChB,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC3B,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;YAC1B,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC1B,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,eAAe,GAAG,sBAAsB,CAAC,eAAe,EAAE,GAAG,CAAC,OAAO,EAAE,WAAW,IAAI,EAAE,CAAC,CAAC;IAChG,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,MAAM,CAAC,IAAI,CAAC,0EAA0E,CAAC,CAAC;QACxF,KAAK,MAAM,IAAI,IAAI,eAAe,EAAE,CAAC;YACnC,MAAM,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;AAC7C,CAAC;AAED,SAAS,oBAAoB,CAAC,KAS7B;IACC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,sBAAsB,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;IACrD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,uCAAuC,KAAK,CAAC,UAAU,MAAM,CAAC,CAAC;IAC1E,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACzB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,sBAAsB,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;IACrD,KAAK,CAAC,IAAI,CAAC,mBAAmB,KAAK,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;IACxG,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAC/B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,kBAAkB,KAAK,CAAC,YAAY,CAAC,WAAW,IAAI,QAAQ,EAAE,CAAC,CAAC;IAC3E,KAAK,CAAC,IAAI,CAAC,0BAA0B,KAAK,CAAC,YAAY,CAAC,mBAAmB,CAAC,MAAM,EAAE,CAAC,CAAC;IACtF,KAAK,CAAC,IAAI,CAAC,sBAAsB,KAAK,CAAC,YAAY,CAAC,eAAe,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9E,IAAI,KAAK,CAAC,YAAY,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClD,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,CAAC;YACnD,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,IAAI,KAAK,CAAC,gBAAgB,EAAE,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;QACpC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,aAAa,KAAK,CAAC,cAAc,IAAI,aAAa,EAAE,CAAC,CAAC;QACjE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IACD,IAAI,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC5B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;YAChC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC1B,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,eAAe,CAAC,KAIxB;IACC,IAAI,OAAO,CAAC;IACZ,IAAI,CAAC;QACH,OAAO,GAAG,QAAQ,CAAC;YACjB,eAAe,EAAE,KAAK,CAAC,cAAc;YACrC,QAAQ,EAAE,KAAK,CAAC,QAAQ;SACzB,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,SAAS,IAAI,GAAG,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;YACnD,MAAM,IAAI,wBAAwB,CAAC;gBACjC,gEAAgE,KAAK,CAAC,UAAU,IAAI;gBACpF,gCAAgC,KAAK,CAAC,UAAU,UAAU;aAC3D,CAAC,CAAC;QACL,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,OAAO;QACL,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC;QACrG,iBAAiB,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC;KAC7G,CAAC;AACJ,CAAC;AAED,SAAS,sBAAsB,CAAC,KAM/B;IACC,MAAM,cAAc,GAAa,EAAE,CAAC;IACpC,IAAI,CAAC;QACH,IAAI,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC;YACxC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,cAAc,CAAC,IAAI,CAAC,mBAAoB,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;IACnE,CAAC;IACD,IAAI,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;YACjE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,cAAc,CAAC,IAAI,CAAC,oBAAqB,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;IACpE,CAAC;IAED,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC,CAAC,EAAE;YACb,KAAK,CAAC,OAAO;YACb,oBAAoB,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;YAC/C,WAAW,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,UAAU,CAAC,oCAAoC;SAC1F,CAAC,CAAC;IACL,CAAC;IAED,OAAO,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,yDAAyD,CAAC,CAAC,CAAC;AAC7F,CAAC;AAED,MAAM,wBAAyB,SAAQ,KAAK;IAEd;IADZ,QAAQ,GAAG,CAAC,CAAC;IAC7B,YAA4B,KAAe;QACzC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QADE,UAAK,GAAL,KAAK,CAAU;QAEzC,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AAED,SAAS,sBAAsB,CAAC,eAA+B,EAAE,WAAqB;IACpF,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IAC/E,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,CAAC,MAAM;YAAE,SAAS;QACtB,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,EAAE,SAAS,IAAI,EAAE,EAAE,CAAC;YAClD,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,SAAS;YAC7B,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACf,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,sBAAsB,CAAC,UAAkB,EAAE,MAAyB;IAC3E,OAAO;QACL,iDAAiD,UAAU,IAAI;QAC/D,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;QAC/D,iCAAiC,UAAU,+BAA+B;KAC3E,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* specdo doctor [--deep]
|
|
3
|
+
*
|
|
4
|
+
* 检查工作区健康度:目录结构、config schema、active vs archive 冲突、
|
|
5
|
+
* .sync-backup 残留、context.json.lock 残留。失败项使用 ✗,可恢复警告
|
|
6
|
+
* 使用 ! ,通过项使用 ✓。任意必须项失败 → exit 1。
|
|
7
|
+
*/
|
|
8
|
+
import { CommandResult } from './_shared.js';
|
|
9
|
+
export interface DoctorOptions {
|
|
10
|
+
cwd: string;
|
|
11
|
+
deep?: boolean;
|
|
12
|
+
json?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface DoctorCheck {
|
|
15
|
+
label: string;
|
|
16
|
+
status: 'ok' | 'warn' | 'fail';
|
|
17
|
+
detail: string;
|
|
18
|
+
required: boolean;
|
|
19
|
+
}
|
|
20
|
+
export declare function handleDoctor(options: DoctorOptions): Promise<CommandResult>;
|
|
21
|
+
//# sourceMappingURL=doctor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,EACL,aAAa,EAMd,MAAM,cAAc,CAAC;AAEtB,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;CACnB;AAID,wBAAsB,YAAY,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CA0KjF"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* specdo doctor [--deep]
|
|
3
|
+
*
|
|
4
|
+
* 检查工作区健康度:目录结构、config schema、active vs archive 冲突、
|
|
5
|
+
* .sync-backup 残留、context.json.lock 残留。失败项使用 ✗,可恢复警告
|
|
6
|
+
* 使用 ! ,通过项使用 ✓。任意必须项失败 → exit 1。
|
|
7
|
+
*/
|
|
8
|
+
import * as fs from 'node:fs';
|
|
9
|
+
import * as path from 'node:path';
|
|
10
|
+
import { loadConfig } from '../core/config-store.js';
|
|
11
|
+
import { findSpecdoConfig, getSpecdoDir, ok, safeExists, safeIsDir, } from './_shared.js';
|
|
12
|
+
const STALE_LOCK_THRESHOLD_MS = 30_000;
|
|
13
|
+
export async function handleDoctor(options) {
|
|
14
|
+
const { cwd } = options;
|
|
15
|
+
const checks = [];
|
|
16
|
+
const specdoDir = getSpecdoDir(cwd);
|
|
17
|
+
checks.push({
|
|
18
|
+
label: 'specdo directory',
|
|
19
|
+
status: safeIsDir(specdoDir) ? 'ok' : 'fail',
|
|
20
|
+
detail: safeIsDir(specdoDir) ? path.relative(cwd, specdoDir) || '.' : "Not found — run 'specdo init'",
|
|
21
|
+
required: true,
|
|
22
|
+
});
|
|
23
|
+
// config + schema
|
|
24
|
+
if (!findSpecdoConfig(cwd)) {
|
|
25
|
+
checks.push({
|
|
26
|
+
label: 'project config',
|
|
27
|
+
status: 'fail',
|
|
28
|
+
detail: "Not found — expected specdo/config.yaml or specdo/config.yml",
|
|
29
|
+
required: true,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
const { config, issues } = loadConfig(cwd);
|
|
34
|
+
if (config && issues.length === 0) {
|
|
35
|
+
checks.push({
|
|
36
|
+
label: 'project config',
|
|
37
|
+
status: 'ok',
|
|
38
|
+
detail: `domainVersion=${config.domainVersion}, overrides=${Object.keys(config.overrides ?? {}).length}`,
|
|
39
|
+
required: true,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
checks.push({
|
|
44
|
+
label: 'project config',
|
|
45
|
+
status: 'fail',
|
|
46
|
+
detail: issues.map((i) => `${i.path}: ${i.message}`).slice(0, 3).join('; ') || 'invalid',
|
|
47
|
+
required: true,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// 子目录
|
|
52
|
+
for (const sub of ['specs', 'changes', 'archive']) {
|
|
53
|
+
const dir = path.join(specdoDir, sub);
|
|
54
|
+
checks.push({
|
|
55
|
+
label: `specdo/${sub}`,
|
|
56
|
+
status: safeIsDir(dir) ? 'ok' : 'warn',
|
|
57
|
+
detail: safeIsDir(dir) ? path.relative(cwd, dir) : 'missing (will be re-created on demand)',
|
|
58
|
+
required: false,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
// active vs archive 冲突
|
|
62
|
+
const changesDir = path.join(specdoDir, 'changes');
|
|
63
|
+
const archiveDir = path.join(specdoDir, 'archive');
|
|
64
|
+
const conflicting = [];
|
|
65
|
+
if (safeIsDir(changesDir) && safeIsDir(archiveDir)) {
|
|
66
|
+
const activeNames = fs.readdirSync(changesDir).filter((n) => safeIsDir(path.join(changesDir, n)));
|
|
67
|
+
const archivedNames = new Set(fs.readdirSync(archiveDir).filter((n) => safeIsDir(path.join(archiveDir, n))));
|
|
68
|
+
for (const name of activeNames) {
|
|
69
|
+
if (archivedNames.has(name))
|
|
70
|
+
conflicting.push(name);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
checks.push({
|
|
74
|
+
label: 'active vs archive',
|
|
75
|
+
status: conflicting.length === 0 ? 'ok' : 'warn',
|
|
76
|
+
detail: conflicting.length === 0
|
|
77
|
+
? 'no overlapping change names'
|
|
78
|
+
: `${conflicting.length} overlapping name(s) detected: ${conflicting.join(', ')}. Run 'specdo archive --change <name>' to retry.`,
|
|
79
|
+
required: false,
|
|
80
|
+
});
|
|
81
|
+
// .sync-backup 残留
|
|
82
|
+
const syncBackupDir = path.join(specdoDir, '.sync-backup');
|
|
83
|
+
checks.push({
|
|
84
|
+
label: 'sync backup',
|
|
85
|
+
status: safeExists(syncBackupDir) ? 'warn' : 'ok',
|
|
86
|
+
detail: safeExists(syncBackupDir)
|
|
87
|
+
? `Leftover at ${path.relative(cwd, syncBackupDir)}/. Review and remove manually.`
|
|
88
|
+
: 'no leftover',
|
|
89
|
+
required: false,
|
|
90
|
+
});
|
|
91
|
+
// context.json.lock 残留
|
|
92
|
+
const stale = [];
|
|
93
|
+
if (safeIsDir(changesDir)) {
|
|
94
|
+
for (const name of fs.readdirSync(changesDir)) {
|
|
95
|
+
const lock = path.join(changesDir, name, 'context.json.lock');
|
|
96
|
+
if (safeExists(lock)) {
|
|
97
|
+
try {
|
|
98
|
+
const stat = fs.statSync(lock);
|
|
99
|
+
const ageMs = Date.now() - stat.mtimeMs;
|
|
100
|
+
if (ageMs > STALE_LOCK_THRESHOLD_MS) {
|
|
101
|
+
stale.push({ path: path.relative(cwd, lock), ageMs });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
/* ignore */
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
checks.push({
|
|
111
|
+
label: 'stale locks',
|
|
112
|
+
status: stale.length === 0 ? 'ok' : 'warn',
|
|
113
|
+
detail: stale.length === 0
|
|
114
|
+
? 'no stale lock files'
|
|
115
|
+
: stale
|
|
116
|
+
.map((s) => `${s.path} (age ${(s.ageMs / 1000).toFixed(0)}s)`)
|
|
117
|
+
.join('; '),
|
|
118
|
+
required: false,
|
|
119
|
+
});
|
|
120
|
+
// ─── deep checks ───
|
|
121
|
+
if (options.deep) {
|
|
122
|
+
// Node 版本(仅作信息展示)
|
|
123
|
+
checks.push({
|
|
124
|
+
label: 'Node runtime',
|
|
125
|
+
status: 'ok',
|
|
126
|
+
detail: `${process.version} (platform=${process.platform})`,
|
|
127
|
+
required: false,
|
|
128
|
+
});
|
|
129
|
+
// 检查 active changes 是否含损坏的 context.json
|
|
130
|
+
if (safeIsDir(changesDir)) {
|
|
131
|
+
let corrupted = 0;
|
|
132
|
+
for (const name of fs.readdirSync(changesDir)) {
|
|
133
|
+
const ctxPath = path.join(changesDir, name, 'context.json');
|
|
134
|
+
if (safeExists(ctxPath)) {
|
|
135
|
+
try {
|
|
136
|
+
JSON.parse(fs.readFileSync(ctxPath, 'utf-8'));
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
corrupted++;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
checks.push({
|
|
144
|
+
label: 'context.json integrity',
|
|
145
|
+
status: corrupted === 0 ? 'ok' : 'warn',
|
|
146
|
+
detail: corrupted === 0 ? `all parseable` : `${corrupted} corrupted (will fall back to .bak on next read)`,
|
|
147
|
+
required: false,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// ─── render ───
|
|
152
|
+
const requiredFailed = checks.filter((c) => c.required && c.status === 'fail');
|
|
153
|
+
if (options.json) {
|
|
154
|
+
return {
|
|
155
|
+
exitCode: requiredFailed.length === 0 ? 0 : 1,
|
|
156
|
+
stdout: [JSON.stringify({ checks, summary: requiredFailed.length === 0 ? 'ok' : 'failed' }, null, 2)],
|
|
157
|
+
stderr: [],
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
const stdout = [];
|
|
161
|
+
stdout.push('SpecDo Doctor');
|
|
162
|
+
stdout.push('');
|
|
163
|
+
for (const c of checks) {
|
|
164
|
+
const icon = c.status === 'ok' ? '✓' : c.status === 'warn' ? '!' : '✗';
|
|
165
|
+
stdout.push(` ${icon} ${c.label.padEnd(22)} ${c.detail}`);
|
|
166
|
+
}
|
|
167
|
+
stdout.push('');
|
|
168
|
+
if (requiredFailed.length > 0) {
|
|
169
|
+
stdout.push('Some required checks failed. Resolve the items above.');
|
|
170
|
+
return { exitCode: 1, stdout, stderr: [] };
|
|
171
|
+
}
|
|
172
|
+
if (checks.some((c) => c.status === 'warn')) {
|
|
173
|
+
stdout.push('Core checks passed. Optional items need attention.');
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
stdout.push('All checks passed.');
|
|
177
|
+
}
|
|
178
|
+
return ok(stdout);
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* specdo domains [list | show <name>] [--json]
|
|
3
|
+
*
|
|
4
|
+
* 默认 `domains list`。`show <name>` 展示 override 应用后的有效配置。
|
|
5
|
+
*/
|
|
6
|
+
import { CommandResult } from './_shared.js';
|
|
7
|
+
export interface DomainsOptions {
|
|
8
|
+
cwd: string;
|
|
9
|
+
subcommand?: 'list' | 'show';
|
|
10
|
+
name?: string;
|
|
11
|
+
json?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare function handleDomains(options: DomainsOptions): Promise<CommandResult>;
|
|
14
|
+
//# sourceMappingURL=domains.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domains.d.ts","sourceRoot":"","sources":["../../src/commands/domains.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EACL,aAAa,EAKd,MAAM,cAAc,CAAC;AAEtB,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CA8FnF"}
|