sillyspec 3.7.24 → 3.7.26
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/package.json +1 -1
- package/src/index.js +1 -1
- package/src/progress.js +11 -11
- package/src/run.js +79 -35
- package/src/stages/plan.js +1 -1
package/package.json
CHANGED
package/src/index.js
CHANGED
package/src/progress.js
CHANGED
|
@@ -39,7 +39,7 @@ function emptyStage() {
|
|
|
39
39
|
function makeInitialProgress(project) {
|
|
40
40
|
const stages = {};
|
|
41
41
|
for (const s of VALID_STAGES) stages[s] = emptyStage();
|
|
42
|
-
return { _version: CURRENT_VERSION, project: project || '', currentStage: '', stages, lastActive: null };
|
|
42
|
+
return { _version: CURRENT_VERSION, project: project || '', currentStage: '', currentChange: null, stages, lastActive: null };
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
// ── ProgressManager ──
|
|
@@ -133,9 +133,9 @@ export class ProgressManager {
|
|
|
133
133
|
data.currentStage = stage;
|
|
134
134
|
if (stageData.status === 'pending') {
|
|
135
135
|
stageData.status = 'in-progress';
|
|
136
|
-
stageData.startedAt = new Date().
|
|
136
|
+
stageData.startedAt = new Date().toLocaleString('zh-CN',{hour12:false});
|
|
137
137
|
}
|
|
138
|
-
data.lastActive = new Date().
|
|
138
|
+
data.lastActive = new Date().toLocaleString('zh-CN',{hour12:false});
|
|
139
139
|
|
|
140
140
|
this._backup(cwd);
|
|
141
141
|
this._write(cwd, data);
|
|
@@ -154,7 +154,7 @@ export class ProgressManager {
|
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
stageData.steps.push({ name: stepName, status: 'pending' });
|
|
157
|
-
data.lastActive = new Date().
|
|
157
|
+
data.lastActive = new Date().toLocaleString('zh-CN',{hour12:false});
|
|
158
158
|
|
|
159
159
|
this._backup(cwd);
|
|
160
160
|
this._write(cwd, data);
|
|
@@ -183,11 +183,11 @@ export class ProgressManager {
|
|
|
183
183
|
// 检查是否所有步骤都 completed
|
|
184
184
|
if (stageData.steps.length > 0 && stageData.steps.every(s => s.status === 'completed')) {
|
|
185
185
|
stageData.status = 'completed';
|
|
186
|
-
stageData.completedAt = new Date().
|
|
186
|
+
stageData.completedAt = new Date().toLocaleString('zh-CN',{hour12:false});
|
|
187
187
|
console.log(`✅ 阶段 ${stage} 所有步骤已完成,阶段已标记为 completed`);
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
-
data.lastActive = new Date().
|
|
190
|
+
data.lastActive = new Date().toLocaleString('zh-CN',{hour12:false});
|
|
191
191
|
this._backup(cwd);
|
|
192
192
|
this._write(cwd, data);
|
|
193
193
|
console.log(`✅ 步骤已更新: ${stage}/${stepName} → ${status || step.status}`);
|
|
@@ -205,7 +205,7 @@ export class ProgressManager {
|
|
|
205
205
|
if (!data.stages[stage]) data.stages[stage] = emptyStage();
|
|
206
206
|
const stageData = data.stages[stage];
|
|
207
207
|
stageData.status = 'completed';
|
|
208
|
-
stageData.completedAt = new Date().
|
|
208
|
+
stageData.completedAt = new Date().toLocaleString('zh-CN',{hour12:false});
|
|
209
209
|
|
|
210
210
|
// 标记所有未完成步骤为 completed
|
|
211
211
|
for (const step of stageData.steps) {
|
|
@@ -228,7 +228,7 @@ export class ProgressManager {
|
|
|
228
228
|
if (!data.stages[nextStage]) data.stages[nextStage] = emptyStage();
|
|
229
229
|
if (data.stages[nextStage].status === 'pending') {
|
|
230
230
|
data.stages[nextStage].status = 'in-progress';
|
|
231
|
-
data.stages[nextStage].startedAt = new Date().
|
|
231
|
+
data.stages[nextStage].startedAt = new Date().toLocaleString('zh-CN',{hour12:false});
|
|
232
232
|
}
|
|
233
233
|
console.log(`✅ 阶段 ${stage} 已完成,推进到: ${STAGE_LABELS[nextStage] || nextStage}`);
|
|
234
234
|
} else {
|
|
@@ -236,12 +236,12 @@ export class ProgressManager {
|
|
|
236
236
|
console.log(`✅ 阶段 ${stage} 已完成(已是最后阶段)`);
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
-
data.lastActive = new Date().
|
|
239
|
+
data.lastActive = new Date().toLocaleString('zh-CN',{hour12:false});
|
|
240
240
|
|
|
241
241
|
// 归档到 history/
|
|
242
242
|
const historyDir = this._path(cwd, 'history');
|
|
243
243
|
mkdirSync(historyDir, { recursive: true });
|
|
244
|
-
const ts = new Date().
|
|
244
|
+
const ts = new Date().toLocaleString('zh-CN',{hour12:false}).replace(/[:.]/g, '-');
|
|
245
245
|
writeFileSync(join(historyDir, `${stage}-${ts}.json`), JSON.stringify({ stage, data: stageData, completedAt: stageData.completedAt }, null, 2) + '\n');
|
|
246
246
|
|
|
247
247
|
this._backup(cwd);
|
|
@@ -336,7 +336,7 @@ export class ProgressManager {
|
|
|
336
336
|
if (!data) { console.log('❌ 无法读取 progress.json'); return; }
|
|
337
337
|
if (!data.stages[stage]) { console.log(`❌ 未知阶段: ${stage}`); return; }
|
|
338
338
|
data.stages[stage] = emptyStage();
|
|
339
|
-
data.lastActive = new Date().
|
|
339
|
+
data.lastActive = new Date().toLocaleString('zh-CN',{hour12:false});
|
|
340
340
|
this._write(cwd, data);
|
|
341
341
|
console.log(`✅ 已重置阶段: ${stage}`);
|
|
342
342
|
} else {
|
package/src/run.js
CHANGED
|
@@ -12,13 +12,40 @@ import { buildExecuteSteps } from './stages/execute.js'
|
|
|
12
12
|
/**
|
|
13
13
|
* 获取阶段的步骤定义(execute 需要动态构建)
|
|
14
14
|
*/
|
|
15
|
-
function getStageSteps(stageName, cwd) {
|
|
15
|
+
async function getStageSteps(stageName, cwd, progress) {
|
|
16
16
|
if (stageName === 'execute') {
|
|
17
|
-
const
|
|
17
|
+
const changesDir = join(cwd, '.sillyspec', 'changes')
|
|
18
18
|
let planFile = null
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
// 优先用 currentChange 指定的变更名
|
|
20
|
+
if (progress.currentChange) {
|
|
21
|
+
const target = join(changesDir, progress.currentChange, 'plan.md')
|
|
22
|
+
if (existsSync(target)) planFile = target
|
|
23
|
+
}
|
|
24
|
+
// fallback:扫描 changes/ 非 archive 目录下的 plan.md
|
|
25
|
+
if (!planFile && existsSync(changesDir)) {
|
|
26
|
+
const candidates = []
|
|
27
|
+
for (const entry of readdirSync(changesDir, { withFileTypes: true })) {
|
|
28
|
+
if (!entry.isDirectory() || entry.name === 'archive') continue
|
|
29
|
+
const p = join(changesDir, entry.name, 'plan.md')
|
|
30
|
+
if (existsSync(p)) candidates.push({ name: entry.name, path: p })
|
|
31
|
+
}
|
|
32
|
+
if (candidates.length === 1) {
|
|
33
|
+
planFile = candidates[0].path
|
|
34
|
+
} else if (candidates.length > 1) {
|
|
35
|
+
console.log('⚠️ 检测到多个变更,请选择:')
|
|
36
|
+
candidates.forEach((c, i) => console.log(` ${i + 1}. ${c.name}`))
|
|
37
|
+
const readline = await import('readline')
|
|
38
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
|
|
39
|
+
const answer = await new Promise(resolve => {
|
|
40
|
+
rl.question(`\n请输入编号(默认 1):`, input => {
|
|
41
|
+
rl.close()
|
|
42
|
+
const num = parseInt(input) || 1
|
|
43
|
+
resolve(num >= 1 && num <= candidates.length ? num - 1 : 0)
|
|
44
|
+
})
|
|
45
|
+
})
|
|
46
|
+
planFile = candidates[answer].path
|
|
47
|
+
console.log(`✅ 已选择:${candidates[answer].name}\n`)
|
|
48
|
+
}
|
|
22
49
|
}
|
|
23
50
|
return buildExecuteSteps(planFile)
|
|
24
51
|
}
|
|
@@ -29,16 +56,16 @@ function getStageSteps(stageName, cwd) {
|
|
|
29
56
|
/**
|
|
30
57
|
* 确保阶段的 steps 已初始化到 progress.json
|
|
31
58
|
*/
|
|
32
|
-
function ensureStageSteps(progress, stageName, cwd) {
|
|
59
|
+
async function ensureStageSteps(progress, stageName, cwd) {
|
|
33
60
|
if (!progress.stages) progress.stages = {}
|
|
34
61
|
|
|
35
|
-
const steps = getStageSteps(stageName, cwd)
|
|
62
|
+
const steps = await getStageSteps(stageName, cwd, progress)
|
|
36
63
|
if (!steps) return false
|
|
37
64
|
|
|
38
65
|
if (!progress.stages[stageName] || !progress.stages[stageName].steps || progress.stages[stageName].steps.length === 0) {
|
|
39
66
|
progress.stages[stageName] = {
|
|
40
67
|
status: 'in-progress',
|
|
41
|
-
startedAt: new Date().
|
|
68
|
+
startedAt: new Date().toLocaleString('zh-CN',{hour12:false}),
|
|
42
69
|
completedAt: null,
|
|
43
70
|
steps: steps.map(s => ({ name: s.name, status: 'pending' }))
|
|
44
71
|
}
|
|
@@ -78,9 +105,10 @@ function outputStep(stageName, stepIndex, steps, cwd) {
|
|
|
78
105
|
console.log(step.prompt)
|
|
79
106
|
console.log(`\n### ⚠️ 铁律`)
|
|
80
107
|
console.log('- 只做本步骤描述的操作,不得自行扩展或跳过')
|
|
81
|
-
|
|
108
|
+
console.log('- 不要回头修改已完成的步骤')
|
|
82
109
|
console.log('- 完成后立即执行 --done 命令,不得跳过')
|
|
83
110
|
console.log('- 生成的文件头部必须包含 author(git 用户名)和 created_at(精确到秒)')
|
|
111
|
+
console.log('- 执行构建/测试前必须先读 local.yaml,优先使用其中配置的命令、路径和环境变量;未配置时才使用默认值')
|
|
84
112
|
console.log(`\n### 完成后执行`)
|
|
85
113
|
console.log(`sillyspec run ${stageName} --done --output "你的摘要"`)
|
|
86
114
|
}
|
|
@@ -88,7 +116,7 @@ function outputStep(stageName, stepIndex, steps, cwd) {
|
|
|
88
116
|
/**
|
|
89
117
|
* sillyspec run <stage> 主命令
|
|
90
118
|
*/
|
|
91
|
-
export function runCommand(args, cwd) {
|
|
119
|
+
export async function runCommand(args, cwd) {
|
|
92
120
|
// 解析参数
|
|
93
121
|
const stageName = args[0]
|
|
94
122
|
const flags = args.slice(1)
|
|
@@ -111,6 +139,13 @@ export function runCommand(args, cwd) {
|
|
|
111
139
|
outputText = flags[outputIdx + 1]
|
|
112
140
|
}
|
|
113
141
|
|
|
142
|
+
// 解析 --change <name>
|
|
143
|
+
let changeName = null
|
|
144
|
+
const changeIdx = flags.indexOf('--change')
|
|
145
|
+
if (changeIdx !== -1 && flags[changeIdx + 1]) {
|
|
146
|
+
changeName = flags[changeIdx + 1]
|
|
147
|
+
}
|
|
148
|
+
|
|
114
149
|
const isAuxiliary = auxiliaryStages.includes(stageName)
|
|
115
150
|
|
|
116
151
|
const pm = new ProgressManager()
|
|
@@ -125,13 +160,22 @@ export function runCommand(args, cwd) {
|
|
|
125
160
|
progress = pm.init(cwd)
|
|
126
161
|
}
|
|
127
162
|
|
|
163
|
+
// --change 设置当前变更名
|
|
164
|
+
if (changeName) {
|
|
165
|
+
progress.currentChange = changeName
|
|
166
|
+
progress.lastActive = new Date().toLocaleString('zh-CN', { hour12: false })
|
|
167
|
+
pm._write(cwd, progress)
|
|
168
|
+
console.log(`✅ 当前变更设置为:${changeName}`)
|
|
169
|
+
return
|
|
170
|
+
}
|
|
171
|
+
|
|
128
172
|
// --reset
|
|
129
173
|
if (isReset) {
|
|
130
|
-
return resetStage(pm, progress, stageName, cwd)
|
|
174
|
+
return await resetStage(pm, progress, stageName, cwd)
|
|
131
175
|
}
|
|
132
176
|
|
|
133
177
|
// 确保步骤已初始化
|
|
134
|
-
const changed = ensureStageSteps(progress, stageName, cwd)
|
|
178
|
+
const changed = await ensureStageSteps(progress, stageName, cwd)
|
|
135
179
|
if (changed) {
|
|
136
180
|
pm._write(cwd, progress)
|
|
137
181
|
progress = pm.read(cwd)
|
|
@@ -144,19 +188,19 @@ export function runCommand(args, cwd) {
|
|
|
144
188
|
|
|
145
189
|
// --skip
|
|
146
190
|
if (isSkip) {
|
|
147
|
-
return skipStep(pm, progress, stageName, cwd)
|
|
191
|
+
return await skipStep(pm, progress, stageName, cwd)
|
|
148
192
|
}
|
|
149
193
|
|
|
150
194
|
// --done
|
|
151
195
|
if (isDone) {
|
|
152
|
-
return completeStep(pm, progress, stageName, cwd, outputText)
|
|
196
|
+
return await completeStep(pm, progress, stageName, cwd, outputText)
|
|
153
197
|
}
|
|
154
198
|
|
|
155
199
|
// 默认:输出当前步骤
|
|
156
|
-
return runStage(pm, progress, stageName, cwd)
|
|
200
|
+
return await runStage(pm, progress, stageName, cwd)
|
|
157
201
|
}
|
|
158
202
|
|
|
159
|
-
function runStage(pm, progress, stageName, cwd) {
|
|
203
|
+
async function runStage(pm, progress, stageName, cwd) {
|
|
160
204
|
const stageData = progress.stages[stageName]
|
|
161
205
|
if (!stageData || !stageData.steps) {
|
|
162
206
|
console.error(`❌ 阶段 ${stageName} 未初始化`)
|
|
@@ -177,7 +221,7 @@ function runStage(pm, progress, stageName, cwd) {
|
|
|
177
221
|
}
|
|
178
222
|
|
|
179
223
|
const stageDef = stageRegistry[stageName]
|
|
180
|
-
const defSteps = getStageSteps(stageName, cwd)
|
|
224
|
+
const defSteps = await getStageSteps(stageName, cwd, progress)
|
|
181
225
|
if (defSteps && defSteps[currentIdx]) {
|
|
182
226
|
outputStep(stageName, currentIdx, defSteps, cwd)
|
|
183
227
|
}
|
|
@@ -215,7 +259,7 @@ function validateMetadata(cwd, stageName) {
|
|
|
215
259
|
}
|
|
216
260
|
}
|
|
217
261
|
|
|
218
|
-
function completeStep(pm, progress, stageName, cwd, outputText) {
|
|
262
|
+
async function completeStep(pm, progress, stageName, cwd, outputText) {
|
|
219
263
|
const stageData = progress.stages[stageName]
|
|
220
264
|
if (!stageData || !stageData.steps) {
|
|
221
265
|
console.error(`❌ 阶段 ${stageName} 未初始化`)
|
|
@@ -232,7 +276,7 @@ function completeStep(pm, progress, stageName, cwd, outputText) {
|
|
|
232
276
|
|
|
233
277
|
// 标记完成
|
|
234
278
|
steps[currentIdx].status = 'completed'
|
|
235
|
-
steps[currentIdx].completedAt = new Date().
|
|
279
|
+
steps[currentIdx].completedAt = new Date().toLocaleString('zh-CN',{hour12:false})
|
|
236
280
|
if (outputText) {
|
|
237
281
|
const MAX_OUTPUT = 200
|
|
238
282
|
if (outputText.length > MAX_OUTPUT) {
|
|
@@ -240,7 +284,7 @@ function completeStep(pm, progress, stageName, cwd, outputText) {
|
|
|
240
284
|
// Save full output to artifacts/
|
|
241
285
|
const artifactsDir = join(cwd, '.sillyspec', '.runtime', 'artifacts')
|
|
242
286
|
mkdirSync(artifactsDir, { recursive: true })
|
|
243
|
-
const ts = new Date().
|
|
287
|
+
const ts = new Date().toLocaleString('zh-CN',{hour12:false}).replace(/[:.]/g, '-')
|
|
244
288
|
writeFileSync(join(artifactsDir, `${stageName}-step${currentIdx + 1}-${ts}.txt`), outputText)
|
|
245
289
|
} else {
|
|
246
290
|
steps[currentIdx].output = outputText
|
|
@@ -253,7 +297,7 @@ function completeStep(pm, progress, stageName, cwd, outputText) {
|
|
|
253
297
|
if (nextPendingIdx === -1) {
|
|
254
298
|
// 全部完成
|
|
255
299
|
stageData.status = 'completed'
|
|
256
|
-
stageData.completedAt = new Date().
|
|
300
|
+
stageData.completedAt = new Date().toLocaleString('zh-CN',{hour12:false})
|
|
257
301
|
|
|
258
302
|
const next = getNextStage(stageName)
|
|
259
303
|
if (next) {
|
|
@@ -261,17 +305,17 @@ function completeStep(pm, progress, stageName, cwd, outputText) {
|
|
|
261
305
|
if (!progress.stages[next]) progress.stages[next] = { status: 'pending', steps: [], startedAt: null, completedAt: null }
|
|
262
306
|
if (progress.stages[next].status === 'pending' || !progress.stages[next].status) {
|
|
263
307
|
progress.stages[next].status = 'in-progress'
|
|
264
|
-
progress.stages[next].startedAt = new Date().
|
|
308
|
+
progress.stages[next].startedAt = new Date().toLocaleString('zh-CN',{hour12:false})
|
|
265
309
|
}
|
|
266
310
|
}
|
|
267
311
|
|
|
268
|
-
progress.lastActive = new Date().
|
|
312
|
+
progress.lastActive = new Date().toLocaleString('zh-CN',{hour12:false})
|
|
269
313
|
pm._write(cwd, progress)
|
|
270
314
|
|
|
271
315
|
// Append to user-inputs.md
|
|
272
316
|
if (outputText) {
|
|
273
317
|
const inputsPath = join(cwd, '.sillyspec', '.runtime', 'user-inputs.md')
|
|
274
|
-
const entry = `\n## ${new Date().
|
|
318
|
+
const entry = `\n## ${new Date().toLocaleString('zh-CN',{hour12:false})} | ${stageName}: ${steps[currentIdx].name}\n- 输出:${outputText}\n`
|
|
275
319
|
appendFileSync(inputsPath, entry)
|
|
276
320
|
}
|
|
277
321
|
|
|
@@ -287,22 +331,22 @@ function completeStep(pm, progress, stageName, cwd, outputText) {
|
|
|
287
331
|
return
|
|
288
332
|
}
|
|
289
333
|
|
|
290
|
-
progress.lastActive = new Date().
|
|
334
|
+
progress.lastActive = new Date().toLocaleString('zh-CN',{hour12:false})
|
|
291
335
|
pm._write(cwd, progress)
|
|
292
336
|
|
|
293
337
|
// Append to user-inputs.md
|
|
294
338
|
if (outputText) {
|
|
295
339
|
const inputsPath = join(cwd, '.sillyspec', '.runtime', 'user-inputs.md')
|
|
296
|
-
const entry = `\n## ${new Date().
|
|
340
|
+
const entry = `\n## ${new Date().toLocaleString('zh-CN',{hour12:false})} | ${stageName}: ${steps[currentIdx].name}\n- 输出:${outputText}\n`
|
|
297
341
|
appendFileSync(inputsPath, entry)
|
|
298
342
|
}
|
|
299
343
|
|
|
300
|
-
const defSteps = getStageSteps(stageName, cwd)
|
|
344
|
+
const defSteps = await getStageSteps(stageName, cwd, progress)
|
|
301
345
|
console.log(`✅ Step ${currentIdx + 1}/${steps.length} 完成:${steps[currentIdx].name}\n`)
|
|
302
346
|
outputStep(stageName, nextPendingIdx, defSteps, cwd)
|
|
303
347
|
}
|
|
304
348
|
|
|
305
|
-
function skipStep(pm, progress, stageName, cwd) {
|
|
349
|
+
async function skipStep(pm, progress, stageName, cwd) {
|
|
306
350
|
const stageData = progress.stages[stageName]
|
|
307
351
|
if (!stageData || !stageData.steps) {
|
|
308
352
|
console.error(`❌ 阶段 ${stageName} 未初始化`)
|
|
@@ -317,7 +361,7 @@ function skipStep(pm, progress, stageName, cwd) {
|
|
|
317
361
|
process.exit(1)
|
|
318
362
|
}
|
|
319
363
|
|
|
320
|
-
const defSteps = getStageSteps(stageName, cwd)
|
|
364
|
+
const defSteps = await getStageSteps(stageName, cwd, progress)
|
|
321
365
|
const stepDef = defSteps ? defSteps[currentIdx] : null
|
|
322
366
|
if (stepDef && !stepDef.optional) {
|
|
323
367
|
console.error(`❌ 步骤 "${steps[currentIdx].name}" 不可跳过`)
|
|
@@ -325,8 +369,8 @@ function skipStep(pm, progress, stageName, cwd) {
|
|
|
325
369
|
}
|
|
326
370
|
|
|
327
371
|
steps[currentIdx].status = 'skipped'
|
|
328
|
-
steps[currentIdx].skippedAt = new Date().
|
|
329
|
-
progress.lastActive = new Date().
|
|
372
|
+
steps[currentIdx].skippedAt = new Date().toLocaleString('zh-CN',{hour12:false})
|
|
373
|
+
progress.lastActive = new Date().toLocaleString('zh-CN',{hour12:false})
|
|
330
374
|
pm._write(cwd, progress)
|
|
331
375
|
|
|
332
376
|
console.log(`⏭️ Step ${currentIdx + 1}/${steps.length} 已跳过:${steps[currentIdx].name}`)
|
|
@@ -365,15 +409,15 @@ function showStatus(progress, stageName) {
|
|
|
365
409
|
})
|
|
366
410
|
}
|
|
367
411
|
|
|
368
|
-
function resetStage(pm, progress, stageName, cwd) {
|
|
369
|
-
const defSteps = getStageSteps(stageName, cwd)
|
|
412
|
+
async function resetStage(pm, progress, stageName, cwd) {
|
|
413
|
+
const defSteps = await getStageSteps(stageName, cwd, progress)
|
|
370
414
|
progress.stages[stageName] = {
|
|
371
415
|
status: 'in-progress',
|
|
372
|
-
startedAt: new Date().
|
|
416
|
+
startedAt: new Date().toLocaleString('zh-CN',{hour12:false}),
|
|
373
417
|
completedAt: null,
|
|
374
418
|
steps: defSteps ? defSteps.map(s => ({ name: s.name, status: 'pending' })) : []
|
|
375
419
|
}
|
|
376
|
-
progress.lastActive = new Date().
|
|
420
|
+
progress.lastActive = new Date().toLocaleString('zh-CN',{hour12:false})
|
|
377
421
|
pm._write(cwd, progress)
|
|
378
422
|
console.log(`🔄 ${stageName} 阶段已重置`)
|
|
379
423
|
}
|