@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,12 +1,12 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import { normalizeAgentToken } from '../agent-clients/tokens.js';
|
|
3
3
|
import { resolveTaskRef } from './resolve-ref.js';
|
|
4
|
-
import { locateActivityLog, appendActivityEntry } from './activity-log.js';
|
|
4
|
+
import { locateActivityLog, appendActivityEntry, inspectActivityLog } from './activity-log.js';
|
|
5
|
+
import { lifecycleExecutions, prReviewExecution, serializeLifecycleExecution } from './lifecycle-execution.js';
|
|
5
6
|
import { assertWritableInventory, buildArtifactLinkSection, inspectTaskArtifacts } from './artifact-lifecycle.js';
|
|
6
7
|
import { parseArtifactName } from './artifact-name.js';
|
|
7
8
|
import { captureTaskWriteMetadata, writeTask } from './write.js';
|
|
8
9
|
const HEAD_RE = /^[0-9a-f]{40}$/;
|
|
9
|
-
const REVIEW_ACTION_RE = /^Review PR \(Round ([1-9]\d*)\)( \[started\])?$/;
|
|
10
10
|
const VERDICTS = new Set(['approved', 'changes-requested', 'commented']);
|
|
11
11
|
const OUTCOMES = new Set(['aborted', 'superseded']);
|
|
12
12
|
const SUCCESS_STATUSES = new Set(['applied', 'no-op']);
|
|
@@ -76,47 +76,37 @@ function readSnapshot(taskRef, repoRoot) {
|
|
|
76
76
|
catch (error) {
|
|
77
77
|
return { ok: false, code: 'TASK_READ_FAILED', message: error instanceof Error ? error.message : String(error), taskId: resolved.taskId };
|
|
78
78
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
if (match && !knownRounds.has(Number(match[1]))) {
|
|
86
|
-
return { ok: false, code: 'ACTIVITY_STATE_CONFLICT', message: `Activity Log round ${match[1]} has no canonical pr-review artifact`, taskId: resolved.taskId };
|
|
87
|
-
}
|
|
79
|
+
let pr;
|
|
80
|
+
try {
|
|
81
|
+
pr = prReviewExecution(content);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
return { ok: false, code: 'ACTIVITY_STATE_CONFLICT', message: String(error), taskId: resolved.taskId };
|
|
88
85
|
}
|
|
89
86
|
const states = [];
|
|
90
87
|
for (const identity of inventory.artifacts) {
|
|
91
88
|
const parsed = parseArtifactRecord(identity);
|
|
92
89
|
if ('code' in parsed)
|
|
93
90
|
return { ok: false, ...parsed, taskId: resolved.taskId };
|
|
94
|
-
const
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
91
|
+
const started = pr.open?.artifact === identity.name ? pr.open : null;
|
|
92
|
+
const terminals = pr.terminals.filter((entry) => entry.artifact === identity.name);
|
|
93
|
+
if (terminals.length > 1)
|
|
94
|
+
return { ok: false, code: 'ACTIVITY_STATE_CONFLICT', message: `duplicate PR review terminal for ${identity.name}`, taskId: resolved.taskId };
|
|
95
|
+
const terminal = terminals[0];
|
|
96
|
+
if (terminal) {
|
|
97
|
+
const matches = (terminal.note.startsWith('Verdict: ') && LOCAL_COMPLETION_STATUSES.has(parsed.status))
|
|
98
|
+
|| (terminal.note.startsWith('Outcome: Aborted, ') && parsed.status === 'aborted')
|
|
99
|
+
|| (terminal.note.startsWith('Outcome: Superseded, ') && parsed.status === 'superseded')
|
|
100
|
+
|| (terminal.note.startsWith('receipt ') && SUCCESS_STATUSES.has(parsed.status));
|
|
101
|
+
if (!matches)
|
|
102
|
+
return { ok: false, code: 'ACTIVITY_STATE_CONFLICT', message: `terminal note conflicts with artifact status ${parsed.status}`, taskId: resolved.taskId };
|
|
102
103
|
}
|
|
103
|
-
if (terminal.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|| (note.startsWith('Outcome: Aborted, ') && parsed.status === 'aborted')
|
|
107
|
-
|| (note.startsWith('Outcome: Superseded, ') && parsed.status === 'superseded')
|
|
108
|
-
|| (note.startsWith('receipt ') && SUCCESS_STATUSES.has(parsed.status));
|
|
109
|
-
if (!terminalMatchesStatus) {
|
|
110
|
-
return { ok: false, code: 'ACTIVITY_STATE_CONFLICT', message: `${base} terminal note conflicts with artifact status ${parsed.status}`, taskId: resolved.taskId };
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
states.push({
|
|
114
|
-
...parsed,
|
|
115
|
-
startedAgent: started[0]?.agent ?? null,
|
|
116
|
-
terminalAgent: terminal[0]?.agent ?? null,
|
|
117
|
-
terminalNote: terminal[0]?.note ?? null
|
|
118
|
-
});
|
|
104
|
+
if ((started && started.head !== parsed.head) || (terminal && terminal.head !== parsed.head))
|
|
105
|
+
return { ok: false, code: 'ACTIVITY_IDENTITY_MISMATCH', message: `head does not match ${identity.name}`, taskId: resolved.taskId };
|
|
106
|
+
states.push({ ...parsed, startedAgent: started?.agent ?? null, terminalAgent: terminal?.agent ?? null, terminalNote: terminal?.note ?? null });
|
|
119
107
|
}
|
|
108
|
+
if ((pr.open && !states.some((state) => state.identity.name === pr.open.artifact)) || pr.terminals.some((entry) => !states.some((state) => state.identity.name === entry.artifact)))
|
|
109
|
+
return { ok: false, code: 'ACTIVITY_STATE_CONFLICT', message: 'PR review execution references a missing artifact', taskId: resolved.taskId };
|
|
120
110
|
const openStates = states.filter((state) => state.startedAgent !== null && state.terminalNote === null);
|
|
121
111
|
const preparedStates = states.filter((state) => state.status === 'pending' && state.startedAgent === null && state.terminalNote === null);
|
|
122
112
|
if (openStates.length > 1 || preparedStates.length > 1) {
|
|
@@ -250,10 +240,16 @@ function applyActivityIntent(intent, normalizedAgent, options) {
|
|
|
250
240
|
return failed(intent, 'METADATA_CAPTURE_FAILED', error instanceof Error ? error.message : String(error), state.taskId);
|
|
251
241
|
}
|
|
252
242
|
const section = locateActivityLog(state.content);
|
|
253
|
-
const
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
243
|
+
const pr = prReviewExecution(state.content);
|
|
244
|
+
if (intent.kind === 'pr-review-start')
|
|
245
|
+
pr.open = { artifact: intent.artifact, head: intent.head, agent: normalizedAgent, startedAt: metadata.timestamp };
|
|
246
|
+
else {
|
|
247
|
+
pr.open = null;
|
|
248
|
+
pr.terminals.push({ artifact: intent.artifact, head: intent.head, agent: normalizedAgent, note });
|
|
249
|
+
}
|
|
250
|
+
const mutations = [{ kind: 'frontmatter', lifecycleExecutionDomain: 'pr-review', set: { lifecycle_execution: serializeLifecycleExecution(lifecycleExecutions(state.content), state.content, pr) } }];
|
|
251
|
+
if (section)
|
|
252
|
+
mutations.push({ kind: 'section', aliases: ['活动日志', 'Activity Log'], heading: section.heading, body: appendActivityEntry(section, { time: metadata.timestamp, step, agent: normalizedAgent, note }) });
|
|
257
253
|
if (linkArtifact) {
|
|
258
254
|
const link = buildArtifactLinkSection(state.content, roundState.identity);
|
|
259
255
|
mutations.push({ kind: 'section', aliases: link.aliases, heading: link.heading, body: link.body });
|
|
@@ -296,6 +292,15 @@ export function applyPrReviewActivityIntent(intent, options = {}) {
|
|
|
296
292
|
if (resolved.state !== 'active') {
|
|
297
293
|
return failed(intent, 'TASK_STATE_MISMATCH', `task ${resolved.taskId} is ${resolved.state}, expected active`, resolved.taskId);
|
|
298
294
|
}
|
|
299
|
-
|
|
295
|
+
let warnings = [];
|
|
296
|
+
try {
|
|
297
|
+
const inspected = inspectActivityLog(fs.readFileSync(resolved.taskMdPath, 'utf8'));
|
|
298
|
+
warnings = !inspected.section ? [{ code: 'ACTIVITY_LOG_UNAVAILABLE', message: 'Activity Log is missing or ambiguous' }] : inspected.invalidEntries.length ? [{ code: 'ACTIVITY_LOG_INVALID_ENTRIES', message: 'Activity Log contains malformed entries' }] : [];
|
|
299
|
+
}
|
|
300
|
+
catch { /* The operation reports read errors. */ }
|
|
301
|
+
const result = applyActivityIntent(intent, validated.agent, { ...options, repoRoot: resolved.repoRoot });
|
|
302
|
+
if (result.status === 'failed')
|
|
303
|
+
return result;
|
|
304
|
+
return warnings.length ? { ...result, warnings } : result;
|
|
300
305
|
}
|
|
301
306
|
//# sourceMappingURL=activity-intent.js.map
|
|
@@ -3,8 +3,6 @@ const ENTRY_RE = /^- (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}[+-]\d{2}:\d{2}) — \*
|
|
|
3
3
|
const STARTED_SUFFIX_RE = /\s*\[started\]\s*$/;
|
|
4
4
|
const ABORTED_SUFFIX_RE = /\s*\[aborted\]\s*$/;
|
|
5
5
|
const ATTEMPT_RE = /(?:^|;\s*)attempt=([A-Za-z0-9-]{8,64})(?:;|$)/;
|
|
6
|
-
const COMMIT_STARTED_RE = /^started; attempt=([A-Za-z0-9-]{8,64}); baseline=([a-f0-9]{40,64}); agent=([a-z-]+)$/;
|
|
7
|
-
const LIFECYCLE_STEP_RE = /^(?:Complete Manual Validation|(?:Analyze Task|Review Analysis|Plan Task|Review Plan|Code Task|Review Code|Run Manual Validation) \(Round [1-9]\d*(?:(?:, fix for review-code(?:-r[2-9]|-r[1-9]\d+)?\.md)|(?:, decision II-[1-9]\d*))?\))$/;
|
|
8
6
|
function parseActivityLog(content) {
|
|
9
7
|
const section = locateActivityLog(content);
|
|
10
8
|
return section ? { sectionFound: true, entries: section.entries } : { sectionFound: false, entries: [] };
|
|
@@ -33,6 +31,14 @@ function inspectActivityLog(content) {
|
|
|
33
31
|
const body = content.slice(heading.end + 1, end).replace(/\r\n/g, '\n').replace(/^\n+|\n+$/g, '');
|
|
34
32
|
return { section: { heading: heading.text, body, entries }, invalidEntries };
|
|
35
33
|
}
|
|
34
|
+
function activityWarnings(content) {
|
|
35
|
+
const inspected = inspectActivityLog(content);
|
|
36
|
+
if (!inspected.section)
|
|
37
|
+
return [{ code: 'ACTIVITY_LOG_UNAVAILABLE', message: 'Activity Log is missing or ambiguous; repair the section to resume logging' }];
|
|
38
|
+
if (inspected.invalidEntries.length)
|
|
39
|
+
return [{ code: 'ACTIVITY_LOG_INVALID_ENTRIES', message: 'Activity Log contains malformed entries; repair the entries' }];
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
36
42
|
function locateActivityLog(content) {
|
|
37
43
|
const { section } = inspectActivityLog(content);
|
|
38
44
|
if (!section)
|
|
@@ -47,13 +53,6 @@ function appendActivityEntry(section, entry) {
|
|
|
47
53
|
function activityAttempt(note) {
|
|
48
54
|
return ATTEMPT_RE.exec(note)?.[1] ?? null;
|
|
49
55
|
}
|
|
50
|
-
function parseCommitAttemptStarted(note) {
|
|
51
|
-
const match = COMMIT_STARTED_RE.exec(note);
|
|
52
|
-
return match ? { attempt: match[1], baseline: match[2], agent: match[3] } : null;
|
|
53
|
-
}
|
|
54
|
-
function commitAttemptStartedNote(attempt) {
|
|
55
|
-
return `started; attempt=${attempt.attempt}; baseline=${attempt.baseline}; agent=${attempt.agent}`;
|
|
56
|
-
}
|
|
57
56
|
function pairEntries(entries) {
|
|
58
57
|
const rows = [];
|
|
59
58
|
const open = new Map();
|
|
@@ -94,11 +93,5 @@ function pairEntries(entries) {
|
|
|
94
93
|
function startedBackedRows(rows) {
|
|
95
94
|
return rows.filter((row) => row.started !== '');
|
|
96
95
|
}
|
|
97
|
-
|
|
98
|
-
const section = locateActivityLog(content);
|
|
99
|
-
if (!section)
|
|
100
|
-
return false;
|
|
101
|
-
return pairEntries(section.entries).some((row) => row.done === '' && LIFECYCLE_STEP_RE.test(row.step));
|
|
102
|
-
}
|
|
103
|
-
export { activityAttempt, appendActivityEntry, hasOpenLifecycleExecution, commitAttemptStartedNote, inspectActivityLog, locateActivityLog, pairEntries, parseActivityLog, parseCommitAttemptStarted, startedBackedRows };
|
|
96
|
+
export { activityAttempt, activityWarnings, appendActivityEntry, inspectActivityLog, locateActivityLog, pairEntries, parseActivityLog, startedBackedRows };
|
|
104
97
|
//# sourceMappingURL=activity-log.js.map
|
|
@@ -88,7 +88,7 @@ export function executeArtifactCommand(command, options = {}) {
|
|
|
88
88
|
}
|
|
89
89
|
catch { /* an absent candidate is created only for the selected identity */ }
|
|
90
90
|
if ((context.status !== 'ready' && !matchingInitializedSkeleton) || (context.next?.name !== artifact
|
|
91
|
-
&& !hasOpenArtifactRound(fs.readFileSync(resolved.taskMdPath, 'utf8'), family, parsed.round)
|
|
91
|
+
&& !hasOpenArtifactRound(taskDir, fs.readFileSync(resolved.taskMdPath, 'utf8'), family, parsed.round)
|
|
92
92
|
&& !matchingInitializedSkeleton)) {
|
|
93
93
|
return fail('ARTIFACT_INIT_CONTEXT_INVALID', context.error?.message ?? `artifact '${artifact}' is not the next ${family} artifact`);
|
|
94
94
|
}
|
|
@@ -2,46 +2,42 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { ARTIFACT_FAMILY_CATALOG, artifactName, parseArtifactName } from './artifact-name.js';
|
|
4
4
|
import { resolveTaskRef } from './resolve-ref.js';
|
|
5
|
-
import {
|
|
5
|
+
import { lifecycleExecutions } from './lifecycle-execution.js';
|
|
6
6
|
import { parseImplementationInputs, selectPendingImplementationInput } from './implementation-inputs.js';
|
|
7
7
|
import { parseTypedTaskFrontmatter } from './frontmatter.js';
|
|
8
8
|
import { parseVerdict } from './review-artifacts.js';
|
|
9
9
|
import { extractSection, findSectionHeading } from './sections.js';
|
|
10
10
|
import { receiptForOutput, receiptsForOutput, sha256File } from './artifact-receipts.js';
|
|
11
|
-
import {
|
|
11
|
+
import { hasArtifactCompletionRecord, hasValidArtifactCompletion } from './completion-facts.js';
|
|
12
12
|
import { inspectReviewIdentity } from './review-identity.js';
|
|
13
13
|
import { parseLifecyclePathDecision } from './lifecycle-path.js';
|
|
14
14
|
import { parseReworkIntentDocument } from './rework-intent.js';
|
|
15
15
|
import { selectArtifactDisposition } from './artifact-selection.js';
|
|
16
16
|
import { executionInputsMatchLatest } from './execution-inputs.js';
|
|
17
17
|
const artifactFamilyCatalog = ARTIFACT_FAMILY_CATALOG;
|
|
18
|
-
const ARTIFACT_STEPS = {
|
|
19
|
-
analysis: 'Analyze Task', 'review-analysis': 'Review Analysis',
|
|
20
|
-
plan: 'Plan Task', 'review-plan': 'Review Plan',
|
|
21
|
-
code: 'Code Task', 'review-code': 'Review Code'
|
|
22
|
-
};
|
|
23
18
|
/** Init, repair and finalization share the same authoritative round identity. */
|
|
24
|
-
export function hasOpenArtifactRound(content, family, round) {
|
|
25
|
-
return openArtifactRounds(content, family).includes(round);
|
|
19
|
+
export function hasOpenArtifactRound(taskDir, content, family, round) {
|
|
20
|
+
return openArtifactRounds(taskDir, content, family).includes(round);
|
|
26
21
|
}
|
|
27
|
-
function openArtifactRounds(content, family) {
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
22
|
+
function openArtifactRounds(taskDir, content, family) {
|
|
23
|
+
const executionFamily = family === 'analysis' ? 'analyze' : family;
|
|
24
|
+
const event = completionEvent(family);
|
|
25
|
+
return [...new Set(lifecycleExecutions(content)
|
|
26
|
+
.filter((item) => item.family === executionFamily && item.round !== undefined)
|
|
27
|
+
.flatMap((item) => {
|
|
28
|
+
const round = item.round;
|
|
29
|
+
const name = artifactName(family, round);
|
|
30
|
+
if (!event || !hasArtifactCompletionRecord(content, name, event))
|
|
31
|
+
return [round];
|
|
32
|
+
if (!hasValidArtifactCompletion(content, taskDir, name, event))
|
|
33
|
+
throw new Error(`completion evidence for started ${family} Round ${round} is invalid`);
|
|
34
|
+
return [];
|
|
35
|
+
}))].sort((left, right) => left - right);
|
|
39
36
|
}
|
|
40
|
-
function hasCompletedArtifactRound(content, family, round, name) {
|
|
37
|
+
function hasCompletedArtifactRound(taskDir, content, family, round, name) {
|
|
41
38
|
const event = completionEvent(family);
|
|
42
39
|
return Boolean(event && parseArtifactName(name)?.round === round
|
|
43
|
-
&&
|
|
44
|
-
&& hasArtifactCompletionFact(content, name, event));
|
|
40
|
+
&& hasValidArtifactCompletion(content, taskDir, name, event));
|
|
45
41
|
}
|
|
46
42
|
function completionEvent(family) {
|
|
47
43
|
if (family === 'analysis')
|
|
@@ -153,7 +149,16 @@ function inspectArtifactDirectory(taskDir, family, identity = {}) {
|
|
|
153
149
|
}
|
|
154
150
|
artifacts.sort((left, right) => left.round - right.round);
|
|
155
151
|
knownArtifacts.sort((left, right) => left.round - right.round);
|
|
156
|
-
|
|
152
|
+
let openRounds;
|
|
153
|
+
try {
|
|
154
|
+
openRounds = openArtifactRounds(taskDir, taskContent, family);
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
return failure(requestRef, family, {
|
|
158
|
+
code: 'ARTIFACT_SELECTION_INDETERMINATE',
|
|
159
|
+
message: error instanceof Error ? error.message : String(error)
|
|
160
|
+
}, { taskId: identity.taskId ?? null, taskDir, taskState: identity.taskState ?? null });
|
|
161
|
+
}
|
|
157
162
|
const knownRounds = new Set(knownArtifacts.map((item) => item.round));
|
|
158
163
|
for (const round of openRounds)
|
|
159
164
|
knownRounds.add(round);
|
|
@@ -166,11 +171,8 @@ function inspectArtifactDirectory(taskDir, family, identity = {}) {
|
|
|
166
171
|
}
|
|
167
172
|
const event = completionEvent(family);
|
|
168
173
|
const completed = event
|
|
169
|
-
? artifacts.
|
|
170
|
-
|
|
171
|
-
return order !== null && hasArtifactCompletionFact(taskContent, artifact.path, event)
|
|
172
|
-
? [{ artifact, order }] : [];
|
|
173
|
-
}).sort((left, right) => left.order - right.order).map(({ artifact }) => artifact)
|
|
174
|
+
? artifacts.filter((artifact) => hasValidArtifactCompletion(taskContent, taskDir, artifact.name, event))
|
|
175
|
+
.sort((left, right) => left.round - right.round)
|
|
174
176
|
: [];
|
|
175
177
|
if (openRounds.length > 1)
|
|
176
178
|
diagnostics.push(diagnostic('MULTIPLE_OPEN_ROUNDS', family, null, `multiple incomplete ${family} rounds are open: ${openRounds.join(', ')}`));
|
|
@@ -321,8 +323,8 @@ function hasSelectionEvidence(content, family, options, context, pathState) {
|
|
|
321
323
|
const reportContent = fs.readFileSync(context.latest.path, 'utf8');
|
|
322
324
|
const identity = inspectReviewIdentity(context.taskDir, reportContent, options.repoRoot);
|
|
323
325
|
return identity.status !== 'matched'
|
|
324
|
-
|| !
|
|
325
|
-
|| !
|
|
326
|
+
|| !context.taskDir
|
|
327
|
+
|| !hasValidArtifactCompletion(content, context.taskDir, context.latest.name, 'review-code.completed');
|
|
326
328
|
}
|
|
327
329
|
catch {
|
|
328
330
|
return true;
|
|
@@ -366,14 +368,11 @@ function attachArtifactSelection(context, pathState, options) {
|
|
|
366
368
|
});
|
|
367
369
|
if (!context.next)
|
|
368
370
|
return fail('ARTIFACT_SELECTION_INDETERMINATE', 'artifact inventory did not provide a writable identity');
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
return fail('ARTIFACT_SELECTION_INDETERMINATE', error instanceof Error ? error.message : String(error));
|
|
375
|
-
}
|
|
376
|
-
const openRounds = openArtifactRounds(taskContent, family);
|
|
371
|
+
const state = readArtifactSelectionState(context.taskDir, family);
|
|
372
|
+
if (!state.ok)
|
|
373
|
+
return fail('ARTIFACT_SELECTION_INDETERMINATE', state.message);
|
|
374
|
+
const taskContent = state.content;
|
|
375
|
+
const openRounds = state.openRounds;
|
|
377
376
|
if (openRounds.length > 1)
|
|
378
377
|
return fail('ARTIFACT_TOPOLOGY_CONFLICT', `multiple incomplete ${family} rounds are open: ${openRounds.join(', ')}`);
|
|
379
378
|
const openRound = openRounds[0] ?? null;
|
|
@@ -399,6 +398,15 @@ function attachArtifactSelection(context, pathState, options) {
|
|
|
399
398
|
return fail('ARTIFACT_SELECTION_INDETERMINATE', error instanceof Error ? error.message : String(error));
|
|
400
399
|
}
|
|
401
400
|
}
|
|
401
|
+
function readArtifactSelectionState(taskDir, family) {
|
|
402
|
+
try {
|
|
403
|
+
const content = fs.readFileSync(path.join(taskDir, 'task.md'), 'utf8');
|
|
404
|
+
return { ok: true, content, openRounds: openArtifactRounds(taskDir, content, family) };
|
|
405
|
+
}
|
|
406
|
+
catch (error) {
|
|
407
|
+
return { ok: false, message: error instanceof Error ? error.message : String(error) };
|
|
408
|
+
}
|
|
409
|
+
}
|
|
402
410
|
function resolveArtifactContextFromTask(taskRef, family, options, resolvedTask) {
|
|
403
411
|
const inventory = inspectTaskArtifacts(taskRef, family, options, resolvedTask);
|
|
404
412
|
if (inventory.status === 'failed')
|
|
@@ -469,9 +477,6 @@ function resolveArtifactContextFromTask(taskRef, family, options, resolvedTask)
|
|
|
469
477
|
function resolveArtifactContext(taskRef, family, options = {}) {
|
|
470
478
|
return resolveArtifactContextFromTask(taskRef, family, options);
|
|
471
479
|
}
|
|
472
|
-
export function resolveArtifactContextForResolvedTask(resolvedTask, family, options = {}) {
|
|
473
|
-
return resolveArtifactContextFromTask(resolvedTask.taskId, family, options, resolvedTask);
|
|
474
|
-
}
|
|
475
480
|
function resolveCodeContext(inventory, options, resolvedTask) {
|
|
476
481
|
const taskRef = inventory.requestRef;
|
|
477
482
|
const pathState = lifecyclePathState(inventory.taskDir);
|
|
@@ -486,8 +491,7 @@ function resolveCodeContext(inventory, options, resolvedTask) {
|
|
|
486
491
|
const taskContent = fs.readFileSync(path.join(inventory.taskDir, 'task.md'), 'utf8');
|
|
487
492
|
const hasPendingImplementation = parseImplementationInputs(taskContent).rows.some((input) => input.needsImplementation && input.status === 'pending');
|
|
488
493
|
if (hasPendingImplementation && !reviewCode.latest) {
|
|
489
|
-
|
|
490
|
-
return contextFailure(inventory, 'ARTIFACT_REFERENCE_INVALID', `cannot find completed Activity Log identity for ${candidate}`);
|
|
494
|
+
return contextFailure(inventory, 'ARTIFACT_REFERENCE_INVALID', 'no valid review-code completion fact is available for pending implementation inputs');
|
|
491
495
|
}
|
|
492
496
|
}
|
|
493
497
|
catch (error) {
|
|
@@ -508,12 +512,10 @@ function resolveCodeContext(inventory, options, resolvedTask) {
|
|
|
508
512
|
const review = reviewCode.latest;
|
|
509
513
|
const openInputs = review ? [...inputs, review] : inputs;
|
|
510
514
|
const openVerdict = review ? parseVerdict(review.path) : null;
|
|
511
|
-
const openRow =
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
const decisionInput = /, decision (II-[1-9]\d*)\)$/u.exec(openRow?.step ?? '')?.[1] ?? null;
|
|
516
|
-
const fixInput = /, fix for (review-code(?:-r\d+)?\.md)\)$/u.exec(openRow?.step ?? '')?.[1] ?? null;
|
|
515
|
+
const openRow = lifecycleExecutions(taskContent)
|
|
516
|
+
.find((row) => row.family === 'code' && row.round === openRound);
|
|
517
|
+
const decisionInput = openRow?.implementationInput ?? null;
|
|
518
|
+
const fixInput = openRow?.fixFor ?? null;
|
|
517
519
|
const mode = decisionInput ? 'decision'
|
|
518
520
|
: fixInput || (openVerdict?.ok && openVerdict.verdict === 'Changes Requested') ? 'fix'
|
|
519
521
|
: 'init';
|
|
@@ -544,7 +546,7 @@ function resolveCodeContext(inventory, options, resolvedTask) {
|
|
|
544
546
|
const verdict = parseVerdict(review.path);
|
|
545
547
|
if (!verdict.ok)
|
|
546
548
|
return contextFailure(inventory, 'ARTIFACT_VERDICT_INVALID', `${verdict.code}: ${verdict.message}`, review.name);
|
|
547
|
-
const decision = resolveDecisionImplementationInput(
|
|
549
|
+
const decision = resolveDecisionImplementationInput(reviewCode, review);
|
|
548
550
|
if ('error' in decision)
|
|
549
551
|
return contextFailure(inventory, 'ARTIFACT_REFERENCE_INVALID', decision.error, review.name);
|
|
550
552
|
if (decision.input) {
|
|
@@ -598,12 +600,10 @@ function resolveDecisionImplementationInput(inventory, review) {
|
|
|
598
600
|
const pending = rows.filter((row) => row.needsImplementation && row.status === 'pending');
|
|
599
601
|
if (pending.length === 0)
|
|
600
602
|
return { input: null };
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
return { error:
|
|
604
|
-
|
|
605
|
-
if (!completed)
|
|
606
|
-
return { error: `cannot find completed Activity Log identity for ${review.name}` };
|
|
603
|
+
if (inventory.latest?.name !== review.name
|
|
604
|
+
|| !inventory.completed.some((artifact) => artifact.name === review.name)) {
|
|
605
|
+
return { error: `Review Code completion facts do not validate ${review.name}` };
|
|
606
|
+
}
|
|
607
607
|
try {
|
|
608
608
|
return { input: selectPendingImplementationInput(rows) };
|
|
609
609
|
}
|
|
@@ -653,14 +653,12 @@ export function validateArtifactPublication(taskDir, family, name) {
|
|
|
653
653
|
if (existing) {
|
|
654
654
|
try {
|
|
655
655
|
const task = fs.readFileSync(path.join(taskDir, 'task.md'), 'utf8');
|
|
656
|
-
if (hasCompletedArtifactRound(task, family, existing.round, name)) {
|
|
656
|
+
if (hasCompletedArtifactRound(taskDir, task, family, existing.round, name)) {
|
|
657
657
|
return { code: 'ARTIFACT_IDENTITY_INVALID', message: `completed artifact '${name}' is immutable` };
|
|
658
658
|
}
|
|
659
659
|
const event = completionEvent(family);
|
|
660
|
-
const
|
|
661
|
-
|
|
662
|
-
.some((fact) => fact.event === event && fact.output === name);
|
|
663
|
-
if (event && completionFactExists && artifactCompletionOrder(task, name, event) !== null) {
|
|
660
|
+
const completionFactExists = event !== null && hasArtifactCompletionRecord(task, name, event);
|
|
661
|
+
if (event && completionFactExists) {
|
|
664
662
|
return { code: 'ARTIFACT_IDENTITY_INVALID', message: `completion evidence for '${name}' does not match its current content` };
|
|
665
663
|
}
|
|
666
664
|
}
|
|
@@ -26,11 +26,5 @@ export function parseArtifactName(name) {
|
|
|
26
26
|
return null;
|
|
27
27
|
return { family: match[1], round, name };
|
|
28
28
|
}
|
|
29
|
-
export function maxArtifactRound(names, family) {
|
|
30
|
-
return names.reduce((max, name) => {
|
|
31
|
-
const identity = parseArtifactName(name);
|
|
32
|
-
return identity?.family === family ? Math.max(max, identity.round) : max;
|
|
33
|
-
}, 0);
|
|
34
|
-
}
|
|
35
29
|
export { ARTIFACT_FAMILY_CATALOG };
|
|
36
30
|
//# sourceMappingURL=artifact-name.js.map
|
|
@@ -59,7 +59,7 @@ function stripHtmlComments(content) {
|
|
|
59
59
|
function diagnostic(code, message, sectionId, line) {
|
|
60
60
|
return { code, message, sectionId, line };
|
|
61
61
|
}
|
|
62
|
-
function sectionHeadings(
|
|
62
|
+
function sectionHeadings(section) {
|
|
63
63
|
return [section.headings.zh, section.headings.en];
|
|
64
64
|
}
|
|
65
65
|
function canonicalContent(content) {
|
|
@@ -82,7 +82,7 @@ function inspectArtifactStructure(content, schema) {
|
|
|
82
82
|
diagnostics.push(diagnostic('ARTIFACT_UNCLOSED_FENCE', 'artifact contains an unclosed Markdown fence', null, null));
|
|
83
83
|
const headingsBySection = new Map();
|
|
84
84
|
for (const section of schema.sections) {
|
|
85
|
-
const aliases = sectionHeadings(
|
|
85
|
+
const aliases = sectionHeadings(section);
|
|
86
86
|
const exact = scanned.headings.filter((heading) => heading.level === 2 && aliases.includes(heading.text));
|
|
87
87
|
const punctuated = scanned.headings.filter((heading) => heading.level === 2 && aliases.some((alias) => heading.text === `${alias}:` || heading.text === `${alias}:`));
|
|
88
88
|
headingsBySection.set(section.id, exact.length > 0 ? exact : punctuated);
|
|
@@ -182,7 +182,7 @@ function inspectArtifactStateCheck(content, schema, scopeToStateCheckSection) {
|
|
|
182
182
|
};
|
|
183
183
|
}
|
|
184
184
|
const scanned = scanVisibleMarkdown(content);
|
|
185
|
-
const headings = scanned.headings.filter((heading) => (heading.level === 2 && sectionHeadings(
|
|
185
|
+
const headings = scanned.headings.filter((heading) => (heading.level === 2 && sectionHeadings(stateCheck).includes(heading.text)));
|
|
186
186
|
if (headings.length !== 1) {
|
|
187
187
|
return { ok: true, family: schema.family, semanticDigest: canonicalSemanticDigest(content), diagnostics: [] };
|
|
188
188
|
}
|
|
@@ -7,11 +7,11 @@ import { parseLedgerDocument, summarizeLedgerStage, validateLedgerRows } from '.
|
|
|
7
7
|
import { parseReviewSummary, resolveCanonicalVerdict } from './review-artifacts.js';
|
|
8
8
|
import { parseReworkIntentDocument } from './rework-intent.js';
|
|
9
9
|
import { sha256File } from './artifact-receipts.js';
|
|
10
|
-
import {
|
|
10
|
+
import { lifecycleExecutions } from './lifecycle-execution.js';
|
|
11
11
|
import { parseQualificationAudit, parseTaskQualification } from './qualification-audit.js';
|
|
12
12
|
import { parseLifecyclePathDecision, pathIncludes } from './lifecycle-path.js';
|
|
13
13
|
import { parseImplementationInputs } from './implementation-inputs.js';
|
|
14
|
-
import {
|
|
14
|
+
import { hasValidArtifactCompletion } from './completion-facts.js';
|
|
15
15
|
import { inspectReviewIdentity } from './review-identity.js';
|
|
16
16
|
import { inspectArtifactDirectory } from './artifact-lifecycle.js';
|
|
17
17
|
import { executionInputsMatchLatest as executionReceiptsMatchLatest } from './execution-inputs.js';
|
|
@@ -389,8 +389,7 @@ function buildLifecycleFacts(taskDir, content, taskState = 'active', executionBu
|
|
|
389
389
|
if (family === 'review-code') {
|
|
390
390
|
const identity = inspectReviewIdentity(taskDir, reviewContent, repositoryRoot);
|
|
391
391
|
reviewCodeIdentityValid = identity.status === 'matched'
|
|
392
|
-
&&
|
|
393
|
-
&& hasArtifactCompletionLog(content, latest, 'review-code.completed');
|
|
392
|
+
&& hasValidArtifactCompletion(content, taskDir, latest, 'review-code.completed');
|
|
394
393
|
}
|
|
395
394
|
const parsed = parseReviewSummary(reviewContent);
|
|
396
395
|
if (!parsed.ok)
|
|
@@ -455,7 +454,7 @@ function buildLifecycleFacts(taskDir, content, taskState = 'active', executionBu
|
|
|
455
454
|
reviewedInputs, executionInputs, artifactHashes,
|
|
456
455
|
reworkIntents: rework.intents,
|
|
457
456
|
unresolvedLedger,
|
|
458
|
-
executionBusy:
|
|
457
|
+
executionBusy: lifecycleExecutions(content).some((item) => item.family !== 'other') || executionBusy,
|
|
459
458
|
recommendedAction: null,
|
|
460
459
|
qualificationStale: qualificationStaleArtifacts.length > 0,
|
|
461
460
|
qualificationStaleArtifacts,
|
|
@@ -84,12 +84,6 @@ function humanValidationCount(note) {
|
|
|
84
84
|
function isHumanCountField(field) {
|
|
85
85
|
return fieldNumber(field, 'manual-validation') !== undefined || fieldNumber(field, 'human-decision') !== undefined;
|
|
86
86
|
}
|
|
87
|
-
// A step is human-executed when its agent token is not a known AI token.
|
|
88
|
-
// Known long names classify as AI; empty or unknown tokens classify as non-AI
|
|
89
|
-
// (human).
|
|
90
|
-
export function isHumanAgent(agent) {
|
|
91
|
-
return classifyAgent(agent).status !== 'ai';
|
|
92
|
-
}
|
|
93
87
|
// Fold the two human counts into a review row's verdict NOTE: comma-joined, right
|
|
94
88
|
// after the blockers/major/minor list and before the ` → artifact` link, mirroring
|
|
95
89
|
// the review count line. Review done notes already carry `Manual-validation` as a
|
|
@@ -9,7 +9,8 @@ import { parseTaskFrontmatter, extractTitle } from '../frontmatter.js';
|
|
|
9
9
|
import { loadShortIdByTaskId } from '../short-id.js';
|
|
10
10
|
import { getOpenWorkflowWarnings, formatWorkflowWarningSummary } from '../workflow-warnings.js';
|
|
11
11
|
import { parseActivityLog, pairEntries, startedBackedRows } from '../activity-log.js';
|
|
12
|
-
import {
|
|
12
|
+
import { lifecycleExecutions } from '../lifecycle-execution.js';
|
|
13
|
+
import { parseTypedTaskFrontmatter } from '../frontmatter.js';
|
|
13
14
|
import { statusCard } from '../../server/display.js';
|
|
14
15
|
import { buildLifecycleFacts, recommendNext } from '../capabilities.js';
|
|
15
16
|
const USAGE = `Usage: ai task status [--task <ref> | -t <ref>]
|
|
@@ -151,6 +152,18 @@ function parseActivityTime(value) {
|
|
|
151
152
|
const epoch = Date.parse(value.replace(' ', 'T'));
|
|
152
153
|
return Number.isFinite(epoch) ? epoch : Number.NaN;
|
|
153
154
|
}
|
|
155
|
+
function collectStructuredWorkflow(content, now) {
|
|
156
|
+
try {
|
|
157
|
+
const current = lifecycleExecutions(content).filter((row) => row.family !== 'other').at(-1);
|
|
158
|
+
if (!current)
|
|
159
|
+
return { state: 'idle', step: DASH, agent: DASH, startedAt: DASH, doneAt: DASH, stale: DASH };
|
|
160
|
+
const started = parseActivityTime(current.startedAt);
|
|
161
|
+
return { state: 'in-progress', step: current.family, agent: current.agent, startedAt: current.startedAt, doneAt: DASH, stale: Number.isFinite(started) ? (now.getTime() - started > STALE_MS ? 'yes' : 'no') : 'unknown' };
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
return { state: 'unknown', step: DASH, agent: DASH, startedAt: DASH, doneAt: DASH, stale: DASH };
|
|
165
|
+
}
|
|
166
|
+
}
|
|
154
167
|
function collectWorkflow(content, now = new Date()) {
|
|
155
168
|
const parsed = parseActivityLog(content);
|
|
156
169
|
if (!parsed.sectionFound || parsed.entries.length === 0) {
|
|
@@ -264,38 +277,6 @@ function collectRuntime(taskDir, workflow, run) {
|
|
|
264
277
|
log: record.log_file
|
|
265
278
|
};
|
|
266
279
|
}
|
|
267
|
-
function pendingDelegationInfo(receipt) {
|
|
268
|
-
if (!receipt)
|
|
269
|
-
return null;
|
|
270
|
-
return {
|
|
271
|
-
id: receipt.id,
|
|
272
|
-
role: receipt.role,
|
|
273
|
-
stage: receipt.stage,
|
|
274
|
-
round: receipt.round,
|
|
275
|
-
artifact: receipt.artifact,
|
|
276
|
-
client: receipt.client,
|
|
277
|
-
status: receipt.status
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
function collectOrchestration(taskDir) {
|
|
281
|
-
const run = readRun(taskDir);
|
|
282
|
-
if (!run) {
|
|
283
|
-
return {
|
|
284
|
-
status: 'absent',
|
|
285
|
-
runId: DASH,
|
|
286
|
-
nextStage: DASH,
|
|
287
|
-
pause: null,
|
|
288
|
-
pendingDelegation: null
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
return {
|
|
292
|
-
status: run.status,
|
|
293
|
-
runId: run.runId,
|
|
294
|
-
nextStage: run.nextStage ?? DASH,
|
|
295
|
-
pause: run.pause,
|
|
296
|
-
pendingDelegation: pendingDelegationInfo(run.pendingDelegation)
|
|
297
|
-
};
|
|
298
|
-
}
|
|
299
280
|
// Indent each label/value pair by two spaces and pad labels to a common width so
|
|
300
281
|
// every section reads as an aligned "key value" block.
|
|
301
282
|
function renderPairs(rows) {
|
|
@@ -323,21 +304,6 @@ function renderStatus(model) {
|
|
|
323
304
|
['action', model.recommendation ?? DASH],
|
|
324
305
|
['reason', model.recommendationReason ?? DASH]
|
|
325
306
|
]));
|
|
326
|
-
lines.push('', 'Orchestration', ...renderPairs([
|
|
327
|
-
['status', model.orchestration.status],
|
|
328
|
-
['run_id', model.orchestration.runId],
|
|
329
|
-
['next_stage', model.orchestration.nextStage],
|
|
330
|
-
['pause_code', model.orchestration.pause?.code ?? DASH],
|
|
331
|
-
['pause_message', model.orchestration.pause?.message ?? DASH],
|
|
332
|
-
['recoverable', model.orchestration.pause ? String(model.orchestration.pause.recoverable) : DASH],
|
|
333
|
-
['pending_id', model.orchestration.pendingDelegation?.id ?? DASH],
|
|
334
|
-
['pending_role', model.orchestration.pendingDelegation?.role ?? DASH],
|
|
335
|
-
['pending_stage', model.orchestration.pendingDelegation?.stage ?? DASH],
|
|
336
|
-
['pending_round', model.orchestration.pendingDelegation ? String(model.orchestration.pendingDelegation.round) : DASH],
|
|
337
|
-
['pending_artifact', model.orchestration.pendingDelegation?.artifact ?? DASH],
|
|
338
|
-
['pending_client', model.orchestration.pendingDelegation?.client ?? DASH],
|
|
339
|
-
['pending_status', model.orchestration.pendingDelegation?.status ?? DASH]
|
|
340
|
-
]));
|
|
341
307
|
lines.push('', 'Workflow', ...renderPairs([
|
|
342
308
|
['state', model.workflow.state],
|
|
343
309
|
['step', model.workflow.step],
|
|
@@ -367,12 +333,6 @@ function renderStatus(model) {
|
|
|
367
333
|
return lines;
|
|
368
334
|
}
|
|
369
335
|
function modelTone(model) {
|
|
370
|
-
if (model.orchestration.status === 'paused')
|
|
371
|
-
return 'warning';
|
|
372
|
-
if (model.orchestration.status === 'running')
|
|
373
|
-
return 'running';
|
|
374
|
-
if (model.orchestration.status === 'completed')
|
|
375
|
-
return 'success';
|
|
376
336
|
if (model.workflow.state === 'in-progress')
|
|
377
337
|
return model.workflow.stale === 'yes' ? 'warning' : 'running';
|
|
378
338
|
if (model.metadata.some(([key, value]) => key === 'status' && value === 'completed'))
|
|
@@ -387,7 +347,8 @@ function buildFromResolved(input) {
|
|
|
387
347
|
const fm = parseTaskFrontmatter(content);
|
|
388
348
|
const run = input.run ?? makeRunner(input.repoRoot);
|
|
389
349
|
const artifacts = enumerateArtifacts(input.taskDir);
|
|
390
|
-
const workflow =
|
|
350
|
+
const workflow = parseTypedTaskFrontmatter(content).lifecycle_execution !== undefined
|
|
351
|
+
? collectStructuredWorkflow(content, input.now ?? new Date()) : collectWorkflow(content, input.now);
|
|
391
352
|
const facts = buildLifecycleFacts(input.taskDir, content, fm.status ?? 'active', false, input.repoRoot);
|
|
392
353
|
const next = facts.ok ? recommendNext(facts.facts) : null;
|
|
393
354
|
const recommendation = next?.action ?? DASH;
|
|
@@ -400,7 +361,6 @@ function buildFromResolved(input) {
|
|
|
400
361
|
artifacts: { count: artifacts.length, groups: groupArtifacts(artifacts) },
|
|
401
362
|
workflow,
|
|
402
363
|
runtime: collectRuntime(input.taskDir, workflow, run),
|
|
403
|
-
orchestration: collectOrchestration(input.taskDir),
|
|
404
364
|
recommendation,
|
|
405
365
|
recommendationReason: next?.reasonCode ?? 'TASK_CAPABILITY_FACTS_INVALID',
|
|
406
366
|
lifecyclePath: facts.ok && facts.facts.pathState?.status === 'valid' ? facts.facts.pathState.decision.path : facts.ok ? facts.facts.pathState?.status ?? DASH : DASH,
|
|
@@ -426,9 +386,6 @@ function buildStatusModel(refOrInput, options = {}) {
|
|
|
426
386
|
}
|
|
427
387
|
function statusModelToDisplay(model) {
|
|
428
388
|
return statusCard(`Task ${model.taskId} (${model.shortId})`, modelTone(model), [
|
|
429
|
-
['orchestration', model.orchestration.status],
|
|
430
|
-
['run', model.orchestration.runId],
|
|
431
|
-
['next', model.orchestration.nextStage],
|
|
432
389
|
['workflow', model.workflow.state],
|
|
433
390
|
['step', model.workflow.step],
|
|
434
391
|
['runtime', model.runtime.status],
|
|
@@ -463,5 +420,5 @@ function status(args = []) {
|
|
|
463
420
|
process.stdout.write(`${line}\n`);
|
|
464
421
|
}
|
|
465
422
|
}
|
|
466
|
-
export { status, makeRunner, buildStatusModel, collectMetadata, groupArtifacts, collectGit, collectWorkflow, collectRuntime,
|
|
423
|
+
export { status, makeRunner, buildStatusModel, collectMetadata, groupArtifacts, collectGit, collectWorkflow, collectRuntime, renderStatus, statusModelToDisplay, METADATA_KEYS };
|
|
467
424
|
//# sourceMappingURL=status.js.map
|