@fitlab-ai/agent-infra 0.12.1 → 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 +18 -10
- 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 +1 -16
- 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 +1 -4
- package/dist/lib/platform/pr-checks.js +2 -8
- 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/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 +11 -519
- 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 +44 -8
- 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 +67 -24
- 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 +16 -9
- 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 +0 -21
- package/lib/platform/issues.ts +0 -2
- package/lib/platform/operation-coordinator.ts +4 -2
- package/lib/platform/pr-change-report.ts +0 -5
- package/lib/platform/pr-checks.ts +1 -10
- package/lib/platform/pr-review.ts +1 -1
- 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/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 +11 -696
- 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 +41 -9
- 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 +50 -26
- 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 +1 -1
- package/templates/.agents/rules/pr-sync.zh-CN.md +1 -1
- 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/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/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
|
@@ -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
|
|
|
@@ -29,10 +28,8 @@ import { inspectDecisionDetailDuplicates } from "./decision-details.ts";
|
|
|
29
28
|
import { parseImplementationInputs, type ImplementationInput } from "./implementation-inputs.ts";
|
|
30
29
|
import { scanVisibleMarkdown } from "./markdown.ts";
|
|
31
30
|
import { loadVerificationConfig } from "./verification-config.ts";
|
|
32
|
-
import { inspectActivityLog
|
|
31
|
+
import { inspectActivityLog } from "./activity-log.ts";
|
|
33
32
|
import { parseWorkflowWarnings } from "./workflow-warnings.ts";
|
|
34
|
-
import { OrchestrationStateError, readRun } from "./orchestration.ts";
|
|
35
|
-
import type { OrchestrationRun } from "./orchestration.ts";
|
|
36
33
|
import { readPrDeliveryFact } from "./pr-delivery-fact.ts";
|
|
37
34
|
import { validateLocalArtifact } from "./local-artifact-finalization.ts";
|
|
38
35
|
import { getArtifactSchema } from "./artifact-schema.ts";
|
|
@@ -41,13 +38,12 @@ import type { VerificationShared } from "./verification-types.ts";
|
|
|
41
38
|
import { normalizeVerificationRecord } from './gate-policy.ts';
|
|
42
39
|
import { manualValidationFinalSummaryProjectionMatches } from "./manual-validation-receipt.ts";
|
|
43
40
|
import { readManualValidationCompletion } from "./manual-validation-completion.ts";
|
|
44
|
-
import { sha256File } from "./artifact-receipts.ts";
|
|
41
|
+
import { parseArtifactReceipts, receiptForOutput, sha256File } from "./artifact-receipts.ts";
|
|
45
42
|
import { inspectArtifactDirectory } from "./artifact-lifecycle.ts";
|
|
46
|
-
import { getAgentClientAdapter } from "../agent-clients/registry.ts";
|
|
47
43
|
import { parseArtifactName } from "./artifact-name.ts";
|
|
48
44
|
import { summaryCommentState } from "../platform/pr-summary.ts";
|
|
49
45
|
import { taskIssueIdentity } from "../platform/task-identities.ts";
|
|
50
|
-
import {
|
|
46
|
+
import { hasValidArtifactCompletion } from './completion-facts.ts';
|
|
51
47
|
import { inspectReviewIdentity } from './review-identity.ts';
|
|
52
48
|
|
|
53
49
|
const TASK_ENUMS = {
|
|
@@ -70,11 +66,9 @@ const DEFAULT_REQUIRED_FIELDS = [
|
|
|
70
66
|
|
|
71
67
|
const DATE_TIME_PATTERN = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:[+-]\d{2}:\d{2})?$/;
|
|
72
68
|
// Started rows do not represent completed lifecycle actions.
|
|
73
|
-
const ACTIVITY_LOG_STARTED_RE = /\s*\[started\]\s*$/;
|
|
74
69
|
const BRANCH_SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
75
70
|
|
|
76
71
|
// Review disagreement ledger (see .agents/rules/review-handshake.md).
|
|
77
|
-
const LEDGER_SECTION_NAMES = ["审查分歧账本", "Review Disagreement Ledger"];
|
|
78
72
|
const POST_REVIEW_COMMIT_STAGE = "post-review-commit";
|
|
79
73
|
const SHA_PATTERN = /^[0-9a-f]{7,40}$/i;
|
|
80
74
|
|
|
@@ -126,10 +120,6 @@ async function runCheck(type: any, context: any, shared: any): Promise<any> {
|
|
|
126
120
|
return checkPostReviewCommit(context);
|
|
127
121
|
case "required-pr-delivery":
|
|
128
122
|
return checkRequiredPrDelivery(context);
|
|
129
|
-
case "orchestration-state":
|
|
130
|
-
return checkOrchestrationState(context);
|
|
131
|
-
case "orchestration-evidence":
|
|
132
|
-
return checkOrchestrationEvidence(context);
|
|
133
123
|
default: {
|
|
134
124
|
const adapter = PLATFORM_ADAPTERS[type];
|
|
135
125
|
if (!adapter) {
|
|
@@ -145,162 +135,6 @@ async function runCheck(type: any, context: any, shared: any): Promise<any> {
|
|
|
145
135
|
}
|
|
146
136
|
}
|
|
147
137
|
|
|
148
|
-
function checkOrchestrationState({ taskDir }: any): any {
|
|
149
|
-
const file = path.join(taskDir, '.runtime', 'orchestration.json');
|
|
150
|
-
const stat = safeStat(file);
|
|
151
|
-
if (!stat?.isFile()) return failResult('orchestration-state', 'orchestration.json is missing');
|
|
152
|
-
let run: OrchestrationRun | null;
|
|
153
|
-
try {
|
|
154
|
-
run = readRun(taskDir);
|
|
155
|
-
} catch (error) {
|
|
156
|
-
const message = error instanceof OrchestrationStateError ? error.message : String(error);
|
|
157
|
-
return failResult('orchestration-state', `Invalid orchestration.json: ${message}`);
|
|
158
|
-
}
|
|
159
|
-
if (!run || !['paused', 'completed'].includes(run.status)) {
|
|
160
|
-
return failResult('orchestration-state', `Expected paused or completed run, received '${run?.status ?? 'missing'}'`);
|
|
161
|
-
}
|
|
162
|
-
const adapterEvidenceError = validateAdapterReceiptEvidence(run);
|
|
163
|
-
if (adapterEvidenceError) return failResult('orchestration-state', adapterEvidenceError);
|
|
164
|
-
if (run.status === 'paused' && (!run.pause?.code || !run.pause?.message)) {
|
|
165
|
-
return failResult('orchestration-state', 'Paused run requires a stable pause code and message');
|
|
166
|
-
}
|
|
167
|
-
if (run.status === 'completed') {
|
|
168
|
-
const evidenceError = validateCleanCompletionEvidence(run);
|
|
169
|
-
if (evidenceError) return failResult('orchestration-state', evidenceError);
|
|
170
|
-
} else if (run.completionEvidence != null) {
|
|
171
|
-
return failResult('orchestration-state', 'Clean completion evidence requires a completed run');
|
|
172
|
-
} else if (run.pendingDelegation?.status === 'sealed') {
|
|
173
|
-
return failResult('orchestration-state', 'Paused run has a sealed delegation that could still advance');
|
|
174
|
-
}
|
|
175
|
-
return passResult('orchestration-state', `Orchestration run is safely ${run.status}`);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
function exactText(value: unknown): value is string {
|
|
179
|
-
return typeof value === 'string' && value.length > 0 && value.trim() === value;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
function validateCleanCompletionEvidence(run: OrchestrationRun): string | null {
|
|
183
|
-
const evidence = run.completionEvidence;
|
|
184
|
-
const shaPattern = /^[0-9a-f]{40}$/i;
|
|
185
|
-
if (
|
|
186
|
-
!evidence
|
|
187
|
-
|| Number.isNaN(Date.parse(evidence.observedAt))
|
|
188
|
-
|| !shaPattern.test(evidence.head)
|
|
189
|
-
|| !shaPattern.test(evidence.headTree)
|
|
190
|
-
|| !shaPattern.test(evidence.worktreeTree)
|
|
191
|
-
|| !shaPattern.test(evidence.lastReviewedCommit)
|
|
192
|
-
|| !(evidence.prHead === null || shaPattern.test(evidence.prHead))
|
|
193
|
-
) {
|
|
194
|
-
return 'Clean completion evidence has an invalid structure';
|
|
195
|
-
}
|
|
196
|
-
if (
|
|
197
|
-
evidence.head !== evidence.lastReviewedCommit
|
|
198
|
-
|| (evidence.prHead !== null && evidence.head !== evidence.prHead)
|
|
199
|
-
|| evidence.headTree !== evidence.worktreeTree
|
|
200
|
-
) {
|
|
201
|
-
return 'Clean completion evidence does not bind matching commit and tree identities';
|
|
202
|
-
}
|
|
203
|
-
if (
|
|
204
|
-
run.status !== 'completed'
|
|
205
|
-
|| run.pendingDelegation !== null
|
|
206
|
-
|| run.receipts.some((receipt) => receipt.stage === 'commit')
|
|
207
|
-
) {
|
|
208
|
-
return 'Clean completion evidence conflicts with pending delegation or commit receipt state';
|
|
209
|
-
}
|
|
210
|
-
return null;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
function validateAdapterReceiptEvidence(run: OrchestrationRun): string | null {
|
|
214
|
-
const receipts = [...run.receipts, ...(run.pendingDelegation ? [run.pendingDelegation] : [])];
|
|
215
|
-
for (const receipt of receipts) {
|
|
216
|
-
const validate = getAgentClientAdapter(receipt.client).orchestrationAdapter?.validateReceiptEvidence;
|
|
217
|
-
if (validate && !validate(receipt)) {
|
|
218
|
-
return `Receipt '${receipt.id}' has invalid evidence from its agent adapter`;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
return null;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
function checkOrchestrationEvidence({ taskDir }: any): any {
|
|
225
|
-
const file = path.join(taskDir, '.runtime', 'orchestration.json');
|
|
226
|
-
const stat = safeStat(file);
|
|
227
|
-
if (!stat?.isFile()) return failResult('orchestration-evidence', 'orchestration.json is missing');
|
|
228
|
-
let run: OrchestrationRun | null;
|
|
229
|
-
try {
|
|
230
|
-
run = readRun(taskDir);
|
|
231
|
-
} catch (error) {
|
|
232
|
-
const message = error instanceof OrchestrationStateError ? error.message : String(error);
|
|
233
|
-
return failResult('orchestration-evidence', `Invalid orchestration.json: ${message}`);
|
|
234
|
-
}
|
|
235
|
-
if (!run) return failResult('orchestration-evidence', 'orchestration.json is missing');
|
|
236
|
-
const adapterEvidenceError = validateAdapterReceiptEvidence(run);
|
|
237
|
-
if (adapterEvidenceError) return failResult('orchestration-evidence', adapterEvidenceError);
|
|
238
|
-
// readRun validates the persisted schema, receipt identities and client provenance.
|
|
239
|
-
const policy = run.modelPolicy;
|
|
240
|
-
if (run.completionEvidence != null) {
|
|
241
|
-
const evidenceError = validateCleanCompletionEvidence(run);
|
|
242
|
-
if (evidenceError) return failResult('orchestration-evidence', evidenceError);
|
|
243
|
-
} else if (run.status === 'completed') {
|
|
244
|
-
return failResult('orchestration-evidence', 'Completed run requires reviewed-head-clean completion evidence');
|
|
245
|
-
}
|
|
246
|
-
if (run.pendingDelegation && !['prepared', 'activated', 'stage-completed'].includes(run.pendingDelegation.status)) {
|
|
247
|
-
return failResult('orchestration-evidence', `Pending receipt has unsafe status '${run.pendingDelegation.status}'`);
|
|
248
|
-
}
|
|
249
|
-
const receipts = [...run.receipts, ...(run.pendingDelegation ? [run.pendingDelegation] : [])];
|
|
250
|
-
for (const receipt of receipts) {
|
|
251
|
-
const expectedPolicy = policy[receipt.role];
|
|
252
|
-
if (!expectedPolicy || receipt.requestedModel !== expectedPolicy.model) {
|
|
253
|
-
return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' requested model does not match its role policy`);
|
|
254
|
-
}
|
|
255
|
-
if (receipt.requestedReasoningEffort !== expectedPolicy.reasoningEffort) {
|
|
256
|
-
return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' requested reasoning effort does not match its role policy`);
|
|
257
|
-
}
|
|
258
|
-
const activated = ['activated', 'stage-completed', 'sealed', 'consumed'].includes(receipt.status);
|
|
259
|
-
if (activated) {
|
|
260
|
-
const evidencePolicy = getAgentClientAdapter(receipt.client).delegationEvidence;
|
|
261
|
-
if (evidencePolicy.actualModelRequired !== false) {
|
|
262
|
-
if (!exactText(receipt.actualModel)) {
|
|
263
|
-
return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' has no host-observed actual model`);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
if (evidencePolicy.actualReasoningEffortRequired !== false) {
|
|
267
|
-
if (!exactText(receipt.actualReasoningEffort)) {
|
|
268
|
-
return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' has no host-observed actual reasoning effort`);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
if (evidencePolicy.spawnModeRequired !== false && receipt.spawnMode !== 'fresh') {
|
|
272
|
-
return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' has invalid fresh delegation identity`);
|
|
273
|
-
}
|
|
274
|
-
if (receipt.actualModel != null && receipt.actualModel !== receipt.requestedModel) {
|
|
275
|
-
if (evidencePolicy.fallbackReasonRequired !== false && !exactText(receipt.modelFallbackReason)) {
|
|
276
|
-
return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' model fallback is not justified`);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
if (
|
|
280
|
-
(receipt.actualModel == null || receipt.actualModel === receipt.requestedModel)
|
|
281
|
-
&& receipt.modelFallbackReason !== null
|
|
282
|
-
) {
|
|
283
|
-
return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' has an unrelated model fallback reason`);
|
|
284
|
-
}
|
|
285
|
-
if (receipt.actualReasoningEffort != null && receipt.actualReasoningEffort !== receipt.requestedReasoningEffort) {
|
|
286
|
-
if (evidencePolicy.fallbackReasonRequired !== false && !exactText(receipt.reasoningEffortFallbackReason)) {
|
|
287
|
-
return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' reasoning-effort fallback is not justified`);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
if (
|
|
291
|
-
(receipt.actualReasoningEffort == null || receipt.actualReasoningEffort === receipt.requestedReasoningEffort)
|
|
292
|
-
&& receipt.reasoningEffortFallbackReason !== null
|
|
293
|
-
) {
|
|
294
|
-
return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' has an unrelated reasoning-effort fallback reason`);
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
if (run.receipts.some((receipt) => receipt.status !== 'consumed')) {
|
|
299
|
-
return failResult('orchestration-evidence', 'Historical receipts must be consumed');
|
|
300
|
-
}
|
|
301
|
-
return passResult('orchestration-evidence', 'Persisted orchestration model and delegation evidence is internally consistent');
|
|
302
|
-
}
|
|
303
|
-
|
|
304
138
|
// === Check Functions ===
|
|
305
139
|
|
|
306
140
|
function checkTaskMeta({ taskDir, config, repositoryRoot, skillName, artifactFile }: any): any {
|
|
@@ -356,12 +190,9 @@ function checkTaskMeta({ taskDir, config, repositoryRoot, skillName, artifactFil
|
|
|
356
190
|
if (expectedStep && metadata.current_step !== expectedStep) {
|
|
357
191
|
let validLifecycleArtifact = false;
|
|
358
192
|
if (currentTask) {
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
taskDir, artifactFile, skillName, task, section.entries
|
|
363
|
-
)?.status === "pass";
|
|
364
|
-
}
|
|
193
|
+
validLifecycleArtifact = checkArtifactLifecycleActivityLog(
|
|
194
|
+
taskDir, artifactFile, skillName, task
|
|
195
|
+
)?.status === "pass";
|
|
365
196
|
}
|
|
366
197
|
if (!validLifecycleArtifact) {
|
|
367
198
|
return failResult(
|
|
@@ -678,12 +509,6 @@ function checkImplementationInput({ taskDir, artifactFile }: any): any {
|
|
|
678
509
|
return failResult("implementation-input", `Invalid Implementation Inputs: ${error instanceof Error ? error.message : String(error)}`);
|
|
679
510
|
}
|
|
680
511
|
|
|
681
|
-
const doneActions = (inspectActivityLog(task.content).section?.entries ?? [])
|
|
682
|
-
.filter((entry) => !ACTIVITY_LOG_STARTED_RE.test(entry.step))
|
|
683
|
-
.map((entry) => entry.step)
|
|
684
|
-
.filter((step) => /^(?:Code Task|Code) \(Round \d+/.test(step));
|
|
685
|
-
const latestAction = doneActions.at(-1) || "";
|
|
686
|
-
const actionDecision = /(?:Code Task|Code) \(Round \d+, decision (II-[1-9]\d*)\)/.exec(latestAction)?.[1] || null;
|
|
687
512
|
const report = fs.readFileSync(artifactPath, "utf8");
|
|
688
513
|
const reportSection = getSectionContent(report, ["实现输入", "Implementation Input"]);
|
|
689
514
|
if (!reportSection) return failResult("implementation-input", "Implementation Input report section not found");
|
|
@@ -696,37 +521,31 @@ function checkImplementationInput({ taskDir, artifactFile }: any): any {
|
|
|
696
521
|
const reportLedger = field("账本 ID", "Ledger ID");
|
|
697
522
|
const reportEvidence = field("裁决证据", "Decision Evidence");
|
|
698
523
|
|
|
699
|
-
if (!
|
|
700
|
-
if (reportInput && reportInput !== "N/A") {
|
|
701
|
-
return failResult("implementation-input", "Non-decision code action must report Decision Input as N/A");
|
|
702
|
-
}
|
|
524
|
+
if (!reportInput || reportInput === "N/A") {
|
|
703
525
|
return passResult("implementation-input", "Non-decision implementation input identity is consistent");
|
|
704
526
|
}
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
}
|
|
708
|
-
const matches = rows.filter((row) => row.id === actionDecision);
|
|
709
|
-
if (matches.length !== 1) return failResult("implementation-input", `${actionDecision} is missing or duplicated in task table`);
|
|
527
|
+
const matches = rows.filter((row) => row.id === reportInput);
|
|
528
|
+
if (matches.length !== 1) return failResult("implementation-input", `${reportInput} is missing or duplicated in task table`);
|
|
710
529
|
const row = matches[0]!;
|
|
711
530
|
if (row.stage !== "code" || !row.needsImplementation || row.status !== "consumed" || row.consumedBy !== artifactFile || !row.decisionEvidence) {
|
|
712
|
-
return failResult("implementation-input", `${
|
|
531
|
+
return failResult("implementation-input", `${reportInput} is not a consumed input for ${artifactFile}`);
|
|
713
532
|
}
|
|
714
533
|
if (reportLedger !== row.ledgerId || reportEvidence !== row.decisionEvidence) {
|
|
715
|
-
return failResult("implementation-input", `${
|
|
534
|
+
return failResult("implementation-input", `${reportInput} report identity does not match task table evidence`);
|
|
716
535
|
}
|
|
717
|
-
return passResult("implementation-input", `${
|
|
536
|
+
return passResult("implementation-input", `${reportInput} matches report and task table`);
|
|
718
537
|
}
|
|
719
538
|
|
|
720
|
-
const ARTIFACT_ACTIVITY_STAGES: Readonly<Record<string, { family: string; event: string
|
|
721
|
-
"analyze-task": { family: "analysis", event: "analyze.completed"
|
|
722
|
-
"plan-task": { family: "plan", event: "plan.completed"
|
|
723
|
-
"review-analysis": { family: "review-analysis", event: "review-analysis.completed"
|
|
724
|
-
"review-plan": { family: "review-plan", event: "review-plan.completed"
|
|
725
|
-
"code-task": { family: "code", event: "code.completed"
|
|
726
|
-
"review-code": { family: "review-code", event: "review-code.completed"
|
|
539
|
+
const ARTIFACT_ACTIVITY_STAGES: Readonly<Record<string, { family: string; event: string }>> = {
|
|
540
|
+
"analyze-task": { family: "analysis", event: "analyze.completed" },
|
|
541
|
+
"plan-task": { family: "plan", event: "plan.completed" },
|
|
542
|
+
"review-analysis": { family: "review-analysis", event: "review-analysis.completed" },
|
|
543
|
+
"review-plan": { family: "review-plan", event: "review-plan.completed" },
|
|
544
|
+
"code-task": { family: "code", event: "code.completed" },
|
|
545
|
+
"review-code": { family: "review-code", event: "review-code.completed" }
|
|
727
546
|
};
|
|
728
547
|
|
|
729
|
-
function checkArtifactLifecycleActivityLog(taskDir: string, artifactFile: string | undefined, skillName: string, task: any
|
|
548
|
+
function checkArtifactLifecycleActivityLog(taskDir: string, artifactFile: string | undefined, skillName: string, task: any): any {
|
|
730
549
|
const stage = ARTIFACT_ACTIVITY_STAGES[skillName];
|
|
731
550
|
if (!stage) return null;
|
|
732
551
|
const inventory = inspectArtifactDirectory(taskDir, stage.family as any);
|
|
@@ -741,38 +560,21 @@ function checkArtifactLifecycleActivityLog(taskDir: string, artifactFile: string
|
|
|
741
560
|
if (!identity || identity.family !== stage.family) {
|
|
742
561
|
return failResult("activity-log", `Artifact '${output}' does not belong to ${stage.family}`);
|
|
743
562
|
}
|
|
744
|
-
if (!
|
|
563
|
+
if (!hasValidArtifactCompletion(task.content, taskDir, output, stage.event)) {
|
|
745
564
|
return failResult("activity-log", `Completion fact for '${output}' is missing or stale; rerun ${skillName} to record a current completion`);
|
|
746
565
|
}
|
|
747
566
|
|
|
748
|
-
const
|
|
749
|
-
const
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
return failResult("activity-log", `Completion fact for '${output}' has no input snapshot; rerun ${skillName}`);
|
|
753
|
-
}
|
|
754
|
-
for (const input of fact.lifecycleInputs) {
|
|
755
|
-
if (!input || typeof input.name !== "string" || !/^[a-f0-9]{64}$/u.test(input.sha256)) {
|
|
756
|
-
return failResult("activity-log", `Completion fact for '${output}' has an invalid input snapshot; rerun ${skillName}`);
|
|
757
|
-
}
|
|
758
|
-
const inputIdentity = parseArtifactName(input.name);
|
|
759
|
-
if (!inputIdentity) return failResult("activity-log", `Completion fact for '${output}' has invalid input '${input.name}'; rerun ${skillName}`);
|
|
567
|
+
const receipts = parseArtifactReceipts(task.content).rows.filter((receipt) => receipt.output === output);
|
|
568
|
+
for (const receipt of receipts) {
|
|
569
|
+
const inputIdentity = parseArtifactName(receipt.input);
|
|
570
|
+
if (!inputIdentity) return failResult("activity-log", `Completion receipt for '${output}' has invalid input '${receipt.input}'; rerun ${skillName}`);
|
|
760
571
|
const inputInventory = inspectArtifactDirectory(taskDir, inputIdentity.family as any);
|
|
761
|
-
if (inputInventory.status !== "ready" || inputInventory.latest?.name !== input
|
|
762
|
-
|| sha256File(path.join(taskDir, input
|
|
763
|
-
return failResult("activity-log", `Input '${input
|
|
572
|
+
if (inputInventory.status !== "ready" || inputInventory.latest?.name !== receipt.input
|
|
573
|
+
|| sha256File(path.join(taskDir, receipt.input)) !== receipt.inputSha256) {
|
|
574
|
+
return failResult("activity-log", `Input '${receipt.input}' changed or is no longer current; rerun ${skillName} to refresh '${output}'`);
|
|
764
575
|
}
|
|
765
576
|
}
|
|
766
577
|
|
|
767
|
-
const roundActionPattern = new RegExp(`^${stage.action} \\(Round ${identity.round}(?:, [^)]+)?\\)$`);
|
|
768
|
-
const roundAction = entries.find((entry) => {
|
|
769
|
-
return !ACTIVITY_LOG_STARTED_RE.test(entry.step)
|
|
770
|
-
&& roundActionPattern.test(entry.step)
|
|
771
|
-
&& entry.note.includes(`→ ${output}`);
|
|
772
|
-
});
|
|
773
|
-
if (!roundAction) {
|
|
774
|
-
return failResult("activity-log", `No completed Activity Log row records '${output}' for ${skillName} Round ${identity.round}`);
|
|
775
|
-
}
|
|
776
578
|
return passResult("activity-log", `Current ${stage.family} completion '${output}' is valid for Round ${identity.round}`);
|
|
777
579
|
}
|
|
778
580
|
|
|
@@ -782,22 +584,19 @@ function checkActivityLog({ taskDir, skillName, artifactFile }: any): any {
|
|
|
782
584
|
return failResult("activity-log", task.message);
|
|
783
585
|
}
|
|
784
586
|
|
|
785
|
-
const
|
|
786
|
-
if (
|
|
787
|
-
if (invalidEntries.length) return failResult("activity-log", `Invalid Activity Log entry format: ${invalidEntries[0]}`);
|
|
788
|
-
const entries = section.entries;
|
|
789
|
-
if (entries.length === 0) return failResult("activity-log", "Activity Log has no entries");
|
|
587
|
+
const artifactLifecycleResult = checkArtifactLifecycleActivityLog(taskDir, artifactFile, skillName, task);
|
|
588
|
+
if (artifactLifecycleResult && artifactLifecycleResult.status !== "pass") return artifactLifecycleResult;
|
|
790
589
|
|
|
791
|
-
|
|
792
|
-
|
|
590
|
+
const { section, invalidEntries } = inspectActivityLog(task.content);
|
|
591
|
+
const warnings: string[] = [];
|
|
592
|
+
if (!section) warnings.push('Activity Log section is missing or ambiguous');
|
|
593
|
+
else {
|
|
594
|
+
if (invalidEntries.length) warnings.push('Activity Log contains malformed entries');
|
|
595
|
+
if (!section.entries.length) warnings.push('Activity Log has no entries');
|
|
596
|
+
if (section.entries.some((entry) => !entry.note.trim())) warnings.push('Activity Log entry note is empty');
|
|
793
597
|
}
|
|
598
|
+
return passResult("activity-log", artifactLifecycleResult?.message ?? "Business checks are valid", warnings);
|
|
794
599
|
|
|
795
|
-
const artifactLifecycleResult = checkArtifactLifecycleActivityLog(
|
|
796
|
-
taskDir, artifactFile, skillName, task, entries
|
|
797
|
-
);
|
|
798
|
-
if (artifactLifecycleResult) return artifactLifecycleResult;
|
|
799
|
-
|
|
800
|
-
return passResult("activity-log", "Activity Log is valid");
|
|
801
600
|
}
|
|
802
601
|
|
|
803
602
|
function checkCompletionChecklist({ taskDir, config }: any): any {
|
|
@@ -837,18 +636,7 @@ function checkCompletionChecklist({ taskDir, config }: any): any {
|
|
|
837
636
|
return passResult("completion-checklist", `Completion Checklist valid (${items.length} items checked)`);
|
|
838
637
|
}
|
|
839
638
|
|
|
840
|
-
function
|
|
841
|
-
if (config && config[key] !== undefined && config[key] !== null) {
|
|
842
|
-
return config[key];
|
|
843
|
-
}
|
|
844
|
-
const reviewConfig = loadPostReviewConfig(repoRoot);
|
|
845
|
-
if (reviewConfig[key] !== undefined && reviewConfig[key] !== null) {
|
|
846
|
-
return reviewConfig[key];
|
|
847
|
-
}
|
|
848
|
-
return fallback;
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
function checkReviewLedger({ taskDir, config, repositoryRoot }: any): any {
|
|
639
|
+
function checkReviewLedger({ taskDir, config }: any): any {
|
|
852
640
|
const task = loadTask(taskDir);
|
|
853
641
|
if (!task.ok) {
|
|
854
642
|
return failResult("review-ledger", task.message);
|
|
@@ -931,8 +719,7 @@ async function checkManualValidation({ taskDir, repositoryRoot }: any): Promise<
|
|
|
931
719
|
`${parsed.summary.manualValidation} manual validation item(s) pending: run /complete-manual-validation`
|
|
932
720
|
);
|
|
933
721
|
}
|
|
934
|
-
// 5.
|
|
935
|
-
// is derived with path.basename (resolveArtifactPath does not return fileName).
|
|
722
|
+
// 5. Validate the committed receipt, transaction, and artifact.
|
|
936
723
|
const artifactName = path.basename(resolved.path);
|
|
937
724
|
const task = loadTask(taskDir);
|
|
938
725
|
if (!task.ok) return failResult("manual-validation", task.message);
|
|
@@ -954,29 +741,21 @@ async function checkManualValidation({ taskDir, repositoryRoot }: any): Promise<
|
|
|
954
741
|
if (sha256File(resolved.path) !== receipt.artifactSha256) {
|
|
955
742
|
return failResult("manual-validation", `Manual validation artifact digest does not match the receipt for ${artifactName}`);
|
|
956
743
|
}
|
|
957
|
-
// 6.
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
);
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
const completedIndex = inspectedLog.section.entries.findIndex((entry) => entry.step === "Complete Manual Validation"
|
|
973
|
-
&& entry.note.includes(`Manual validation passed → ${artifactName};`)
|
|
974
|
-
&& entry.note.includes(`transaction=${receipt.transactionId};`)
|
|
975
|
-
&& entry.note.includes(`receipt=${receipt.receiptDigest};`)
|
|
976
|
-
&& entry.note.includes(`head=${receipt.prHeadSha}`));
|
|
977
|
-
if (reviewDoneIndex === -1) return failResult("manual-validation", `Latest review-code (round ${review.round}) completion entry is missing from the Activity Log`);
|
|
978
|
-
if (completedIndex === -1) return failResult("manual-validation", `Committed manual validation completion is not recorded for ${artifactName}`);
|
|
979
|
-
if (completedIndex < reviewDoneIndex) return failResult("manual-validation", `Latest review-code (round ${review.round}) came after the manual validation completion recorded for ${artifactName}`);
|
|
744
|
+
// 6. Compare the review completion and committed manual-validation times.
|
|
745
|
+
let reviewReceipt;
|
|
746
|
+
try {
|
|
747
|
+
reviewReceipt = receiptForOutput(task.content, review.fileName!);
|
|
748
|
+
} catch (error) {
|
|
749
|
+
return failResult("manual-validation", `Review-code receipt is invalid: ${error instanceof Error ? error.message : String(error)}`);
|
|
750
|
+
}
|
|
751
|
+
if (!reviewReceipt || reviewReceipt.event !== "review-code.completed") {
|
|
752
|
+
return failResult("manual-validation", `Review-code completion time is unavailable for ${review.fileName}`);
|
|
753
|
+
}
|
|
754
|
+
const reviewTime = Date.parse(reviewReceipt.completedAt.replace(' ', 'T'));
|
|
755
|
+
const validationTime = Date.parse(receipt.committedAt);
|
|
756
|
+
if (!Number.isFinite(reviewTime) || !Number.isFinite(validationTime) || validationTime <= reviewTime) {
|
|
757
|
+
return failResult("manual-validation", `Manual validation must be completed after review-code ${review.fileName}`);
|
|
758
|
+
}
|
|
980
759
|
|
|
981
760
|
const fact = readPrDeliveryFact(task.metadata);
|
|
982
761
|
if (fact.status === "invalid") return failResult("manual-validation", fact.error.message);
|
|
@@ -1212,12 +991,9 @@ function checkReviewFact({ taskDir, artifactFile, repositoryRoot }: any): any {
|
|
|
1212
991
|
}
|
|
1213
992
|
|
|
1214
993
|
const content = fs.readFileSync(resolvedArtifact.path, "utf8");
|
|
1215
|
-
if (!
|
|
994
|
+
if (!hasValidArtifactCompletion(task.content, taskDir, path.basename(resolvedArtifact.path), 'review-code.completed')) {
|
|
1216
995
|
return failResult("review-fact", `Review Code completion fact does not match ${path.basename(resolvedArtifact.path)}`);
|
|
1217
996
|
}
|
|
1218
|
-
if (!hasArtifactCompletionLog(task.content, path.basename(resolvedArtifact.path), 'review-code.completed')) {
|
|
1219
|
-
return failResult("review-fact", `Review Code completion entry does not reference ${path.basename(resolvedArtifact.path)}`);
|
|
1220
|
-
}
|
|
1221
997
|
const verdict = parseReviewVerdict(content);
|
|
1222
998
|
const reviewTargetHead = extractReviewTargetHead(content);
|
|
1223
999
|
const reviewReviewedHead = extractReviewedHead(content);
|
|
@@ -1368,13 +1144,6 @@ function normalizeContent(text: any): any {
|
|
|
1368
1144
|
.trim();
|
|
1369
1145
|
}
|
|
1370
1146
|
|
|
1371
|
-
function interpolate(template: any, taskDir: any, artifactFile: any): any {
|
|
1372
|
-
const artifactStem = artifactFile ? path.basename(artifactFile, path.extname(artifactFile)) : "";
|
|
1373
|
-
return template
|
|
1374
|
-
.replace(/\{task-id\}/g, path.basename(taskDir))
|
|
1375
|
-
.replace(/\{artifact-stem\}/g, artifactStem);
|
|
1376
|
-
}
|
|
1377
|
-
|
|
1378
1147
|
function summarizeGate(checks: any): any {
|
|
1379
1148
|
if (checks.some((check: any) => check.effectiveStatus === "blocked")) {
|
|
1380
1149
|
return "blocked";
|
package/lib/task/verification.ts
CHANGED
|
@@ -17,8 +17,7 @@ type VerificationEvent =
|
|
|
17
17
|
| 'create-pr.completed' | 'create-task.completed'
|
|
18
18
|
| 'import-codescan.completed' | 'import-dependabot.completed'
|
|
19
19
|
| 'import-issue.completed' | 'watch-pr.completed'
|
|
20
|
-
| 'review-pr.completed'
|
|
21
|
-
| 'run-task.paused' | 'run-task.completed';
|
|
20
|
+
| 'review-pr.completed';
|
|
22
21
|
type VerificationSpec = {
|
|
23
22
|
skill: string;
|
|
24
23
|
expectedState: 'active' | 'blocked' | 'completed';
|
|
@@ -75,9 +74,7 @@ const VERIFICATION_CATALOG: Readonly<Record<VerificationEvent, VerificationSpec>
|
|
|
75
74
|
'import-dependabot.completed': gate('import-dependabot', 'active'),
|
|
76
75
|
'import-issue.completed': gate('import-issue', 'active'),
|
|
77
76
|
'watch-pr.completed': gate('watch-pr', 'active'),
|
|
78
|
-
'review-pr.completed': gate('review-pr', 'active', 'pr-review')
|
|
79
|
-
'run-task.paused': { skill: 'run-task', expectedState: 'active', mode: 'checks', checks: ['orchestration-state', 'orchestration-evidence'] },
|
|
80
|
-
'run-task.completed': { skill: 'run-task', expectedState: 'active', mode: 'checks', checks: ['orchestration-state', 'orchestration-evidence'] }
|
|
77
|
+
'review-pr.completed': gate('review-pr', 'active', 'pr-review')
|
|
81
78
|
};
|
|
82
79
|
|
|
83
80
|
function failure(request: { taskRef: string; event: string; artifact?: string }, code: string, message: string, extra: Partial<TaskVerificationResult> = {}): TaskVerificationResult {
|
|
@@ -161,6 +158,9 @@ function renderTaskVerification(result: TaskVerificationResult): string {
|
|
|
161
158
|
&& typeof message === 'string'
|
|
162
159
|
&& /\bhuman-decided (?:post-review )?exemption\b/i.test(message)
|
|
163
160
|
&& /\bPRC-\d+\s*:/.test(message);
|
|
161
|
+
if (Array.isArray(check.warnings)) {
|
|
162
|
+
for (const warning of check.warnings) if (typeof warning === 'string') lines.push(`Warning: ${id} - ${warning}`);
|
|
163
|
+
}
|
|
164
164
|
if (effectiveStatus === 'pass' && !isSoftWarning && !isHumanExemptionNotice) continue;
|
|
165
165
|
lines.push(isSoftWarning
|
|
166
166
|
? `Warning: ${id} (${rawStatus === 'blocked' ? `raw BLOCKED; ` : ''}${reason}) - ${message}; ${action}`
|
package/lib/task/write.ts
CHANGED
|
@@ -14,6 +14,7 @@ import type {
|
|
|
14
14
|
TaskWorkspaceState
|
|
15
15
|
} from './resolve-ref.ts';
|
|
16
16
|
import { mutateTableRow, upsertSection } from './sections.ts';
|
|
17
|
+
import { lifecycleExecutions, prReviewExecution, serializeLifecycleExecution } from './lifecycle-execution.ts';
|
|
17
18
|
import { validateCurrentTaskContract } from './current-contract.ts';
|
|
18
19
|
import type {
|
|
19
20
|
TableRowDeleteMutation,
|
|
@@ -24,6 +25,7 @@ type FrontmatterMutation = {
|
|
|
24
25
|
kind: 'frontmatter';
|
|
25
26
|
set: Readonly<Record<string, FrontmatterScalar>>;
|
|
26
27
|
remove?: readonly string[];
|
|
28
|
+
lifecycleExecutionDomain?: 'ordinary' | 'pr-review';
|
|
27
29
|
};
|
|
28
30
|
|
|
29
31
|
type SectionMutation = {
|
|
@@ -288,7 +290,16 @@ function writeTaskCore(request: TaskWriteRequest, options: TaskWriteOptions = {}
|
|
|
288
290
|
}
|
|
289
291
|
const before = candidate;
|
|
290
292
|
if (mutation.kind === 'frontmatter') {
|
|
291
|
-
|
|
293
|
+
let set = mutation.set;
|
|
294
|
+
if (mutation.lifecycleExecutionDomain) {
|
|
295
|
+
const proposed = updateTaskFrontmatter(candidate, mutation.set);
|
|
296
|
+
const open = mutation.lifecycleExecutionDomain === 'ordinary'
|
|
297
|
+
? lifecycleExecutions(proposed)
|
|
298
|
+
: lifecycleExecutions(candidate);
|
|
299
|
+
const pr = prReviewExecution(mutation.lifecycleExecutionDomain === 'pr-review' ? proposed : candidate);
|
|
300
|
+
set = { ...mutation.set, lifecycle_execution: serializeLifecycleExecution(open, undefined, pr) };
|
|
301
|
+
}
|
|
302
|
+
candidate = updateTaskFrontmatter(candidate, set, mutation.remove);
|
|
292
303
|
operations.push({
|
|
293
304
|
index,
|
|
294
305
|
kind: 'frontmatter',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fitlab-ai/agent-infra",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.2",
|
|
4
4
|
"description": "Bootstrap tool for AI multi-tool collaboration infrastructure — works with Claude Code, Codex, Antigravity CLI, and OpenCode",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"@clack/prompts": "1.8.1",
|
|
56
56
|
"@larksuiteoapi/node-sdk": "^1.68.0",
|
|
57
57
|
"cross-spawn": "^7.0.6",
|
|
58
|
-
"fs-native-extensions": "1.5.
|
|
58
|
+
"fs-native-extensions": "1.5.2",
|
|
59
59
|
"picocolors": "1.1.1",
|
|
60
60
|
"semver": "^7.8.1",
|
|
61
61
|
"smol-toml": "^1.6.1",
|
|
@@ -222,16 +222,14 @@ Ordinary `managed` files keep their overwrite semantics. A small set of platform
|
|
|
222
222
|
|
|
223
223
|
## Agent Client Configuration
|
|
224
224
|
|
|
225
|
-
Use the top-level `.agents/.airc.json` `agentClients` array to configure all five built-in clients (`claude-code`, `codex`, `antigravity-cli`, `opencode`, `traecli`). Each canonical entry has three required fields
|
|
225
|
+
Use the top-level `.agents/.airc.json` `agentClients` array to configure all five built-in clients (`claude-code`, `codex`, `antigravity-cli`, `opencode`, `traecli`). Each canonical entry has three required fields:
|
|
226
226
|
|
|
227
227
|
| Field | Meaning |
|
|
228
228
|
|-------|---------|
|
|
229
229
|
| `id` | Built-in Agent Client id. The canonical array contains exactly one entry for each built-in client. |
|
|
230
230
|
| `enabled` | Whether agent-infra writes and maintains that client's project integration and seed command. |
|
|
231
231
|
| `installInSandbox` | Whether the sandbox image installs that client's CLI. This is independent from `enabled`. |
|
|
232
|
-
| `orchestration` | Optional `run-task` default. It must include executor/reviewer `model` and host-native `reasoningEffort`; both roles may use the same model. |
|
|
233
232
|
|
|
234
|
-
Explicit `run-task` model/effort flags are atomic: any one requires all four role fields and configuration never fills omissions. With no explicit policy, only the current client's `orchestration` is used. Query model-selection context with `agent-infra-internal agent-client model-selection --client <id>`; it labels results complete, partial, or interactive-only and never presents a local override list as a complete catalog.
|
|
235
233
|
|
|
236
234
|
Manage these settings without hand-editing JSON:
|
|
237
235
|
|
|
@@ -228,9 +228,7 @@ disable-model-invocation: true # 可选;由支持该能力的 TUI 适配器
|
|
|
228
228
|
| `id` | 内建 Agent Client id。规范数组为每个内建客户端保留且仅保留一个条目。 |
|
|
229
229
|
| `enabled` | agent-infra 是否写入并维护该客户端的项目集成与种子命令。 |
|
|
230
230
|
| `installInSandbox` | 沙箱镜像是否安装该客户端 CLI;此字段与 `enabled` 相互独立。 |
|
|
231
|
-
| `orchestration` | `run-task` 可选默认策略;必须同时提供 executor/reviewer 的 `model` 与宿主原生 `reasoningEffort`,两个角色可以使用同一模型。 |
|
|
232
231
|
|
|
233
|
-
`run-task` 的显式 model/effort 参数是原子输入:只要提供其中任一字段,就必须完整提供四个 role 字段,不能从配置补齐。完全没有显式策略时,只读取当前客户端的 `orchestration`。模型目录通过 `agent-infra-internal agent-client model-selection --client <id>` 查询,并明确标记 complete、partial 或 interactive-only;局部 override 列表不能当作完整目录。
|
|
234
232
|
|
|
235
233
|
无需手工编辑 JSON,可使用:
|
|
236
234
|
|
|
@@ -31,7 +31,6 @@ so you can quickly find "which ones to read" without opening each file.
|
|
|
31
31
|
## Task Workflow
|
|
32
32
|
|
|
33
33
|
- [`task-management.md`](task-management.md) — Task intent detection, workflow-command mapping, and skill blocking boundaries.
|
|
34
|
-
- [`lifecycle-orchestration.md`](lifecycle-orchestration.md) — Fresh executor/reviewer, one-use receipt, pause/recovery, and safe endpoint rules for `run-task`.
|
|
35
34
|
- [`review-handshake.md`](review-handshake.md) — Three-stage bidirectional review handshake: four-state disposition, symmetric evidence, disagreement ledger, convergence and post-review commit gate.
|
|
36
35
|
- [`review-method.md`](review-method.md) — Shared three-stage review method: multi-pass review, risk lenses, traceability, and finding evidence.
|
|
37
36
|
- [`local-artifact-repair.md`](local-artifact-repair.md) — Pre-completion local artifact validation for analysis/plan/code and model-per-case repair, safety gates, and convergence for failed review artifacts.
|
|
@@ -30,7 +30,6 @@
|
|
|
30
30
|
## 任务工作流
|
|
31
31
|
|
|
32
32
|
- [`task-management.md`](task-management.md) — 任务语义识别、工作流命令映射与技能阻塞边界。
|
|
33
|
-
- [`lifecycle-orchestration.md`](lifecycle-orchestration.md) — `run-task` 的 fresh executor/reviewer、一次性 receipt、暂停恢复与安全终点规则。
|
|
34
33
|
- [`review-handshake.md`](review-handshake.md) — 三阶段双向审查握手协议:四态处置、对称证据、分歧账本、收敛与 post-review commit 门禁。
|
|
35
34
|
- [`review-method.md`](review-method.md) — 三阶段共享检视方法:多遍检视、风险镜头、追踪与 finding 证据契约。
|
|
36
35
|
- [`local-artifact-repair.md`](local-artifact-repair.md) — analysis/plan/code completed 前的本地产物校验、review artifact 失败后的模型逐例修复、机械安全门与收敛契约。
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
## Commit Execution Boundary
|
|
11
11
|
|
|
12
12
|
- Do not run `git add` or `git commit` directly. All automatic commits must use the shared `agent-infra-internal git-workflow commit` core and follow the paths, HEAD/tree, and delivery-mode constraints of the applicable skill.
|
|
13
|
-
- The active workflow defines whether a commit is required. Completing `code-task` requires a local checkpoint through the shared core after tests and report preflight pass.
|
|
13
|
+
- The active workflow defines whether a commit is required. Completing `code-task` requires a local checkpoint through the shared core after tests and report preflight pass. The current code-task invocation calls the shared core.
|
|
14
14
|
- A `code-task` checkpoint never pushes to a remote. Other skills may call the shared core only when their workflow explicitly requires it. The standalone `commit` skill still requires an explicit user invocation and follows its push-delivery flow.
|
|
15
15
|
- Do not create a commit when the workflow does not require one. When a separate user commit is needed, remind the user to use the appropriate TUI command.
|
|
16
16
|
|