@fitlab-ai/agent-infra 0.11.5 → 0.11.7
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/dist/lib/git/primary-worktree.js +58 -0
- package/dist/lib/merge.js +62 -10
- package/dist/lib/platform/github-provider.js +9 -14
- package/dist/lib/platform/github-release-notes.js +80 -11
- package/dist/lib/platform/none-provider.js +1 -1
- package/dist/lib/platform/provider-contract.d.ts +39 -16
- package/dist/lib/platform/provider-contract.js +1 -1
- package/dist/lib/platform/provider-validation.js +83 -13
- package/dist/lib/platform/pull-requests.js +29 -3
- package/dist/lib/platform/release-notes.js +7 -8
- package/dist/lib/sandbox/capture.js +1 -1
- package/dist/lib/sandbox/commands/create.js +46 -1
- package/dist/lib/sandbox/commands/enter.js +1 -1
- package/dist/lib/sandbox/commands/start.js +1 -1
- package/dist/lib/sandbox/config.js +10 -0
- package/dist/lib/sandbox/control/lifecycle.js +18 -13
- package/dist/lib/sandbox/control/server.js +6 -2
- package/dist/lib/sandbox/task-resolver.js +62 -2
- package/dist/lib/server/config.js +7 -27
- package/dist/lib/server/daemon.js +4 -3
- package/dist/lib/server/process-control.js +4 -2
- package/dist/lib/server/runner.js +4 -3
- package/dist/lib/task/artifact-lifecycle.js +42 -10
- package/dist/lib/task/artifact-receipts.js +62 -22
- package/dist/lib/task/capabilities.js +22 -4
- package/dist/lib/task/completion-facts.js +56 -0
- package/dist/lib/task/create-service.js +6 -2
- package/dist/lib/task/create.js +46 -82
- package/dist/lib/task/events.js +268 -195
- package/dist/lib/task/finalization-handoff.js +2 -1
- package/dist/lib/task/invalidation-command.js +4 -2
- package/dist/lib/task/invalidation.js +38 -9
- package/dist/lib/task/local-artifact-finalization.js +17 -3
- package/dist/lib/task/qualification-audit.js +23 -105
- package/dist/lib/task/resolve-ref.js +3 -3
- package/dist/lib/task/review-finalization.js +7 -0
- package/dist/lib/task/review-identity.js +69 -0
- package/dist/lib/task/sections.js +6 -5
- package/dist/lib/task/task-execution-lock.js +6 -3
- package/dist/lib/task/verification-engine.js +14 -63
- package/dist/lib/task/verification.js +35 -38
- package/dist/lib/task/write.js +121 -1
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/git/primary-worktree.ts +62 -0
- package/lib/merge.ts +59 -10
- package/lib/platform/github-provider.ts +11 -18
- package/lib/platform/github-release-notes.ts +89 -14
- package/lib/platform/none-provider.ts +1 -1
- package/lib/platform/provider-contract.ts +38 -12
- package/lib/platform/provider-validation.ts +83 -12
- package/lib/platform/pull-requests.ts +27 -3
- package/lib/platform/release-notes.ts +11 -12
- package/lib/sandbox/capture.ts +1 -1
- package/lib/sandbox/commands/create.ts +52 -1
- package/lib/sandbox/commands/enter.ts +1 -1
- package/lib/sandbox/commands/start.ts +1 -1
- package/lib/sandbox/config.ts +12 -0
- package/lib/sandbox/control/lifecycle.ts +22 -13
- package/lib/sandbox/control/server.ts +5 -2
- package/lib/sandbox/task-resolver.ts +51 -2
- package/lib/server/config.ts +7 -29
- package/lib/server/daemon.ts +5 -3
- package/lib/server/process-control.ts +4 -2
- package/lib/server/runner.ts +7 -4
- package/lib/server/server.schema.json +0 -4
- package/lib/task/artifact-lifecycle.ts +35 -11
- package/lib/task/artifact-receipts.ts +55 -15
- package/lib/task/capabilities.ts +17 -3
- package/lib/task/completion-facts.ts +66 -0
- package/lib/task/create-service.ts +7 -3
- package/lib/task/create.ts +44 -71
- package/lib/task/events.ts +248 -182
- package/lib/task/finalization-handoff.ts +2 -1
- package/lib/task/invalidation-command.ts +4 -2
- package/lib/task/invalidation.ts +35 -10
- package/lib/task/local-artifact-finalization.ts +13 -3
- package/lib/task/qualification-audit.ts +21 -114
- package/lib/task/resolve-ref.ts +3 -3
- package/lib/task/review-finalization.ts +7 -0
- package/lib/task/review-identity.ts +85 -0
- package/lib/task/sections.ts +6 -6
- package/lib/task/task-execution-lock.ts +7 -3
- package/lib/task/verification-engine.ts +13 -86
- package/lib/task/verification.ts +34 -38
- package/lib/task/write.ts +115 -1
- package/package.json +1 -1
- package/templates/.agents/rules/README.en.md +1 -0
- package/templates/.agents/rules/README.zh-CN.md +1 -0
- package/templates/.agents/rules/decision-qualification.en.md +4 -3
- package/templates/.agents/rules/decision-qualification.zh-CN.md +4 -3
- package/templates/.agents/rules/evidence-reporting.en.md +1 -2
- package/templates/.agents/rules/evidence-reporting.zh-CN.md +1 -2
- package/templates/.agents/rules/validation-output.en.md +19 -0
- package/templates/.agents/rules/validation-output.zh-CN.md +19 -0
- package/templates/.agents/skills/analyze-task/SKILL.en.md +3 -1
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/archive-tasks/SKILL.en.md +2 -2
- package/templates/.agents/skills/archive-tasks/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/archive-tasks/scripts/archive-tasks.sh +109 -6
- package/templates/.agents/skills/block-task/SKILL.en.md +2 -0
- package/templates/.agents/skills/block-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/cancel-task/SKILL.en.md +2 -0
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/code-task/SKILL.en.md +3 -1
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/code-task/reference/report-template.en.md +4 -8
- package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +4 -8
- package/templates/.agents/skills/commit/SKILL.en.md +1 -1
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +1 -1
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/complete-task/SKILL.en.md +2 -0
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +2 -0
- package/templates/.agents/skills/create-pr/SKILL.en.md +2 -0
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/create-release-note/SKILL.en.md +17 -11
- package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +17 -11
- package/templates/.agents/skills/create-task/SKILL.en.md +2 -0
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/import-codescan/SKILL.en.md +2 -0
- package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/import-dependabot/SKILL.en.md +2 -0
- package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/import-issue/SKILL.en.md +2 -0
- package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/plan-task/SKILL.en.md +3 -1
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/review-analysis/SKILL.en.md +3 -1
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +3 -1
- package/templates/.agents/skills/review-analysis/reference/report-template.en.md +4 -8
- package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +4 -8
- package/templates/.agents/skills/review-code/SKILL.en.md +13 -12
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +11 -12
- package/templates/.agents/skills/review-code/config/verify.en.json +1 -3
- package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -3
- package/templates/.agents/skills/review-code/reference/output-templates.en.md +23 -46
- package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +27 -48
- package/templates/.agents/skills/review-code/reference/report-template.en.md +8 -11
- package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +8 -11
- package/templates/.agents/skills/review-code/reference/review-criteria.en.md +2 -2
- package/templates/.agents/skills/review-code/reference/review-criteria.zh-CN.md +2 -2
- package/templates/.agents/skills/review-plan/SKILL.en.md +3 -1
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +3 -1
- package/templates/.agents/skills/review-plan/reference/report-template.en.md +5 -9
- package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +5 -9
- package/templates/.agents/skills/review-pr/SKILL.en.md +2 -0
- package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +2 -0
- package/templates/.agents/skills/run-manual-validation/SKILL.en.md +1 -1
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/watch-pr/SKILL.en.md +2 -0
- package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +1 -1
- package/templates/.agents/templates/task.en.md +2 -2
- package/templates/.agents/templates/task.zh-CN.md +2 -2
|
@@ -6,12 +6,9 @@ import { execFileSync } from "node:child_process";
|
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
7
|
|
|
8
8
|
import {
|
|
9
|
-
extractReviewBaseline,
|
|
10
9
|
extractReviewTargetHead,
|
|
11
10
|
extractReviewedHead,
|
|
12
11
|
extractReviewDiffBase,
|
|
13
|
-
extractReviewDiffFingerprint,
|
|
14
|
-
extractReviewedSnapshotTree,
|
|
15
12
|
findAuthoritativeReviewCodeArtifact,
|
|
16
13
|
loadPostReviewConfig,
|
|
17
14
|
parseReviewVerdict,
|
|
@@ -23,7 +20,6 @@ import { inspectPlatformPullRequest } from "../platform/pull-requests.ts";
|
|
|
23
20
|
import { resolveMaterializedReviewedHeadRelation } from "../platform/change-request-git-evidence.ts";
|
|
24
21
|
import { resolveReviewedHeadRelation } from "../platform/merged-pr-equivalence.ts";
|
|
25
22
|
import { resolveLocalReviewedCommitRelation } from "../git/reviewed-commit-equivalence.ts";
|
|
26
|
-
import { resolveBranchWorktree } from "../git/branch-worktree.ts";
|
|
27
23
|
import { parseTypedTaskFrontmatter } from "./frontmatter.ts";
|
|
28
24
|
import { LEDGER_TERMINAL, LEDGER_SECTION_MISSING_CODE, LEDGER_SECTION_MISSING_MESSAGE, parseLedgerDocument, summarizeLedgerStage, validateLedgerRows } from "./ledger.ts";
|
|
29
25
|
import type { LedgerRow } from "./ledger.ts";
|
|
@@ -33,12 +29,10 @@ import { inspectDecisionDetailDuplicates } from "./decision-details.ts";
|
|
|
33
29
|
import { parseImplementationInputs, type ImplementationInput } from "./implementation-inputs.ts";
|
|
34
30
|
import { scanVisibleMarkdown } from "./markdown.ts";
|
|
35
31
|
import { loadVerificationConfig } from "./verification-config.ts";
|
|
36
|
-
import { snapshotReview } from "../git/review-snapshot.ts";
|
|
37
32
|
import { inspectActivityLog } from "./activity-log.ts";
|
|
38
33
|
import { parseWorkflowWarnings } from "./workflow-warnings.ts";
|
|
39
34
|
import { OrchestrationStateError, readRun } from "./orchestration.ts";
|
|
40
35
|
import type { OrchestrationRun } from "./orchestration.ts";
|
|
41
|
-
import { resolveDeliveryTarget } from "./delivery-target.ts";
|
|
42
36
|
import { readPrDeliveryFact } from "./pr-delivery-fact.ts";
|
|
43
37
|
import { validateLocalArtifact } from "./local-artifact-finalization.ts";
|
|
44
38
|
import { getArtifactSchema } from "./artifact-schema.ts";
|
|
@@ -50,6 +44,8 @@ import { readManualValidationCompletion } from "./manual-validation-completion.t
|
|
|
50
44
|
import { sha256File } from "./artifact-receipts.ts";
|
|
51
45
|
import { summaryCommentState } from "../platform/pr-summary.ts";
|
|
52
46
|
import { taskIssueIdentity } from "../platform/task-identities.ts";
|
|
47
|
+
import { hasArtifactCompletionFact, hasArtifactCompletionLog } from './completion-facts.ts';
|
|
48
|
+
import { inspectReviewIdentity } from './review-identity.ts';
|
|
53
49
|
|
|
54
50
|
const TASK_ENUMS = {
|
|
55
51
|
type: ["feature", "bugfix", "refactor", "docs", "chore"],
|
|
@@ -1159,12 +1155,16 @@ function checkReviewFact({ taskDir, artifactFile, repositoryRoot }: any): any {
|
|
|
1159
1155
|
}
|
|
1160
1156
|
|
|
1161
1157
|
const content = fs.readFileSync(resolvedArtifact.path, "utf8");
|
|
1158
|
+
if (!hasArtifactCompletionFact(task.content, resolvedArtifact.path, 'review-code.completed')) {
|
|
1159
|
+
return failResult("review-fact", `Review Code completion fact does not match ${path.basename(resolvedArtifact.path)}`);
|
|
1160
|
+
}
|
|
1161
|
+
if (!hasArtifactCompletionLog(task.content, path.basename(resolvedArtifact.path), 'review-code.completed')) {
|
|
1162
|
+
return failResult("review-fact", `Review Code completion entry does not reference ${path.basename(resolvedArtifact.path)}`);
|
|
1163
|
+
}
|
|
1162
1164
|
const verdict = parseReviewVerdict(content);
|
|
1163
1165
|
const reviewTargetHead = extractReviewTargetHead(content);
|
|
1164
1166
|
const reviewReviewedHead = extractReviewedHead(content);
|
|
1165
1167
|
const reviewDiffBase = extractReviewDiffBase(content);
|
|
1166
|
-
const reviewedFingerprint = extractReviewDiffFingerprint(content);
|
|
1167
|
-
const reviewedTree = extractReviewedSnapshotTree(content);
|
|
1168
1168
|
|
|
1169
1169
|
if (!["通过", "需要修改", "拒绝", "Approved", "Changes Requested", "Rejected"].includes(verdict)) {
|
|
1170
1170
|
return failResult("review-fact", `Unsupported review verdict '${verdict}'`);
|
|
@@ -1179,86 +1179,20 @@ function checkReviewFact({ taskDir, artifactFile, repositoryRoot }: any): any {
|
|
|
1179
1179
|
return failResult("review-fact", "Review fact must record target head, reviewed head, and diff base");
|
|
1180
1180
|
}
|
|
1181
1181
|
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
let targetHead;
|
|
1186
|
-
let diffBase;
|
|
1187
|
-
try {
|
|
1188
|
-
const taskRepositoryRoot = execFileSync("git", ["-C", taskDir, "rev-parse", "--show-toplevel"], { encoding: "utf8" }).trim();
|
|
1189
|
-
gitRoot = reviewWorktreeForTask(taskRepositoryRoot, String(task.metadata.branch || "").trim()) ?? taskRepositoryRoot;
|
|
1190
|
-
head = execFileSync("git", ["-C", gitRoot, "rev-parse", "HEAD"], { encoding: "utf8" }).trim();
|
|
1191
|
-
const target = resolveDeliveryTarget(gitRoot, { remote: deliveryRemote, baseRef: deliveryBaseRef });
|
|
1192
|
-
if (!target.ok) throw new Error(target.message);
|
|
1193
|
-
const reviewedRef = reviewReviewedHead;
|
|
1194
|
-
baseline = execFileSync("git", ["-C", gitRoot, "rev-parse", `${reviewedRef}^{commit}`], { encoding: "utf8" }).trim();
|
|
1195
|
-
targetHead = execFileSync("git", ["-C", gitRoot, "rev-parse", `${reviewTargetHead}^{commit}`], { encoding: "utf8" }).trim();
|
|
1196
|
-
const computed = execFileSync("git", ["-C", gitRoot, "merge-base", baseline, targetHead], { encoding: "utf8" }).trim();
|
|
1197
|
-
diffBase = execFileSync("git", ["-C", gitRoot, "rev-parse", `${reviewDiffBase}^{commit}`], { encoding: "utf8" }).trim();
|
|
1198
|
-
if (diffBase !== computed) throw new Error('saved review diff base does not match merge-base(reviewed head, target head)');
|
|
1199
|
-
} catch {
|
|
1200
|
-
return blockedResult(
|
|
1201
|
-
"review-fact",
|
|
1202
|
-
`Unable to resolve saved review commits in the task repository; re-run review-code`
|
|
1203
|
-
);
|
|
1204
|
-
}
|
|
1205
|
-
|
|
1206
|
-
if (baseline !== head) {
|
|
1207
|
-
return failResult(
|
|
1208
|
-
"review-fact",
|
|
1209
|
-
`Reviewed head ${baseline.slice(0, 8)} does not match current HEAD ${head.slice(0, 8)}; re-run review-code`
|
|
1210
|
-
);
|
|
1211
|
-
}
|
|
1212
|
-
|
|
1213
|
-
let actualSnapshot;
|
|
1214
|
-
try {
|
|
1215
|
-
actualSnapshot = snapshotReview({
|
|
1216
|
-
cwd: gitRoot,
|
|
1217
|
-
mode: "worktree",
|
|
1218
|
-
baseline,
|
|
1219
|
-
diffBase,
|
|
1220
|
-
globs: resolvePostReviewGlobs({}, loadPostReviewConfig(repositoryRoot))
|
|
1221
|
-
});
|
|
1222
|
-
} catch {
|
|
1223
|
-
return blockedResult(
|
|
1224
|
-
"review-fact",
|
|
1225
|
-
`Unable to recompute reviewed diff fingerprint from baseline ${baseline.slice(0, 8)}; re-run review-code`
|
|
1226
|
-
);
|
|
1227
|
-
}
|
|
1228
|
-
|
|
1229
|
-
if (actualSnapshot.fingerprint !== reviewedFingerprint) {
|
|
1230
|
-
return failResult(
|
|
1231
|
-
"review-fact",
|
|
1232
|
-
`Reviewed diff fingerprint does not match the current worktree for baseline ${baseline.slice(0, 8)}; re-run review-code`
|
|
1233
|
-
);
|
|
1234
|
-
}
|
|
1235
|
-
|
|
1236
|
-
if (!reviewedTree || actualSnapshot.tree !== reviewedTree) {
|
|
1237
|
-
return failResult(
|
|
1238
|
-
"review-fact",
|
|
1239
|
-
`Reviewed snapshot tree does not match the current worktree for baseline ${baseline.slice(0, 8)}; re-run review-code`
|
|
1240
|
-
);
|
|
1182
|
+
const identity = inspectReviewIdentity(taskDir, content, repositoryRoot);
|
|
1183
|
+
if (identity.status !== 'matched' || !identity.reviewedHead) {
|
|
1184
|
+
return failResult('review-fact', `Review identity is ${identity.status}: ${identity.message}; re-run review-code`);
|
|
1241
1185
|
}
|
|
1186
|
+
const baseline = identity.reviewedHead;
|
|
1242
1187
|
|
|
1243
1188
|
if (["通过", "Approved"].includes(verdict)) {
|
|
1244
1189
|
const lastReviewedCommit = String(task.metadata.last_reviewed_commit || "").trim();
|
|
1245
|
-
|
|
1246
|
-
"git",
|
|
1247
|
-
["-C", gitRoot, "rev-parse", `${baseline}^{tree}`],
|
|
1248
|
-
{ encoding: "utf8" }
|
|
1249
|
-
).trim();
|
|
1250
|
-
if (cleanSnapshot && lastReviewedCommit !== baseline) {
|
|
1190
|
+
if (lastReviewedCommit !== baseline) {
|
|
1251
1191
|
return failResult(
|
|
1252
1192
|
"review-fact",
|
|
1253
1193
|
`Approved clean review must set task last_reviewed_commit to reviewed head ${baseline.slice(0, 8)}`
|
|
1254
1194
|
);
|
|
1255
1195
|
}
|
|
1256
|
-
if (!cleanSnapshot && lastReviewedCommit) {
|
|
1257
|
-
return failResult(
|
|
1258
|
-
"review-fact",
|
|
1259
|
-
"Approved review with uncommitted changes must remain unanchored until commit"
|
|
1260
|
-
);
|
|
1261
|
-
}
|
|
1262
1196
|
}
|
|
1263
1197
|
|
|
1264
1198
|
return passResult(
|
|
@@ -1267,13 +1201,6 @@ function checkReviewFact({ taskDir, artifactFile, repositoryRoot }: any): any {
|
|
|
1267
1201
|
);
|
|
1268
1202
|
}
|
|
1269
1203
|
|
|
1270
|
-
function reviewWorktreeForTask(repositoryRoot: string, branch: string): string | null {
|
|
1271
|
-
if (!branch) return null;
|
|
1272
|
-
const worktree = resolveBranchWorktree(repositoryRoot, branch);
|
|
1273
|
-
if (worktree) return worktree;
|
|
1274
|
-
throw new Error(`Task branch '${branch}' is not checked out in a registered worktree`);
|
|
1275
|
-
}
|
|
1276
|
-
|
|
1277
1204
|
function resolvePostReviewBaseline({ gitRoot, lastReviewedCommit, reviewArtifact }: any): any {
|
|
1278
1205
|
if (SHA_PATTERN.test(lastReviewedCommit) && gitCommitExists(gitRoot, lastReviewedCommit)) {
|
|
1279
1206
|
return { ok: true, sha: lastReviewedCommit };
|
package/lib/task/verification.ts
CHANGED
|
@@ -134,46 +134,42 @@ function statusLabel(status: unknown): string {
|
|
|
134
134
|
return status === 'fail' ? 'FAIL' : status === 'blocked' ? 'BLOCKED' : 'pass';
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
-
function renderPayload(payload: Record<string, unknown>): string {
|
|
138
|
-
const lines: string[] = [];
|
|
139
|
-
if (Array.isArray(payload.checks)) {
|
|
140
|
-
const gateMode = typeof payload.gate === 'string';
|
|
141
|
-
lines.push(gateMode
|
|
142
|
-
? `Verification: ${payload.gate} | Skill: ${payload.skill}`
|
|
143
|
-
: `Check: ${payload.status} | Skill: ${payload.skill} | Type: ${payload.type}`, '');
|
|
144
|
-
for (const check of payload.checks as Array<Record<string, unknown>>) {
|
|
145
|
-
const raw = statusLabel(check.status);
|
|
146
|
-
const effective = statusLabel(check.effectiveStatus ?? check.status);
|
|
147
|
-
const reason = check.reason ?? 'CHECK_FAILED';
|
|
148
|
-
const message = check.message ?? reason;
|
|
149
|
-
lines.push(` [${effective}] ${check.checkId ?? check.type} (${check.classification ?? 'hard'}; raw ${raw}; reason ${reason}) - ${message}; ${check.action ?? 'Review validation output'}`);
|
|
150
|
-
}
|
|
151
|
-
const summary = payload.summary ?? (() => {
|
|
152
|
-
const checks = payload.checks as Array<Record<string, unknown>>;
|
|
153
|
-
const statuses = checks.map((check) => check.effectiveStatus ?? check.status);
|
|
154
|
-
return `${statuses.filter((status) => status === 'pass').length} passed, ${statuses.filter((status) => status === 'fail').length} failed${statuses.includes('blocked') ? `, ${statuses.filter((status) => status === 'blocked').length} blocked` : ''}`;
|
|
155
|
-
})();
|
|
156
|
-
lines.push('', `Result: ${summary} - ${payload.action}`);
|
|
157
|
-
} else {
|
|
158
|
-
lines.push(`Check: ${payload.status} | Skill: ${payload.skill} | Type: ${payload.type}`, '');
|
|
159
|
-
const raw = statusLabel(payload.status);
|
|
160
|
-
const effective = statusLabel(payload.effectiveStatus ?? payload.status);
|
|
161
|
-
const reason = payload.reason ?? 'CHECK_FAILED';
|
|
162
|
-
lines.push(` [${effective}] ${payload.checkId ?? payload.type} (${payload.classification ?? 'hard'}; raw ${raw}; reason ${reason}) - ${payload.message ?? reason}; ${payload.action ?? 'Review validation output'}`);
|
|
163
|
-
const status = payload.effectiveStatus ?? payload.status;
|
|
164
|
-
const summary = status === 'pass' ? '1 passed, 0 failed'
|
|
165
|
-
: status === 'blocked' ? '0 passed, 0 failed, 1 blocked' : '0 passed, 1 failed';
|
|
166
|
-
const action = status === 'pass' ? 'Requested check passed'
|
|
167
|
-
: status === 'blocked' ? `Resolve blocked ${payload.type} check and re-run check`
|
|
168
|
-
: `Fix ${payload.type} issues and re-run check`;
|
|
169
|
-
lines.push('', `Result: ${summary} - ${action}`);
|
|
170
|
-
}
|
|
171
|
-
return `${lines.join('\n')}\n`;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
137
|
function renderTaskVerification(result: TaskVerificationResult): string {
|
|
175
138
|
if (result.status === 'failed') return `Verification failed: ${result.error?.code ?? 'VERIFY_FAILED'} - ${result.error?.message ?? 'unknown error'}\n`;
|
|
176
|
-
|
|
139
|
+
const target = `${result.event}${result.artifact ? ` (${result.artifact})` : ''}`;
|
|
140
|
+
const lines = [`Verification: ${result.status} | Target: ${target} | Skill: ${result.skill}`];
|
|
141
|
+
const checks = result.invocations.flatMap(({ payload }) => {
|
|
142
|
+
if (Array.isArray(payload.checks)) return payload.checks as Array<Record<string, unknown>>;
|
|
143
|
+
return [payload];
|
|
144
|
+
});
|
|
145
|
+
const counts = {
|
|
146
|
+
pass: checks.filter((check) => (check.effectiveStatus ?? check.status) === 'pass').length,
|
|
147
|
+
fail: checks.filter((check) => (check.effectiveStatus ?? check.status) === 'fail').length,
|
|
148
|
+
blocked: checks.filter((check) => (check.effectiveStatus ?? check.status) === 'blocked').length
|
|
149
|
+
};
|
|
150
|
+
const summary = `${counts.pass} passed, ${counts.fail} failed${counts.blocked > 0 ? `, ${counts.blocked} blocked` : ''}`;
|
|
151
|
+
lines.push('', `Result: ${summary}`);
|
|
152
|
+
|
|
153
|
+
for (const check of checks) {
|
|
154
|
+
const rawStatus = check.status;
|
|
155
|
+
const effectiveStatus = check.effectiveStatus ?? rawStatus;
|
|
156
|
+
const isSoftWarning = (rawStatus === 'fail' || rawStatus === 'blocked') && effectiveStatus === 'pass';
|
|
157
|
+
const reason = check.reason ?? 'CHECK_FAILED';
|
|
158
|
+
const message = check.message ?? reason;
|
|
159
|
+
const action = check.action ?? 'Review validation output';
|
|
160
|
+
const id = check.checkId ?? check.type;
|
|
161
|
+
const isHumanExemptionNotice = id === 'post-review-commit'
|
|
162
|
+
&& typeof message === 'string'
|
|
163
|
+
&& /\bhuman-decided (?:post-review )?exemption\b/i.test(message)
|
|
164
|
+
&& /\bPRC-\d+\s*:/.test(message);
|
|
165
|
+
if (effectiveStatus === 'pass' && !isSoftWarning && !isHumanExemptionNotice) continue;
|
|
166
|
+
lines.push(isSoftWarning
|
|
167
|
+
? `Warning: ${id} (${rawStatus === 'blocked' ? `raw BLOCKED; ` : ''}${reason}) - ${message}; ${action}`
|
|
168
|
+
: isHumanExemptionNotice
|
|
169
|
+
? `Notice: ${id} - ${message}; ${action}`
|
|
170
|
+
: ` [${statusLabel(effectiveStatus)}] ${id} (${reason}) - ${message}; ${action}`);
|
|
171
|
+
}
|
|
172
|
+
return `${lines.join('\n')}\n`;
|
|
177
173
|
}
|
|
178
174
|
|
|
179
175
|
export { VERIFICATION_CATALOG, renderTaskVerification, verifyTaskEvent };
|
package/lib/task/write.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
import crypto from 'node:crypto';
|
|
3
4
|
|
|
4
5
|
import { isValidAgentInfraVersion, VERSION } from '../version.ts';
|
|
5
6
|
import {
|
|
@@ -223,7 +224,7 @@ function errorDetails(error: unknown, fallback: TaskWriteErrorCode): TaskWriteEr
|
|
|
223
224
|
};
|
|
224
225
|
}
|
|
225
226
|
|
|
226
|
-
function
|
|
227
|
+
function writeTaskCore(request: TaskWriteRequest, options: TaskWriteOptions = {}): TaskWriteResult {
|
|
227
228
|
const resolved = options.taskLocation
|
|
228
229
|
? {
|
|
229
230
|
ok: true as const,
|
|
@@ -479,6 +480,119 @@ function writeTask(request: TaskWriteRequest, options: TaskWriteOptions = {}): T
|
|
|
479
480
|
return { ...successBase, status: 'applied', changed: true };
|
|
480
481
|
}
|
|
481
482
|
|
|
483
|
+
function archiveContentsHash(localDir: string): string {
|
|
484
|
+
const files: string[] = [];
|
|
485
|
+
const walk = (dir: string) => {
|
|
486
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
487
|
+
if (entry.name.includes('\n') || entry.name.includes('\r') || entry.name === 'manifest.md') {
|
|
488
|
+
throw new Error(`Archive source path is not valid: ${path.join(dir, entry.name)}`);
|
|
489
|
+
}
|
|
490
|
+
const target = path.join(dir, entry.name);
|
|
491
|
+
const stat = fs.lstatSync(target);
|
|
492
|
+
if (stat.isSymbolicLink()) throw new Error(`Archive source cannot contain symbolic links: ${target}`);
|
|
493
|
+
if (stat.isDirectory()) walk(target);
|
|
494
|
+
else if (stat.isFile()) {
|
|
495
|
+
if (entry.name !== 'contents.sha256') files.push(target);
|
|
496
|
+
}
|
|
497
|
+
else throw new Error(`Archive source cannot contain special files: ${target}`);
|
|
498
|
+
}
|
|
499
|
+
};
|
|
500
|
+
walk(localDir);
|
|
501
|
+
const rows = files
|
|
502
|
+
.map((file) => ({ file, relative: path.relative(localDir, file).split(path.sep).join('/') }))
|
|
503
|
+
.sort((left, right) => Buffer.compare(Buffer.from(left.relative), Buffer.from(right.relative)))
|
|
504
|
+
.map(({ file, relative }) => `${crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex')} ${relative}`);
|
|
505
|
+
return `${rows.join('\n')}${rows.length ? '\n' : ''}`;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
function writeArchiveContentsHash(localDir: string): void {
|
|
509
|
+
const contents = archiveContentsHash(localDir);
|
|
510
|
+
const hashPath = path.join(localDir, 'contents.sha256');
|
|
511
|
+
const tempPath = path.join(localDir, `.contents.sha256.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`);
|
|
512
|
+
try {
|
|
513
|
+
fs.writeFileSync(tempPath, contents, { flag: 'wx' });
|
|
514
|
+
fs.renameSync(tempPath, hashPath);
|
|
515
|
+
} catch (error) {
|
|
516
|
+
try {
|
|
517
|
+
fs.unlinkSync(tempPath);
|
|
518
|
+
} catch (cleanupError) {
|
|
519
|
+
if ((cleanupError as NodeJS.ErrnoException).code !== 'ENOENT') {
|
|
520
|
+
throw new Error(`${error instanceof Error ? error.message : String(error)}; failed to remove ${tempPath}: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
throw error;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
function restoreArchivedTask(taskMdPath: string, contents: Buffer, mode: number): void {
|
|
528
|
+
const tempPath = `${taskMdPath}.${process.pid}.${Math.random().toString(36).slice(2)}.rollback`;
|
|
529
|
+
fs.writeFileSync(tempPath, contents, { flag: 'wx', mode });
|
|
530
|
+
try {
|
|
531
|
+
fs.renameSync(tempPath, taskMdPath);
|
|
532
|
+
} catch (error) {
|
|
533
|
+
try {
|
|
534
|
+
fs.unlinkSync(tempPath);
|
|
535
|
+
} catch (cleanupError) {
|
|
536
|
+
if ((cleanupError as NodeJS.ErrnoException).code !== 'ENOENT') {
|
|
537
|
+
throw new Error(`${error instanceof Error ? error.message : String(error)}; failed to remove ${tempPath}: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
throw error;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
function writeTask(request: TaskWriteRequest, options: TaskWriteOptions = {}): TaskWriteResult {
|
|
545
|
+
const resolved = options.taskLocation
|
|
546
|
+
? {
|
|
547
|
+
ok: true as const,
|
|
548
|
+
repoRoot: options.taskLocation.repoRoot,
|
|
549
|
+
taskId: options.taskLocation.taskId,
|
|
550
|
+
taskDir: path.dirname(options.taskLocation.taskMdPath),
|
|
551
|
+
taskMdPath: options.taskLocation.taskMdPath,
|
|
552
|
+
state: options.taskLocation.state
|
|
553
|
+
}
|
|
554
|
+
: resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
|
|
555
|
+
if (!resolved.ok) {
|
|
556
|
+
return failure(request, { taskId: resolved.taskId, taskMdPath: null, actualState: null }, resolved.code, resolved.message);
|
|
557
|
+
}
|
|
558
|
+
if (resolved.state !== 'archive' || request.expectedState !== 'archive' || request.dryRun) {
|
|
559
|
+
return writeTaskCore(request, { ...options, taskLocation: {
|
|
560
|
+
repoRoot: resolved.repoRoot,
|
|
561
|
+
taskId: resolved.taskId,
|
|
562
|
+
taskMdPath: resolved.taskMdPath,
|
|
563
|
+
state: resolved.state
|
|
564
|
+
} });
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
const identity = { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, actualState: resolved.state };
|
|
568
|
+
try {
|
|
569
|
+
const originalTask = fs.readFileSync(resolved.taskMdPath);
|
|
570
|
+
const originalMode = fs.statSync(resolved.taskMdPath).mode;
|
|
571
|
+
archiveContentsHash(resolved.taskDir);
|
|
572
|
+
const result = writeTaskCore(request, { ...options, taskLocation: {
|
|
573
|
+
repoRoot: resolved.repoRoot,
|
|
574
|
+
taskId: resolved.taskId,
|
|
575
|
+
taskMdPath: resolved.taskMdPath,
|
|
576
|
+
state: resolved.state
|
|
577
|
+
} });
|
|
578
|
+
if (result.status === 'applied') {
|
|
579
|
+
try {
|
|
580
|
+
writeArchiveContentsHash(resolved.taskDir);
|
|
581
|
+
} catch (error) {
|
|
582
|
+
try {
|
|
583
|
+
restoreArchivedTask(resolved.taskMdPath, originalTask, originalMode);
|
|
584
|
+
} catch (rollbackError) {
|
|
585
|
+
throw new Error(`Archive checksum update failed: ${error instanceof Error ? error.message : String(error)}; task rollback failed: ${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)}`);
|
|
586
|
+
}
|
|
587
|
+
throw error;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
return result;
|
|
591
|
+
} catch (error) {
|
|
592
|
+
return failure(request, identity, 'TASK_READ_FAILED', error instanceof Error ? error.message : String(error));
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
482
596
|
export { writeTask, captureTaskWriteMetadata, canonicalTimestamp };
|
|
483
597
|
export type {
|
|
484
598
|
FrontmatterMutation,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fitlab-ai/agent-infra",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.7",
|
|
4
4
|
"description": "Bootstrap tool for AI multi-tool collaboration infrastructure — works with Claude Code, Codex, Antigravity CLI, and OpenCode",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -14,6 +14,7 @@ so you can quickly find "which ones to read" without opening each file.
|
|
|
14
14
|
- [`debugging-guide.md`](debugging-guide.md) — Structured debugging flow: gather evidence → form hypothesis → verify hypothesis → fix the root cause; no blind patch-and-retry.
|
|
15
15
|
- [`compatibility-policy.md`](compatibility-policy.md) — Compatibility by exception: admission evidence, implementation boundaries, exit conditions, and lifecycle review requirements.
|
|
16
16
|
- [`evidence-reporting.md`](evidence-reporting.md) — Minimum evidence semantics for state checks, successful summaries, exceptional results, identity fields, and sensitive data boundaries.
|
|
17
|
+
- [`validation-output.md`](validation-output.md) — User-facing validation summaries, failure diagnostics, soft warnings, and consumer boundaries.
|
|
17
18
|
- [`sync-content-generation.md`](sync-content-generation.md) — Producer-side Markdown constraints for task and lifecycle content synchronized to Issues.
|
|
18
19
|
- [`decision-qualification.md`](decision-qualification.md) — Constraint, candidate, human-confirmation, and six-artifact qualification-audit contract.
|
|
19
20
|
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
- [`debugging-guide.md`](debugging-guide.md) — 结构化调试流程:收集证据→形成假设→验证假设→修复根因,禁止盲目改代码重试。
|
|
14
14
|
- [`compatibility-policy.md`](compatibility-policy.md) — 兼容性默认关闭:准入证据、实现边界、退出条件与生命周期审查要求。
|
|
15
15
|
- [`evidence-reporting.md`](evidence-reporting.md) — 生命周期报告的状态核对、成功摘要、异常证据、身份字段和敏感信息边界。
|
|
16
|
+
- [`validation-output.md`](validation-output.md) — 面向用户的校验状态摘要、失败诊断、软警告及消费边界。
|
|
16
17
|
- [`sync-content-generation.md`](sync-content-generation.md) — 同步到 Issue 的任务和生命周期 Markdown 生成约束。
|
|
17
18
|
- [`decision-qualification.md`](decision-qualification.md) — 约束、候选、人工确认和六类 artifact 资格审计契约。
|
|
18
19
|
|
|
@@ -6,7 +6,8 @@ Any analysis, plan, implementation, or review that decides whether a human decis
|
|
|
6
6
|
|
|
7
7
|
- The `### Constraints` and `### Candidate and Rejected Options` tables in `task.md` are the only constraint and candidate fact source.
|
|
8
8
|
- The constraint table uses `constraint_id`, `statement`, `status`, `authority`, `source`, `evidence`, `derived_from`, and `approval_evidence`; the candidate table uses `candidate_id`, `statement`, `status`, `constraint_ids`, `impact`, and `evidence`.
|
|
9
|
-
-
|
|
9
|
+
- Qualification audits are optional in all six lifecycle artifact families. When `## Qualification Audit` is present, it must contain three decision tables (constraint dependencies, candidate qualification, classification results) and one snapshot row (`task_input_digest`, `non_constraint_input_digest`). Candidate qualification must cover the complete candidate set in the task.
|
|
10
|
+
- Lifecycle input relationships belong in the `Artifact Lifecycle Receipts` section of `task.md`. Freeze each stage's actual artifact inputs and SHA-256 values at stage start, then verify and record each input edge at completion. Do not duplicate lifecycle edges in qualification audits.
|
|
10
11
|
|
|
11
12
|
## Status and confirmation
|
|
12
13
|
|
|
@@ -17,6 +18,6 @@ Any analysis, plan, implementation, or review that decides whether a human decis
|
|
|
17
18
|
|
|
18
19
|
## Invalidation and review
|
|
19
20
|
|
|
20
|
-
When a
|
|
21
|
+
When a lifecycle artifact is replaced, start from the old artifact and follow verified input edges in the task receipts to find and invalidate every downstream consumer. Exclude the new artifact from the old graph. If any relation is missing, identity or SHA-256 does not match, or the graph cannot be verified, use the existing static downstream invalidation scope.
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
When a qualification audit is present, missing or unknown references and digest mismatches block finalization. Audits in the old format with an upstream-relations table must be regenerated in the current format. Formatting-only changes must not change semantic digests; changes to meaning, provenance, status, or candidates require a new audit.
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
- `task.md` 的 `### 约束` 和 `### 候选与否决方案` 是唯一约束/候选事实源。
|
|
8
8
|
- 约束表必须使用 `constraint_id`、`statement`、`status`、`authority`、`source`、`evidence`、`derived_from`、`approval_evidence`;候选表必须使用 `candidate_id`、`statement`、`status`、`constraint_ids`、`impact`、`evidence`。
|
|
9
|
-
-
|
|
9
|
+
- 六类阶段产物可以省略资格审计。若填写 `## 资格审计`,必须包含约束依赖、候选资格、分类结果三张决策表,以及一行资格快照(`task_input_digest`、`non_constraint_input_digest`)。候选资格必须覆盖任务中的完整候选集合。
|
|
10
|
+
- 生命周期输入关系由 `task.md` 的“产物生命周期收据”记录;阶段开始时冻结实际输入 artifact 和 SHA-256,完成时验证后写入每条输入边。不要在资格审计中复制生命周期关系。
|
|
10
11
|
|
|
11
12
|
## 状态与确认
|
|
12
13
|
|
|
@@ -17,6 +18,6 @@
|
|
|
17
18
|
|
|
18
19
|
## 失效与审查
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
替换某个阶段产物时,系统从被替换的旧 artifact 出发,沿任务收据中验证过的输入边计算所有下游消费者,并使旧消费者失效;新产物不进入旧图。若任一关系缺失、身份不匹配、SHA-256 不匹配或图无法验证,则使用既有静态下游失效范围。
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
资格审计存在时,缺失、未知引用或 digest 不匹配都必须拒绝收尾。旧版包含“上游关系”表的资格审计不再读取,应按当前格式重新生成。排版变化不应改变语义 digest;语义、来源、状态或候选变化必须触发重新审计。
|
|
@@ -21,8 +21,7 @@ Record a reproducible command or entry point, the exact file/line/object/version
|
|
|
21
21
|
- Preserve artifact SHA-256, semantic digest, review head, receipt, request-id, snapshot tree, and platform marker exactly.
|
|
22
22
|
- The Issue continues to mirror the complete report; the report must not depend on logs accessible only on the local machine.
|
|
23
23
|
- Manual validation keeps its stricter basename-only and sanitized-result rules; this shared rule does not expand public fields.
|
|
24
|
-
- A `$ ` command line satisfies the structural gate but does not require complete successful output.
|
|
25
24
|
|
|
26
25
|
## Evidence Pairing
|
|
27
26
|
|
|
28
|
-
Pair every verification claim with
|
|
27
|
+
Pair every verification claim with an executable command and a proportionate result summary. Include a decisive raw excerpt only for failure, blocking, or dispute conclusions. When a command contains sensitive arguments, use its allowed public name or a redacted command.
|
|
@@ -21,8 +21,7 @@
|
|
|
21
21
|
- artifact SHA-256、semantic digest、review head、receipt、request-id、快照树和平台 marker 必须精确保留。
|
|
22
22
|
- Issue 继续镜像报告全文;报告不得依赖只有本机可访问的日志。
|
|
23
23
|
- 人工验证继续使用 basename-only、sanitized result 等更严格规则;共享规则不扩大可公开字段。
|
|
24
|
-
- `$ ` 命令行标记满足结构门禁,但不要求附带完整成功输出。
|
|
25
24
|
|
|
26
25
|
## 证据配对
|
|
27
26
|
|
|
28
|
-
|
|
27
|
+
报告中的每个验证断言都应配一个可执行命令和相称结果摘要;只有失败、阻塞或争议结论才附决定性原文摘录。命令含敏感参数时使用允许公开的命令名或脱敏命令。
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Validation Output Summary
|
|
2
|
+
|
|
3
|
+
This rule governs how `task-verify --format text` and lifecycle skills present validation results to users. It does not change validation logic, structured results, or persisted evidence requirements.
|
|
4
|
+
|
|
5
|
+
## Overall Summary
|
|
6
|
+
|
|
7
|
+
- Show the overall status, validation target, and pass, fail, and blocked counts.
|
|
8
|
+
- For successful results, show only the summary; do not list passing check names.
|
|
9
|
+
- Keep failure and blocked states distinct. List only effective failed or blocked checks, with a stable identifier, concise reason, and actionable step.
|
|
10
|
+
- A soft check whose raw status is failed but effective status is pass must not count as a failure. When a user-facing notice is needed, show a concise warning with the necessary reason and action.
|
|
11
|
+
- A soft check whose raw status is blocked but effective status is pass must also show a concise warning that preserves the raw blocked state, necessary reason, and action.
|
|
12
|
+
- If a passing result carries a consumed human exemption or other required exception evidence, show a concise notice that preserves the exception evidence; continue to count the check by its effective status.
|
|
13
|
+
|
|
14
|
+
## Consumer Boundaries
|
|
15
|
+
|
|
16
|
+
- Do not copy complete successful stdout into the final response. Read structured details or rerun the command when passing check details are needed.
|
|
17
|
+
- Consume structured host finalization results through their status, receipt, and warning projection; do not present receipt contents as the user summary.
|
|
18
|
+
- Persisted lifecycle reports continue to follow `evidence-reporting.md`, recording reproducible scope, status, and necessary evidence. Issue artifact comments continue to sync the required report content.
|
|
19
|
+
- JSON payloads, check order, check set, effective-status decisions, and exit codes remain unchanged.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# 校验输出摘要规则
|
|
2
|
+
|
|
3
|
+
本规则约束 `task-verify --format text` 及生命周期技能向用户展示校验结果的方式。它不改变校验逻辑、结构化结果或持久化证据要求。
|
|
4
|
+
|
|
5
|
+
## 总体摘要
|
|
6
|
+
|
|
7
|
+
- 展示总体状态、校验目标,以及通过、失败和阻塞计数。
|
|
8
|
+
- 成功结果只展示摘要,不列出通过项名称。
|
|
9
|
+
- 失败与阻塞保持不同状态;只列出有效失败或阻塞项的稳定标识、简明原因和可执行动作。
|
|
10
|
+
- raw 状态失败但 effective 状态通过的软检查,不得计入失败;需要提醒用户时用简短警告及必要原因和动作说明。
|
|
11
|
+
- raw 状态阻塞但 effective 状态通过的软检查,也必须显示简短警告,并保留 raw 阻塞状态、必要原因和动作说明。
|
|
12
|
+
- 通过结果若包含已消费的人工作出豁免或其他必须保留的例外证据,应显示简短提示并保留例外证据;该检查仍按 effective 状态计数。
|
|
13
|
+
|
|
14
|
+
## 消费边界
|
|
15
|
+
|
|
16
|
+
- 不把完整成功 stdout 复制到最终回复。需要检查通过项明细时,按需读取结构化结果或重新运行命令。
|
|
17
|
+
- 宿主 finalization 等结构化结果按其状态、receipt 和 warning projection 消费;不要将 receipt 原文当作用户摘要。
|
|
18
|
+
- 持久化生命周期报告继续遵循 `evidence-reporting.md`,记录可复现范围、状态和必要证据;Issue artifact 评论继续同步所需报告内容。
|
|
19
|
+
- JSON payload、检查顺序、检查集合、effective status 判定和退出码均不受本规则影响。
|
|
@@ -21,7 +21,7 @@ The analysis artifact must record `Path`, `Basis`, `Unmet Higher-path Conditions
|
|
|
21
21
|
|
|
22
22
|
Before generating the analysis report, read `.agents/rules/evidence-reporting.md`. Record the command, target scope, status or structured result, actual result, and uncovered parts for state checks and successful checks; include decisive raw excerpts only for failures, blocking conditions, or disputes.
|
|
23
23
|
|
|
24
|
-
- When evaluating candidate qualification or `HD-N`, read `.agents/rules/decision-qualification.md`, audit normalized task constraints/candidates, and record the
|
|
24
|
+
- When evaluating candidate qualification or `HD-N`, read `.agents/rules/decision-qualification.md`, audit normalized task constraints/candidates, and record the three qualification-audit decision tables and snapshot in the analysis artifact; unknown or unconfirmed constraints must not automatically exclude a candidate
|
|
25
25
|
- This skill only outputs a requirements analysis document (`analysis.md` or `analysis-r{N}.md`) and does not modify any business code
|
|
26
26
|
- Base the analysis strictly on the existing task input, requirements, context, and source information in `task.md`
|
|
27
27
|
- Before generating task or lifecycle Markdown that will be synchronized to an Issue, read `.agents/rules/sync-content-generation.md` and apply its producer-side constraints; the sync path does not parse or rewrite the body
|
|
@@ -258,6 +258,8 @@ Run the verification gate to confirm the task artifact and sync state are valid:
|
|
|
258
258
|
agent-infra-internal task-verify {task-id} analyze.completed --artifact {analysis-artifact} --format text
|
|
259
259
|
```
|
|
260
260
|
|
|
261
|
+
Present the verification summary per `.agents/rules/validation-output.md`, retaining necessary failure, blocked, and soft-warning diagnostics.
|
|
262
|
+
|
|
261
263
|
Handle the result as follows:
|
|
262
264
|
- exit code 0 (all checks passed) -> continue to the "Inform User" step
|
|
263
265
|
- exit code 1 (validation failed) -> fix the reported issues and run the gate again
|
|
@@ -21,7 +21,7 @@ description: >
|
|
|
21
21
|
|
|
22
22
|
生成分析报告时,先读取 `.agents/rules/evidence-reporting.md`。状态核对和成功检查记录命令、目标范围、状态/结构化结果、实际结果和未覆盖部分;失败、阻塞或争议才附决定性原文摘录。
|
|
23
23
|
|
|
24
|
-
- 涉及候选资格或 `HD-N` 判断时,先读取 `.agents/rules/decision-qualification.md`,基于 task.md
|
|
24
|
+
- 涉及候选资格或 `HD-N` 判断时,先读取 `.agents/rules/decision-qualification.md`,基于 task.md 规范化约束/候选完成资格审计,并在分析产物记录三张资格审计决策表和资格快照;不得把来源不明或未确认约束自动升级为排除条件
|
|
25
25
|
- 本技能仅产出需求分析文档(`analysis.md` 或 `analysis-r{N}.md`)—— 不修改任何业务代码
|
|
26
26
|
- 严格基于 `task.md` 中已有的任务输入、需求、上下文和来源信息展开分析
|
|
27
27
|
- 生成会同步到 Issue 的任务或生命周期 Markdown 前,先读取 `.agents/rules/sync-content-generation.md` 并遵循其中的生成端约束;同步端不解析或改写正文
|
|
@@ -201,7 +201,7 @@ agent-infra-internal task-artifact {task-id} init --family analysis --artifact {
|
|
|
201
201
|
|
|
202
202
|
## 资格审计
|
|
203
203
|
|
|
204
|
-
>
|
|
204
|
+
> 仅当本阶段实际判断候选资格、约束依赖或人工裁决资格时填写本节,并按 `.agents/rules/decision-qualification.md` 完整记录三张决策表和资格快照;否则删除整个审计段。
|
|
205
205
|
|
|
206
206
|
## 假设
|
|
207
207
|
|
|
@@ -263,7 +263,7 @@ agent-infra-internal task-verify {task-id} analyze.completed --artifact {analysi
|
|
|
263
263
|
- 退出码 1(校验失败)-> 根据输出修复问题后重新运行校验
|
|
264
264
|
- 退出码 2(网络中断)-> 停止执行并告知用户需要人工介入
|
|
265
265
|
|
|
266
|
-
|
|
266
|
+
按 `.agents/rules/validation-output.md` 展示当次校验摘要;没有当次校验输出,不得声明完成。
|
|
267
267
|
|
|
268
268
|
### 9. 告知用户
|
|
269
269
|
|
|
@@ -7,7 +7,7 @@ description: >
|
|
|
7
7
|
|
|
8
8
|
# Archive Completed Tasks
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Archive completed tasks from `.agents/workspace/completed/` into `.agents/workspace/archive/YYYY/MM/DD/TASK-xxx/local/` and rebuild a three-level archive index. Local task materials live in `local/` with a path-sorted `contents.sha256`; the TASK root contains no ordinary files.
|
|
11
11
|
- root manifest: `.agents/workspace/archive/manifest.md`
|
|
12
12
|
- yearly manifest: `.agents/workspace/archive/YYYY/manifest.md`
|
|
13
13
|
- monthly manifest: `.agents/workspace/archive/YYYY/MM/manifest.md`
|
|
@@ -32,7 +32,7 @@ bash .agents/skills/archive-tasks/scripts/archive-tasks.sh [--days N | --before
|
|
|
32
32
|
|
|
33
33
|
The script is responsible for:
|
|
34
34
|
- reading `completed_at` from `task.md` frontmatter and falling back to `updated_at`
|
|
35
|
-
-
|
|
35
|
+
- storing local task materials under `YYYY/MM/DD/TASK-xxx/local/` without compression
|
|
36
36
|
- skipping already archived, missing, or malformed tasks
|
|
37
37
|
- rebuilding root, yearly, and monthly manifests from all archived tasks
|
|
38
38
|
- printing an archive and skip summary
|
|
@@ -7,7 +7,7 @@ description: >
|
|
|
7
7
|
|
|
8
8
|
# 归档已完成任务
|
|
9
9
|
|
|
10
|
-
将 `.agents/workspace/completed/`
|
|
10
|
+
将 `.agents/workspace/completed/` 中的已完成任务归档到 `.agents/workspace/archive/YYYY/MM/DD/TASK-xxx/local/`,并重建三级归档索引。TASK 本地材料位于 `local/`,含按路径排序的 `contents.sha256`;TASK 根目录不存放普通文件。
|
|
11
11
|
- 根 manifest:`.agents/workspace/archive/manifest.md`
|
|
12
12
|
- 年 manifest:`.agents/workspace/archive/YYYY/manifest.md`
|
|
13
13
|
- 月 manifest:`.agents/workspace/archive/YYYY/MM/manifest.md`
|
|
@@ -32,7 +32,7 @@ bash .agents/skills/archive-tasks/scripts/archive-tasks.sh [--days N | --before
|
|
|
32
32
|
|
|
33
33
|
脚本负责:
|
|
34
34
|
- 解析 `task.md` frontmatter 中的 `completed_at`(缺失时回退到 `updated_at`)
|
|
35
|
-
- 按 `YYYY/MM/DD/TASK-xxx/`
|
|
35
|
+
- 按 `YYYY/MM/DD/TASK-xxx/local/` 保存任务本地材料,不压缩
|
|
36
36
|
- 跳过已归档、缺少元数据或不存在的任务
|
|
37
37
|
- 全量重建根 / 年 / 月三级 manifest
|
|
38
38
|
- 输出归档与跳过摘要
|