@fitlab-ai/agent-infra 0.7.1 → 0.7.3
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 +7 -1
- package/README.zh-CN.md +9 -3
- package/bin/cli.ts +11 -0
- package/dist/bin/cli.js +12 -0
- package/dist/lib/defaults.json +0 -1
- package/dist/lib/init.js +0 -3
- package/dist/lib/sandbox/commands/create.js +10 -2
- package/dist/lib/sandbox/commands/enter.js +17 -18
- package/dist/lib/sandbox/commands/list-running.js +56 -32
- package/dist/lib/sandbox/commands/ls.js +27 -24
- package/dist/lib/sandbox/commands/start.js +36 -0
- package/dist/lib/sandbox/index.js +15 -3
- package/dist/lib/sandbox/task-resolver.js +1 -1
- package/dist/lib/sandbox/tools.js +1 -1
- package/dist/lib/table.js +38 -0
- package/dist/lib/task/commands/ls.js +122 -0
- package/dist/lib/task/commands/show.js +135 -0
- package/dist/lib/task/frontmatter.js +32 -0
- package/dist/lib/task/index.js +41 -0
- package/dist/lib/task/short-id.js +90 -0
- package/dist/lib/update.js +25 -8
- package/lib/defaults.json +0 -1
- package/lib/init.ts +0 -10
- package/lib/sandbox/commands/create.ts +11 -2
- package/lib/sandbox/commands/enter.ts +40 -20
- package/lib/sandbox/commands/list-running.ts +65 -37
- package/lib/sandbox/commands/ls.ts +35 -27
- package/lib/sandbox/commands/start.ts +61 -0
- package/lib/sandbox/index.ts +15 -3
- package/lib/sandbox/task-resolver.ts +1 -1
- package/lib/sandbox/tools.ts +1 -1
- package/lib/table.ts +44 -0
- package/lib/task/commands/ls.ts +138 -0
- package/lib/task/commands/show.ts +139 -0
- package/lib/task/frontmatter.ts +30 -0
- package/lib/task/index.ts +44 -0
- package/lib/task/short-id.ts +107 -0
- package/lib/update.ts +28 -10
- package/package.json +1 -1
- package/templates/.agents/hooks/auto-resume.sh +104 -0
- package/templates/.agents/rules/create-issue.github.en.md +1 -1
- package/templates/.agents/rules/create-issue.github.zh-CN.md +1 -1
- package/templates/.agents/rules/milestone-inference.github.en.md +4 -1
- package/templates/.agents/rules/milestone-inference.github.zh-CN.md +4 -1
- package/templates/.agents/rules/next-step-output.en.md +62 -0
- package/templates/.agents/rules/next-step-output.zh-CN.md +62 -0
- package/templates/.agents/rules/pr-checks-commands.en.md +5 -0
- package/templates/.agents/rules/pr-checks-commands.github.en.md +62 -0
- package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +62 -0
- package/templates/.agents/rules/pr-checks-commands.zh-CN.md +5 -0
- package/templates/.agents/rules/pr-sync.github.en.md +7 -0
- package/templates/.agents/rules/pr-sync.github.zh-CN.md +7 -0
- package/templates/.agents/rules/task-short-id.en.md +54 -62
- package/templates/.agents/rules/task-short-id.zh-CN.md +35 -54
- package/templates/.agents/scripts/platform-adapters/platform-sync.github.js +17 -0
- package/templates/.agents/scripts/task-short-id.js +32 -189
- package/templates/.agents/skills/analyze-task/SKILL.en.md +10 -12
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +10 -12
- package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -1
- package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/block-task/SKILL.en.md +13 -6
- package/templates/.agents/skills/block-task/SKILL.zh-CN.md +13 -6
- package/templates/.agents/skills/block-task/config/verify.json +1 -1
- package/templates/.agents/skills/cancel-task/SKILL.en.md +13 -6
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +13 -6
- package/templates/.agents/skills/cancel-task/config/verify.json +1 -1
- package/templates/.agents/skills/check-task/SKILL.en.md +12 -10
- package/templates/.agents/skills/check-task/SKILL.zh-CN.md +12 -10
- package/templates/.agents/skills/close-codescan/SKILL.en.md +13 -6
- package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +13 -6
- package/templates/.agents/skills/close-dependabot/SKILL.en.md +13 -6
- package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +13 -6
- package/templates/.agents/skills/code-task/SKILL.en.md +10 -6
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +11 -6
- package/templates/.agents/skills/code-task/config/verify.en.json +2 -1
- package/templates/.agents/skills/code-task/config/verify.zh-CN.json +2 -1
- package/templates/.agents/skills/code-task/reference/fix-mode.en.md +10 -5
- package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +10 -5
- package/templates/.agents/skills/code-task/reference/output-template.en.md +3 -3
- package/templates/.agents/skills/code-task/reference/output-template.zh-CN.md +3 -3
- package/templates/.agents/skills/code-task/reference/report-template.en.md +8 -0
- package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +8 -0
- package/templates/.agents/skills/commit/SKILL.en.md +3 -4
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +3 -4
- package/templates/.agents/skills/commit/reference/task-status-update.en.md +37 -29
- package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +37 -29
- package/templates/.agents/skills/complete-task/SKILL.en.md +41 -4
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +41 -4
- package/templates/.agents/skills/complete-task/config/verify.en.json +1 -1
- package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/create-pr/SKILL.en.md +20 -11
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +20 -11
- package/templates/.agents/skills/create-pr/config/verify.json +2 -1
- package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +2 -1
- package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +2 -1
- package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +3 -3
- package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +3 -3
- package/templates/.agents/skills/create-task/SKILL.en.md +17 -17
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +17 -17
- package/templates/.agents/skills/create-task/config/verify.json +1 -1
- package/templates/.agents/skills/import-codescan/SKILL.en.md +8 -8
- package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +8 -8
- package/templates/.agents/skills/import-codescan/config/verify.json +1 -1
- package/templates/.agents/skills/import-dependabot/SKILL.en.md +8 -8
- package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +8 -8
- package/templates/.agents/skills/import-dependabot/config/verify.json +1 -1
- package/templates/.agents/skills/import-issue/SKILL.en.md +7 -7
- package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +7 -7
- package/templates/.agents/skills/plan-task/SKILL.en.md +10 -12
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +10 -12
- package/templates/.agents/skills/plan-task/config/verify.en.json +1 -1
- package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/restore-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/review-analysis/SKILL.en.md +4 -2
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +4 -2
- package/templates/.agents/skills/review-analysis/config/verify.en.json +3 -2
- package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +3 -2
- package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +15 -15
- package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +15 -15
- package/templates/.agents/skills/review-analysis/reference/report-template.en.md +7 -1
- package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +7 -1
- package/templates/.agents/skills/review-analysis/reference/review-criteria.en.md +2 -0
- package/templates/.agents/skills/review-analysis/reference/review-criteria.zh-CN.md +2 -0
- package/templates/.agents/skills/review-code/SKILL.en.md +5 -2
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +5 -2
- package/templates/.agents/skills/review-code/config/verify.en.json +3 -2
- package/templates/.agents/skills/review-code/config/verify.zh-CN.json +3 -2
- package/templates/.agents/skills/review-code/reference/output-templates.en.md +9 -9
- package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +9 -9
- package/templates/.agents/skills/review-code/reference/report-template.en.md +7 -1
- package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +7 -1
- package/templates/.agents/skills/review-code/reference/review-criteria.en.md +2 -0
- package/templates/.agents/skills/review-code/reference/review-criteria.zh-CN.md +2 -0
- package/templates/.agents/skills/review-plan/SKILL.en.md +4 -2
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +4 -2
- package/templates/.agents/skills/review-plan/config/verify.en.json +3 -2
- package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +3 -2
- package/templates/.agents/skills/review-plan/reference/output-templates.en.md +15 -15
- package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +15 -15
- package/templates/.agents/skills/review-plan/reference/report-template.en.md +7 -1
- package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +7 -1
- package/templates/.agents/skills/review-plan/reference/review-criteria.en.md +2 -0
- package/templates/.agents/skills/review-plan/reference/review-criteria.zh-CN.md +2 -0
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +0 -1
- package/templates/.agents/skills/watch-pr/SKILL.en.md +131 -0
- package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +131 -0
- package/templates/.agents/skills/watch-pr/config/verify.json +22 -0
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +43 -0
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +43 -0
- package/templates/.agents/templates/task.en.md +1 -1
- package/templates/.agents/templates/task.zh-CN.md +1 -1
- package/templates/.agents/workflows/bug-fix.en.yaml +7 -5
- package/templates/.agents/workflows/bug-fix.zh-CN.yaml +6 -5
- package/templates/.agents/workflows/feature-development.en.yaml +7 -5
- package/templates/.agents/workflows/feature-development.zh-CN.yaml +6 -5
- package/templates/.agents/workflows/refactoring.en.yaml +7 -5
- package/templates/.agents/workflows/refactoring.zh-CN.yaml +6 -5
- package/templates/.claude/commands/watch-pr.en.md +8 -0
- package/templates/.claude/commands/watch-pr.zh-CN.md +8 -0
- package/templates/.claude/settings.json +11 -0
- package/templates/.gemini/commands/_project_/watch-pr.en.toml +8 -0
- package/templates/.gemini/commands/_project_/watch-pr.zh-CN.toml +8 -0
- package/templates/.opencode/commands/watch-pr.en.md +11 -0
- package/templates/.opencode/commands/watch-pr.zh-CN.md +11 -0
|
@@ -32,11 +32,11 @@ function usage() {
|
|
|
32
32
|
"Usage: task-short-id.js <subcommand> [args]",
|
|
33
33
|
"",
|
|
34
34
|
"Subcommands:",
|
|
35
|
-
" alloc <task-id> Allocate short id for a task
|
|
35
|
+
" alloc <task-id> Allocate short id for a task in the registry",
|
|
36
36
|
" release <task-id> Release short id (idempotent; exit 0 if not present)",
|
|
37
37
|
" resolve <#N> Resolve short id to full task id",
|
|
38
38
|
" list Print registry JSON",
|
|
39
|
-
" list --verify Read-only check; exit 1 if active dir / registry
|
|
39
|
+
" list --verify Read-only check; exit 1 if active dir / registry disagree",
|
|
40
40
|
"",
|
|
41
41
|
"Options:",
|
|
42
42
|
" --active-dir <path> Override active dir (default: <repo>/.agents/workspace/active)",
|
|
@@ -161,17 +161,6 @@ function withRegistryLock(activeDir, fn, timeoutMs = DEFAULT_LOCK_TIMEOUT_MS) {
|
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
function writeTaskMdShortId(taskMdPath, shortId) {
|
|
165
|
-
const content = fs.readFileSync(taskMdPath, "utf8");
|
|
166
|
-
let updated;
|
|
167
|
-
if (/^short_id:.*$/m.test(content)) {
|
|
168
|
-
updated = content.replace(/^short_id:.*$/m, `short_id: ${shortId}`);
|
|
169
|
-
} else {
|
|
170
|
-
updated = content.replace(/^(id:.*)$/m, `$1\nshort_id: ${shortId}`);
|
|
171
|
-
}
|
|
172
|
-
fs.writeFileSync(taskMdPath, updated);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
164
|
function padShortId(n, shortIdLength) {
|
|
176
165
|
return String(n).padStart(shortIdLength, "0");
|
|
177
166
|
}
|
|
@@ -185,24 +174,34 @@ function allocateMinFreeInt(registry, shortIdLength) {
|
|
|
185
174
|
}
|
|
186
175
|
|
|
187
176
|
function parseShortIdArg(arg, shortIdLength) {
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
177
|
+
const L = shortIdLength;
|
|
178
|
+
const max = Math.pow(10, L) - 1;
|
|
179
|
+
// Accept bare numeric or '#'-prefixed; canonicalize to zero-padded key.
|
|
180
|
+
// Bare numeric is the recommended form (no shell quoting needed).
|
|
181
|
+
const m = /^#?(\d+)$/.exec(arg);
|
|
182
|
+
if (!m) {
|
|
192
183
|
writeStderr(
|
|
193
184
|
`Error: invalid short id format '${arg}', ` +
|
|
194
|
-
`expected
|
|
185
|
+
`expected bare digits (recommended) or '#'-prefixed digits; ` +
|
|
186
|
+
`e.g. '11' or '#11' (shortIdLength=${L}, max=${max})\n`
|
|
187
|
+
);
|
|
188
|
+
process.exit(1);
|
|
189
|
+
}
|
|
190
|
+
const n = Number(m[1]);
|
|
191
|
+
if (n === 0) {
|
|
192
|
+
writeStderr(
|
|
193
|
+
`Error: short id '${arg}' is invalid (#${"0".repeat(L)} is reserved)\n`
|
|
195
194
|
);
|
|
196
195
|
process.exit(1);
|
|
197
196
|
}
|
|
198
|
-
|
|
199
|
-
if (Number(key) === 0) {
|
|
197
|
+
if (n > max) {
|
|
200
198
|
writeStderr(
|
|
201
|
-
`Error: short id
|
|
199
|
+
`Error: short id ${n} exceeds shortIdLength=${L} capacity (max=${max}); ` +
|
|
200
|
+
`archive tasks or raise task.shortIdLength in .agents/.airc.json\n`
|
|
202
201
|
);
|
|
203
202
|
process.exit(1);
|
|
204
203
|
}
|
|
205
|
-
return
|
|
204
|
+
return String(n).padStart(L, "0");
|
|
206
205
|
}
|
|
207
206
|
|
|
208
207
|
function planTransaction(registry, activeDir, shortIdLength) {
|
|
@@ -216,7 +215,7 @@ function planTransaction(registry, activeDir, shortIdLength) {
|
|
|
216
215
|
.filter((d) => fs.existsSync(path.join(activeDir, d, "task.md")))
|
|
217
216
|
);
|
|
218
217
|
|
|
219
|
-
// A2: stale entries
|
|
218
|
+
// A2: stale entries (registry points at a task no longer active)
|
|
220
219
|
const pendingRegistryDeletes = [];
|
|
221
220
|
for (const [key, taskId] of Object.entries(registry.ids)) {
|
|
222
221
|
if (!activeTaskIds.has(taskId)) pendingRegistryDeletes.push(key);
|
|
@@ -238,106 +237,17 @@ function planTransaction(registry, activeDir, shortIdLength) {
|
|
|
238
237
|
taskIdToKey.set(taskId, key);
|
|
239
238
|
}
|
|
240
239
|
|
|
241
|
-
//
|
|
240
|
+
// The registry is the sole source of truth: short ids are allocated only by
|
|
241
|
+
// explicit `alloc` (planAlloc), never inferred from task.md or auto-allocated
|
|
242
|
+
// for active tasks. Read paths (resolve/list) only run stale cleanup (A2).
|
|
242
243
|
const plannedRegistryWrites = [];
|
|
243
|
-
const plannedTaskMdWrites = [];
|
|
244
|
-
const pendingAlloc = [];
|
|
245
|
-
|
|
246
|
-
for (const taskId of activeTaskIds) {
|
|
247
|
-
const taskMdPath = path.join(activeDir, taskId, "task.md");
|
|
248
|
-
const originalStat = fs.statSync(taskMdPath);
|
|
249
|
-
const originalContent = fs.readFileSync(taskMdPath, "utf8");
|
|
250
|
-
const existing = originalContent.match(/^short_id:\s*(#\d+)\s*$/m);
|
|
251
|
-
|
|
252
|
-
if (existing) {
|
|
253
|
-
const declared = existing[1];
|
|
254
|
-
const n = declared.slice(1);
|
|
255
|
-
if (projectedIds[n] === taskId) continue; // 4a
|
|
256
|
-
if (taskIdToKey.has(taskId)) {
|
|
257
|
-
const registryKey = taskIdToKey.get(taskId);
|
|
258
|
-
writeStderr(
|
|
259
|
-
`Inconsistent: task ${taskId} declares ${declared} but registry holds it at #${registryKey}\n`
|
|
260
|
-
);
|
|
261
|
-
process.exit(2);
|
|
262
|
-
}
|
|
263
|
-
if (projectedIds[n] && projectedIds[n] !== taskId) {
|
|
264
|
-
writeStderr(
|
|
265
|
-
`Inconsistent: task ${taskId} declares ${declared} but registry maps ${declared} to ${projectedIds[n]}\n`
|
|
266
|
-
);
|
|
267
|
-
process.exit(2);
|
|
268
|
-
}
|
|
269
|
-
// 4d
|
|
270
|
-
plannedRegistryWrites.push({ key: n, taskId });
|
|
271
|
-
projectedIds[n] = taskId;
|
|
272
|
-
taskIdToKey.set(taskId, n);
|
|
273
|
-
continue;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
if (taskIdToKey.has(taskId)) {
|
|
277
|
-
// 4e
|
|
278
|
-
const registryKey = taskIdToKey.get(taskId);
|
|
279
|
-
plannedTaskMdWrites.push({
|
|
280
|
-
taskMdPath,
|
|
281
|
-
originalContent,
|
|
282
|
-
originalAtime: originalStat.atime,
|
|
283
|
-
originalMtime: originalStat.mtime,
|
|
284
|
-
shortId: `#${registryKey}`,
|
|
285
|
-
kind: "4e"
|
|
286
|
-
});
|
|
287
|
-
continue;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
// 4f: deferred
|
|
291
|
-
pendingAlloc.push({
|
|
292
|
-
taskId,
|
|
293
|
-
taskMdPath,
|
|
294
|
-
originalContent,
|
|
295
|
-
originalAtime: originalStat.atime,
|
|
296
|
-
originalMtime: originalStat.mtime
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
// A5: capacity pre-check
|
|
301
|
-
const availableSlots = maxN - Object.keys(projectedIds).length;
|
|
302
|
-
if (pendingAlloc.length > availableSlots) {
|
|
303
|
-
writeStderr(
|
|
304
|
-
`Error: cold-start migration needs ${pendingAlloc.length} short id(s) but only ${availableSlots} ` +
|
|
305
|
-
`slot(s) available (capacity=${maxN}, in-use after stale-cleanup=${Object.keys(projectedIds).length}). ` +
|
|
306
|
-
`Archive some active tasks (complete-task / cancel-task / block-task) ` +
|
|
307
|
-
`or raise task.shortIdLength in .agents/.airc.json.\n`
|
|
308
|
-
);
|
|
309
|
-
process.exit(2);
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
pendingAlloc.sort((a, b) => a.taskId.localeCompare(b.taskId));
|
|
313
|
-
|
|
314
|
-
for (const item of pendingAlloc) {
|
|
315
|
-
const n = allocateMinFreeInt({ ids: projectedIds }, shortIdLength);
|
|
316
|
-
if (n === null) {
|
|
317
|
-
throw new Error("Internal invariant: pendingAlloc capacity check failed");
|
|
318
|
-
}
|
|
319
|
-
const key = padShortId(n, shortIdLength);
|
|
320
|
-
projectedIds[key] = item.taskId;
|
|
321
|
-
taskIdToKey.set(item.taskId, key);
|
|
322
|
-
plannedRegistryWrites.push({ key, taskId: item.taskId });
|
|
323
|
-
plannedTaskMdWrites.push({
|
|
324
|
-
taskMdPath: item.taskMdPath,
|
|
325
|
-
originalContent: item.originalContent,
|
|
326
|
-
originalAtime: item.originalAtime,
|
|
327
|
-
originalMtime: item.originalMtime,
|
|
328
|
-
shortId: `#${key}`,
|
|
329
|
-
kind: "4f"
|
|
330
|
-
});
|
|
331
|
-
}
|
|
332
244
|
|
|
333
|
-
// Build transaction object
|
|
334
245
|
const tx = {
|
|
335
246
|
_registry: registry,
|
|
336
247
|
_activeDir: activeDir,
|
|
337
248
|
_registrySnapshot: { ...registry.ids },
|
|
338
249
|
_pendingRegistryDeletes: pendingRegistryDeletes,
|
|
339
250
|
_plannedRegistryWrites: plannedRegistryWrites,
|
|
340
|
-
_plannedTaskMdWrites: plannedTaskMdWrites,
|
|
341
251
|
_projectedIds: projectedIds,
|
|
342
252
|
_taskIdToKey: taskIdToKey,
|
|
343
253
|
_shortIdLength: shortIdLength,
|
|
@@ -363,20 +273,6 @@ function planTransaction(registry, activeDir, shortIdLength) {
|
|
|
363
273
|
this._projectedIds[key] = taskId;
|
|
364
274
|
this._taskIdToKey.set(taskId, key);
|
|
365
275
|
this._plannedRegistryWrites.push({ key, taskId });
|
|
366
|
-
const originalStat = fs.statSync(taskMdPath);
|
|
367
|
-
const originalContent = fs.readFileSync(taskMdPath, "utf8");
|
|
368
|
-
// If task.md already declares the same short id (e.g. R-alloc replay), skip writing.
|
|
369
|
-
const existing = originalContent.match(/^short_id:\s*(#\d+)\s*$/m);
|
|
370
|
-
if (!existing || existing[1] !== `#${key}`) {
|
|
371
|
-
this._plannedTaskMdWrites.push({
|
|
372
|
-
taskMdPath,
|
|
373
|
-
originalContent,
|
|
374
|
-
originalAtime: originalStat.atime,
|
|
375
|
-
originalMtime: originalStat.mtime,
|
|
376
|
-
shortId: `#${key}`,
|
|
377
|
-
kind: "caller-alloc"
|
|
378
|
-
});
|
|
379
|
-
}
|
|
380
276
|
return key; // zero-padded; matches registry key
|
|
381
277
|
},
|
|
382
278
|
|
|
@@ -386,54 +282,22 @@ function planTransaction(registry, activeDir, shortIdLength) {
|
|
|
386
282
|
this._plannedRegistryWrites = this._plannedRegistryWrites.filter(
|
|
387
283
|
(w) => w.taskId !== taskId
|
|
388
284
|
);
|
|
389
|
-
this._plannedTaskMdWrites = this._plannedTaskMdWrites.filter(
|
|
390
|
-
(w) => path.basename(path.dirname(w.taskMdPath)) !== taskId
|
|
391
|
-
);
|
|
392
285
|
this._pendingRegistryDeletes.push(key);
|
|
393
286
|
delete this._projectedIds[key];
|
|
394
287
|
this._taskIdToKey.delete(taskId);
|
|
395
288
|
},
|
|
396
289
|
|
|
397
290
|
commit(registryPath) {
|
|
398
|
-
//
|
|
291
|
+
// Apply registry mutation in memory, then persist atomically.
|
|
399
292
|
for (const key of this._pendingRegistryDeletes) delete this._registry.ids[key];
|
|
400
293
|
for (const { key, taskId } of this._plannedRegistryWrites) {
|
|
401
294
|
this._registry.ids[key] = taskId;
|
|
402
295
|
}
|
|
403
|
-
|
|
404
|
-
const completedWrites = [];
|
|
405
|
-
const rollback = (reason) => {
|
|
406
|
-
for (const done of completedWrites.reverse()) {
|
|
407
|
-
try {
|
|
408
|
-
fs.writeFileSync(done.taskMdPath, done.originalContent);
|
|
409
|
-
fs.utimesSync(done.taskMdPath, done.originalAtime, done.originalMtime);
|
|
410
|
-
} catch {
|
|
411
|
-
/* best-effort */
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
this._registry.ids = this._registrySnapshot;
|
|
415
|
-
const tail =
|
|
416
|
-
completedWrites.length > 0
|
|
417
|
-
? `; rolled back ${completedWrites.length} prior task.md write(s)`
|
|
418
|
-
: "";
|
|
419
|
-
throw new Error(`${reason}${tail}`);
|
|
420
|
-
};
|
|
421
|
-
|
|
422
|
-
// B2: write task.md per plan
|
|
423
|
-
for (const write of this._plannedTaskMdWrites) {
|
|
424
|
-
try {
|
|
425
|
-
writeTaskMdShortId(write.taskMdPath, write.shortId);
|
|
426
|
-
completedWrites.push(write);
|
|
427
|
-
} catch (e) {
|
|
428
|
-
rollback(`Failed to write short_id to ${write.taskMdPath}: ${e.message}`);
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
// B3: atomic registry persistence
|
|
433
296
|
try {
|
|
434
297
|
writeRegistryAtomic(this._registry, registryPath);
|
|
435
298
|
} catch (e) {
|
|
436
|
-
|
|
299
|
+
this._registry.ids = this._registrySnapshot;
|
|
300
|
+
throw new Error(`Failed to persist registry to ${registryPath}: ${e.message}`);
|
|
437
301
|
}
|
|
438
302
|
}
|
|
439
303
|
};
|
|
@@ -449,27 +313,10 @@ function verifyRegistry(registry, activeDir) {
|
|
|
449
313
|
.filter((d) => fs.existsSync(path.join(activeDir, d, "task.md")))
|
|
450
314
|
);
|
|
451
315
|
const registryTaskIds = new Set(Object.values(registry.ids));
|
|
452
|
-
const taskmdShortIds = new Map();
|
|
453
|
-
for (const taskId of activeTaskIds) {
|
|
454
|
-
const taskMdPath = path.join(activeDir, taskId, "task.md");
|
|
455
|
-
const content = fs.readFileSync(taskMdPath, "utf8");
|
|
456
|
-
const m = content.match(/^short_id:\s*(#\d+)\s*$/m);
|
|
457
|
-
taskmdShortIds.set(taskId, m ? m[1] : null);
|
|
458
|
-
}
|
|
459
316
|
const missing_in_registry = [];
|
|
460
317
|
for (const taskId of activeTaskIds) {
|
|
461
318
|
if (!registryTaskIds.has(taskId)) {
|
|
462
|
-
missing_in_registry.push({ taskId
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
const missing_in_taskmd = [];
|
|
466
|
-
for (const [key, taskId] of Object.entries(registry.ids)) {
|
|
467
|
-
if (!activeTaskIds.has(taskId)) continue;
|
|
468
|
-
const declared = taskmdShortIds.get(taskId);
|
|
469
|
-
if (declared === null) {
|
|
470
|
-
missing_in_taskmd.push({ taskId, expected: `#${key}` });
|
|
471
|
-
} else if (declared !== `#${key}`) {
|
|
472
|
-
missing_in_taskmd.push({ taskId, expected: `#${key}`, declared });
|
|
319
|
+
missing_in_registry.push({ taskId });
|
|
473
320
|
}
|
|
474
321
|
}
|
|
475
322
|
const orphans_in_registry = [];
|
|
@@ -491,7 +338,6 @@ function verifyRegistry(registry, activeDir) {
|
|
|
491
338
|
}
|
|
492
339
|
return {
|
|
493
340
|
missing_in_registry,
|
|
494
|
-
missing_in_taskmd,
|
|
495
341
|
orphans_in_registry,
|
|
496
342
|
duplicate_registry_keys
|
|
497
343
|
};
|
|
@@ -548,8 +394,8 @@ function cmdRelease(taskId, activeDir, registryPath, shortIdLength) {
|
|
|
548
394
|
}
|
|
549
395
|
|
|
550
396
|
function cmdResolve(shortIdArg, activeDir, registryPath, shortIdLength) {
|
|
551
|
-
//
|
|
552
|
-
//
|
|
397
|
+
// Accepts bare digits ('11') or '#'-prefixed form ('#11', '#11', '#005'); normalized by
|
|
398
|
+
// numeric value with capacity check (n > 10^L-1) and reserved-zero rejection.
|
|
553
399
|
const key = parseShortIdArg(shortIdArg, shortIdLength);
|
|
554
400
|
return withRegistryLock(activeDir, () => {
|
|
555
401
|
const registry = readRegistry(registryPath);
|
|
@@ -558,8 +404,7 @@ function cmdResolve(shortIdArg, activeDir, registryPath, shortIdLength) {
|
|
|
558
404
|
if (!taskId) {
|
|
559
405
|
const hasPendingMutations =
|
|
560
406
|
tx._plannedRegistryWrites.length > 0 ||
|
|
561
|
-
tx._pendingRegistryDeletes.length > 0
|
|
562
|
-
tx._plannedTaskMdWrites.length > 0;
|
|
407
|
+
tx._pendingRegistryDeletes.length > 0;
|
|
563
408
|
if (hasPendingMutations) {
|
|
564
409
|
try {
|
|
565
410
|
tx.commit(registryPath);
|
|
@@ -604,7 +449,6 @@ function cmdList(activeDir, registryPath, verify) {
|
|
|
604
449
|
const diff = verifyRegistry(registry, activeDir);
|
|
605
450
|
const hasIssues =
|
|
606
451
|
diff.missing_in_registry.length > 0 ||
|
|
607
|
-
diff.missing_in_taskmd.length > 0 ||
|
|
608
452
|
diff.orphans_in_registry.length > 0 ||
|
|
609
453
|
diff.duplicate_registry_keys.length > 0;
|
|
610
454
|
if (hasIssues) {
|
|
@@ -699,7 +543,6 @@ export {
|
|
|
699
543
|
readRegistry,
|
|
700
544
|
writeRegistryAtomic,
|
|
701
545
|
withRegistryLock,
|
|
702
|
-
writeTaskMdShortId,
|
|
703
546
|
padShortId,
|
|
704
547
|
parseShortIdArg,
|
|
705
548
|
allocateMinFreeInt,
|
|
@@ -29,7 +29,7 @@ Before the state check is complete, do not make external-state assertions such a
|
|
|
29
29
|
|
|
30
30
|
## Task id short ref
|
|
31
31
|
|
|
32
|
-
> If `{task-id}`
|
|
32
|
+
> If `{task-id}` matches `^[#]?[0-9]+$` (bare numeric or `#`-prefixed), follow the "SKILL parameter resolver" section of `.agents/rules/task-short-id.md`; treat `{task-id}` as the resolved full `TASK-YYYYMMDD-HHMMSS` form for every downstream command.
|
|
33
33
|
|
|
34
34
|
## Steps
|
|
35
35
|
|
|
@@ -65,6 +65,8 @@ If `task.md` contains these source fields, also read the corresponding source in
|
|
|
65
65
|
- `codescan_alert_number` - Code Scanning alert
|
|
66
66
|
- `security_alert_number` - Dependabot alert
|
|
67
67
|
|
|
68
|
+
**Round ≥ 2: respond to the prior review (only when a review artifact exists)**: if the task directory contains `review-analysis.md` / `review-analysis-r{N}.md`, read the highest-round review report; add a `## Response to Prior Review` section to this round's analysis artifact, and for each finding verify it via Read/Grep before acting (holds → accept and fix; judged hallucinated/unfounded → rebut with counter-evidence rather than defaulting to compliance); record any open disagreement under `## Open Questions`. Round 1 has no review, so skip this section.
|
|
69
|
+
|
|
68
70
|
### 4. Perform Requirements Analysis
|
|
69
71
|
|
|
70
72
|
Before analysis begins: if `start_date` in the frontmatter is empty, write today's date immediately (command: `date +%F`, format `YYYY-MM-DD`); keep any existing value. Before writing, read `.agents/rules/version-stamp.md` and refresh `updated_at` / `agent_infra_version` at the same time.
|
|
@@ -154,15 +156,11 @@ Update `.agents/workspace/active/{task-id}/task.md`:
|
|
|
154
156
|
- Mark requirement-analysis as complete in workflow progress and include the actual round when the task template supports it
|
|
155
157
|
- Before appending the workflow Activity Log entry, re-estimate `priority` based on the analysis findings (business impact, risks, dependencies, blockers). If the re-estimated value differs from the current value in `task.md`:
|
|
156
158
|
- Overwrite the `priority` field in frontmatter with the new value
|
|
157
|
-
-
|
|
158
|
-
|
|
159
|
-
- {YYYY-MM-DD HH:mm:ss±HH:MM} — **Analysis Re-estimate** by {agent} — priority {old} → {new} (rationale: {short basis grounded in this analysis})
|
|
160
|
-
```
|
|
161
|
-
Both entries may share the same timestamp; ordering is conveyed by list position only.
|
|
162
|
-
If the re-estimated value matches the current value, skip the Re-estimate entry. The Flow A sync that follows reads the possibly updated frontmatter and propagates the new value to the Issue automatically.
|
|
159
|
+
- Append a `## Priority Re-estimate` section to this round's analysis artifact `{analysis-artifact}`, recording: `priority {old} → {new} (rationale: {short basis grounded in this analysis})`
|
|
160
|
+
If the re-estimated value matches the current value, skip it: do not write the `## Priority Re-estimate` section. The Flow A sync that follows reads the possibly updated frontmatter and propagates the new value to the Issue automatically.
|
|
163
161
|
- **Append** to `## Activity Log` (do NOT overwrite previous entries):
|
|
164
162
|
```
|
|
165
|
-
- {YYYY-MM-DD HH:mm:ss±HH:MM} — **
|
|
163
|
+
- {YYYY-MM-DD HH:mm:ss±HH:MM} — **Analyze Task (Round {N})** by {agent} — Analysis completed → {analysis-artifact}
|
|
166
164
|
```
|
|
167
165
|
|
|
168
166
|
If task.md contains a valid `issue_number`, perform these sync actions (skip and continue on any failure):
|
|
@@ -191,7 +189,7 @@ Keep the gate output in your reply as fresh evidence. Do not claim completion wi
|
|
|
191
189
|
|
|
192
190
|
> Execute this step only after the verification gate passes.
|
|
193
191
|
|
|
194
|
-
> **IMPORTANT**: All TUI command formats listed below must be output in full. Do not show only the format for the current AI agent. If `.agents/.airc.json` configures custom TUIs (via `customTUIs`), read each tool's `name` and `invoke`, then add the matching command line in the same format (`${skillName}` becomes the skill name and `${projectName}` becomes the project name).
|
|
192
|
+
> **IMPORTANT**: All TUI command formats listed below must be output in full. Do not show only the format for the current AI agent. If `.agents/.airc.json` configures custom TUIs (via `customTUIs`), read each tool's `name` and `invoke`, then add the matching command line in the same format (`${skillName}` becomes the skill name and `${projectName}` becomes the project name). Before rendering the final output, read `.agents/rules/next-step-output.md` and apply both of its rules: (1) render `{task-ref}` in the "Next steps" commands as the short id `#NN` (falling back to the full TASK-id when unallocated or released); (2) append the `Completed at` line as the very last line of the user-facing output (this applies to every user-facing output — success, error, and early-return paths alike, not only the success path).
|
|
195
193
|
|
|
196
194
|
Output format:
|
|
197
195
|
```
|
|
@@ -206,9 +204,9 @@ Output file:
|
|
|
206
204
|
- Analysis report: .agents/workspace/active/{task-id}/{analysis-artifact}
|
|
207
205
|
|
|
208
206
|
Next step - review the analysis:
|
|
209
|
-
- Claude Code / OpenCode: /review-analysis {task-
|
|
210
|
-
- Gemini CLI: /{{project}}:review-analysis {task-
|
|
211
|
-
- Codex CLI: $review-analysis {task-
|
|
207
|
+
- Claude Code / OpenCode: /review-analysis {task-ref}
|
|
208
|
+
- Gemini CLI: /{{project}}:review-analysis {task-ref}
|
|
209
|
+
- Codex CLI: $review-analysis {task-ref}
|
|
212
210
|
```
|
|
213
211
|
|
|
214
212
|
## Completion Checklist
|
|
@@ -29,7 +29,7 @@ tail .agents/workspace/active/{task-id}/task.md
|
|
|
29
29
|
|
|
30
30
|
## 任务入参短号别名
|
|
31
31
|
|
|
32
|
-
> 如果 `{task-id}`
|
|
32
|
+
> 如果 `{task-id}` 入参匹配 `^[#]?[0-9]+$`(裸数字或带 `#` 前缀),先读取 `.agents/rules/task-short-id.md` 的「SKILL 入参解析」段执行解析;后续命令视 `{task-id}` 为解析后的全长 `TASK-YYYYMMDD-HHMMSS` 形式。
|
|
33
33
|
|
|
34
34
|
## 执行步骤
|
|
35
35
|
### 1. 验证前置条件
|
|
@@ -64,6 +64,8 @@ tail .agents/workspace/active/{task-id}/task.md
|
|
|
64
64
|
- `codescan_alert_number` - Code Scanning 告警
|
|
65
65
|
- `security_alert_number` - Dependabot 告警
|
|
66
66
|
|
|
67
|
+
**Round ≥ 2:响应上一轮审查(仅当存在审查产物时)**:若任务目录存在 `review-analysis.md` / `review-analysis-r{N}.md`,读取最高轮次的审查报告;在本轮分析产物中新增 `## 对上一轮审查的响应` 段,对每条发现先 Read/Grep 核实再处置(成立 → 接受并修正;判定为幻觉/不成立 → 附反证反驳,不默认顺从),未决分歧写入 `## 未决问题`。Round 1 无审查,跳过本段。
|
|
68
|
+
|
|
67
69
|
### 4. 执行需求分析
|
|
68
70
|
|
|
69
71
|
开始分析前:若 frontmatter 的 `start_date` 为空,立即写入当日日期(命令 `date +%F`,格式 `YYYY-MM-DD`);已有值则保留。写入前先读取 `.agents/rules/version-stamp.md`,并同步刷新 `updated_at` / `agent_infra_version`。
|
|
@@ -153,15 +155,11 @@ date "+%Y-%m-%d %H:%M:%S%:z"
|
|
|
153
155
|
- 在工作流进度中标记 requirement-analysis 为已完成,并注明实际轮次(如果任务模板支持)
|
|
154
156
|
- 在追加工作流 Activity Log 条目之前,基于分析结果(业务影响、风险、依赖、阻塞条件)重估 `priority`。若重估值与 `task.md` 当前值不一致:
|
|
155
157
|
- 用新值覆盖 frontmatter 的 `priority` 字段
|
|
156
|
-
-
|
|
157
|
-
|
|
158
|
-
- {YYYY-MM-DD HH:mm:ss±HH:MM} — **Analysis Re-estimate** by {agent} — priority {old} → {new} (rationale: {基于本轮分析的简短依据})
|
|
159
|
-
```
|
|
160
|
-
两条条目可共用同一时间戳,顺序仅通过列表位置表达。
|
|
161
|
-
若重估值与当前值一致,跳过 Re-estimate 条目。后续 Flow A 同步会读取可能更新过的 frontmatter,并自动把新值同步到 Issue。
|
|
158
|
+
- 在本轮分析产物 `{analysis-artifact}` 中追加 `## 优先级重估` 段,记录一条:`priority {old} → {new} (rationale: {基于本轮分析的简短依据})`
|
|
159
|
+
若重估值与当前值一致,跳过:不写入 `## 优先级重估` 段。后续 Flow A 同步会读取可能更新过的 frontmatter,并自动把新值同步到 Issue。
|
|
162
160
|
- **追加**到 `## Activity Log`(不要覆盖之前的记录):
|
|
163
161
|
```
|
|
164
|
-
- {YYYY-MM-DD HH:mm:ss±HH:MM} — **
|
|
162
|
+
- {YYYY-MM-DD HH:mm:ss±HH:MM} — **Analyze Task (Round {N})** by {agent} — Analysis completed → {analysis-artifact}
|
|
165
163
|
```
|
|
166
164
|
|
|
167
165
|
如果 task.md 中存在有效的 `issue_number`,执行以下同步操作(任一失败则跳过并继续):
|
|
@@ -190,7 +188,7 @@ node .agents/scripts/validate-artifact.js gate analyze-task .agents/workspace/ac
|
|
|
190
188
|
|
|
191
189
|
> 仅在校验通过后执行本步骤。
|
|
192
190
|
|
|
193
|
-
> **重要**:以下「下一步」中列出的所有 TUI 命令格式必须完整输出,不要只展示当前 AI 代理对应的格式。如果 `.agents/.airc.json` 中配置了自定义 TUI(`customTUIs`),读取每个工具的 `name` 和 `invoke`,按同样格式补充对应命令行(`${skillName}` 替换为技能名,`${projectName}` 替换为项目名)。
|
|
191
|
+
> **重要**:以下「下一步」中列出的所有 TUI 命令格式必须完整输出,不要只展示当前 AI 代理对应的格式。如果 `.agents/.airc.json` 中配置了自定义 TUI(`customTUIs`),读取每个工具的 `name` 和 `invoke`,按同样格式补充对应命令行(`${skillName}` 替换为技能名,`${projectName}` 替换为项目名)。 渲染最终输出前,先读取 `.agents/rules/next-step-output.md` 并落实其两类规则:(1) 「下一步」命令把 `{task-ref}` 渲染为短号 `#NN`(未分配/已释放时回退完整 TASK-id);(2) 在面向用户输出的绝对最后一行追加 `Completed at` 收尾行(成功、错误、早退等任何面向用户输出都适用,不限于校验通过的成功态)。
|
|
194
192
|
|
|
195
193
|
输出格式:
|
|
196
194
|
```
|
|
@@ -205,9 +203,9 @@ node .agents/scripts/validate-artifact.js gate analyze-task .agents/workspace/ac
|
|
|
205
203
|
- 分析报告:.agents/workspace/active/{task-id}/{analysis-artifact}
|
|
206
204
|
|
|
207
205
|
下一步 - 审查需求分析:
|
|
208
|
-
- Claude Code / OpenCode:/review-analysis {task-
|
|
209
|
-
- Gemini CLI:/agent-infra:review-analysis {task-
|
|
210
|
-
- Codex CLI:$review-analysis {task-
|
|
206
|
+
- Claude Code / OpenCode:/review-analysis {task-ref}
|
|
207
|
+
- Gemini CLI:/agent-infra:review-analysis {task-ref}
|
|
208
|
+
- Codex CLI:$review-analysis {task-ref}
|
|
211
209
|
```
|
|
212
210
|
|
|
213
211
|
## 完成检查清单
|
|
@@ -21,7 +21,7 @@ Version stamp rule: when creating or updating `task.md` frontmatter, read `.agen
|
|
|
21
21
|
|
|
22
22
|
## Task id short ref
|
|
23
23
|
|
|
24
|
-
> If `{task-id}`
|
|
24
|
+
> If `{task-id}` matches `^[#]?[0-9]+$` (bare numeric or `#`-prefixed), follow the "SKILL parameter resolver" section of `.agents/rules/task-short-id.md`; treat `{task-id}` as the resolved full `TASK-YYYYMMDD-HHMMSS` form for every downstream command.
|
|
25
25
|
|
|
26
26
|
## Steps
|
|
27
27
|
|
|
@@ -56,7 +56,7 @@ Update `.agents/workspace/active/{task-id}/task.md`:
|
|
|
56
56
|
- `agent_infra_version`: value from `.agents/rules/version-stamp.md`
|
|
57
57
|
- **Append** to `## Activity Log` (do NOT overwrite previous entries):
|
|
58
58
|
```
|
|
59
|
-
- {YYYY-MM-DD HH:mm:ss±HH:MM} — **
|
|
59
|
+
- {YYYY-MM-DD HH:mm:ss±HH:MM} — **Block Task** by {agent} — {one-line reason}
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
Add a blocking information section to task.md.
|
|
@@ -106,7 +106,9 @@ Keep the gate output in your reply as fresh evidence. Do not claim completion wi
|
|
|
106
106
|
|
|
107
107
|
> Execute this step only after the verification gate passes.
|
|
108
108
|
|
|
109
|
-
> **IMPORTANT**: All TUI command formats listed below must be output in full. Do not show only the format for the current AI agent. If `.agents/.airc.json` configures custom TUIs (via `customTUIs`), read each tool's `name` and `invoke`, then add the matching command line in the same format (`${skillName}` becomes the skill name and `${projectName}` becomes the project name).
|
|
109
|
+
> **IMPORTANT**: All TUI command formats listed below must be output in full. Do not show only the format for the current AI agent. If `.agents/.airc.json` configures custom TUIs (via `customTUIs`), read each tool's `name` and `invoke`, then add the matching command line in the same format (`${skillName}` becomes the skill name and `${projectName}` becomes the project name). Before rendering the final output, read `.agents/rules/next-step-output.md` and apply both of its rules: (1) render `{task-ref}` in the "Next steps" commands as the short id `#NN` (falling back to the full TASK-id when unallocated or released); (2) append the `Completed at` line as the very last line of the user-facing output (this applies to every user-facing output — success, error, and early-return paths alike, not only the success path).
|
|
110
|
+
|
|
111
|
+
> **Optional sandbox-cleanup hint (gated)**: Render the "Optional: clean up this task's sandbox" block — placed after "Archived to" and before "To unblock" in the output below — only when BOTH (1) `.agents/.airc.json` has a `sandbox` field and (2) task.md's `branch` field exists and is not `main` / `master`; otherwise omit the whole block. `{branch}` is the `branch` value from the task.md you already loaded (the task has moved to blocked/, so read it from `.agents/workspace/blocked/{task-id}/task.md`). This block is independent of "Next step" semantics.
|
|
110
112
|
|
|
111
113
|
Output format:
|
|
112
114
|
```
|
|
@@ -116,14 +118,19 @@ Blocking reason: {summary}
|
|
|
116
118
|
Required to unblock: {what's needed}
|
|
117
119
|
Archived to: .agents/workspace/blocked/{task-id}/
|
|
118
120
|
|
|
121
|
+
Optional: clean up this task's sandbox
|
|
122
|
+
(The task is blocked and moved to blocked/; the sandbox container and per-branch config directory are not reclaimed automatically. Run this if you no longer need them:)
|
|
123
|
+
|
|
124
|
+
ai sandbox rm {branch}
|
|
125
|
+
|
|
119
126
|
To unblock when the issue is resolved:
|
|
120
127
|
mv .agents/workspace/blocked/{task-id} .agents/workspace/active/{task-id}
|
|
121
128
|
# Then update task.md: status -> active, remove blocked_at
|
|
122
129
|
|
|
123
130
|
Next step - check task status after unblocking:
|
|
124
|
-
- Claude Code / OpenCode: /check-task {task-
|
|
125
|
-
- Gemini CLI: /{{project}}:check-task {task-
|
|
126
|
-
- Codex CLI: $check-task {task-
|
|
131
|
+
- Claude Code / OpenCode: /check-task {task-ref}
|
|
132
|
+
- Gemini CLI: /{{project}}:check-task {task-ref}
|
|
133
|
+
- Codex CLI: $check-task {task-ref}
|
|
127
134
|
```
|
|
128
135
|
|
|
129
136
|
|
|
@@ -21,7 +21,7 @@ description: "标记任务为阻塞状态并记录原因"
|
|
|
21
21
|
|
|
22
22
|
## 任务入参短号别名
|
|
23
23
|
|
|
24
|
-
> 如果 `{task-id}`
|
|
24
|
+
> 如果 `{task-id}` 入参匹配 `^[#]?[0-9]+$`(裸数字或带 `#` 前缀),先读取 `.agents/rules/task-short-id.md` 的「SKILL 入参解析」段执行解析;后续命令视 `{task-id}` 为解析后的全长 `TASK-YYYYMMDD-HHMMSS` 形式。
|
|
25
25
|
|
|
26
26
|
## 执行步骤
|
|
27
27
|
### 1. 验证任务存在
|
|
@@ -55,7 +55,7 @@ date "+%Y-%m-%d %H:%M:%S%:z"
|
|
|
55
55
|
- `agent_infra_version`:按 `.agents/rules/version-stamp.md` 取值
|
|
56
56
|
- **追加**到 `## Activity Log`(不要覆盖之前的记录):
|
|
57
57
|
```
|
|
58
|
-
- {YYYY-MM-DD HH:mm:ss±HH:MM} — **
|
|
58
|
+
- {YYYY-MM-DD HH:mm:ss±HH:MM} — **Block Task** by {agent} — {一行原因}
|
|
59
59
|
```
|
|
60
60
|
|
|
61
61
|
在 task.md 中添加阻塞信息部分。
|
|
@@ -105,7 +105,9 @@ node .agents/scripts/validate-artifact.js gate block-task .agents/workspace/bloc
|
|
|
105
105
|
|
|
106
106
|
> 仅在校验通过后执行本步骤。
|
|
107
107
|
|
|
108
|
-
> **重要**:以下「下一步」中列出的所有 TUI 命令格式必须完整输出,不要只展示当前 AI 代理对应的格式。如果 `.agents/.airc.json` 中配置了自定义 TUI(`customTUIs`),读取每个工具的 `name` 和 `invoke`,按同样格式补充对应命令行(`${skillName}` 替换为技能名,`${projectName}` 替换为项目名)。
|
|
108
|
+
> **重要**:以下「下一步」中列出的所有 TUI 命令格式必须完整输出,不要只展示当前 AI 代理对应的格式。如果 `.agents/.airc.json` 中配置了自定义 TUI(`customTUIs`),读取每个工具的 `name` 和 `invoke`,按同样格式补充对应命令行(`${skillName}` 替换为技能名,`${projectName}` 替换为项目名)。 渲染最终输出前,先读取 `.agents/rules/next-step-output.md` 并落实其两类规则:(1) 「下一步」命令把 `{task-ref}` 渲染为短号 `#NN`(未分配/已释放时回退完整 TASK-id);(2) 在面向用户输出的绝对最后一行追加 `Completed at` 收尾行(成功、错误、早退等任何面向用户输出都适用,不限于校验通过的成功态)。
|
|
109
|
+
|
|
110
|
+
> **可选沙箱清理提示(门控渲染)**:仅当同时满足 (1) `.agents/.airc.json` 存在 `sandbox` 字段、(2) task.md 的 `branch` 字段存在且不是 `main` / `master` 时,才渲染下方输出中「归档路径」之后、「解除阻塞时执行」之前的「可选:清理本任务的沙箱」块;任一不满足则整段省略。`{branch}` 取已读入的 task.md 的 `branch` 值(任务此时已移动到 blocked/,从 `.agents/workspace/blocked/{task-id}/task.md` 读取)。该块独立于「下一步」语义。
|
|
109
111
|
|
|
110
112
|
输出格式:
|
|
111
113
|
```
|
|
@@ -115,14 +117,19 @@ node .agents/scripts/validate-artifact.js gate block-task .agents/workspace/bloc
|
|
|
115
117
|
解除阻塞所需:{需要什么}
|
|
116
118
|
归档路径:.agents/workspace/blocked/{task-id}/
|
|
117
119
|
|
|
120
|
+
可选:清理本任务的沙箱
|
|
121
|
+
(任务已阻塞并移到 blocked/,沙箱容器和 per-branch 配置目录不会自动回收。如果不再需要可执行:)
|
|
122
|
+
|
|
123
|
+
ai sandbox rm {branch}
|
|
124
|
+
|
|
118
125
|
解除阻塞时执行:
|
|
119
126
|
mv .agents/workspace/blocked/{task-id} .agents/workspace/active/{task-id}
|
|
120
127
|
# 然后更新 task.md:status -> active,移除 blocked_at
|
|
121
128
|
|
|
122
129
|
下一步 - 检查任务状态(解除阻塞后):
|
|
123
|
-
- Claude Code / OpenCode:/check-task {task-
|
|
124
|
-
- Gemini CLI:/agent-infra:check-task {task-
|
|
125
|
-
- Codex CLI:$check-task {task-
|
|
130
|
+
- Claude Code / OpenCode:/check-task {task-ref}
|
|
131
|
+
- Gemini CLI:/agent-infra:check-task {task-ref}
|
|
132
|
+
- Codex CLI:$check-task {task-ref}
|
|
126
133
|
```
|
|
127
134
|
|
|
128
135
|
|
|
@@ -15,7 +15,7 @@ Version stamp rule: when creating or updating `task.md` frontmatter, read `.agen
|
|
|
15
15
|
|
|
16
16
|
## Task id short ref
|
|
17
17
|
|
|
18
|
-
> If `{task-id}`
|
|
18
|
+
> If `{task-id}` matches `^[#]?[0-9]+$` (bare numeric or `#`-prefixed), follow the "SKILL parameter resolver" section of `.agents/rules/task-short-id.md`; treat `{task-id}` as the resolved full `TASK-YYYYMMDD-HHMMSS` form for every downstream command.
|
|
19
19
|
|
|
20
20
|
## Steps
|
|
21
21
|
|
|
@@ -57,7 +57,7 @@ Update `task.md` in the task directory:
|
|
|
57
57
|
- `agent_infra_version`: value from `.agents/rules/version-stamp.md`
|
|
58
58
|
- **Append** to `## Activity Log` (do NOT overwrite previous entries):
|
|
59
59
|
```
|
|
60
|
-
- {YYYY-MM-DD HH:mm:ss±HH:MM} — **
|
|
60
|
+
- {YYYY-MM-DD HH:mm:ss±HH:MM} — **Cancel Task** by {agent} — {one-line cancellation reason}
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
### 4. Move the Task
|
|
@@ -119,7 +119,9 @@ Keep the gate output in your reply as fresh evidence. Do not claim completion wi
|
|
|
119
119
|
|
|
120
120
|
> Execute this step only after the verification gate passes.
|
|
121
121
|
|
|
122
|
-
> **IMPORTANT**: All TUI command formats listed below must be output in full. Do not show only the format for the current AI agent. If `.agents/.airc.json` configures custom TUIs (via `customTUIs`), read each tool's `name` and `invoke`, then add the matching command line in the same format (`${skillName}` becomes the skill name and `${projectName}` becomes the project name).
|
|
122
|
+
> **IMPORTANT**: All TUI command formats listed below must be output in full. Do not show only the format for the current AI agent. If `.agents/.airc.json` configures custom TUIs (via `customTUIs`), read each tool's `name` and `invoke`, then add the matching command line in the same format (`${skillName}` becomes the skill name and `${projectName}` becomes the project name). Before rendering the final output, read `.agents/rules/next-step-output.md` and apply both of its rules: (1) render `{task-ref}` in the "Next steps" commands as the short id `#NN` (falling back to the full TASK-id when unallocated or released); (2) append the `Completed at` line as the very last line of the user-facing output (this applies to every user-facing output — success, error, and early-return paths alike, not only the success path).
|
|
123
|
+
|
|
124
|
+
> **Optional sandbox-cleanup hint (gated)**: Render the "Optional: clean up this task's sandbox" block — placed after "Target path" and before "Next step" in the output below — only when BOTH (1) `.agents/.airc.json` has a `sandbox` field and (2) task.md's `branch` field exists and is not `main` / `master`; otherwise omit the whole block. `{branch}` is the `branch` value from the task.md you already loaded (the task has moved to completed/, so read it from `.agents/workspace/completed/{task-id}/task.md`). This block is independent of "Next steps" semantics.
|
|
123
125
|
|
|
124
126
|
Output format:
|
|
125
127
|
```
|
|
@@ -129,10 +131,15 @@ Cancellation reason: {reason}
|
|
|
129
131
|
Status label: {status-label or skipped}
|
|
130
132
|
Target path: .agents/workspace/completed/{task-id}/
|
|
131
133
|
|
|
134
|
+
Optional: clean up this task's sandbox
|
|
135
|
+
(The task is archived; the sandbox container and per-branch config directory are not reclaimed automatically. Run this if you no longer need them:)
|
|
136
|
+
|
|
137
|
+
ai sandbox rm {branch}
|
|
138
|
+
|
|
132
139
|
Next step - inspect the moved task:
|
|
133
|
-
- Claude Code / OpenCode: /check-task {task-
|
|
134
|
-
- Gemini CLI: /{{project}}:check-task {task-
|
|
135
|
-
- Codex CLI: $check-task {task-
|
|
140
|
+
- Claude Code / OpenCode: /check-task {task-ref}
|
|
141
|
+
- Gemini CLI: /{{project}}:check-task {task-ref}
|
|
142
|
+
- Codex CLI: $check-task {task-ref}
|
|
136
143
|
```
|
|
137
144
|
|
|
138
145
|
|