@fitlab-ai/agent-infra 0.9.1 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -4
- package/README.zh-CN.md +16 -4
- package/bin/cli.ts +12 -0
- package/dist/bin/cli.js +14 -0
- package/dist/bin/internal-cli.js +15 -0
- package/dist/lib/agent-client.js +163 -0
- package/dist/lib/agent-clients/adapter.js +294 -0
- package/dist/lib/agent-clients/adapters/claude-code.js +62 -0
- package/dist/lib/agent-clients/adapters/codex-sandbox.js +210 -0
- package/dist/lib/agent-clients/adapters/codex.js +54 -0
- package/dist/lib/agent-clients/adapters/gemini-cli.js +64 -0
- package/dist/lib/agent-clients/adapters/index.js +20 -0
- package/dist/lib/agent-clients/adapters/opencode.js +64 -0
- package/dist/lib/agent-clients/config.js +177 -0
- package/dist/lib/agent-clients/custom-tuis.js +99 -0
- package/dist/lib/agent-clients/invocation.js +9 -0
- package/dist/lib/agent-clients/next-steps.js +38 -0
- package/dist/lib/agent-clients/project-assets.js +45 -0
- package/dist/lib/agent-clients/reconcile.js +235 -0
- package/dist/lib/agent-clients/registry.js +72 -0
- package/dist/lib/agent-clients/schema.js +57 -0
- package/dist/lib/agent-clients/types.js +29 -0
- package/dist/lib/builtin-tuis.js +9 -14
- package/dist/lib/defaults.json +85 -73
- package/dist/lib/git/review-snapshot.js +25 -10
- package/dist/lib/git/reviewed-commit-equivalence.js +110 -0
- package/dist/lib/init.js +47 -91
- package/dist/lib/internal/agent-client.js +117 -0
- package/dist/lib/internal/git-workflow.js +1 -1
- package/dist/lib/internal/release-workflow.js +71 -16
- package/dist/lib/internal/task-orchestration.js +151 -0
- package/dist/lib/internal/task-review.js +65 -0
- package/dist/lib/merge.js +2 -1
- package/dist/lib/platform/adapters.js +38 -1
- package/dist/lib/platform/change-request-git-evidence.js +113 -0
- package/dist/lib/platform/merged-pr-equivalence.js +41 -11
- package/dist/lib/platform/pr-checks.js +38 -10
- package/dist/lib/platform/pull-requests.js +110 -6
- package/dist/lib/platform/releases.js +1 -1
- package/dist/lib/platform/verification-required.js +8 -10
- package/dist/lib/prompt.js +15 -3
- package/dist/lib/release/channels.js +4 -1
- package/dist/lib/release/workflow.js +4 -2
- package/dist/lib/remove-dir.js +25 -0
- package/dist/lib/run/tui.js +8 -2
- package/dist/lib/sandbox/agent-client-reconciler.js +234 -0
- package/dist/lib/sandbox/clipboard/linux.js +2 -1
- package/dist/lib/sandbox/commands/create.js +76 -180
- package/dist/lib/sandbox/commands/enter.js +17 -1
- package/dist/lib/sandbox/commands/prune.js +2 -2
- package/dist/lib/sandbox/commands/rm.js +3 -2
- package/dist/lib/sandbox/config.js +21 -4
- package/dist/lib/sandbox/constants.js +3 -0
- package/dist/lib/sandbox/dockerfile.js +2 -1
- package/dist/lib/sandbox/managed-fs.js +10 -5
- package/dist/lib/sandbox/recovery.js +52 -36
- package/dist/lib/sandbox/shell.js +1 -1
- package/dist/lib/sandbox/tool-types.js +8 -0
- package/dist/lib/sandbox/tools.js +2 -126
- package/dist/lib/task/artifact-lifecycle.js +1 -49
- package/dist/lib/task/commands/decisions.js +50 -20
- package/dist/lib/task/delegation-receipts.js +107 -0
- package/dist/lib/task/events.js +100 -1
- package/dist/lib/task/orchestration.js +420 -0
- package/dist/lib/task/review-artifacts.js +143 -59
- package/dist/lib/task/review-finalization.js +166 -0
- package/dist/lib/task/review-fingerprint.js +4 -0
- package/dist/lib/task/verification-checks.js +2 -1
- package/dist/lib/task/verification-engine.js +156 -28
- package/dist/lib/task/verification-review.js +1 -1
- package/dist/lib/task/verification.js +3 -1
- package/dist/lib/task/workspace-snapshot.js +34 -0
- package/dist/lib/update.js +42 -161
- package/lib/agent-client.ts +214 -0
- package/lib/agent-clients/adapter.ts +461 -0
- package/lib/agent-clients/adapters/claude-code.ts +70 -0
- package/lib/agent-clients/adapters/codex-sandbox.ts +245 -0
- package/lib/agent-clients/adapters/codex.ts +58 -0
- package/lib/agent-clients/adapters/gemini-cli.ts +65 -0
- package/lib/agent-clients/adapters/index.ts +27 -0
- package/lib/agent-clients/adapters/opencode.ts +66 -0
- package/lib/agent-clients/config.ts +278 -0
- package/lib/agent-clients/custom-tuis.ts +149 -0
- package/lib/agent-clients/invocation.ts +19 -0
- package/lib/agent-clients/next-steps.ts +72 -0
- package/lib/agent-clients/project-assets.ts +96 -0
- package/lib/agent-clients/reconcile.ts +324 -0
- package/lib/agent-clients/registry.ts +144 -0
- package/lib/agent-clients/schema.ts +62 -0
- package/lib/agent-clients/types.ts +78 -0
- package/lib/benchmark/schemas/v1.0.0/case-manifest.schema.json +120 -0
- package/lib/benchmark/schemas/v1.0.0/common.schema.json +109 -0
- package/lib/benchmark/schemas/v1.0.0/grader-result.schema.json +160 -0
- package/lib/benchmark/schemas/v1.0.0/run-manifest.schema.json +122 -0
- package/lib/benchmark/schemas/v1.0.0/subject.schema.json +227 -0
- package/lib/builtin-tuis.ts +16 -15
- package/lib/defaults.json +24 -12
- package/lib/git/review-snapshot.ts +39 -9
- package/lib/git/reviewed-commit-equivalence.ts +135 -0
- package/lib/init.ts +53 -121
- package/lib/internal/agent-client.ts +131 -0
- package/lib/internal/git-workflow.ts +1 -1
- package/lib/internal/release-workflow.ts +68 -16
- package/lib/internal/task-orchestration.ts +132 -0
- package/lib/internal/task-review.ts +65 -0
- package/lib/merge.ts +2 -1
- package/lib/platform/adapters.ts +142 -3
- package/lib/platform/change-request-git-evidence.ts +159 -0
- package/lib/platform/merged-pr-equivalence.ts +51 -14
- package/lib/platform/pr-checks.ts +50 -22
- package/lib/platform/pull-requests.ts +134 -25
- package/lib/platform/releases.ts +1 -1
- package/lib/platform/verification-required.ts +12 -10
- package/lib/prompt.ts +16 -3
- package/lib/release/channels.ts +4 -1
- package/lib/release/workflow.ts +4 -3
- package/lib/remove-dir.ts +28 -0
- package/lib/run/tui.ts +9 -1
- package/lib/sandbox/agent-client-reconciler.ts +378 -0
- package/lib/sandbox/clipboard/linux.ts +2 -1
- package/lib/sandbox/commands/create.ts +111 -192
- package/lib/sandbox/commands/enter.ts +23 -1
- package/lib/sandbox/commands/prune.ts +2 -2
- package/lib/sandbox/commands/rm.ts +3 -2
- package/lib/sandbox/config.ts +31 -4
- package/lib/sandbox/constants.ts +6 -0
- package/lib/sandbox/dockerfile.ts +2 -1
- package/lib/sandbox/managed-fs.ts +18 -5
- package/lib/sandbox/recovery.ts +98 -67
- package/lib/sandbox/shell.ts +1 -1
- package/lib/sandbox/tool-types.ts +143 -0
- package/lib/sandbox/tools.ts +5 -157
- package/lib/task/artifact-lifecycle.ts +1 -38
- package/lib/task/commands/decisions.ts +53 -20
- package/lib/task/delegation-receipts.ts +170 -0
- package/lib/task/events.ts +110 -2
- package/lib/task/orchestration.ts +543 -0
- package/lib/task/review-artifacts.ts +201 -69
- package/lib/task/review-finalization.ts +275 -0
- package/lib/task/review-fingerprint.ts +5 -0
- package/lib/task/verification-checks.ts +2 -1
- package/lib/task/verification-engine.ts +177 -28
- package/lib/task/verification-review.ts +1 -0
- package/lib/task/verification.ts +5 -2
- package/lib/task/workspace-snapshot.ts +36 -0
- package/lib/update.ts +48 -184
- package/package.json +2 -2
- package/templates/.agents/README.en.md +21 -20
- package/templates/.agents/README.zh-CN.md +21 -20
- package/templates/.agents/hooks/lifecycle-delegation.js +64 -0
- package/templates/.agents/rules/README.en.md +2 -0
- package/templates/.agents/rules/README.zh-CN.md +2 -0
- package/templates/.agents/rules/commit-and-pr.en.md +1 -0
- package/templates/.agents/rules/commit-and-pr.zh-CN.md +1 -0
- package/templates/.agents/rules/human-decision-context.en.md +14 -12
- package/templates/.agents/rules/human-decision-context.zh-CN.md +14 -12
- package/templates/.agents/rules/lifecycle-orchestration.en.md +21 -0
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +21 -0
- package/templates/.agents/rules/next-step-output.en.md +16 -0
- package/templates/.agents/rules/next-step-output.zh-CN.md +16 -0
- package/templates/.agents/rules/no-mid-flow-questions.en.md +2 -0
- package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +2 -0
- package/templates/.agents/rules/release-commands.github.en.md +11 -5
- package/templates/.agents/rules/release-commands.github.zh-CN.md +11 -5
- package/templates/.agents/rules/review-handshake.en.md +4 -4
- package/templates/.agents/rules/review-handshake.zh-CN.md +4 -4
- package/templates/.agents/rules/review-method.en.md +113 -0
- package/templates/.agents/rules/review-method.zh-CN.md +98 -0
- package/templates/.agents/skills/analyze-task/SKILL.en.md +5 -5
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/block-task/SKILL.en.md +4 -4
- package/templates/.agents/skills/block-task/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/cancel-task/SKILL.en.md +4 -4
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/check-task/SKILL.en.md +16 -16
- package/templates/.agents/skills/check-task/SKILL.zh-CN.md +16 -16
- package/templates/.agents/skills/close-codescan/SKILL.en.md +4 -4
- package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/close-dependabot/SKILL.en.md +4 -4
- package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/code-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/code-task/reference/fix-mode.en.md +14 -16
- package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +14 -16
- 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/commit/SKILL.en.md +11 -1
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +11 -1
- package/templates/.agents/skills/commit/reference/task-status-update.en.md +24 -28
- package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +24 -28
- package/templates/.agents/skills/complete-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/create-pr/SKILL.en.md +10 -10
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +10 -10
- 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 +11 -11
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +11 -11
- package/templates/.agents/skills/import-codescan/SKILL.en.md +5 -5
- package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/import-dependabot/SKILL.en.md +5 -5
- package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/import-issue/SKILL.en.md +5 -5
- package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/init-labels/SKILL.en.md +4 -4
- package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/init-milestones/SKILL.en.md +4 -4
- package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/plan-task/SKILL.en.md +5 -5
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/refine-title/SKILL.en.md +1 -1
- package/templates/.agents/skills/refine-title/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/release/SKILL.en.md +1 -1
- package/templates/.agents/skills/review-analysis/SKILL.en.md +13 -2
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +14 -3
- package/templates/.agents/skills/review-analysis/config/verify.en.json +6 -0
- package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +6 -0
- package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +13 -15
- package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +13 -15
- package/templates/.agents/skills/review-analysis/reference/report-template.en.md +51 -5
- package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +52 -6
- package/templates/.agents/skills/review-analysis/reference/review-criteria.en.md +25 -22
- package/templates/.agents/skills/review-analysis/reference/review-criteria.zh-CN.md +25 -22
- package/templates/.agents/skills/review-code/SKILL.en.md +28 -8
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +28 -8
- package/templates/.agents/skills/review-code/config/verify.en.json +7 -0
- package/templates/.agents/skills/review-code/config/verify.zh-CN.json +7 -0
- package/templates/.agents/skills/review-code/reference/concurrency-risks.en.md +25 -0
- package/templates/.agents/skills/review-code/reference/concurrency-risks.zh-CN.md +25 -0
- package/templates/.agents/skills/review-code/reference/cross-platform-risks.en.md +27 -0
- package/templates/.agents/skills/review-code/reference/cross-platform-risks.zh-CN.md +27 -0
- package/templates/.agents/skills/review-code/reference/documentation-antipatterns.en.md +13 -0
- package/templates/.agents/skills/review-code/reference/documentation-antipatterns.zh-CN.md +13 -0
- package/templates/.agents/skills/review-code/reference/migration-risks.en.md +25 -0
- package/templates/.agents/skills/review-code/reference/migration-risks.zh-CN.md +25 -0
- package/templates/.agents/skills/review-code/reference/output-templates.en.md +22 -24
- package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +22 -24
- package/templates/.agents/skills/review-code/reference/report-template.en.md +54 -7
- package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +54 -7
- package/templates/.agents/skills/review-code/reference/review-criteria.en.md +29 -24
- package/templates/.agents/skills/review-code/reference/review-criteria.zh-CN.md +29 -24
- package/templates/.agents/skills/review-code/reference/security-risks.en.md +25 -0
- package/templates/.agents/skills/review-code/reference/security-risks.zh-CN.md +25 -0
- package/templates/.agents/skills/review-plan/SKILL.en.md +13 -2
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +14 -3
- package/templates/.agents/skills/review-plan/config/verify.en.json +6 -0
- package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +6 -0
- package/templates/.agents/skills/review-plan/reference/output-templates.en.md +13 -15
- package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +13 -15
- package/templates/.agents/skills/review-plan/reference/report-template.en.md +61 -5
- package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +61 -5
- package/templates/.agents/skills/review-plan/reference/review-criteria.en.md +21 -24
- package/templates/.agents/skills/review-plan/reference/review-criteria.zh-CN.md +21 -24
- package/templates/.agents/skills/run-task/SKILL.en.md +22 -0
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +22 -0
- package/templates/.agents/skills/run-task/config/verify.en.json +9 -0
- package/templates/.agents/skills/run-task/config/verify.zh-CN.json +9 -0
- package/templates/.agents/skills/test/SKILL.en.md +4 -4
- package/templates/.agents/skills/test/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/test-integration/SKILL.en.md +4 -4
- package/templates/.agents/skills/test-integration/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/update-agent-infra/SKILL.en.md +5 -5
- package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +647 -203
- package/templates/.agents/skills/upgrade-dependency/SKILL.en.md +4 -4
- package/templates/.agents/skills/upgrade-dependency/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/watch-pr/SKILL.en.md +8 -8
- package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +8 -8
- package/templates/.claude/agents/agent-infra-lifecycle-executor.en.md +6 -0
- package/templates/.claude/agents/agent-infra-lifecycle-executor.zh-CN.md +6 -0
- package/templates/.claude/agents/agent-infra-lifecycle-reviewer.en.md +6 -0
- package/templates/.claude/agents/agent-infra-lifecycle-reviewer.zh-CN.md +6 -0
- package/templates/.claude/commands/run-task.en.md +8 -0
- package/templates/.claude/commands/run-task.zh-CN.md +8 -0
- package/templates/.claude/settings.json +24 -0
- package/templates/.codex/agents/agent-infra-lifecycle-executor.en.toml +3 -0
- package/templates/.codex/agents/agent-infra-lifecycle-executor.zh-CN.toml +3 -0
- package/templates/.codex/agents/agent-infra-lifecycle-reviewer.en.toml +3 -0
- package/templates/.codex/agents/agent-infra-lifecycle-reviewer.zh-CN.toml +3 -0
- package/templates/.gemini/commands/_project_/run-task.en.toml +8 -0
- package/templates/.gemini/commands/_project_/run-task.zh-CN.toml +8 -0
- package/templates/.opencode/commands/run-task.en.md +11 -0
- package/templates/.opencode/commands/run-task.zh-CN.md +11 -0
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
const SUMMARY_HEADINGS = new Set(['审查摘要', 'Review Summary']);
|
|
4
|
+
const PLACEHOLDERS = [
|
|
5
|
+
'{unresolved-blockers}',
|
|
6
|
+
'{unresolved-major}',
|
|
7
|
+
'{unresolved-minor}'
|
|
8
|
+
];
|
|
9
|
+
function escapeRegExp(value) {
|
|
10
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
9
11
|
}
|
|
10
|
-
|
|
12
|
+
function maxRound(entries, stem) {
|
|
11
13
|
let max = 0;
|
|
12
14
|
for (const entry of entries) {
|
|
13
15
|
if (entry === `${stem}.md`) {
|
|
@@ -15,87 +17,169 @@ export function maxRound(entries, stem) {
|
|
|
15
17
|
continue;
|
|
16
18
|
}
|
|
17
19
|
const match = entry.match(new RegExp(`^${escapeRegExp(stem)}-r(\\d+)\\.md$`));
|
|
18
|
-
if (match)
|
|
20
|
+
if (match)
|
|
19
21
|
max = Math.max(max, Number(match[1]));
|
|
20
|
-
}
|
|
21
22
|
}
|
|
22
23
|
return max;
|
|
23
24
|
}
|
|
24
|
-
|
|
25
|
+
function artifactName(stem, round) {
|
|
25
26
|
return round === 1 ? `${stem}.md` : `${stem}-r${round}.md`;
|
|
26
27
|
}
|
|
27
|
-
|
|
28
|
+
function normalizeVerdict(raw) {
|
|
28
29
|
const value = String(raw).trim().toLowerCase();
|
|
29
|
-
if (value ===
|
|
30
|
-
return
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
return "Rejected";
|
|
37
|
-
}
|
|
38
|
-
return "";
|
|
30
|
+
if (value === '通过' || value === 'approved')
|
|
31
|
+
return 'Approved';
|
|
32
|
+
if (value === '需要修改' || value === 'changes requested')
|
|
33
|
+
return 'Changes Requested';
|
|
34
|
+
if (value === '拒绝' || value === 'rejected')
|
|
35
|
+
return 'Rejected';
|
|
36
|
+
return '';
|
|
39
37
|
}
|
|
40
|
-
|
|
38
|
+
function extractSection(content, names) {
|
|
41
39
|
const lines = content.split(/\r?\n/);
|
|
42
40
|
const nameSet = new Set(names);
|
|
43
41
|
const start = lines.findIndex((line) => {
|
|
44
42
|
const match = line.trim().match(/^##\s+(.+?)\s*$/);
|
|
45
43
|
return match ? nameSet.has(match[1]) : false;
|
|
46
44
|
});
|
|
47
|
-
if (start === -1)
|
|
48
|
-
return
|
|
49
|
-
}
|
|
45
|
+
if (start === -1)
|
|
46
|
+
return '';
|
|
50
47
|
const sectionLines = [];
|
|
51
48
|
for (let index = start + 1; index < lines.length; index += 1) {
|
|
52
|
-
if (/^##\s+/.test(lines[index]))
|
|
49
|
+
if (/^##\s+/.test(lines[index]))
|
|
53
50
|
break;
|
|
54
|
-
}
|
|
55
51
|
sectionLines.push(lines[index]);
|
|
56
52
|
}
|
|
57
|
-
return sectionLines.join(
|
|
53
|
+
return sectionLines.join('\n');
|
|
58
54
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (
|
|
64
|
-
return
|
|
55
|
+
function summaryBounds(content) {
|
|
56
|
+
const headings = [...content.matchAll(/^##\s+(.+?)\s*$/gm)]
|
|
57
|
+
.map((match) => ({ index: match.index, end: match.index + match[0].length, name: match[1] }));
|
|
58
|
+
const summaries = headings.filter((heading) => SUMMARY_HEADINGS.has(heading.name));
|
|
59
|
+
if (summaries.length !== 1)
|
|
60
|
+
return null;
|
|
61
|
+
const summary = summaries[0];
|
|
62
|
+
const next = headings.find((heading) => heading.index > summary.index);
|
|
63
|
+
return { start: summary.end, end: next?.index ?? content.length };
|
|
64
|
+
}
|
|
65
|
+
function uniqueLine(content, bounds, pattern) {
|
|
66
|
+
const section = content.slice(bounds.start, bounds.end);
|
|
67
|
+
const matches = [...section.matchAll(pattern)];
|
|
68
|
+
if (matches.length !== 1)
|
|
69
|
+
return null;
|
|
70
|
+
const match = matches[0];
|
|
71
|
+
return {
|
|
72
|
+
value: match[1],
|
|
73
|
+
start: bounds.start + match.index,
|
|
74
|
+
end: bounds.start + match.index + match[0].length
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function parseCounts(value) {
|
|
78
|
+
const zh = /^(\d+)\s*阻塞项,\s*(\d+)\s*主要,\s*(\d+)\s*次要(?:\s*\/.*)?$/.exec(value);
|
|
79
|
+
const en = /^(\d+)\s*blockers?,\s*(\d+)\s*majors?,\s*(\d+)\s*minors?(?:\s*\/.*)?$/i.exec(value);
|
|
80
|
+
const match = zh ?? en;
|
|
81
|
+
if (!match)
|
|
82
|
+
return null;
|
|
83
|
+
const [blocker, major, minor] = match.slice(1, 4).map(Number);
|
|
84
|
+
if (![blocker, major, minor].every(Number.isSafeInteger))
|
|
85
|
+
return null;
|
|
86
|
+
return { blocker: blocker, major: major, minor: minor };
|
|
87
|
+
}
|
|
88
|
+
function parseManualValidation(value) {
|
|
89
|
+
const match = /\*\*(?:人工校验|Manual[- ]validation)\*\*[::]\s*(\d+)/i.exec(value);
|
|
90
|
+
if (!match)
|
|
91
|
+
return null;
|
|
92
|
+
const count = Number(match[1]);
|
|
93
|
+
return Number.isSafeInteger(count) ? count : null;
|
|
94
|
+
}
|
|
95
|
+
function hasCanonicalPlaceholders(value) {
|
|
96
|
+
const zh = /^\{unresolved-blockers\}\s*阻塞项,\s*\{unresolved-major\}\s*主要,\s*\{unresolved-minor\}\s*次要(?:\s*\/.*)?$/.test(value);
|
|
97
|
+
const en = /^\{unresolved-blockers\}\s*blockers?,\s*\{unresolved-major\}\s*majors?,\s*\{unresolved-minor\}\s*minors?(?:\s*\/.*)?$/i.test(value);
|
|
98
|
+
return zh || en;
|
|
99
|
+
}
|
|
100
|
+
function parseReviewSummary(content) {
|
|
101
|
+
const bounds = summaryBounds(content);
|
|
102
|
+
if (!bounds) {
|
|
103
|
+
return { ok: false, code: 'REVIEW_SUMMARY_NOT_FOUND', message: 'review artifact must contain one review summary section' };
|
|
65
104
|
}
|
|
66
|
-
const
|
|
67
|
-
const
|
|
68
|
-
const
|
|
69
|
-
if (!
|
|
70
|
-
return { ok: false,
|
|
105
|
+
const verdictLine = uniqueLine(content, bounds, /^[-*]?\s*\*\*(?:总体结论|Overall Verdict)\*\*[::]\s*(.+?)\s*$/gim);
|
|
106
|
+
const findingsLine = uniqueLine(content, bounds, /^[-*]?\s*\*\*(?:发现(AI 可处理)|Findings \(AI-actionable\))\*\*[::]\s*(.+?)\s*$/gim);
|
|
107
|
+
const verdict = verdictLine ? normalizeVerdict(verdictLine.value) : '';
|
|
108
|
+
if (!verdict || !findingsLine) {
|
|
109
|
+
return { ok: false, code: 'REVIEW_SUMMARY_NOT_FOUND', message: 'review summary verdict or finding count line is missing or repeated' };
|
|
71
110
|
}
|
|
72
|
-
const
|
|
73
|
-
if (
|
|
74
|
-
return {
|
|
111
|
+
const counts = parseCounts(findingsLine.value);
|
|
112
|
+
if (counts) {
|
|
113
|
+
return {
|
|
114
|
+
ok: true,
|
|
115
|
+
summary: { verdict, counts, manualValidation: parseManualValidation(findingsLine.value), countState: 'numeric' },
|
|
116
|
+
findingsStart: findingsLine.start,
|
|
117
|
+
findingsEnd: findingsLine.end
|
|
118
|
+
};
|
|
75
119
|
}
|
|
76
|
-
const
|
|
77
|
-
if (
|
|
120
|
+
const placeholderOccurrences = PLACEHOLDERS.map((token) => ([...findingsLine.value.matchAll(new RegExp(escapeRegExp(token), 'g'))].length));
|
|
121
|
+
if (hasCanonicalPlaceholders(findingsLine.value) && placeholderOccurrences.every((count) => count === 1)) {
|
|
78
122
|
return {
|
|
79
|
-
ok:
|
|
80
|
-
verdict: null,
|
|
81
|
-
|
|
123
|
+
ok: true,
|
|
124
|
+
summary: { verdict, counts: null, manualValidation: parseManualValidation(findingsLine.value), countState: 'placeholders' },
|
|
125
|
+
findingsStart: findingsLine.start,
|
|
126
|
+
findingsEnd: findingsLine.end
|
|
82
127
|
};
|
|
83
128
|
}
|
|
84
|
-
|
|
85
|
-
|
|
129
|
+
return {
|
|
130
|
+
ok: false,
|
|
131
|
+
code: 'REVIEW_SUMMARY_PLACEHOLDER_INVALID',
|
|
132
|
+
message: 'review summary finding counts must be three canonical placeholders or non-negative integers'
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function equalCounts(left, right) {
|
|
136
|
+
return left.blocker === right.blocker && left.major === right.major && left.minor === right.minor;
|
|
137
|
+
}
|
|
138
|
+
function finalizeReviewSummaryContent(content, counts) {
|
|
139
|
+
const parsed = parseReviewSummary(content);
|
|
140
|
+
if (!parsed.ok)
|
|
141
|
+
return parsed;
|
|
142
|
+
if (parsed.summary.countState === 'numeric') {
|
|
143
|
+
if (equalCounts(parsed.summary.counts, counts))
|
|
144
|
+
return { ok: true, changed: false, content };
|
|
145
|
+
return {
|
|
146
|
+
ok: false,
|
|
147
|
+
code: 'REVIEW_SUMMARY_COUNT_MISMATCH',
|
|
148
|
+
message: 'review summary finding counts do not match the ledger snapshot'
|
|
149
|
+
};
|
|
86
150
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
151
|
+
let line = content.slice(parsed.findingsStart, parsed.findingsEnd);
|
|
152
|
+
line = line
|
|
153
|
+
.replace(PLACEHOLDERS[0], String(counts.blocker))
|
|
154
|
+
.replace(PLACEHOLDERS[1], String(counts.major))
|
|
155
|
+
.replace(PLACEHOLDERS[2], String(counts.minor));
|
|
156
|
+
return {
|
|
157
|
+
ok: true,
|
|
158
|
+
changed: true,
|
|
159
|
+
content: content.slice(0, parsed.findingsStart) + line + content.slice(parsed.findingsEnd)
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function parseVerdict(reviewPath) {
|
|
163
|
+
if (!fs.existsSync(reviewPath)) {
|
|
164
|
+
return { ok: false, verdict: null, message: `Review artifact not found: ${path.basename(reviewPath)}` };
|
|
90
165
|
}
|
|
91
|
-
const
|
|
92
|
-
if (!
|
|
93
|
-
return {
|
|
166
|
+
const parsed = parseReviewSummary(fs.readFileSync(reviewPath, 'utf8'));
|
|
167
|
+
if (!parsed.ok) {
|
|
168
|
+
return {
|
|
169
|
+
ok: false,
|
|
170
|
+
verdict: null,
|
|
171
|
+
message: `cannot parse review summary in ${path.basename(reviewPath)}: ${parsed.message}`
|
|
172
|
+
};
|
|
94
173
|
}
|
|
95
|
-
const
|
|
174
|
+
const { verdict, counts } = parsed.summary;
|
|
175
|
+
if (verdict !== 'Approved')
|
|
176
|
+
return { ok: true, verdict };
|
|
96
177
|
return {
|
|
97
178
|
ok: true,
|
|
98
|
-
verdict:
|
|
179
|
+
verdict: counts && equalCounts(counts, { blocker: 0, major: 0, minor: 0 })
|
|
180
|
+
? 'Approved'
|
|
181
|
+
: 'Approved-with-issues'
|
|
99
182
|
};
|
|
100
183
|
}
|
|
184
|
+
export { artifactName, equalCounts, escapeRegExp, extractSection, finalizeReviewSummaryContent, maxRound, normalizeVerdict, parseReviewSummary, parseVerdict };
|
|
101
185
|
//# sourceMappingURL=review-artifacts.js.map
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
import { locateActivityLog, pairEntries } from './activity-log.js';
|
|
5
|
+
import { parseArtifactName, validateCompletedArtifact } from './artifact-lifecycle.js';
|
|
6
|
+
import { parseLedger, summarizeLedgerStage, validateLedgerRows } from './ledger.js';
|
|
7
|
+
import { finalizeReviewSummaryContent } from './review-artifacts.js';
|
|
8
|
+
import { resolveTaskRef } from './resolve-ref.js';
|
|
9
|
+
import { validateOrchestrationStage } from './orchestration.js';
|
|
10
|
+
const STAGES = {
|
|
11
|
+
analysis: { family: 'review-analysis', action: 'Review Analysis' },
|
|
12
|
+
plan: { family: 'review-plan', action: 'Review Plan' },
|
|
13
|
+
code: { family: 'review-code', action: 'Review Code' }
|
|
14
|
+
};
|
|
15
|
+
const DEFAULT_FILE_SYSTEM = {
|
|
16
|
+
readFileSync: (file) => fs.readFileSync(file, 'utf8'),
|
|
17
|
+
statModeSync: (file) => fs.statSync(file).mode,
|
|
18
|
+
writeFileSync: (file, content, mode) => fs.writeFileSync(file, content, { encoding: 'utf8', flag: 'wx', mode }),
|
|
19
|
+
renameSync: (from, to) => fs.renameSync(from, to),
|
|
20
|
+
unlinkSync: (file) => fs.unlinkSync(file)
|
|
21
|
+
};
|
|
22
|
+
function failed(request, code, message, taskId = null, stageStatus = null) {
|
|
23
|
+
return {
|
|
24
|
+
status: 'failed',
|
|
25
|
+
changed: false,
|
|
26
|
+
intent: 'finalize-summary',
|
|
27
|
+
requestRef: request.taskRef,
|
|
28
|
+
taskId,
|
|
29
|
+
stage: request.stage,
|
|
30
|
+
artifact: request.artifact,
|
|
31
|
+
stageStatus,
|
|
32
|
+
operations: [],
|
|
33
|
+
error: { code, message }
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function openReviewRound(content, action, round) {
|
|
37
|
+
const section = locateActivityLog(content);
|
|
38
|
+
if (!section)
|
|
39
|
+
return false;
|
|
40
|
+
const expected = `${action} (Round ${round})`;
|
|
41
|
+
return pairEntries(section.entries).filter((row) => (row.step === expected && Boolean(row.started) && !row.done)).length === 1;
|
|
42
|
+
}
|
|
43
|
+
function cleanupTemp(fileSystem, tempPath) {
|
|
44
|
+
try {
|
|
45
|
+
fileSystem.unlinkSync(tempPath);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// Best-effort cleanup preserves the primary failure.
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function finalizeReviewSummary(request, options = {}) {
|
|
52
|
+
const stage = request.stage;
|
|
53
|
+
const spec = STAGES[stage];
|
|
54
|
+
if (!spec)
|
|
55
|
+
return failed(request, 'REVIEW_STAGE_INVALID', `unsupported review stage '${request.stage}'`);
|
|
56
|
+
if (!request.taskRef || !request.artifact) {
|
|
57
|
+
return failed(request, 'REVIEW_PAYLOAD_INVALID', 'taskRef, stage, and artifact are required');
|
|
58
|
+
}
|
|
59
|
+
const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
|
|
60
|
+
if (!resolved.ok)
|
|
61
|
+
return failed(request, resolved.code, resolved.message, resolved.taskId);
|
|
62
|
+
if (resolved.state !== 'active') {
|
|
63
|
+
return failed(request, 'TASK_STATE_MISMATCH', `task ${resolved.taskId} is ${resolved.state}, expected active`, resolved.taskId);
|
|
64
|
+
}
|
|
65
|
+
const parsedArtifact = parseArtifactName(request.artifact);
|
|
66
|
+
if (!parsedArtifact || parsedArtifact.family !== spec.family) {
|
|
67
|
+
return failed(request, 'REVIEW_ARTIFACT_IDENTITY_INVALID', `artifact '${request.artifact}' does not match ${spec.family}`, resolved.taskId);
|
|
68
|
+
}
|
|
69
|
+
const validated = validateCompletedArtifact(resolved.taskDir, spec.family, request.artifact, parsedArtifact.round);
|
|
70
|
+
if (!validated.ok) {
|
|
71
|
+
const code = validated.error.code === 'ARTIFACT_NOT_REGULAR'
|
|
72
|
+
? 'REVIEW_ARTIFACT_NOT_REGULAR'
|
|
73
|
+
: 'REVIEW_ARTIFACT_IDENTITY_INVALID';
|
|
74
|
+
return failed(request, code, validated.error.message, resolved.taskId);
|
|
75
|
+
}
|
|
76
|
+
const fileSystem = { ...DEFAULT_FILE_SYSTEM, ...options.fileSystem };
|
|
77
|
+
let taskContent;
|
|
78
|
+
let artifactContent;
|
|
79
|
+
try {
|
|
80
|
+
taskContent = fileSystem.readFileSync(resolved.taskMdPath);
|
|
81
|
+
artifactContent = fileSystem.readFileSync(validated.artifact.path);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
return failed(request, 'REVIEW_ARTIFACT_NOT_REGULAR', String(error), resolved.taskId);
|
|
85
|
+
}
|
|
86
|
+
if (!openReviewRound(taskContent, spec.action, parsedArtifact.round)) {
|
|
87
|
+
return failed(request, 'REVIEW_ARTIFACT_IDENTITY_INVALID', `${request.artifact} does not have one matching open started review event`, resolved.taskId);
|
|
88
|
+
}
|
|
89
|
+
const provenance = validateOrchestrationStage(request.taskRef, {
|
|
90
|
+
stage: spec.family,
|
|
91
|
+
round: parsedArtifact.round,
|
|
92
|
+
artifact: request.artifact,
|
|
93
|
+
role: 'reviewer'
|
|
94
|
+
}, { repoRoot: options.repoRoot });
|
|
95
|
+
if (provenance.status === 'failed' || provenance.status === 'paused') {
|
|
96
|
+
return failed(request, 'REVIEW_PROVENANCE_INVALID', provenance.error?.message ?? provenance.run?.pause?.message ?? 'orchestration provenance validation failed', resolved.taskId);
|
|
97
|
+
}
|
|
98
|
+
let rows;
|
|
99
|
+
try {
|
|
100
|
+
rows = parseLedger(taskContent);
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
return failed(request, 'REVIEW_LEDGER_INVALID', String(error), resolved.taskId);
|
|
104
|
+
}
|
|
105
|
+
const ledgerError = validateLedgerRows(rows);
|
|
106
|
+
if (ledgerError) {
|
|
107
|
+
return failed(request, 'REVIEW_LEDGER_INVALID', `${ledgerError.code}: ${ledgerError.message}`, resolved.taskId);
|
|
108
|
+
}
|
|
109
|
+
const stageStatus = summarizeLedgerStage(rows, stage);
|
|
110
|
+
const transformed = finalizeReviewSummaryContent(artifactContent, stageStatus.unresolvedFindingCounts);
|
|
111
|
+
if (!transformed.ok) {
|
|
112
|
+
return failed(request, transformed.code, transformed.message, resolved.taskId, stageStatus);
|
|
113
|
+
}
|
|
114
|
+
if (!transformed.changed) {
|
|
115
|
+
return {
|
|
116
|
+
...failed(request, 'REVIEW_ARTIFACT_CONFLICT', '', resolved.taskId, stageStatus),
|
|
117
|
+
status: 'no-op',
|
|
118
|
+
error: null
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
const operations = [{ kind: 'artifact', artifact: request.artifact, operation: 'update' }];
|
|
122
|
+
if (request.dryRun) {
|
|
123
|
+
return {
|
|
124
|
+
...failed(request, 'REVIEW_ARTIFACT_CONFLICT', '', resolved.taskId, stageStatus),
|
|
125
|
+
status: 'planned',
|
|
126
|
+
changed: true,
|
|
127
|
+
operations,
|
|
128
|
+
error: null
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
const tempPath = path.join(resolved.taskDir, `.${request.artifact}.tmp-${process.pid}-${(options.randomSuffix ?? randomUUID)()}`);
|
|
132
|
+
let mode;
|
|
133
|
+
try {
|
|
134
|
+
mode = fileSystem.statModeSync(validated.artifact.path);
|
|
135
|
+
fileSystem.writeFileSync(tempPath, transformed.content, mode);
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
cleanupTemp(fileSystem, tempPath);
|
|
139
|
+
return failed(request, 'REVIEW_TEMP_WRITE_FAILED', String(error), resolved.taskId, stageStatus);
|
|
140
|
+
}
|
|
141
|
+
try {
|
|
142
|
+
if (fileSystem.readFileSync(validated.artifact.path) !== artifactContent) {
|
|
143
|
+
cleanupTemp(fileSystem, tempPath);
|
|
144
|
+
return failed(request, 'REVIEW_ARTIFACT_CONFLICT', `${request.artifact} changed during finalization`, resolved.taskId, stageStatus);
|
|
145
|
+
}
|
|
146
|
+
fileSystem.renameSync(tempPath, validated.artifact.path);
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
cleanupTemp(fileSystem, tempPath);
|
|
150
|
+
return failed(request, 'REVIEW_RENAME_FAILED', String(error), resolved.taskId, stageStatus);
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
status: 'applied',
|
|
154
|
+
changed: true,
|
|
155
|
+
intent: 'finalize-summary',
|
|
156
|
+
requestRef: request.taskRef,
|
|
157
|
+
taskId: resolved.taskId,
|
|
158
|
+
stage,
|
|
159
|
+
artifact: request.artifact,
|
|
160
|
+
stageStatus,
|
|
161
|
+
operations,
|
|
162
|
+
error: null
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
export { finalizeReviewSummary };
|
|
166
|
+
//# sourceMappingURL=review-finalization.js.map
|
|
@@ -40,6 +40,10 @@ export function extractReviewBaseline(content) {
|
|
|
40
40
|
const match = String(content).match(/^[-*]?\s*\*\*(?:审查基线提交|Review Baseline Commit)\*\*[::]\s*(.*?)\s*$/m);
|
|
41
41
|
return match ? match[1].trim().replace(/`/g, "") : "";
|
|
42
42
|
}
|
|
43
|
+
export function extractReviewDiffBase(content) {
|
|
44
|
+
const match = String(content).match(/^[-*]?\s*\*\*(?:审查差异基线|Reviewed Diff Base)\*\*[::]\s*(.*?)\s*$/m);
|
|
45
|
+
return match ? match[1].trim().replace(/`/g, "") : "";
|
|
46
|
+
}
|
|
43
47
|
export function extractReviewDiffFingerprint(content) {
|
|
44
48
|
const match = String(content).match(/^[-*]?\s*\*\*(?:审查差异指纹|Reviewed Diff Fingerprint)\*\*[::]\s*(.*?)\s*$/m);
|
|
45
49
|
return match ? match[1].trim().replace(/`/g, "") : "";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const LOCAL_VERIFICATION_CHECKS = [
|
|
2
|
-
'task-meta', 'artifact', 'implementation-input', 'activity-log', 'completion-checklist'
|
|
2
|
+
'task-meta', 'artifact', 'implementation-input', 'activity-log', 'completion-checklist',
|
|
3
|
+
'orchestration-state'
|
|
3
4
|
];
|
|
4
5
|
function isLocalVerificationCheck(value) {
|
|
5
6
|
return LOCAL_VERIFICATION_CHECKS.includes(value);
|