@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
package/lib/task/events.ts
CHANGED
|
@@ -4,7 +4,9 @@ import { execFileSync } from 'node:child_process';
|
|
|
4
4
|
|
|
5
5
|
import { resolveBranchWorktree } from '../git/branch-worktree.ts';
|
|
6
6
|
|
|
7
|
-
import { appendActivityEntry,
|
|
7
|
+
import { appendActivityEntry, inspectActivityLog } from './activity-log.ts';
|
|
8
|
+
import { lifecycleExecutions, serializeLifecycleExecution } from './lifecycle-execution.ts';
|
|
9
|
+
import type { LifecycleExecution } from './lifecycle-execution.ts';
|
|
8
10
|
import {
|
|
9
11
|
buildArtifactLinkSection,
|
|
10
12
|
inspectArtifactDirectory,
|
|
@@ -28,13 +30,9 @@ import { parseReviewSummary, resolveCanonicalVerdict } from './review-artifacts.
|
|
|
28
30
|
import { extractReviewBaseline, extractReviewedHead, extractReviewedSnapshotTree } from './review-fingerprint.ts';
|
|
29
31
|
import { resolveTaskRef } from './resolve-ref.ts';
|
|
30
32
|
import { findSectionHeading } from './sections.ts';
|
|
31
|
-
import { validateLifecycleExecution } from './lifecycle-execution.ts';
|
|
32
|
-
import { commitOrchestrationStageCompletion } from './orchestration.ts';
|
|
33
|
-
import type { OrchestrationStageCompletion } from './orchestration.ts';
|
|
34
33
|
import { captureTaskWriteMetadata, writeTask } from './write.ts';
|
|
35
34
|
import type { TaskOperationSummary, TaskWriteErrorCode, TaskWriteOptions } from './write.ts';
|
|
36
35
|
import { validateLocalArtifact } from './local-artifact-finalization.ts';
|
|
37
|
-
import type { LocalArtifactFamily } from './local-artifact-finalization.ts';
|
|
38
36
|
import { buildLifecycleFacts, canStart, effectiveReworkTarget } from './capabilities.ts';
|
|
39
37
|
import type { ExplicitTrigger, LifecycleAction, TriggerInitiator, TriggerReason } from './capabilities.ts';
|
|
40
38
|
import { consumeReworkIntents, parseReworkIntentDocument, reworkIntentMutation, supersedeReworkIntents } from './rework-intent.ts';
|
|
@@ -43,7 +41,7 @@ import { parseTaskQualification } from './qualification-audit.ts';
|
|
|
43
41
|
import { getArtifactSchema } from './artifact-schema.ts';
|
|
44
42
|
import { canonicalSemanticDigest, inspectArtifactContract } from './artifact-operations.ts';
|
|
45
43
|
import { inspectReviewIdentity } from './review-identity.ts';
|
|
46
|
-
import { parseCompletionFacts, type CompletionFact } from './completion-facts.ts';
|
|
44
|
+
import { hasValidArtifactCompletion, parseCompletionFacts, type CompletionFact } from './completion-facts.ts';
|
|
47
45
|
import { readManualValidationCompletion } from './manual-validation-completion.ts';
|
|
48
46
|
import { parseLifecyclePathDecision } from './lifecycle-path.ts';
|
|
49
47
|
|
|
@@ -65,14 +63,13 @@ type TaskEventErrorCode =
|
|
|
65
63
|
| 'EVENT_LOG_MISSING' | 'EVENT_START_MISSING' | 'EVENT_ALREADY_COMPLETED'
|
|
66
64
|
| 'EVENT_LOG_CONFLICT' | 'EVENT_ARTIFACT_CONFLICT' | 'EVENT_FINDING_COUNT_MISMATCH'
|
|
67
65
|
| 'EVENT_VERDICT_INVALID'
|
|
68
|
-
| 'EVENT_ORCHESTRATION_COMMIT_FAILED'
|
|
69
66
|
| 'MANUAL_VALIDATION_RECEIPT_MISSING' | 'MANUAL_VALIDATION_RECEIPT_INVALID'
|
|
70
67
|
| 'MANUAL_VALIDATION_RECEIPT_IDENTITY_MISMATCH'
|
|
71
68
|
| 'MANUAL_VALIDATION_TRANSACTION_MISSING' | 'MANUAL_VALIDATION_TRANSACTION_INVALID'
|
|
72
69
|
| 'MANUAL_VALIDATION_TRANSACTION_IDENTITY_MISMATCH' | 'MANUAL_VALIDATION_TRANSACTION_PHASE_INVALID'
|
|
73
70
|
| ArtifactErrorCode | TaskWriteErrorCode;
|
|
74
71
|
type TaskEventRequest = {
|
|
75
|
-
taskRef: string; event: TaskEventName | string; agent: string; dryRun?: boolean;
|
|
72
|
+
taskRef: string; event: TaskEventName | string; agent: string; dryRun?: boolean;
|
|
76
73
|
initiator?: TriggerInitiator; requestId?: string; reasonCode?: TriggerReason;
|
|
77
74
|
sourceFinding?: string; sourceArtifact?: string; sourceSha256?: string;
|
|
78
75
|
round?: number; question?: number; artifact?: string; fixFor?: string; implementationInput?: string;
|
|
@@ -83,9 +80,7 @@ type TaskEventRequest = {
|
|
|
83
80
|
transactionId?: string; receiptDigest?: string; prHeadSha?: string;
|
|
84
81
|
};
|
|
85
82
|
type TaskEventError = { code: TaskEventErrorCode; message: string };
|
|
86
|
-
type TaskEventOptions = TaskWriteOptions
|
|
87
|
-
commitOrchestrationCompletion?: (plan: OrchestrationStageCompletion) => void;
|
|
88
|
-
};
|
|
83
|
+
type TaskEventOptions = TaskWriteOptions;
|
|
89
84
|
type TaskEventResult = {
|
|
90
85
|
status: 'planned' | 'applied' | 'no-op' | 'failed'; changed: boolean;
|
|
91
86
|
event: string; requestRef: string; taskId: string | null; taskMdPath: string | null;
|
|
@@ -95,6 +90,7 @@ type TaskEventResult = {
|
|
|
95
90
|
artifactContext: ArtifactContextResult | null;
|
|
96
91
|
timestamp: string | null; agentInfraVersion: string | null;
|
|
97
92
|
operations: readonly TaskOperationSummary[]; error: TaskEventError | null;
|
|
93
|
+
warnings?: readonly { code: string; message: string }[];
|
|
98
94
|
};
|
|
99
95
|
|
|
100
96
|
function branchWorktree(repoRoot: string, branch: string): string | null {
|
|
@@ -125,17 +121,17 @@ const BASE_FIELDS = new Set(['taskRef', 'event', 'agent', 'dryRun', 'initiator',
|
|
|
125
121
|
const SCHEMAS: Record<TaskEventName, { required?: string[]; optional?: string[] }> = {
|
|
126
122
|
'analyze.started': { optional: ['round'] },
|
|
127
123
|
'analyze.awaiting-input': { required: ['question'] },
|
|
128
|
-
'analyze.completed': { required: ['artifact', 'artifactSha256', 'semanticDigest'], optional: ['round'
|
|
124
|
+
'analyze.completed': { required: ['artifact', 'artifactSha256', 'semanticDigest'], optional: ['round'] },
|
|
129
125
|
'review-analysis.started': { optional: ['round'] },
|
|
130
|
-
'review-analysis.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round'
|
|
126
|
+
'review-analysis.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round'] },
|
|
131
127
|
'plan.started': { optional: ['round'] },
|
|
132
|
-
'plan.completed': { required: ['artifact', 'artifactSha256', 'semanticDigest'], optional: ['round'
|
|
128
|
+
'plan.completed': { required: ['artifact', 'artifactSha256', 'semanticDigest'], optional: ['round'] },
|
|
133
129
|
'review-plan.started': { optional: ['round'] },
|
|
134
|
-
'review-plan.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round'
|
|
130
|
+
'review-plan.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round'] },
|
|
135
131
|
'code.started': { optional: ['round', 'fixFor', 'implementationInput'] },
|
|
136
|
-
'code.completed': { required: ['artifact', 'artifactSha256', 'semanticDigest'], optional: ['round', 'fixFor', 'implementationInput', 'filesModified', 'testsPassed', 'blockers', 'major', 'minor', 'manualValidation'
|
|
132
|
+
'code.completed': { required: ['artifact', 'artifactSha256', 'semanticDigest'], optional: ['round', 'fixFor', 'implementationInput', 'filesModified', 'testsPassed', 'blockers', 'major', 'minor', 'manualValidation'] },
|
|
137
133
|
'review-code.started': { optional: ['round'] },
|
|
138
|
-
'review-code.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round'
|
|
134
|
+
'review-code.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round'] },
|
|
139
135
|
'manual-validation.started': { optional: ['round', 'transactionId'] },
|
|
140
136
|
'manual-validation.completed': { required: ['artifact', 'summaryResult', 'transactionId', 'receiptDigest', 'prHeadSha'], optional: ['round'] },
|
|
141
137
|
'validation-run.started': { optional: ['round'] },
|
|
@@ -157,7 +153,7 @@ function validateTaskEventRequest(request: TaskEventRequest): TaskEventError | n
|
|
|
157
153
|
if (value !== undefined && (!Number.isInteger(value) || value < (key === 'round' || key === 'question' ? 1 : 0))) return { code: 'EVENT_PAYLOAD_INVALID', message: `'${key}' must be a ${key === 'round' || key === 'question' ? 'positive' : 'non-negative'} integer` };
|
|
158
154
|
}
|
|
159
155
|
if (request.verdict && !['approved', 'changes-requested', 'rejected'].includes(request.verdict)) return { code: 'EVENT_PAYLOAD_INVALID', message: 'verdict is invalid' };
|
|
160
|
-
if (request.initiator && !['human', 'model'
|
|
156
|
+
if (request.initiator && !['human', 'model'].includes(request.initiator)) return { code: 'EVENT_PAYLOAD_INVALID', message: 'initiator is invalid' };
|
|
161
157
|
if (request.requestId !== undefined && (!request.requestId.trim() || /[\r\n]/.test(request.requestId))) return { code: 'EVENT_PAYLOAD_INVALID', message: 'requestId must be a non-empty single line' };
|
|
162
158
|
if (request.reasonCode && !['user-request', 'new-requirement', 'upstream-fact-doubt', 'review-finding', 'manual-review-supplement', 'retry', 'validation-rerun'].includes(request.reasonCode)) return { code: 'EVENT_PAYLOAD_INVALID', message: 'reasonCode is invalid' };
|
|
163
159
|
for (const [name, value] of [['sourceFinding', request.sourceFinding], ['sourceArtifact', request.sourceArtifact], ['sourceSha256', request.sourceSha256]] as const) {
|
|
@@ -368,27 +364,19 @@ function validateManualValidationCompletion(
|
|
|
368
364
|
return null;
|
|
369
365
|
}
|
|
370
366
|
|
|
371
|
-
function openStartedIdentity(rows:
|
|
372
|
-
const
|
|
367
|
+
function openStartedIdentity(rows: LifecycleExecution[], family: EventFamily) {
|
|
368
|
+
const matches = rows.filter((item) => item.family === family);
|
|
373
369
|
if (family === 'manual-validation') {
|
|
374
|
-
const row =
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
}
|
|
378
|
-
const escaped = spec.label.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
379
|
-
const pattern = new RegExp(`^${escaped} \\(Round (\\d+)(?:(?:, fix for (review-code(?:-r\\d+)?\\.md))|(?:, decision (II-[1-9]\\d*)))?\\)$`);
|
|
380
|
-
const matches = rows.flatMap((row) => {
|
|
381
|
-
if (!row.started || row.done) return [];
|
|
382
|
-
const match = pattern.exec(row.step);
|
|
383
|
-
return match ? [{ row, round: Number(match[1]), fixFor: match[2], implementationInput: match[3] }] : [];
|
|
384
|
-
});
|
|
385
|
-
return matches.length === 1 ? matches[0] : matches.length > 1 ? { conflict: true as const } : null;
|
|
370
|
+
const row = matches.at(-1);
|
|
371
|
+
return row ? { row, round: row.round!, fixFor: undefined, implementationInput: undefined } : null;
|
|
372
|
+
}
|
|
373
|
+
return matches.length === 1 ? { row: matches[0]!, round: matches[0]!.round!, fixFor: matches[0]!.fixFor, implementationInput: matches[0]!.implementationInput } : matches.length > 1 ? { conflict: true as const } : null;
|
|
386
374
|
}
|
|
387
375
|
|
|
388
376
|
function repairMissingCodeFixQualifier(
|
|
389
377
|
request: TaskEventRequest,
|
|
390
378
|
family: EventFamily,
|
|
391
|
-
open: { row:
|
|
379
|
+
open: { row: LifecycleExecution; round: number; fixFor?: string; implementationInput?: string },
|
|
392
380
|
repoRoot: string
|
|
393
381
|
) {
|
|
394
382
|
if (family !== 'code' || open.fixFor !== undefined || !request.fixFor || request.implementationInput !== undefined) {
|
|
@@ -411,12 +399,12 @@ function repairMissingCodeFixQualifier(
|
|
|
411
399
|
function resolveOpenStartedEvent(
|
|
412
400
|
request: TaskEventRequest,
|
|
413
401
|
family: EventFamily,
|
|
414
|
-
open: { row:
|
|
402
|
+
open: { row: LifecycleExecution; round: number; fixFor?: string; implementationInput?: string },
|
|
415
403
|
repoRoot: string
|
|
416
404
|
) {
|
|
417
405
|
if (open.row.agent !== request.agent) return { status: 'error' as const, error: { code: 'EVENT_LOG_CONFLICT', message: 'open started event has a different agent' } as TaskEventError };
|
|
418
406
|
if (family === 'manual-validation' && request.transactionId !== undefined) {
|
|
419
|
-
const existingTransactionId =
|
|
407
|
+
const existingTransactionId = open.row.transactionId;
|
|
420
408
|
if (existingTransactionId !== undefined && existingTransactionId !== request.transactionId) {
|
|
421
409
|
return { status: 'error' as const, error: { code: 'EVENT_LOG_CONFLICT', message: 'open manual-validation started event has a different transactionId' } as TaskEventError };
|
|
422
410
|
}
|
|
@@ -428,7 +416,7 @@ function resolveOpenStartedEvent(
|
|
|
428
416
|
const repair = repairMissingCodeFixQualifier(request, family, open, repoRoot);
|
|
429
417
|
if (!repair) return { status: 'error' as const, error: { code: 'EVENT_ARTIFACT_CONFLICT', message: `fixFor '${request.fixFor}' conflicts with open event` } as TaskEventError };
|
|
430
418
|
if ('error' in repair) return { status: 'error' as const, error: repair.error, context: repair.context };
|
|
431
|
-
return { status: 'repair' as const, repair: repair.request, context: repair.context, superseded: { action: open.row.
|
|
419
|
+
return { status: 'repair' as const, repair: repair.request, context: repair.context, superseded: { action: `${FAMILY[family].label} (Round ${open.round})`, family: open.row.family, round: open.row.round } };
|
|
432
420
|
}
|
|
433
421
|
if (request.implementationInput !== open.implementationInput) {
|
|
434
422
|
return { status: 'error' as const, error: { code: 'EVENT_ARTIFACT_CONFLICT', message: `implementationInput '${request.implementationInput ?? ''}' conflicts with open event` } as TaskEventError };
|
|
@@ -442,19 +430,12 @@ function resolveOpenStartedEvent(
|
|
|
442
430
|
fixFor: open.fixFor,
|
|
443
431
|
implementationInput: open.implementationInput
|
|
444
432
|
},
|
|
445
|
-
startedAt: open.row.
|
|
433
|
+
startedAt: open.row.startedAt
|
|
446
434
|
};
|
|
447
435
|
}
|
|
448
436
|
|
|
449
|
-
function
|
|
450
|
-
return rows.some((row) => row.
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
function hasConflictingOpenStarted(
|
|
454
|
-
rows: ReturnType<typeof pairEntries>,
|
|
455
|
-
recovery: { action: string } | null
|
|
456
|
-
): boolean {
|
|
457
|
-
return recovery ? hasOtherOpenStarted(rows, recovery.action) : rows.some((row) => row.started && !row.done);
|
|
437
|
+
function hasConflictingOpenStarted(rows: LifecycleExecution[], recovery: { family: string; round?: number } | null): boolean {
|
|
438
|
+
return rows.some((row) => !recovery || row.family !== recovery.family || row.round !== recovery.round);
|
|
458
439
|
}
|
|
459
440
|
|
|
460
441
|
function reviewInputFamily(family: EventFamily): ArtifactFamily {
|
|
@@ -467,7 +448,7 @@ function lifecycleAction(family: EventFamily): LifecycleAction {
|
|
|
467
448
|
|
|
468
449
|
function eventTrigger(request: TaskEventRequest, family: EventFamily): ExplicitTrigger {
|
|
469
450
|
return {
|
|
470
|
-
initiator: request.initiator ?? (request.
|
|
451
|
+
initiator: request.initiator ?? (request.agent === 'human' ? 'human' : 'model'),
|
|
471
452
|
requestId: request.requestId ?? `${request.taskRef}:${request.event}:${request.round ?? 1}`,
|
|
472
453
|
requestedAction: lifecycleAction(family),
|
|
473
454
|
reasonCode: request.reasonCode ?? (request.fixFor || request.implementationInput ? 'review-finding' : 'user-request'),
|
|
@@ -475,7 +456,7 @@ function eventTrigger(request: TaskEventRequest, family: EventFamily): ExplicitT
|
|
|
475
456
|
...(request.sourceArtifact ? { sourceArtifact: request.sourceArtifact } : {}),
|
|
476
457
|
...(request.sourceSha256 ? { sourceSha256: request.sourceSha256 } : {}),
|
|
477
458
|
...(request.implementationInput ? { implementationInput: request.implementationInput } : {}),
|
|
478
|
-
explicitRequest: request.requestId !== undefined || request.reasonCode !== undefined || request.initiator !== undefined
|
|
459
|
+
explicitRequest: request.requestId !== undefined || request.reasonCode !== undefined || request.initiator !== undefined
|
|
479
460
|
};
|
|
480
461
|
}
|
|
481
462
|
|
|
@@ -639,12 +620,16 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
|
|
|
639
620
|
let frontmatter;
|
|
640
621
|
try { frontmatter = parseTypedTaskFrontmatter(content); }
|
|
641
622
|
catch (error) { return failed(request, { code: 'TASK_DOCUMENT_INVALID', message: error instanceof Error ? error.message : String(error) }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath }); }
|
|
642
|
-
const section =
|
|
643
|
-
|
|
644
|
-
|
|
623
|
+
const section = inspectActivityLog(content).section;
|
|
624
|
+
let rows: LifecycleExecution[];
|
|
625
|
+
try {
|
|
626
|
+
rows = lifecycleExecutions(content);
|
|
627
|
+
} catch (error) {
|
|
628
|
+
return failed(request, { code: 'EVENT_TRANSITION_INVALID', message: error instanceof Error ? error.message : String(error) }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
|
|
629
|
+
}
|
|
645
630
|
let normalized = request;
|
|
646
631
|
let artifactContext: ArtifactContextResult | null = null;
|
|
647
|
-
let supersededOpenStart: { action: string } | null = null;
|
|
632
|
+
let supersededOpenStart: { action: string; family: string; round?: number } | null = null;
|
|
648
633
|
if (initialParts.phase === 'started') {
|
|
649
634
|
const openIdentity = openStartedIdentity(rows, initialParts.family);
|
|
650
635
|
if (openIdentity && 'conflict' in openIdentity) return failed(request, { code: 'EVENT_LOG_CONFLICT', message: 'artifact family has more than one open started event' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
|
|
@@ -674,10 +659,11 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
|
|
|
674
659
|
}
|
|
675
660
|
const eventIdentity = identity(normalized);
|
|
676
661
|
const currentStep = typeof frontmatter.current_step === 'string' ? frontmatter.current_step : '';
|
|
677
|
-
const matchingRows = rows.filter((item) => item.step === eventIdentity.action);
|
|
678
662
|
const manual = eventIdentity.family === 'manual-validation';
|
|
679
|
-
const openRows =
|
|
680
|
-
const
|
|
663
|
+
const openRows = rows.filter((item) => item.family === eventIdentity.family && (manual || (item.round === normalized.round && item.fixFor === normalized.fixFor && item.implementationInput === normalized.implementationInput)));
|
|
664
|
+
const completionRecorded = normalized.artifact !== undefined && parseCompletionFacts(frontmatter.completion_facts)
|
|
665
|
+
.some((fact) => fact.event === normalized.event && fact.output === normalized.artifact);
|
|
666
|
+
const hasStartedIdentity = openRows.length > 0;
|
|
681
667
|
if (!manual && openRows.length > 1) return failed(normalized, { code: 'EVENT_LOG_CONFLICT', message: 'event identity has more than one open attempt' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase, artifactContext });
|
|
682
668
|
const row = openRows.at(-1);
|
|
683
669
|
let completedArtifact: ArtifactIdentity | null = null;
|
|
@@ -685,14 +671,22 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
|
|
|
685
671
|
if (eventIdentity.phase === 'started' && row) {
|
|
686
672
|
if (row.agent !== normalized.agent) return failed(normalized, { code: 'EVENT_LOG_CONFLICT', message: 'open started event has a different agent' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
|
|
687
673
|
if (manual && normalized.transactionId !== undefined) {
|
|
688
|
-
const existingTransactionId =
|
|
674
|
+
const existingTransactionId = row.transactionId;
|
|
689
675
|
if (existingTransactionId !== undefined && existingTransactionId !== normalized.transactionId) {
|
|
690
676
|
return failed(normalized, { code: 'EVENT_LOG_CONFLICT', message: 'open manual-validation started event has a different transactionId' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
|
|
691
677
|
}
|
|
692
678
|
}
|
|
693
|
-
return successNoOp(normalized, resolved.taskId, resolved.taskMdPath, currentStep, eventIdentity, row.
|
|
694
|
-
}
|
|
695
|
-
|
|
679
|
+
return successNoOp(normalized, resolved.taskId, resolved.taskMdPath, currentStep, eventIdentity, row.startedAt, frontmatter, artifactContext);
|
|
680
|
+
}
|
|
681
|
+
const replayFact = eventIdentity.phase === 'completed' && normalized.artifact && normalized.requestId
|
|
682
|
+
? parseCompletionFacts(frontmatter.completion_facts).find((fact) => fact.event === normalized.event
|
|
683
|
+
&& fact.output === normalized.artifact && fact.requestId === normalized.requestId)
|
|
684
|
+
: undefined;
|
|
685
|
+
const validReplayFact = Boolean(replayFact && normalized.artifact
|
|
686
|
+
&& hasValidArtifactCompletion(content, resolved.taskDir, normalized.artifact, normalized.event));
|
|
687
|
+
const completedByHistory = manual || eventIdentity.family === 'validation-run';
|
|
688
|
+
const completedHistoryReplay = completedByHistory && completionRecorded;
|
|
689
|
+
if (eventIdentity.phase === 'completed' && !hasStartedIdentity && !completedHistoryReplay && !validReplayFact) return failed(normalized, { code: 'EVENT_START_MISSING', message: 'completion requires a started event or an earlier completed attempt' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
696
690
|
if (eventIdentity.phase === 'completed') {
|
|
697
691
|
const validated = validateCompletedArtifact(resolved.taskDir, FAMILY[eventIdentity.family].artifact, normalized.artifact!, normalized.round);
|
|
698
692
|
if (!validated.ok) return failed(normalized, validated.error, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
@@ -750,10 +744,6 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
|
|
|
750
744
|
}
|
|
751
745
|
}
|
|
752
746
|
}
|
|
753
|
-
if (eventIdentity.phase === 'waiting' && section.entries.some((entry) => entry.step === eventIdentity.action && entry.note === eventIdentity.note)) {
|
|
754
|
-
const existing = section.entries.find((entry) => entry.step === eventIdentity.action && entry.note === eventIdentity.note)!;
|
|
755
|
-
return successNoOp(normalized, resolved.taskId, resolved.taskMdPath, currentStep, eventIdentity, existing.time, frontmatter, artifactContext);
|
|
756
|
-
}
|
|
757
747
|
if (eventIdentity.phase === 'started') {
|
|
758
748
|
const trigger = eventTrigger(normalized, eventIdentity.family);
|
|
759
749
|
const facts = buildLifecycleFacts(resolved.taskDir, content, resolved.state, false, resolved.repoRoot);
|
|
@@ -761,7 +751,7 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
|
|
|
761
751
|
const capability = canStart(lifecycleAction(eventIdentity.family), facts.facts, trigger);
|
|
762
752
|
const safetyFailure = capability.reasonCode === 'TASK_NOT_ACTIVE'
|
|
763
753
|
|| capability.reasonCode === 'LIFECYCLE_EXECUTION_OPEN';
|
|
764
|
-
if (!capability.allowed &&
|
|
754
|
+
if (!capability.allowed && safetyFailure
|
|
765
755
|
&& !(supersededOpenStart && capability.reasonCode === 'LIFECYCLE_EXECUTION_OPEN')) {
|
|
766
756
|
return failed(normalized, { code: 'EVENT_TRANSITION_INVALID', message: `${capability.reasonCode}: ${capability.evidence.join(', ')}` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
767
757
|
}
|
|
@@ -773,29 +763,6 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
|
|
|
773
763
|
completedArtifact?.path ?? null
|
|
774
764
|
);
|
|
775
765
|
if (findingCountError) return failed(normalized, findingCountError, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
776
|
-
let orchestrationCompletion: OrchestrationStageCompletion | null = null;
|
|
777
|
-
if (eventIdentity.phase === 'completed' && normalized.orchestrated
|
|
778
|
-
&& eventIdentity.family !== 'manual-validation' && eventIdentity.family !== 'validation-run') {
|
|
779
|
-
const orchestrationStage = eventIdentity.family === 'analyze' ? 'analysis' : eventIdentity.family;
|
|
780
|
-
const execution = validateLifecycleExecution(normalized.taskRef, {
|
|
781
|
-
mode: 'orchestrated',
|
|
782
|
-
identity: {
|
|
783
|
-
stage: orchestrationStage,
|
|
784
|
-
round: normalized.round!,
|
|
785
|
-
artifact: normalized.artifact!,
|
|
786
|
-
role: eventIdentity.family.startsWith('review-') ? 'reviewer' : 'executor'
|
|
787
|
-
},
|
|
788
|
-
agent: normalized.agent,
|
|
789
|
-
dryRun: normalized.dryRun
|
|
790
|
-
}, { repoRoot: options.repoRoot });
|
|
791
|
-
if (!execution.ok) {
|
|
792
|
-
return failed(normalized, {
|
|
793
|
-
code: 'EVENT_TRANSITION_INVALID',
|
|
794
|
-
message: `${execution.error?.code ?? 'ORCHESTRATION_PROVENANCE_MISMATCH'}: ${execution.error?.message ?? 'orchestration provenance validation failed'}`
|
|
795
|
-
}, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase, artifactContext });
|
|
796
|
-
}
|
|
797
|
-
orchestrationCompletion = execution.completionPlan;
|
|
798
|
-
}
|
|
799
766
|
let metadata;
|
|
800
767
|
try { metadata = (options.metadataProvider ?? captureTaskWriteMetadata)(); }
|
|
801
768
|
catch (error) { return failed(normalized, { code: 'METADATA_CAPTURE_FAILED', message: String(error) }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath }); }
|
|
@@ -828,6 +795,9 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
|
|
|
828
795
|
artifactContext
|
|
829
796
|
);
|
|
830
797
|
}
|
|
798
|
+
if (!hasStartedIdentity && !completedHistoryReplay) {
|
|
799
|
+
return failed(normalized, { code: 'EVENT_START_MISSING', message: 'completion replay does not match the existing completion fact' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
800
|
+
}
|
|
831
801
|
try {
|
|
832
802
|
const rework = reworkIntentMutationForCompletion(content, resolved.taskDir, eventIdentity.family, completedArtifact, metadata.timestamp);
|
|
833
803
|
if ('error' in rework) return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: rework.error }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
@@ -838,19 +808,22 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
|
|
|
838
808
|
}
|
|
839
809
|
const step = eventIdentity.phase === 'started' || eventIdentity.target === null ? currentStep : eventIdentity.target;
|
|
840
810
|
const logStep = eventIdentity.phase === 'started' ? `${eventIdentity.action} [started]` : eventIdentity.action;
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
{ time: metadata.timestamp, step: logStep, agent: normalized.agent, note: eventIdentity.note }
|
|
852
|
-
);
|
|
811
|
+
let body: string | null = null;
|
|
812
|
+
if (section) {
|
|
813
|
+
const supersededBody = supersededOpenStart
|
|
814
|
+
? appendActivityEntry(section, {
|
|
815
|
+
time: metadata.timestamp, step: `${supersededOpenStart.action} [aborted]`,
|
|
816
|
+
agent: normalized.agent, note: `superseded by ${eventIdentity.action}`
|
|
817
|
+
}) : section.body;
|
|
818
|
+
body = appendActivityEntry({ ...section, body: supersededBody },
|
|
819
|
+
{ time: metadata.timestamp, step: logStep, agent: normalized.agent, note: eventIdentity.note });
|
|
820
|
+
}
|
|
853
821
|
const frontmatterSet: Record<string, string> = { current_step: step, assigned_to: normalized.agent };
|
|
822
|
+
if (eventIdentity.phase === 'started' || eventIdentity.phase === 'completed') {
|
|
823
|
+
const open = rows.filter((item) => !openRows.includes(item) && (!supersededOpenStart || item.family !== supersededOpenStart.family || item.round !== supersededOpenStart.round));
|
|
824
|
+
if (eventIdentity.phase === 'started') open.push({ family: eventIdentity.family, agent: normalized.agent, startedAt: metadata.timestamp, round: normalized.round, fixFor: normalized.fixFor, implementationInput: normalized.implementationInput, transactionId: normalized.transactionId });
|
|
825
|
+
frontmatterSet.lifecycle_execution = serializeLifecycleExecution(open, content);
|
|
826
|
+
}
|
|
854
827
|
if (currentFact) frontmatterSet.completion_facts = JSON.stringify(replaceCompletionFact(parseCompletionFacts(frontmatter.completion_facts), currentFact));
|
|
855
828
|
if (completedArtifact && ['analyze', 'plan', 'code'].includes(eventIdentity.family)) {
|
|
856
829
|
const task = parseTaskQualification(content);
|
|
@@ -909,7 +882,7 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
|
|
|
909
882
|
}
|
|
910
883
|
if (eventIdentity.phase === 'started' && normalized.implementationInput) frontmatterSet.last_reviewed_commit = '';
|
|
911
884
|
const mutations: Parameters<typeof writeTask>[0]['mutations'][number][] = [
|
|
912
|
-
{ kind: 'frontmatter', set: frontmatterSet, remove: frontmatterRemove }
|
|
885
|
+
{ kind: 'frontmatter', set: frontmatterSet, remove: frontmatterRemove, ...(frontmatterSet.lifecycle_execution ? { lifecycleExecutionDomain: 'ordinary' as const } : {}) }
|
|
913
886
|
];
|
|
914
887
|
if (completedArtifact) {
|
|
915
888
|
const link = buildArtifactLinkSection(content, completedArtifact);
|
|
@@ -942,30 +915,9 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
|
|
|
942
915
|
body: renderImplementationInputs(implementationRows)
|
|
943
916
|
});
|
|
944
917
|
}
|
|
945
|
-
mutations.push({ kind: 'section', aliases: ['活动日志', 'Activity Log'], heading: section.heading, body });
|
|
918
|
+
if (section && body !== null) mutations.push({ kind: 'section', aliases: ['活动日志', 'Activity Log'], heading: section.heading, body });
|
|
946
919
|
const result = writeTask({ taskRef: normalized.taskRef, expectedState: 'active', dryRun: normalized.dryRun, mutations }, { ...options, metadataProvider: () => metadata });
|
|
947
920
|
if (result.status === 'failed') return failed(normalized, result.error, { taskId: result.taskId, taskMdPath: result.taskMdPath, fromStep: currentStep, toStep: step, action: eventIdentity.action, phase: eventIdentity.phase, timestamp: result.timestamp, agentInfraVersion: result.agentInfraVersion, operations: result.operations, artifactContext });
|
|
948
|
-
if (!normalized.dryRun && orchestrationCompletion) {
|
|
949
|
-
try {
|
|
950
|
-
(options.commitOrchestrationCompletion ?? commitOrchestrationStageCompletion)(orchestrationCompletion);
|
|
951
|
-
} catch (error) {
|
|
952
|
-
return failed(normalized, {
|
|
953
|
-
code: 'EVENT_ORCHESTRATION_COMMIT_FAILED',
|
|
954
|
-
message: `task.md was written but orchestration completion could not be persisted; manual recovery is required: ${error instanceof Error ? error.message : String(error)}`
|
|
955
|
-
}, {
|
|
956
|
-
taskId: result.taskId,
|
|
957
|
-
taskMdPath: result.taskMdPath,
|
|
958
|
-
fromStep: currentStep,
|
|
959
|
-
toStep: step,
|
|
960
|
-
action: eventIdentity.action,
|
|
961
|
-
phase: eventIdentity.phase,
|
|
962
|
-
timestamp: result.timestamp,
|
|
963
|
-
agentInfraVersion: result.agentInfraVersion,
|
|
964
|
-
operations: result.operations,
|
|
965
|
-
artifactContext
|
|
966
|
-
});
|
|
967
|
-
}
|
|
968
|
-
}
|
|
969
921
|
return {
|
|
970
922
|
status: result.status, changed: result.changed, event: normalized.event,
|
|
971
923
|
requestRef: normalized.taskRef, taskId: result.taskId, taskMdPath: result.taskMdPath,
|
|
@@ -991,5 +943,19 @@ function successNoOp(
|
|
|
991
943
|
};
|
|
992
944
|
}
|
|
993
945
|
|
|
994
|
-
|
|
946
|
+
function applyTaskEventWithWarnings(request: TaskEventRequest, options: TaskEventOptions = {}): TaskEventResult {
|
|
947
|
+
const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
|
|
948
|
+
let warnings: { code: string; message: string }[] = [];
|
|
949
|
+
if (resolved.ok) {
|
|
950
|
+
try {
|
|
951
|
+
const inspected = inspectActivityLog(fs.readFileSync(resolved.taskMdPath, 'utf8'));
|
|
952
|
+
if (!inspected.section) warnings = [{ code: 'ACTIVITY_LOG_UNAVAILABLE', message: 'Activity Log is missing or ambiguous; no entry was appended' }];
|
|
953
|
+
else if (inspected.invalidEntries.length) warnings = [{ code: 'ACTIVITY_LOG_INVALID_ENTRIES', message: 'Activity Log contains malformed entries' }];
|
|
954
|
+
} catch { /* The core reports task read errors. */ }
|
|
955
|
+
}
|
|
956
|
+
const result = applyTaskEvent(request, options);
|
|
957
|
+
return result.status === 'failed' || warnings.length === 0 ? result : { ...result, warnings };
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
export { eventCatalog, validateTaskEventRequest, applyTaskEventWithWarnings as applyTaskEvent };
|
|
995
961
|
export type { TaskEventName, TaskEventRequest, TaskEventResult, TaskEventError, TaskEventErrorCode, TaskEventOptions, Verdict };
|
package/lib/task/finalization.ts
CHANGED
|
@@ -10,13 +10,13 @@ import { taskIssueIdentity } from '../platform/task-identities.ts';
|
|
|
10
10
|
import { inspectPlatformIssue, syncPlatformIssue } from '../platform/issues.ts';
|
|
11
11
|
import type { IssueResult, SyncOptions as IssueSyncOptions } from '../platform/issues.ts';
|
|
12
12
|
import { resourceIdentityEquals } from '../platform/resource-identity.ts';
|
|
13
|
+
import { activityWarnings } from './activity-log.ts';
|
|
13
14
|
import { parseTaskFrontmatter } from './frontmatter.ts';
|
|
14
15
|
import { recoverPlatformOperations } from './platform-operation-recovery.ts';
|
|
15
16
|
import {
|
|
16
17
|
applyTaskLifecycle,
|
|
17
18
|
inspectTaskLifecycleProgress,
|
|
18
19
|
type TaskLifecycleOptions,
|
|
19
|
-
type TaskLifecycleRequest,
|
|
20
20
|
type TaskLifecycleResult,
|
|
21
21
|
type TaskCompletionProjection,
|
|
22
22
|
previewTaskCompletion
|
|
@@ -106,6 +106,7 @@ type TaskFinalizationStep = Readonly<{
|
|
|
106
106
|
error: FinalizationError | null;
|
|
107
107
|
completedSteps?: readonly string[];
|
|
108
108
|
pendingSteps?: readonly string[];
|
|
109
|
+
warnings?: readonly OperationWarning[];
|
|
109
110
|
}>;
|
|
110
111
|
|
|
111
112
|
type TaskCommentSyncOutcome = Readonly<{
|
|
@@ -332,7 +333,8 @@ function lifecycleStep(result: TaskLifecycleResult): TaskFinalizationStep {
|
|
|
332
333
|
changed: result.changed,
|
|
333
334
|
error: result.error ? errorOf(result.error, 'LIFECYCLE_FAILED') : null,
|
|
334
335
|
completedSteps: result.completedSteps ?? [],
|
|
335
|
-
pendingSteps: result.pendingSteps ?? []
|
|
336
|
+
pendingSteps: result.pendingSteps ?? [],
|
|
337
|
+
warnings: (result.warnings ?? []).map((warning) => ({ ...warning, step: 'lifecycle', target: 'activity-log', severity: 'IMPORTANT' as const, retryable: true }))
|
|
336
338
|
};
|
|
337
339
|
}
|
|
338
340
|
|
|
@@ -348,7 +350,17 @@ function verificationStep(result: TaskVerificationResult): TaskFinalizationStep
|
|
|
348
350
|
return {
|
|
349
351
|
status: result.status,
|
|
350
352
|
changed: false,
|
|
351
|
-
error: result.status === 'pass' ? null : verificationFailure(result)
|
|
353
|
+
error: result.status === 'pass' ? null : verificationFailure(result),
|
|
354
|
+
warnings: result.invocations.flatMap(({ payload }) => {
|
|
355
|
+
const checks = Array.isArray(payload.checks) ? payload.checks : [payload];
|
|
356
|
+
return checks.flatMap((check) => {
|
|
357
|
+
if (!check || typeof check !== 'object' || !Array.isArray(check.warnings)) return [];
|
|
358
|
+
return check.warnings.filter((message: unknown): message is string => typeof message === 'string').map((message: string) => ({
|
|
359
|
+
code: 'VERIFICATION_DIAGNOSTIC', message, retryable: true, step: 'verification',
|
|
360
|
+
target: typeof check.checkId === 'string' ? check.checkId : String(check.type ?? 'check'), severity: 'IMPORTANT' as const
|
|
361
|
+
}));
|
|
362
|
+
});
|
|
363
|
+
})
|
|
352
364
|
};
|
|
353
365
|
}
|
|
354
366
|
|
|
@@ -494,7 +506,7 @@ function issueCapability(receipt: TaskFinalizationReceipt, scope: Exclude<Finali
|
|
|
494
506
|
|
|
495
507
|
function capabilityError(code: 'FINALIZATION_CAPABILITY_STALE' | 'FINALIZATION_SCOPE_INVALID', message: string): Error {
|
|
496
508
|
const error = new Error(message);
|
|
497
|
-
error.name = '
|
|
509
|
+
error.name = 'TaskFinalizationCapabilityError';
|
|
498
510
|
Object.assign(error, { code });
|
|
499
511
|
return error;
|
|
500
512
|
}
|
|
@@ -815,7 +827,7 @@ function terminalResult(
|
|
|
815
827
|
): TaskFinalizationResult {
|
|
816
828
|
const pending = pendingSteps(receipt);
|
|
817
829
|
const blocked = [steps.backfill, steps.lifecycle, steps.taskComment, steps.verification, steps.summary].some((step) => step?.status === 'blocked');
|
|
818
|
-
const warnings = openWarnings(receipt);
|
|
830
|
+
const warnings = mergeOperationWarnings(openWarnings(receipt), steps.lifecycle?.warnings ?? [], steps.verification?.warnings ?? []);
|
|
819
831
|
const postLifecyclePending = receipt.lifecycle === 'done' && (pending.some((step) => step !== 'lifecycle') || receipt.warningProjection === 'pending');
|
|
820
832
|
const terminalVerificationPending = receipt.lifecycle === 'done' && receipt.verification === 'pending';
|
|
821
833
|
const resultError = error ?? (terminalVerificationPending ? steps.verification?.error : null) ?? null;
|
|
@@ -860,7 +872,7 @@ function preparedResult(
|
|
|
860
872
|
verification: steps.verification ?? null,
|
|
861
873
|
summary: steps.summary ?? null,
|
|
862
874
|
completedSteps: completedSteps(receipt), pendingSteps: pendingSteps(receipt),
|
|
863
|
-
result: 'prepared', warnings: openWarnings(receipt), error: null
|
|
875
|
+
result: 'prepared', warnings: mergeOperationWarnings(openWarnings(receipt), steps.lifecycle?.warnings ?? []), error: null
|
|
864
876
|
};
|
|
865
877
|
}
|
|
866
878
|
|
|
@@ -1135,7 +1147,7 @@ async function prepareTaskFinalizationCore(
|
|
|
1135
1147
|
return preparedResult(taskId, receipt, { backfill: backfillResult, lifecycle: lifecycleResult, taskComment, verification, summary: summary.step }, changed);
|
|
1136
1148
|
}
|
|
1137
1149
|
|
|
1138
|
-
async function
|
|
1150
|
+
async function prepareTaskFinalizationInner(request: TaskFinalizationRequest, options: TaskFinalizationOptions): Promise<TaskFinalizationResult> {
|
|
1139
1151
|
if (request.intent !== 'complete' || !request.taskRef || !request.agent) {
|
|
1140
1152
|
return failed(null, { code: 'TASK_FINALIZATION_PAYLOAD_INVALID', message: 'complete finalization requires taskRef and agent', retryable: false });
|
|
1141
1153
|
}
|
|
@@ -1311,6 +1323,25 @@ async function commitPreparedTaskFinalization(request: TaskFinalizationRequest,
|
|
|
1311
1323
|
}
|
|
1312
1324
|
}
|
|
1313
1325
|
|
|
1326
|
+
function withActivityWarnings(result: TaskFinalizationResult, request: TaskFinalizationRequest, options: TaskFinalizationOptions): TaskFinalizationResult {
|
|
1327
|
+
if (result.status === 'failed' || result.status === 'blocked') return result;
|
|
1328
|
+
const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
|
|
1329
|
+
if (!resolved.ok) return result;
|
|
1330
|
+
let diagnostics: ReturnType<typeof activityWarnings>;
|
|
1331
|
+
try { diagnostics = activityWarnings(fs.readFileSync(resolved.taskMdPath, 'utf8')); }
|
|
1332
|
+
catch { return result; }
|
|
1333
|
+
const warnings = diagnostics.map((warning) => ({ ...warning, step: 'lifecycle', target: 'activity-log', severity: 'IMPORTANT' as const, retryable: true }));
|
|
1334
|
+
return { ...result, warnings: mergeOperationWarnings(result.warnings, warnings) };
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
async function prepareTaskFinalization(request: TaskFinalizationRequest, options: TaskFinalizationOptions): Promise<TaskFinalizationResult> {
|
|
1338
|
+
return withActivityWarnings(await prepareTaskFinalizationInner(request, options), request, options);
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
async function commitPreparedTaskFinalizationWithWarnings(request: TaskFinalizationRequest, options: TaskFinalizationOptions): Promise<TaskFinalizationResult> {
|
|
1342
|
+
return withActivityWarnings(await commitPreparedTaskFinalization(request, options), request, options);
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1314
1345
|
async function applyTaskFinalization(request: TaskFinalizationRequest, options: TaskFinalizationOptions): Promise<TaskFinalizationResult> {
|
|
1315
1346
|
const prepared = await prepareTaskFinalization(request, options);
|
|
1316
1347
|
if (prepared.status !== 'prepared') return prepared;
|
|
@@ -1327,12 +1358,13 @@ async function applyTaskFinalization(request: TaskFinalizationRequest, options:
|
|
|
1327
1358
|
});
|
|
1328
1359
|
}
|
|
1329
1360
|
}
|
|
1330
|
-
|
|
1361
|
+
const committed = await commitPreparedTaskFinalizationWithWarnings(request, options);
|
|
1362
|
+
return { ...committed, warnings: mergeOperationWarnings(prepared.warnings, committed.warnings) };
|
|
1331
1363
|
}
|
|
1332
1364
|
|
|
1333
1365
|
export {
|
|
1334
1366
|
applyFinalizationReceiptMutation,
|
|
1335
|
-
commitPreparedTaskFinalization,
|
|
1367
|
+
commitPreparedTaskFinalizationWithWarnings as commitPreparedTaskFinalization,
|
|
1336
1368
|
applyTaskFinalization,
|
|
1337
1369
|
prepareTaskFinalization,
|
|
1338
1370
|
issueCapability as createFinalizationCapability,
|
|
@@ -16,7 +16,7 @@ import { writeTask } from './write.ts';
|
|
|
16
16
|
import type { TaskMutation, TaskOperationSummary, TaskWriteOptions } from './write.ts';
|
|
17
17
|
import { parseLegacyReworkIntentDocument, parseReworkIntentDocument, reworkIntentMutation, upsertReworkIntent } from './rework-intent.ts';
|
|
18
18
|
import type { ReworkClassification, ReworkIntent, ReworkTarget } from './rework-intent.ts';
|
|
19
|
-
import { extractSection
|
|
19
|
+
import { extractSection } from './sections.ts';
|
|
20
20
|
import { parseLifecyclePathDecision } from './lifecycle-path.ts';
|
|
21
21
|
import { scanVisibleMarkdown } from './markdown.ts';
|
|
22
22
|
import { inspectArtifactDirectory } from './artifact-lifecycle.ts';
|