@fitlab-ai/agent-infra 0.12.0 → 0.12.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 +0 -2
- package/README.zh-CN.md +0 -2
- package/dist/bin/internal-cli.js +2 -17
- package/dist/lib/agent-clients/adapter.js +0 -13
- package/dist/lib/agent-clients/adapters/antigravity-cli.js +0 -5
- package/dist/lib/agent-clients/adapters/claude-code-credentials.js +0 -17
- package/dist/lib/agent-clients/adapters/claude-code.js +0 -9
- package/dist/lib/agent-clients/adapters/codex.js +0 -52
- package/dist/lib/agent-clients/adapters/opencode.js +0 -5
- package/dist/lib/agent-clients/adapters/traecli.js +0 -5
- package/dist/lib/agent-clients/config.js +19 -54
- package/dist/lib/agent-clients/registry.js +1 -12
- package/dist/lib/agent-clients/schema.js +0 -18
- package/dist/lib/agent-clients/tokens.js +1 -2
- package/dist/lib/agent-clients/types.js +0 -1
- package/dist/lib/decide.js +2 -0
- package/dist/lib/git/worktree-identity.js +1 -9
- package/dist/lib/internal/agent-client.js +2 -62
- package/dist/lib/internal/cli-route-inventory.js +1 -5
- package/dist/lib/internal/manual-validation.js +29 -27
- package/dist/lib/internal/platform-comment.js +56 -7
- package/dist/lib/internal/task-create.js +1 -1
- package/dist/lib/internal/task-event.js +1 -8
- package/dist/lib/internal/task-finalization.js +0 -1
- package/dist/lib/internal/task-lifecycle.js +2 -2
- package/dist/lib/internal/task-operation-registry.js +4 -20
- package/dist/lib/internal/task-review.js +4 -4
- package/dist/lib/platform/comment-safety.js +1 -7
- package/dist/lib/platform/in-label-sync.js +1 -14
- package/dist/lib/platform/issue-comments.js +373 -282
- package/dist/lib/platform/issue-summary-content.js +112 -0
- package/dist/lib/platform/issues.js +1 -1
- package/dist/lib/platform/operation-coordinator.js +4 -2
- package/dist/lib/platform/pr-change-report.js +176 -30
- package/dist/lib/platform/pr-checks.js +2 -8
- package/dist/lib/platform/pr-summary-content.js +54 -0
- package/dist/lib/platform/pr-summary.js +318 -284
- package/dist/lib/platform/provider-validation.js +0 -20
- package/dist/lib/platform/pull-requests.js +73 -84
- package/dist/lib/platform/releases.js +1 -43
- package/dist/lib/platform/summary-content-pipeline.js +18 -0
- package/dist/lib/platform/verification-required.js +0 -2
- package/dist/lib/platform/verification-sync.js +1 -79
- package/dist/lib/process-data/normalize.js +1 -185
- package/dist/lib/process-data/privacy.js +1 -16
- package/dist/lib/process-data/sources.js +2 -279
- package/dist/lib/render.js +0 -12
- package/dist/lib/run/index.js +15 -10
- package/dist/lib/run/skills.js +0 -3
- package/dist/lib/sandbox/commands/create.js +40 -53
- package/dist/lib/sandbox/commands/list-running.js +0 -18
- package/dist/lib/sandbox/commands/start.js +7 -8
- package/dist/lib/sandbox/constants.js +0 -6
- package/dist/lib/sandbox/control/client.js +0 -1
- package/dist/lib/sandbox/control/container-identity.js +1 -16
- package/dist/lib/sandbox/control/executor.js +0 -4
- package/dist/lib/sandbox/control/identity-sentinel.js +0 -7
- package/dist/lib/sandbox/control/lifecycle.js +21 -37
- package/dist/lib/sandbox/control/native-file-lock.js +0 -3
- package/dist/lib/sandbox/control/server.js +18 -38
- package/dist/lib/sandbox/control/state.js +1 -9
- package/dist/lib/sandbox/dockerfile.js +0 -6
- package/dist/lib/sandbox/engine.js +0 -14
- package/dist/lib/sandbox/engines/docker-exact-discovery.js +1 -4
- package/dist/lib/sandbox/engines/wsl2-paths.js +0 -3
- package/dist/lib/sandbox/recovery.js +24 -26
- package/dist/lib/sandbox/removal.js +67 -518
- package/dist/lib/sandbox/task-resolver.js +0 -41
- package/dist/lib/sandbox/tools.js +1 -4
- package/dist/lib/sandbox/workspace-view.js +1 -2
- package/dist/lib/server/display.js +0 -6
- package/dist/lib/task/activity-intent.js +45 -40
- package/dist/lib/task/activity-log.js +9 -16
- package/dist/lib/task/artifact-command.js +1 -1
- package/dist/lib/task/artifact-lifecycle.js +61 -63
- package/dist/lib/task/artifact-name.js +0 -6
- package/dist/lib/task/artifact-operations.js +3 -3
- package/dist/lib/task/capabilities.js +4 -5
- package/dist/lib/task/commands/log.js +0 -6
- package/dist/lib/task/commands/status.js +17 -60
- package/dist/lib/task/commit-operation.js +28 -39
- package/dist/lib/task/completion-facts.js +56 -43
- package/dist/lib/task/control-authority.js +23 -256
- package/dist/lib/task/control-recovery.js +3 -5
- package/dist/lib/task/create.js +2 -4
- package/dist/lib/task/decision-intents.js +8 -9
- package/dist/lib/task/delivery-target.js +1 -40
- package/dist/lib/task/events.js +84 -107
- package/dist/lib/task/finalization.js +60 -15
- package/dist/lib/task/ledger-intents.js +1 -1
- package/dist/lib/task/lifecycle-execution.js +38 -33
- package/dist/lib/task/lifecycle.js +49 -41
- package/dist/lib/task/local-artifact-finalization.js +1 -4
- package/dist/lib/task/manual-validation-evidence.js +1 -37
- package/dist/lib/task/platform-operation-recovery.js +151 -108
- package/dist/lib/task/pr-delivery-fact.js +2 -5
- package/dist/lib/task/qualification-confirmation.js +5 -7
- package/dist/lib/task/resolve-ref.js +1 -25
- package/dist/lib/task/review-command.js +2 -2
- package/dist/lib/task/review-finalization.js +1 -21
- package/dist/lib/task/review-fingerprint.js +0 -4
- package/dist/lib/task/secure-fs.js +0 -56
- package/dist/lib/task/short-id.js +1 -39
- package/dist/lib/task/skill-scope.js +0 -1
- package/dist/lib/task/verification-engine.js +58 -282
- package/dist/lib/task/verification.js +6 -3
- package/dist/lib/task/write.js +11 -1
- package/lib/agent-clients/adapter.ts +0 -76
- package/lib/agent-clients/adapters/antigravity-cli.ts +0 -5
- package/lib/agent-clients/adapters/claude-code-credentials.ts +0 -19
- package/lib/agent-clients/adapters/claude-code.ts +0 -9
- package/lib/agent-clients/adapters/codex.ts +0 -56
- package/lib/agent-clients/adapters/opencode.ts +0 -5
- package/lib/agent-clients/adapters/traecli.ts +0 -5
- package/lib/agent-clients/config.ts +20 -61
- package/lib/agent-clients/registry.ts +1 -34
- package/lib/agent-clients/schema.ts +0 -18
- package/lib/agent-clients/tokens.ts +1 -2
- package/lib/agent-clients/types.ts +0 -15
- package/lib/decide.ts +1 -0
- package/lib/git/worktree-identity.ts +0 -10
- package/lib/internal/agent-client.ts +2 -70
- package/lib/internal/cli-route-inventory.ts +1 -4
- package/lib/internal/manual-validation.ts +28 -27
- package/lib/internal/platform-comment.ts +46 -4
- package/lib/internal/task-create.ts +0 -1
- package/lib/internal/task-event.ts +1 -5
- package/lib/internal/task-finalization.ts +0 -1
- package/lib/internal/task-lifecycle.ts +3 -5
- package/lib/internal/task-operation-registry.ts +3 -19
- package/lib/internal/task-review.ts +4 -4
- package/lib/platform/comment-safety.ts +0 -10
- package/lib/platform/github-provider.ts +0 -2
- package/lib/platform/in-label-sync.ts +0 -16
- package/lib/platform/issue-comments.ts +478 -301
- package/lib/platform/issue-summary-content.ts +132 -0
- package/lib/platform/issues.ts +0 -2
- package/lib/platform/operation-coordinator.ts +4 -2
- package/lib/platform/pr-change-report.ts +165 -25
- package/lib/platform/pr-checks.ts +1 -10
- package/lib/platform/pr-review.ts +1 -1
- package/lib/platform/pr-summary-content.ts +60 -0
- package/lib/platform/pr-summary.ts +364 -257
- package/lib/platform/provider-bridge.ts +0 -1
- package/lib/platform/provider-loader.ts +1 -5
- package/lib/platform/provider-validation.ts +1 -49
- package/lib/platform/pull-requests.ts +64 -99
- package/lib/platform/releases.ts +1 -40
- package/lib/platform/summary-content-pipeline.ts +23 -0
- package/lib/platform/verification-required.ts +0 -2
- package/lib/platform/verification-sync.ts +0 -94
- package/lib/process-data/normalize.ts +1 -186
- package/lib/process-data/privacy.ts +2 -19
- package/lib/process-data/sources.ts +3 -283
- package/lib/render.ts +0 -15
- package/lib/run/index.ts +13 -7
- package/lib/run/skills.ts +0 -4
- package/lib/sandbox/commands/create.ts +37 -74
- package/lib/sandbox/commands/list-running.ts +0 -19
- package/lib/sandbox/commands/start.ts +7 -10
- package/lib/sandbox/constants.ts +0 -8
- package/lib/sandbox/control/client.ts +0 -1
- package/lib/sandbox/control/container-identity.ts +1 -16
- package/lib/sandbox/control/executor.ts +1 -5
- package/lib/sandbox/control/identity-sentinel.ts +0 -8
- package/lib/sandbox/control/lifecycle.ts +18 -51
- package/lib/sandbox/control/native-file-lock.ts +0 -8
- package/lib/sandbox/control/protocol.ts +0 -2
- package/lib/sandbox/control/server.ts +13 -39
- package/lib/sandbox/control/state.ts +1 -10
- package/lib/sandbox/dockerfile.ts +0 -11
- package/lib/sandbox/engine.ts +0 -17
- package/lib/sandbox/engines/docker-exact-discovery.ts +1 -5
- package/lib/sandbox/engines/wsl2-paths.ts +0 -4
- package/lib/sandbox/recovery.ts +24 -26
- package/lib/sandbox/removal.ts +58 -687
- package/lib/sandbox/shell.ts +1 -1
- package/lib/sandbox/task-resolver.ts +0 -48
- package/lib/sandbox/tools.ts +1 -5
- package/lib/sandbox/workspace-view.ts +2 -4
- package/lib/server/display.ts +0 -14
- package/lib/server/process-control.ts +1 -1
- package/lib/task/activity-intent.ts +36 -44
- package/lib/task/activity-log.ts +9 -22
- package/lib/task/artifact-command.ts +1 -1
- package/lib/task/artifact-lifecycle.ts +58 -67
- package/lib/task/artifact-name.ts +0 -7
- package/lib/task/artifact-operations.ts +3 -3
- package/lib/task/capabilities.ts +5 -6
- package/lib/task/commands/log.ts +0 -7
- package/lib/task/commands/status.ts +14 -79
- package/lib/task/commit-operation.ts +29 -51
- package/lib/task/completion-facts.ts +45 -42
- package/lib/task/control-authority.ts +27 -317
- package/lib/task/control-recovery.ts +2 -5
- package/lib/task/create.ts +2 -5
- package/lib/task/decision-intents.ts +5 -5
- package/lib/task/delivery-target.ts +0 -40
- package/lib/task/events.ts +89 -123
- package/lib/task/finalization.ts +52 -15
- package/lib/task/ledger-intents.ts +1 -1
- package/lib/task/lifecycle-execution.ts +37 -89
- package/lib/task/lifecycle.ts +48 -44
- package/lib/task/local-artifact-finalization.ts +0 -7
- package/lib/task/manual-validation-evidence.ts +1 -47
- package/lib/task/platform-operation-recovery.ts +117 -104
- package/lib/task/pr-delivery-fact.ts +2 -11
- package/lib/task/qualification-confirmation.ts +6 -6
- package/lib/task/resolve-ref.ts +0 -23
- package/lib/task/review-command.ts +2 -2
- package/lib/task/review-finalization.ts +1 -27
- package/lib/task/review-fingerprint.ts +0 -8
- package/lib/task/secure-fs.ts +0 -42
- package/lib/task/short-id.ts +0 -43
- package/lib/task/skill-scope.ts +0 -1
- package/lib/task/verification-engine.ts +56 -287
- package/lib/task/verification.ts +5 -5
- package/lib/task/write.ts +12 -1
- package/package.json +2 -2
- package/templates/.agents/README.en.md +1 -3
- package/templates/.agents/README.zh-CN.md +0 -2
- package/templates/.agents/rules/README.en.md +0 -1
- package/templates/.agents/rules/README.zh-CN.md +0 -1
- package/templates/.agents/rules/commit-and-pr.en.md +1 -1
- package/templates/.agents/rules/commit-and-pr.zh-CN.md +1 -1
- package/templates/.agents/rules/no-mid-flow-questions.en.md +0 -10
- package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +0 -10
- package/templates/.agents/rules/pr-sync.en.md +4 -2
- package/templates/.agents/rules/pr-sync.zh-CN.md +6 -9
- package/templates/.agents/rules/task-management.en.md +3 -3
- package/templates/.agents/rules/task-management.zh-CN.md +3 -3
- package/templates/.agents/skills/analyze-task/SKILL.en.md +3 -3
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/cancel-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/code-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/commit/SKILL.en.md +2 -2
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +6 -6
- package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +6 -6
- package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +1 -1
- package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +1 -1
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +2 -2
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +2 -2
- package/templates/.agents/skills/complete-task/SKILL.en.md +10 -25
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +11 -26
- package/templates/.agents/skills/create-pr/SKILL.en.md +1 -1
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/create-pr/reference/change-report.en.md +9 -2
- package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +9 -2
- package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +2 -2
- package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +2 -2
- package/templates/.agents/skills/create-task/SKILL.en.md +0 -18
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +0 -18
- package/templates/.agents/skills/plan-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/review-analysis/SKILL.en.md +3 -3
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/review-code/SKILL.en.md +5 -5
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/review-plan/SKILL.en.md +3 -3
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/review-pr/SKILL.en.md +4 -4
- package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +4 -4
- 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/update-agent-infra/scripts/sync-templates.js +3 -75
- package/templates/.agents/skills/watch-pr/SKILL.en.md +1 -1
- package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +3 -3
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +3 -3
- package/templates/.agents/templates/task.en.md +1 -0
- package/templates/.agents/templates/task.zh-CN.md +1 -0
- package/templates/.claude/settings.json +0 -24
- package/templates/.codex/hooks.json +0 -50
- package/dist/lib/agent-clients/adapters/codex-lifecycle/app-server.js +0 -582
- package/dist/lib/agent-clients/adapters/codex-lifecycle/binding.js +0 -114
- package/dist/lib/agent-clients/adapters/codex-lifecycle/build-identity.js +0 -237
- package/dist/lib/agent-clients/adapters/codex-lifecycle/cli.js +0 -443
- package/dist/lib/agent-clients/adapters/codex-lifecycle/evidence.js +0 -236
- package/dist/lib/agent-clients/adapters/codex-lifecycle/recovery.js +0 -292
- package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +0 -267
- package/dist/lib/agent-clients/adapters/codex-orchestration.js +0 -466
- package/dist/lib/internal/task-orchestration.js +0 -71
- package/dist/lib/platform/verification.js +0 -6
- package/dist/lib/run/prompt.js +0 -2
- package/dist/lib/sandbox/engines/authority.js +0 -289
- package/dist/lib/task/delegation-receipts.js +0 -410
- package/dist/lib/task/orchestration.js +0 -1233
- package/dist/lib/task/verification-checks.js +0 -9
- package/dist/lib/task/workspace-snapshot.js +0 -121
- package/dist/lifecycle-build-manifest.json +0 -6
- package/lib/agent-clients/adapters/codex-lifecycle/app-server.ts +0 -688
- package/lib/agent-clients/adapters/codex-lifecycle/binding.ts +0 -147
- package/lib/agent-clients/adapters/codex-lifecycle/build-identity.ts +0 -349
- package/lib/agent-clients/adapters/codex-lifecycle/cli.ts +0 -506
- package/lib/agent-clients/adapters/codex-lifecycle/evidence.ts +0 -385
- package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +0 -41
- package/lib/agent-clients/adapters/codex-lifecycle/recovery.ts +0 -418
- package/lib/agent-clients/adapters/codex-lifecycle/store.ts +0 -354
- package/lib/agent-clients/adapters/codex-orchestration.ts +0 -630
- package/lib/internal/task-orchestration.ts +0 -74
- package/lib/platform/verification.ts +0 -11
- package/lib/run/prompt.ts +0 -1
- package/lib/sandbox/engines/authority.ts +0 -365
- package/lib/task/delegation-receipts.ts +0 -547
- package/lib/task/orchestration.ts +0 -1651
- package/lib/task/verification-checks.ts +0 -10
- package/lib/task/workspace-snapshot.ts +0 -144
- package/templates/.agents/hooks/lifecycle-delegation.js +0 -140
- package/templates/.agents/rules/lifecycle-orchestration.en.md +0 -44
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +0 -44
- package/templates/.agents/skills/run-task/SKILL.en.md +0 -29
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +0 -29
- package/templates/.agents/skills/run-task/config/verify.en.json +0 -10
- package/templates/.agents/skills/run-task/config/verify.zh-CN.json +0 -10
- package/templates/.agents/skills/run-task/reference/host-validation.en.md +0 -24
- package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +0 -24
- package/templates/.claude/agents/agent-infra-lifecycle-executor.en.md +0 -6
- package/templates/.claude/agents/agent-infra-lifecycle-executor.zh-CN.md +0 -6
- package/templates/.claude/agents/agent-infra-lifecycle-reviewer.en.md +0 -6
- package/templates/.claude/agents/agent-infra-lifecycle-reviewer.zh-CN.md +0 -6
- package/templates/.claude/commands/run-task.en.md +0 -8
- package/templates/.claude/commands/run-task.zh-CN.md +0 -8
- package/templates/.codex/agents/agent-infra-lifecycle-executor.en.toml +0 -3
- package/templates/.codex/agents/agent-infra-lifecycle-executor.zh-CN.toml +0 -3
- package/templates/.codex/agents/agent-infra-lifecycle-reviewer.en.toml +0 -3
- package/templates/.codex/agents/agent-infra-lifecycle-reviewer.zh-CN.toml +0 -3
- package/templates/.opencode/commands/run-task.en.md +0 -11
- package/templates/.opencode/commands/run-task.zh-CN.md +0 -11
|
@@ -2,7 +2,6 @@ import { createHash } from 'node:crypto';
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
const NO_FOLLOW = fs.constants.O_NOFOLLOW ?? 0;
|
|
5
|
-
const DIRECTORY = fs.constants.O_DIRECTORY ?? 0;
|
|
6
5
|
export class SecureFileError extends Error {
|
|
7
6
|
code;
|
|
8
7
|
constructor(code, message) {
|
|
@@ -30,9 +29,6 @@ function assertNoSymlinkAncestors(candidate) {
|
|
|
30
29
|
current = parent;
|
|
31
30
|
}
|
|
32
31
|
}
|
|
33
|
-
export async function readStableFile(candidate, options) {
|
|
34
|
-
return readStableFileSync(candidate, options);
|
|
35
|
-
}
|
|
36
32
|
export function readStableFileSync(candidate, options) {
|
|
37
33
|
if (!path.isAbsolute(candidate))
|
|
38
34
|
conflict('candidate path must be absolute and terminal');
|
|
@@ -74,56 +70,4 @@ export function readStableFileSync(candidate, options) {
|
|
|
74
70
|
fs.closeSync(descriptor);
|
|
75
71
|
}
|
|
76
72
|
}
|
|
77
|
-
export async function writeAtomicFile(target, bytes, mode = 0o600, expectedSha256) {
|
|
78
|
-
const parent = path.dirname(target);
|
|
79
|
-
let current = path.resolve(parent);
|
|
80
|
-
while (true) {
|
|
81
|
-
let stat;
|
|
82
|
-
try {
|
|
83
|
-
stat = await fs.promises.lstat(current);
|
|
84
|
-
}
|
|
85
|
-
catch {
|
|
86
|
-
throw new SecureFileError('TASK_ARTIFACT_WRITE_CONFLICT', 'authoritative parent directory is missing');
|
|
87
|
-
}
|
|
88
|
-
if (!stat.isDirectory() || stat.isSymbolicLink())
|
|
89
|
-
throw new SecureFileError('TASK_ARTIFACT_WRITE_CONFLICT', 'authoritative parent directory is not a real directory');
|
|
90
|
-
const next = path.dirname(current);
|
|
91
|
-
if (next === current)
|
|
92
|
-
break;
|
|
93
|
-
current = next;
|
|
94
|
-
}
|
|
95
|
-
try {
|
|
96
|
-
const existing = await fs.promises.lstat(target);
|
|
97
|
-
if (existing.isSymbolicLink() || !existing.isFile())
|
|
98
|
-
throw new SecureFileError('TASK_ARTIFACT_WRITE_CONFLICT', 'authoritative target is not a regular file');
|
|
99
|
-
}
|
|
100
|
-
catch (error) {
|
|
101
|
-
if (error.code !== 'ENOENT')
|
|
102
|
-
throw error;
|
|
103
|
-
}
|
|
104
|
-
const temporary = path.join(parent, `.${path.basename(target)}.${process.pid}.${Date.now()}.tmp`);
|
|
105
|
-
let handle;
|
|
106
|
-
try {
|
|
107
|
-
handle = await fs.promises.open(temporary, fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL, mode);
|
|
108
|
-
await handle.writeFile(bytes);
|
|
109
|
-
await handle.sync();
|
|
110
|
-
await handle.chmod(mode);
|
|
111
|
-
await handle.close();
|
|
112
|
-
handle = undefined;
|
|
113
|
-
if (expectedSha256 !== undefined)
|
|
114
|
-
readStableFileSync(target, { maxBytes: 1024 * 1024, expectedSha256 });
|
|
115
|
-
fs.renameSync(temporary, target);
|
|
116
|
-
const directory = await fs.promises.open(parent, fs.constants.O_RDONLY | DIRECTORY);
|
|
117
|
-
try {
|
|
118
|
-
await directory.sync();
|
|
119
|
-
}
|
|
120
|
-
finally {
|
|
121
|
-
await directory.close();
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
finally {
|
|
125
|
-
await handle?.close().catch(() => undefined);
|
|
126
|
-
await fs.promises.rm(temporary, { force: true }).catch(() => undefined);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
73
|
//# sourceMappingURL=secure-fs.js.map
|
|
@@ -343,16 +343,6 @@ function readRegistry(repoRoot) {
|
|
|
343
343
|
return null;
|
|
344
344
|
}
|
|
345
345
|
}
|
|
346
|
-
function readBranchFromTaskMd(repoRoot, taskId) {
|
|
347
|
-
const taskMdPath = path.join(resolveProjectTaskWorkspaceRoot(repoRoot), 'active', taskId, 'task.md');
|
|
348
|
-
if (!fs.existsSync(taskMdPath))
|
|
349
|
-
return null;
|
|
350
|
-
const content = fs.readFileSync(taskMdPath, 'utf8');
|
|
351
|
-
const m = content.match(/^branch:\s*(.+)$/m);
|
|
352
|
-
if (!m || !m[1])
|
|
353
|
-
return null;
|
|
354
|
-
return m[1].trim().replace(/^(["'])(.*)\1$/, '$2');
|
|
355
|
-
}
|
|
356
346
|
function loadShortIdByTaskId(repoRoot) {
|
|
357
347
|
const registry = readRegistry(repoRoot);
|
|
358
348
|
const map = new Map();
|
|
@@ -421,33 +411,5 @@ function inspectShortIdRegistry(repoRoot, shortIdLength = configuredShortIdLengt
|
|
|
421
411
|
};
|
|
422
412
|
}
|
|
423
413
|
}
|
|
424
|
-
|
|
425
|
-
* Resolve a branch to its active-task short id (`NN`), or `null` when no
|
|
426
|
-
* active task is bound to that branch.
|
|
427
|
-
*
|
|
428
|
-
* Two-state semantics: this only consults the active registry
|
|
429
|
-
* (`active/.short-ids.json`) plus each `active/{taskId}/task.md`. Tasks moved
|
|
430
|
-
* to completed/blocked/cancelled/archive have already released their short id,
|
|
431
|
-
* so their branches return `null` — in `ai sandbox ls` that surfaces as `-`,
|
|
432
|
-
* meaning the sandbox is free to remove.
|
|
433
|
-
*/
|
|
434
|
-
function lookupShortIdByBranch(branch, repoRoot, _opts) {
|
|
435
|
-
const registry = readRegistry(repoRoot);
|
|
436
|
-
if (!registry)
|
|
437
|
-
return null;
|
|
438
|
-
const matches = [];
|
|
439
|
-
for (const [key, taskId] of Object.entries(registry.ids)) {
|
|
440
|
-
const taskBranch = readBranchFromTaskMd(repoRoot, taskId);
|
|
441
|
-
if (taskBranch && taskBranch === branch) {
|
|
442
|
-
matches.push(key);
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
if (matches.length === 0)
|
|
446
|
-
return null;
|
|
447
|
-
if (matches.length > 1) {
|
|
448
|
-
process.stderr.write(`Warning: branch '${branch}' is bound to multiple active tasks: ${matches.join(', ')}; using ${matches[0]}\n`);
|
|
449
|
-
}
|
|
450
|
-
return matches[0];
|
|
451
|
-
}
|
|
452
|
-
export { normalizeShortIdInput, isRemovedHashShortIdInput, resolveShortIdReadOnly, lookupShortIdByBranch, loadShortIdByTaskId, inspectShortIdRegistry, configuredShortIdLength, mutateShortIdRegistry, releaseStaleShortIdRegistry, executeShortIdCommand };
|
|
414
|
+
export { normalizeShortIdInput, isRemovedHashShortIdInput, resolveShortIdReadOnly, loadShortIdByTaskId, inspectShortIdRegistry, configuredShortIdLength, mutateShortIdRegistry, releaseStaleShortIdRegistry, executeShortIdCommand };
|
|
453
415
|
//# sourceMappingURL=short-id.js.map
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// frontmatter, ledger, Git snapshot and platform domains are imported below.
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import process from "node:process";
|
|
5
4
|
import { execFileSync } from "node:child_process";
|
|
6
5
|
import { fileURLToPath } from "node:url";
|
|
7
6
|
import { extractReviewTargetHead, extractReviewedHead, extractReviewDiffBase, findAuthoritativeReviewCodeArtifact, loadPostReviewConfig, parseReviewVerdict, resolvePostReviewGlobs } from "./verification-review.js";
|
|
@@ -19,9 +18,8 @@ import { inspectDecisionDetailDuplicates } from "./decision-details.js";
|
|
|
19
18
|
import { parseImplementationInputs } from "./implementation-inputs.js";
|
|
20
19
|
import { scanVisibleMarkdown } from "./markdown.js";
|
|
21
20
|
import { loadVerificationConfig } from "./verification-config.js";
|
|
22
|
-
import { inspectActivityLog
|
|
21
|
+
import { inspectActivityLog } from "./activity-log.js";
|
|
23
22
|
import { parseWorkflowWarnings } from "./workflow-warnings.js";
|
|
24
|
-
import { OrchestrationStateError, readRun } from "./orchestration.js";
|
|
25
23
|
import { readPrDeliveryFact } from "./pr-delivery-fact.js";
|
|
26
24
|
import { validateLocalArtifact } from "./local-artifact-finalization.js";
|
|
27
25
|
import { getArtifactSchema } from "./artifact-schema.js";
|
|
@@ -29,13 +27,12 @@ import { inspectArtifactContract } from "./artifact-operations.js";
|
|
|
29
27
|
import { normalizeVerificationRecord } from './gate-policy.js';
|
|
30
28
|
import { manualValidationFinalSummaryProjectionMatches } from "./manual-validation-receipt.js";
|
|
31
29
|
import { readManualValidationCompletion } from "./manual-validation-completion.js";
|
|
32
|
-
import { sha256File } from "./artifact-receipts.js";
|
|
30
|
+
import { parseArtifactReceipts, receiptForOutput, sha256File } from "./artifact-receipts.js";
|
|
33
31
|
import { inspectArtifactDirectory } from "./artifact-lifecycle.js";
|
|
34
|
-
import { getAgentClientAdapter } from "../agent-clients/registry.js";
|
|
35
32
|
import { parseArtifactName } from "./artifact-name.js";
|
|
36
33
|
import { summaryCommentState } from "../platform/pr-summary.js";
|
|
37
34
|
import { taskIssueIdentity } from "../platform/task-identities.js";
|
|
38
|
-
import {
|
|
35
|
+
import { hasValidArtifactCompletion } from './completion-facts.js';
|
|
39
36
|
import { inspectReviewIdentity } from './review-identity.js';
|
|
40
37
|
const TASK_ENUMS = {
|
|
41
38
|
type: ["feature", "bugfix", "refactor", "docs", "chore"],
|
|
@@ -55,10 +52,8 @@ const DEFAULT_REQUIRED_FIELDS = [
|
|
|
55
52
|
];
|
|
56
53
|
const DATE_TIME_PATTERN = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:[+-]\d{2}:\d{2})?$/;
|
|
57
54
|
// Started rows do not represent completed lifecycle actions.
|
|
58
|
-
const ACTIVITY_LOG_STARTED_RE = /\s*\[started\]\s*$/;
|
|
59
55
|
const BRANCH_SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
60
56
|
// Review disagreement ledger (see .agents/rules/review-handshake.md).
|
|
61
|
-
const LEDGER_SECTION_NAMES = ["审查分歧账本", "Review Disagreement Ledger"];
|
|
62
57
|
const POST_REVIEW_COMMIT_STAGE = "post-review-commit";
|
|
63
58
|
const SHA_PATTERN = /^[0-9a-f]{7,40}$/i;
|
|
64
59
|
const scriptPath = fileURLToPath(import.meta.url);
|
|
@@ -106,10 +101,6 @@ async function runCheck(type, context, shared) {
|
|
|
106
101
|
return checkPostReviewCommit(context);
|
|
107
102
|
case "required-pr-delivery":
|
|
108
103
|
return checkRequiredPrDelivery(context);
|
|
109
|
-
case "orchestration-state":
|
|
110
|
-
return checkOrchestrationState(context);
|
|
111
|
-
case "orchestration-evidence":
|
|
112
|
-
return checkOrchestrationEvidence(context);
|
|
113
104
|
default: {
|
|
114
105
|
const adapter = PLATFORM_ADAPTERS[type];
|
|
115
106
|
if (!adapter) {
|
|
@@ -122,159 +113,6 @@ async function runCheck(type, context, shared) {
|
|
|
122
113
|
}
|
|
123
114
|
}
|
|
124
115
|
}
|
|
125
|
-
function checkOrchestrationState({ taskDir }) {
|
|
126
|
-
const file = path.join(taskDir, '.runtime', 'orchestration.json');
|
|
127
|
-
const stat = safeStat(file);
|
|
128
|
-
if (!stat?.isFile())
|
|
129
|
-
return failResult('orchestration-state', 'orchestration.json is missing');
|
|
130
|
-
let run;
|
|
131
|
-
try {
|
|
132
|
-
run = readRun(taskDir);
|
|
133
|
-
}
|
|
134
|
-
catch (error) {
|
|
135
|
-
const message = error instanceof OrchestrationStateError ? error.message : String(error);
|
|
136
|
-
return failResult('orchestration-state', `Invalid orchestration.json: ${message}`);
|
|
137
|
-
}
|
|
138
|
-
if (!run || !['paused', 'completed'].includes(run.status)) {
|
|
139
|
-
return failResult('orchestration-state', `Expected paused or completed run, received '${run?.status ?? 'missing'}'`);
|
|
140
|
-
}
|
|
141
|
-
const adapterEvidenceError = validateAdapterReceiptEvidence(run);
|
|
142
|
-
if (adapterEvidenceError)
|
|
143
|
-
return failResult('orchestration-state', adapterEvidenceError);
|
|
144
|
-
if (run.status === 'paused' && (!run.pause?.code || !run.pause?.message)) {
|
|
145
|
-
return failResult('orchestration-state', 'Paused run requires a stable pause code and message');
|
|
146
|
-
}
|
|
147
|
-
if (run.status === 'completed') {
|
|
148
|
-
const evidenceError = validateCleanCompletionEvidence(run);
|
|
149
|
-
if (evidenceError)
|
|
150
|
-
return failResult('orchestration-state', evidenceError);
|
|
151
|
-
}
|
|
152
|
-
else if (run.completionEvidence != null) {
|
|
153
|
-
return failResult('orchestration-state', 'Clean completion evidence requires a completed run');
|
|
154
|
-
}
|
|
155
|
-
else if (run.pendingDelegation?.status === 'sealed') {
|
|
156
|
-
return failResult('orchestration-state', 'Paused run has a sealed delegation that could still advance');
|
|
157
|
-
}
|
|
158
|
-
return passResult('orchestration-state', `Orchestration run is safely ${run.status}`);
|
|
159
|
-
}
|
|
160
|
-
function exactText(value) {
|
|
161
|
-
return typeof value === 'string' && value.length > 0 && value.trim() === value;
|
|
162
|
-
}
|
|
163
|
-
function validateCleanCompletionEvidence(run) {
|
|
164
|
-
const evidence = run.completionEvidence;
|
|
165
|
-
const shaPattern = /^[0-9a-f]{40}$/i;
|
|
166
|
-
if (!evidence
|
|
167
|
-
|| Number.isNaN(Date.parse(evidence.observedAt))
|
|
168
|
-
|| !shaPattern.test(evidence.head)
|
|
169
|
-
|| !shaPattern.test(evidence.headTree)
|
|
170
|
-
|| !shaPattern.test(evidence.worktreeTree)
|
|
171
|
-
|| !shaPattern.test(evidence.lastReviewedCommit)
|
|
172
|
-
|| !(evidence.prHead === null || shaPattern.test(evidence.prHead))) {
|
|
173
|
-
return 'Clean completion evidence has an invalid structure';
|
|
174
|
-
}
|
|
175
|
-
if (evidence.head !== evidence.lastReviewedCommit
|
|
176
|
-
|| (evidence.prHead !== null && evidence.head !== evidence.prHead)
|
|
177
|
-
|| evidence.headTree !== evidence.worktreeTree) {
|
|
178
|
-
return 'Clean completion evidence does not bind matching commit and tree identities';
|
|
179
|
-
}
|
|
180
|
-
if (run.status !== 'completed'
|
|
181
|
-
|| run.pendingDelegation !== null
|
|
182
|
-
|| run.receipts.some((receipt) => receipt.stage === 'commit')) {
|
|
183
|
-
return 'Clean completion evidence conflicts with pending delegation or commit receipt state';
|
|
184
|
-
}
|
|
185
|
-
return null;
|
|
186
|
-
}
|
|
187
|
-
function validateAdapterReceiptEvidence(run) {
|
|
188
|
-
const receipts = [...run.receipts, ...(run.pendingDelegation ? [run.pendingDelegation] : [])];
|
|
189
|
-
for (const receipt of receipts) {
|
|
190
|
-
const validate = getAgentClientAdapter(receipt.client).orchestrationAdapter?.validateReceiptEvidence;
|
|
191
|
-
if (validate && !validate(receipt)) {
|
|
192
|
-
return `Receipt '${receipt.id}' has invalid evidence from its agent adapter`;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
return null;
|
|
196
|
-
}
|
|
197
|
-
function checkOrchestrationEvidence({ taskDir }) {
|
|
198
|
-
const file = path.join(taskDir, '.runtime', 'orchestration.json');
|
|
199
|
-
const stat = safeStat(file);
|
|
200
|
-
if (!stat?.isFile())
|
|
201
|
-
return failResult('orchestration-evidence', 'orchestration.json is missing');
|
|
202
|
-
let run;
|
|
203
|
-
try {
|
|
204
|
-
run = readRun(taskDir);
|
|
205
|
-
}
|
|
206
|
-
catch (error) {
|
|
207
|
-
const message = error instanceof OrchestrationStateError ? error.message : String(error);
|
|
208
|
-
return failResult('orchestration-evidence', `Invalid orchestration.json: ${message}`);
|
|
209
|
-
}
|
|
210
|
-
if (!run)
|
|
211
|
-
return failResult('orchestration-evidence', 'orchestration.json is missing');
|
|
212
|
-
const adapterEvidenceError = validateAdapterReceiptEvidence(run);
|
|
213
|
-
if (adapterEvidenceError)
|
|
214
|
-
return failResult('orchestration-evidence', adapterEvidenceError);
|
|
215
|
-
// readRun validates the persisted schema, receipt identities and client provenance.
|
|
216
|
-
const policy = run.modelPolicy;
|
|
217
|
-
if (run.completionEvidence != null) {
|
|
218
|
-
const evidenceError = validateCleanCompletionEvidence(run);
|
|
219
|
-
if (evidenceError)
|
|
220
|
-
return failResult('orchestration-evidence', evidenceError);
|
|
221
|
-
}
|
|
222
|
-
else if (run.status === 'completed') {
|
|
223
|
-
return failResult('orchestration-evidence', 'Completed run requires reviewed-head-clean completion evidence');
|
|
224
|
-
}
|
|
225
|
-
if (run.pendingDelegation && !['prepared', 'activated', 'stage-completed'].includes(run.pendingDelegation.status)) {
|
|
226
|
-
return failResult('orchestration-evidence', `Pending receipt has unsafe status '${run.pendingDelegation.status}'`);
|
|
227
|
-
}
|
|
228
|
-
const receipts = [...run.receipts, ...(run.pendingDelegation ? [run.pendingDelegation] : [])];
|
|
229
|
-
for (const receipt of receipts) {
|
|
230
|
-
const expectedPolicy = policy[receipt.role];
|
|
231
|
-
if (!expectedPolicy || receipt.requestedModel !== expectedPolicy.model) {
|
|
232
|
-
return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' requested model does not match its role policy`);
|
|
233
|
-
}
|
|
234
|
-
if (receipt.requestedReasoningEffort !== expectedPolicy.reasoningEffort) {
|
|
235
|
-
return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' requested reasoning effort does not match its role policy`);
|
|
236
|
-
}
|
|
237
|
-
const activated = ['activated', 'stage-completed', 'sealed', 'consumed'].includes(receipt.status);
|
|
238
|
-
if (activated) {
|
|
239
|
-
const evidencePolicy = getAgentClientAdapter(receipt.client).delegationEvidence;
|
|
240
|
-
if (evidencePolicy.actualModelRequired !== false) {
|
|
241
|
-
if (!exactText(receipt.actualModel)) {
|
|
242
|
-
return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' has no host-observed actual model`);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
if (evidencePolicy.actualReasoningEffortRequired !== false) {
|
|
246
|
-
if (!exactText(receipt.actualReasoningEffort)) {
|
|
247
|
-
return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' has no host-observed actual reasoning effort`);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
if (evidencePolicy.spawnModeRequired !== false && receipt.spawnMode !== 'fresh') {
|
|
251
|
-
return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' has invalid fresh delegation identity`);
|
|
252
|
-
}
|
|
253
|
-
if (receipt.actualModel != null && receipt.actualModel !== receipt.requestedModel) {
|
|
254
|
-
if (evidencePolicy.fallbackReasonRequired !== false && !exactText(receipt.modelFallbackReason)) {
|
|
255
|
-
return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' model fallback is not justified`);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
if ((receipt.actualModel == null || receipt.actualModel === receipt.requestedModel)
|
|
259
|
-
&& receipt.modelFallbackReason !== null) {
|
|
260
|
-
return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' has an unrelated model fallback reason`);
|
|
261
|
-
}
|
|
262
|
-
if (receipt.actualReasoningEffort != null && receipt.actualReasoningEffort !== receipt.requestedReasoningEffort) {
|
|
263
|
-
if (evidencePolicy.fallbackReasonRequired !== false && !exactText(receipt.reasoningEffortFallbackReason)) {
|
|
264
|
-
return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' reasoning-effort fallback is not justified`);
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
if ((receipt.actualReasoningEffort == null || receipt.actualReasoningEffort === receipt.requestedReasoningEffort)
|
|
268
|
-
&& receipt.reasoningEffortFallbackReason !== null) {
|
|
269
|
-
return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' has an unrelated reasoning-effort fallback reason`);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
if (run.receipts.some((receipt) => receipt.status !== 'consumed')) {
|
|
274
|
-
return failResult('orchestration-evidence', 'Historical receipts must be consumed');
|
|
275
|
-
}
|
|
276
|
-
return passResult('orchestration-evidence', 'Persisted orchestration model and delegation evidence is internally consistent');
|
|
277
|
-
}
|
|
278
116
|
// === Check Functions ===
|
|
279
117
|
function checkTaskMeta({ taskDir, config, repositoryRoot, skillName, artifactFile }) {
|
|
280
118
|
const task = loadTask(taskDir);
|
|
@@ -320,10 +158,7 @@ function checkTaskMeta({ taskDir, config, repositoryRoot, skillName, artifactFil
|
|
|
320
158
|
if (expectedStep && metadata.current_step !== expectedStep) {
|
|
321
159
|
let validLifecycleArtifact = false;
|
|
322
160
|
if (currentTask) {
|
|
323
|
-
|
|
324
|
-
if (section && invalidEntries.length === 0) {
|
|
325
|
-
validLifecycleArtifact = checkArtifactLifecycleActivityLog(taskDir, artifactFile, skillName, task, section.entries)?.status === "pass";
|
|
326
|
-
}
|
|
161
|
+
validLifecycleArtifact = checkArtifactLifecycleActivityLog(taskDir, artifactFile, skillName, task)?.status === "pass";
|
|
327
162
|
}
|
|
328
163
|
if (!validLifecycleArtifact) {
|
|
329
164
|
return failResult("task-meta", `Expected current_step '${expectedStep}', got '${metadata.current_step || "(empty)"}'`);
|
|
@@ -586,12 +421,6 @@ function checkImplementationInput({ taskDir, artifactFile }) {
|
|
|
586
421
|
catch (error) {
|
|
587
422
|
return failResult("implementation-input", `Invalid Implementation Inputs: ${error instanceof Error ? error.message : String(error)}`);
|
|
588
423
|
}
|
|
589
|
-
const doneActions = (inspectActivityLog(task.content).section?.entries ?? [])
|
|
590
|
-
.filter((entry) => !ACTIVITY_LOG_STARTED_RE.test(entry.step))
|
|
591
|
-
.map((entry) => entry.step)
|
|
592
|
-
.filter((step) => /^(?:Code Task|Code) \(Round \d+/.test(step));
|
|
593
|
-
const latestAction = doneActions.at(-1) || "";
|
|
594
|
-
const actionDecision = /(?:Code Task|Code) \(Round \d+, decision (II-[1-9]\d*)\)/.exec(latestAction)?.[1] || null;
|
|
595
424
|
const report = fs.readFileSync(artifactPath, "utf8");
|
|
596
425
|
const reportSection = getSectionContent(report, ["实现输入", "Implementation Input"]);
|
|
597
426
|
if (!reportSection)
|
|
@@ -604,36 +433,30 @@ function checkImplementationInput({ taskDir, artifactFile }) {
|
|
|
604
433
|
const reportInput = field("裁决输入", "Decision Input");
|
|
605
434
|
const reportLedger = field("账本 ID", "Ledger ID");
|
|
606
435
|
const reportEvidence = field("裁决证据", "Decision Evidence");
|
|
607
|
-
if (!
|
|
608
|
-
if (reportInput && reportInput !== "N/A") {
|
|
609
|
-
return failResult("implementation-input", "Non-decision code action must report Decision Input as N/A");
|
|
610
|
-
}
|
|
436
|
+
if (!reportInput || reportInput === "N/A") {
|
|
611
437
|
return passResult("implementation-input", "Non-decision implementation input identity is consistent");
|
|
612
438
|
}
|
|
613
|
-
|
|
614
|
-
return failResult("implementation-input", `Report decision input '${reportInput}' does not match Activity Log ${actionDecision}`);
|
|
615
|
-
}
|
|
616
|
-
const matches = rows.filter((row) => row.id === actionDecision);
|
|
439
|
+
const matches = rows.filter((row) => row.id === reportInput);
|
|
617
440
|
if (matches.length !== 1)
|
|
618
|
-
return failResult("implementation-input", `${
|
|
441
|
+
return failResult("implementation-input", `${reportInput} is missing or duplicated in task table`);
|
|
619
442
|
const row = matches[0];
|
|
620
443
|
if (row.stage !== "code" || !row.needsImplementation || row.status !== "consumed" || row.consumedBy !== artifactFile || !row.decisionEvidence) {
|
|
621
|
-
return failResult("implementation-input", `${
|
|
444
|
+
return failResult("implementation-input", `${reportInput} is not a consumed input for ${artifactFile}`);
|
|
622
445
|
}
|
|
623
446
|
if (reportLedger !== row.ledgerId || reportEvidence !== row.decisionEvidence) {
|
|
624
|
-
return failResult("implementation-input", `${
|
|
447
|
+
return failResult("implementation-input", `${reportInput} report identity does not match task table evidence`);
|
|
625
448
|
}
|
|
626
|
-
return passResult("implementation-input", `${
|
|
449
|
+
return passResult("implementation-input", `${reportInput} matches report and task table`);
|
|
627
450
|
}
|
|
628
451
|
const ARTIFACT_ACTIVITY_STAGES = {
|
|
629
|
-
"analyze-task": { family: "analysis", event: "analyze.completed"
|
|
630
|
-
"plan-task": { family: "plan", event: "plan.completed"
|
|
631
|
-
"review-analysis": { family: "review-analysis", event: "review-analysis.completed"
|
|
632
|
-
"review-plan": { family: "review-plan", event: "review-plan.completed"
|
|
633
|
-
"code-task": { family: "code", event: "code.completed"
|
|
634
|
-
"review-code": { family: "review-code", event: "review-code.completed"
|
|
452
|
+
"analyze-task": { family: "analysis", event: "analyze.completed" },
|
|
453
|
+
"plan-task": { family: "plan", event: "plan.completed" },
|
|
454
|
+
"review-analysis": { family: "review-analysis", event: "review-analysis.completed" },
|
|
455
|
+
"review-plan": { family: "review-plan", event: "review-plan.completed" },
|
|
456
|
+
"code-task": { family: "code", event: "code.completed" },
|
|
457
|
+
"review-code": { family: "review-code", event: "review-code.completed" }
|
|
635
458
|
};
|
|
636
|
-
function checkArtifactLifecycleActivityLog(taskDir, artifactFile, skillName, task
|
|
459
|
+
function checkArtifactLifecycleActivityLog(taskDir, artifactFile, skillName, task) {
|
|
637
460
|
const stage = ARTIFACT_ACTIVITY_STAGES[skillName];
|
|
638
461
|
if (!stage)
|
|
639
462
|
return null;
|
|
@@ -649,38 +472,20 @@ function checkArtifactLifecycleActivityLog(taskDir, artifactFile, skillName, tas
|
|
|
649
472
|
if (!identity || identity.family !== stage.family) {
|
|
650
473
|
return failResult("activity-log", `Artifact '${output}' does not belong to ${stage.family}`);
|
|
651
474
|
}
|
|
652
|
-
if (!
|
|
475
|
+
if (!hasValidArtifactCompletion(task.content, taskDir, output, stage.event)) {
|
|
653
476
|
return failResult("activity-log", `Completion fact for '${output}' is missing or stale; rerun ${skillName} to record a current completion`);
|
|
654
477
|
}
|
|
655
|
-
const
|
|
656
|
-
const
|
|
657
|
-
|
|
658
|
-
return failResult("activity-log", `Completion fact for '${output}' is missing; rerun ${skillName}`);
|
|
659
|
-
if (!Array.isArray(fact.lifecycleInputs)) {
|
|
660
|
-
return failResult("activity-log", `Completion fact for '${output}' has no input snapshot; rerun ${skillName}`);
|
|
661
|
-
}
|
|
662
|
-
for (const input of fact.lifecycleInputs) {
|
|
663
|
-
if (!input || typeof input.name !== "string" || !/^[a-f0-9]{64}$/u.test(input.sha256)) {
|
|
664
|
-
return failResult("activity-log", `Completion fact for '${output}' has an invalid input snapshot; rerun ${skillName}`);
|
|
665
|
-
}
|
|
666
|
-
const inputIdentity = parseArtifactName(input.name);
|
|
478
|
+
const receipts = parseArtifactReceipts(task.content).rows.filter((receipt) => receipt.output === output);
|
|
479
|
+
for (const receipt of receipts) {
|
|
480
|
+
const inputIdentity = parseArtifactName(receipt.input);
|
|
667
481
|
if (!inputIdentity)
|
|
668
|
-
return failResult("activity-log", `Completion
|
|
482
|
+
return failResult("activity-log", `Completion receipt for '${output}' has invalid input '${receipt.input}'; rerun ${skillName}`);
|
|
669
483
|
const inputInventory = inspectArtifactDirectory(taskDir, inputIdentity.family);
|
|
670
|
-
if (inputInventory.status !== "ready" || inputInventory.latest?.name !== input
|
|
671
|
-
|| sha256File(path.join(taskDir, input
|
|
672
|
-
return failResult("activity-log", `Input '${input
|
|
484
|
+
if (inputInventory.status !== "ready" || inputInventory.latest?.name !== receipt.input
|
|
485
|
+
|| sha256File(path.join(taskDir, receipt.input)) !== receipt.inputSha256) {
|
|
486
|
+
return failResult("activity-log", `Input '${receipt.input}' changed or is no longer current; rerun ${skillName} to refresh '${output}'`);
|
|
673
487
|
}
|
|
674
488
|
}
|
|
675
|
-
const roundActionPattern = new RegExp(`^${stage.action} \\(Round ${identity.round}(?:, [^)]+)?\\)$`);
|
|
676
|
-
const roundAction = entries.find((entry) => {
|
|
677
|
-
return !ACTIVITY_LOG_STARTED_RE.test(entry.step)
|
|
678
|
-
&& roundActionPattern.test(entry.step)
|
|
679
|
-
&& entry.note.includes(`→ ${output}`);
|
|
680
|
-
});
|
|
681
|
-
if (!roundAction) {
|
|
682
|
-
return failResult("activity-log", `No completed Activity Log row records '${output}' for ${skillName} Round ${identity.round}`);
|
|
683
|
-
}
|
|
684
489
|
return passResult("activity-log", `Current ${stage.family} completion '${output}' is valid for Round ${identity.round}`);
|
|
685
490
|
}
|
|
686
491
|
function checkActivityLog({ taskDir, skillName, artifactFile }) {
|
|
@@ -688,22 +493,22 @@ function checkActivityLog({ taskDir, skillName, artifactFile }) {
|
|
|
688
493
|
if (!task.ok) {
|
|
689
494
|
return failResult("activity-log", task.message);
|
|
690
495
|
}
|
|
496
|
+
const artifactLifecycleResult = checkArtifactLifecycleActivityLog(taskDir, artifactFile, skillName, task);
|
|
497
|
+
if (artifactLifecycleResult && artifactLifecycleResult.status !== "pass")
|
|
498
|
+
return artifactLifecycleResult;
|
|
691
499
|
const { section, invalidEntries } = inspectActivityLog(task.content);
|
|
500
|
+
const warnings = [];
|
|
692
501
|
if (!section)
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
const artifactLifecycleResult = checkArtifactLifecycleActivityLog(taskDir, artifactFile, skillName, task, entries);
|
|
704
|
-
if (artifactLifecycleResult)
|
|
705
|
-
return artifactLifecycleResult;
|
|
706
|
-
return passResult("activity-log", "Activity Log is valid");
|
|
502
|
+
warnings.push('Activity Log section is missing or ambiguous');
|
|
503
|
+
else {
|
|
504
|
+
if (invalidEntries.length)
|
|
505
|
+
warnings.push('Activity Log contains malformed entries');
|
|
506
|
+
if (!section.entries.length)
|
|
507
|
+
warnings.push('Activity Log has no entries');
|
|
508
|
+
if (section.entries.some((entry) => !entry.note.trim()))
|
|
509
|
+
warnings.push('Activity Log entry note is empty');
|
|
510
|
+
}
|
|
511
|
+
return passResult("activity-log", artifactLifecycleResult?.message ?? "Business checks are valid", warnings);
|
|
707
512
|
}
|
|
708
513
|
function checkCompletionChecklist({ taskDir, config }) {
|
|
709
514
|
const task = loadTask(taskDir);
|
|
@@ -732,17 +537,7 @@ function checkCompletionChecklist({ taskDir, config }) {
|
|
|
732
537
|
}
|
|
733
538
|
return passResult("completion-checklist", `Completion Checklist valid (${items.length} items checked)`);
|
|
734
539
|
}
|
|
735
|
-
function
|
|
736
|
-
if (config && config[key] !== undefined && config[key] !== null) {
|
|
737
|
-
return config[key];
|
|
738
|
-
}
|
|
739
|
-
const reviewConfig = loadPostReviewConfig(repoRoot);
|
|
740
|
-
if (reviewConfig[key] !== undefined && reviewConfig[key] !== null) {
|
|
741
|
-
return reviewConfig[key];
|
|
742
|
-
}
|
|
743
|
-
return fallback;
|
|
744
|
-
}
|
|
745
|
-
function checkReviewLedger({ taskDir, config, repositoryRoot }) {
|
|
540
|
+
function checkReviewLedger({ taskDir, config }) {
|
|
746
541
|
const task = loadTask(taskDir);
|
|
747
542
|
if (!task.ok) {
|
|
748
543
|
return failResult("review-ledger", task.message);
|
|
@@ -818,8 +613,7 @@ async function checkManualValidation({ taskDir, repositoryRoot }) {
|
|
|
818
613
|
if (!resolved.ok) {
|
|
819
614
|
return failResult("manual-validation", `${parsed.summary.manualValidation} manual validation item(s) pending: run /complete-manual-validation`);
|
|
820
615
|
}
|
|
821
|
-
// 5.
|
|
822
|
-
// is derived with path.basename (resolveArtifactPath does not return fileName).
|
|
616
|
+
// 5. Validate the committed receipt, transaction, and artifact.
|
|
823
617
|
const artifactName = path.basename(resolved.path);
|
|
824
618
|
const task = loadTask(taskDir);
|
|
825
619
|
if (!task.ok)
|
|
@@ -842,31 +636,22 @@ async function checkManualValidation({ taskDir, repositoryRoot }) {
|
|
|
842
636
|
if (sha256File(resolved.path) !== receipt.artifactSha256) {
|
|
843
637
|
return failResult("manual-validation", `Manual validation artifact digest does not match the receipt for ${artifactName}`);
|
|
844
638
|
}
|
|
845
|
-
// 6.
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
if (!
|
|
854
|
-
return failResult("manual-validation",
|
|
855
|
-
|
|
856
|
-
const
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
&& entry.note.includes(`transaction=${receipt.transactionId};`)
|
|
862
|
-
&& entry.note.includes(`receipt=${receipt.receiptDigest};`)
|
|
863
|
-
&& entry.note.includes(`head=${receipt.prHeadSha}`));
|
|
864
|
-
if (reviewDoneIndex === -1)
|
|
865
|
-
return failResult("manual-validation", `Latest review-code (round ${review.round}) completion entry is missing from the Activity Log`);
|
|
866
|
-
if (completedIndex === -1)
|
|
867
|
-
return failResult("manual-validation", `Committed manual validation completion is not recorded for ${artifactName}`);
|
|
868
|
-
if (completedIndex < reviewDoneIndex)
|
|
869
|
-
return failResult("manual-validation", `Latest review-code (round ${review.round}) came after the manual validation completion recorded for ${artifactName}`);
|
|
639
|
+
// 6. Compare the review completion and committed manual-validation times.
|
|
640
|
+
let reviewReceipt;
|
|
641
|
+
try {
|
|
642
|
+
reviewReceipt = receiptForOutput(task.content, review.fileName);
|
|
643
|
+
}
|
|
644
|
+
catch (error) {
|
|
645
|
+
return failResult("manual-validation", `Review-code receipt is invalid: ${error instanceof Error ? error.message : String(error)}`);
|
|
646
|
+
}
|
|
647
|
+
if (!reviewReceipt || reviewReceipt.event !== "review-code.completed") {
|
|
648
|
+
return failResult("manual-validation", `Review-code completion time is unavailable for ${review.fileName}`);
|
|
649
|
+
}
|
|
650
|
+
const reviewTime = Date.parse(reviewReceipt.completedAt.replace(' ', 'T'));
|
|
651
|
+
const validationTime = Date.parse(receipt.committedAt);
|
|
652
|
+
if (!Number.isFinite(reviewTime) || !Number.isFinite(validationTime) || validationTime <= reviewTime) {
|
|
653
|
+
return failResult("manual-validation", `Manual validation must be completed after review-code ${review.fileName}`);
|
|
654
|
+
}
|
|
870
655
|
const fact = readPrDeliveryFact(task.metadata);
|
|
871
656
|
if (fact.status === "invalid")
|
|
872
657
|
return failResult("manual-validation", fact.error.message);
|
|
@@ -1069,12 +854,9 @@ function checkReviewFact({ taskDir, artifactFile, repositoryRoot }) {
|
|
|
1069
854
|
return failResult("review-fact", task.message);
|
|
1070
855
|
}
|
|
1071
856
|
const content = fs.readFileSync(resolvedArtifact.path, "utf8");
|
|
1072
|
-
if (!
|
|
857
|
+
if (!hasValidArtifactCompletion(task.content, taskDir, path.basename(resolvedArtifact.path), 'review-code.completed')) {
|
|
1073
858
|
return failResult("review-fact", `Review Code completion fact does not match ${path.basename(resolvedArtifact.path)}`);
|
|
1074
859
|
}
|
|
1075
|
-
if (!hasArtifactCompletionLog(task.content, path.basename(resolvedArtifact.path), 'review-code.completed')) {
|
|
1076
|
-
return failResult("review-fact", `Review Code completion entry does not reference ${path.basename(resolvedArtifact.path)}`);
|
|
1077
|
-
}
|
|
1078
860
|
const verdict = parseReviewVerdict(content);
|
|
1079
861
|
const reviewTargetHead = extractReviewTargetHead(content);
|
|
1080
862
|
const reviewReviewedHead = extractReviewedHead(content);
|
|
@@ -1194,12 +976,6 @@ function normalizeContent(text) {
|
|
|
1194
976
|
.replace(/\n{3,}/g, "\n\n")
|
|
1195
977
|
.trim();
|
|
1196
978
|
}
|
|
1197
|
-
function interpolate(template, taskDir, artifactFile) {
|
|
1198
|
-
const artifactStem = artifactFile ? path.basename(artifactFile, path.extname(artifactFile)) : "";
|
|
1199
|
-
return template
|
|
1200
|
-
.replace(/\{task-id\}/g, path.basename(taskDir))
|
|
1201
|
-
.replace(/\{artifact-stem\}/g, artifactStem);
|
|
1202
|
-
}
|
|
1203
979
|
function summarizeGate(checks) {
|
|
1204
980
|
if (checks.some((check) => check.effectiveStatus === "blocked")) {
|
|
1205
981
|
return "blocked";
|
|
@@ -29,9 +29,7 @@ const VERIFICATION_CATALOG = {
|
|
|
29
29
|
'import-dependabot.completed': gate('import-dependabot', 'active'),
|
|
30
30
|
'import-issue.completed': gate('import-issue', 'active'),
|
|
31
31
|
'watch-pr.completed': gate('watch-pr', 'active'),
|
|
32
|
-
'review-pr.completed': gate('review-pr', 'active', 'pr-review')
|
|
33
|
-
'run-task.paused': { skill: 'run-task', expectedState: 'active', mode: 'checks', checks: ['orchestration-state', 'orchestration-evidence'] },
|
|
34
|
-
'run-task.completed': { skill: 'run-task', expectedState: 'active', mode: 'checks', checks: ['orchestration-state', 'orchestration-evidence'] }
|
|
32
|
+
'review-pr.completed': gate('review-pr', 'active', 'pr-review')
|
|
35
33
|
};
|
|
36
34
|
function failure(request, code, message, extra = {}) {
|
|
37
35
|
return {
|
|
@@ -117,6 +115,11 @@ function renderTaskVerification(result) {
|
|
|
117
115
|
&& typeof message === 'string'
|
|
118
116
|
&& /\bhuman-decided (?:post-review )?exemption\b/i.test(message)
|
|
119
117
|
&& /\bPRC-\d+\s*:/.test(message);
|
|
118
|
+
if (Array.isArray(check.warnings)) {
|
|
119
|
+
for (const warning of check.warnings)
|
|
120
|
+
if (typeof warning === 'string')
|
|
121
|
+
lines.push(`Warning: ${id} - ${warning}`);
|
|
122
|
+
}
|
|
120
123
|
if (effectiveStatus === 'pass' && !isSoftWarning && !isHumanExemptionNotice)
|
|
121
124
|
continue;
|
|
122
125
|
lines.push(isSoftWarning
|