@fitlab-ai/agent-infra 0.12.0 → 0.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -2
- package/README.zh-CN.md +0 -2
- package/dist/bin/internal-cli.js +2 -17
- package/dist/lib/agent-clients/adapter.js +0 -13
- package/dist/lib/agent-clients/adapters/antigravity-cli.js +0 -5
- package/dist/lib/agent-clients/adapters/claude-code-credentials.js +0 -17
- package/dist/lib/agent-clients/adapters/claude-code.js +0 -9
- package/dist/lib/agent-clients/adapters/codex.js +0 -52
- package/dist/lib/agent-clients/adapters/opencode.js +0 -5
- package/dist/lib/agent-clients/adapters/traecli.js +0 -5
- package/dist/lib/agent-clients/config.js +19 -54
- package/dist/lib/agent-clients/registry.js +1 -12
- package/dist/lib/agent-clients/schema.js +0 -18
- package/dist/lib/agent-clients/tokens.js +1 -2
- package/dist/lib/agent-clients/types.js +0 -1
- package/dist/lib/decide.js +2 -0
- package/dist/lib/git/worktree-identity.js +1 -9
- package/dist/lib/internal/agent-client.js +2 -62
- package/dist/lib/internal/cli-route-inventory.js +1 -5
- package/dist/lib/internal/manual-validation.js +29 -27
- package/dist/lib/internal/platform-comment.js +56 -7
- package/dist/lib/internal/task-create.js +1 -1
- package/dist/lib/internal/task-event.js +1 -8
- package/dist/lib/internal/task-finalization.js +0 -1
- package/dist/lib/internal/task-lifecycle.js +2 -2
- package/dist/lib/internal/task-operation-registry.js +4 -20
- package/dist/lib/internal/task-review.js +4 -4
- package/dist/lib/platform/comment-safety.js +1 -7
- package/dist/lib/platform/in-label-sync.js +1 -14
- package/dist/lib/platform/issue-comments.js +373 -282
- package/dist/lib/platform/issue-summary-content.js +112 -0
- package/dist/lib/platform/issues.js +1 -1
- package/dist/lib/platform/operation-coordinator.js +4 -2
- package/dist/lib/platform/pr-change-report.js +176 -30
- package/dist/lib/platform/pr-checks.js +2 -8
- package/dist/lib/platform/pr-summary-content.js +54 -0
- package/dist/lib/platform/pr-summary.js +318 -284
- package/dist/lib/platform/provider-validation.js +0 -20
- package/dist/lib/platform/pull-requests.js +73 -84
- package/dist/lib/platform/releases.js +1 -43
- package/dist/lib/platform/summary-content-pipeline.js +18 -0
- package/dist/lib/platform/verification-required.js +0 -2
- package/dist/lib/platform/verification-sync.js +1 -79
- package/dist/lib/process-data/normalize.js +1 -185
- package/dist/lib/process-data/privacy.js +1 -16
- package/dist/lib/process-data/sources.js +2 -279
- package/dist/lib/render.js +0 -12
- package/dist/lib/run/index.js +15 -10
- package/dist/lib/run/skills.js +0 -3
- package/dist/lib/sandbox/commands/create.js +40 -53
- package/dist/lib/sandbox/commands/list-running.js +0 -18
- package/dist/lib/sandbox/commands/start.js +7 -8
- package/dist/lib/sandbox/constants.js +0 -6
- package/dist/lib/sandbox/control/client.js +0 -1
- package/dist/lib/sandbox/control/container-identity.js +1 -16
- package/dist/lib/sandbox/control/executor.js +0 -4
- package/dist/lib/sandbox/control/identity-sentinel.js +0 -7
- package/dist/lib/sandbox/control/lifecycle.js +21 -37
- package/dist/lib/sandbox/control/native-file-lock.js +0 -3
- package/dist/lib/sandbox/control/server.js +18 -38
- package/dist/lib/sandbox/control/state.js +1 -9
- package/dist/lib/sandbox/dockerfile.js +0 -6
- package/dist/lib/sandbox/engine.js +0 -14
- package/dist/lib/sandbox/engines/docker-exact-discovery.js +1 -4
- package/dist/lib/sandbox/engines/wsl2-paths.js +0 -3
- package/dist/lib/sandbox/recovery.js +24 -26
- package/dist/lib/sandbox/removal.js +67 -518
- package/dist/lib/sandbox/task-resolver.js +0 -41
- package/dist/lib/sandbox/tools.js +1 -4
- package/dist/lib/sandbox/workspace-view.js +1 -2
- package/dist/lib/server/display.js +0 -6
- package/dist/lib/task/activity-intent.js +45 -40
- package/dist/lib/task/activity-log.js +9 -16
- package/dist/lib/task/artifact-command.js +1 -1
- package/dist/lib/task/artifact-lifecycle.js +61 -63
- package/dist/lib/task/artifact-name.js +0 -6
- package/dist/lib/task/artifact-operations.js +3 -3
- package/dist/lib/task/capabilities.js +4 -5
- package/dist/lib/task/commands/log.js +0 -6
- package/dist/lib/task/commands/status.js +17 -60
- package/dist/lib/task/commit-operation.js +28 -39
- package/dist/lib/task/completion-facts.js +56 -43
- package/dist/lib/task/control-authority.js +23 -256
- package/dist/lib/task/control-recovery.js +3 -5
- package/dist/lib/task/create.js +2 -4
- package/dist/lib/task/decision-intents.js +8 -9
- package/dist/lib/task/delivery-target.js +1 -40
- package/dist/lib/task/events.js +84 -107
- package/dist/lib/task/finalization.js +60 -15
- package/dist/lib/task/ledger-intents.js +1 -1
- package/dist/lib/task/lifecycle-execution.js +38 -33
- package/dist/lib/task/lifecycle.js +49 -41
- package/dist/lib/task/local-artifact-finalization.js +1 -4
- package/dist/lib/task/manual-validation-evidence.js +1 -37
- package/dist/lib/task/platform-operation-recovery.js +151 -108
- package/dist/lib/task/pr-delivery-fact.js +2 -5
- package/dist/lib/task/qualification-confirmation.js +5 -7
- package/dist/lib/task/resolve-ref.js +1 -25
- package/dist/lib/task/review-command.js +2 -2
- package/dist/lib/task/review-finalization.js +1 -21
- package/dist/lib/task/review-fingerprint.js +0 -4
- package/dist/lib/task/secure-fs.js +0 -56
- package/dist/lib/task/short-id.js +1 -39
- package/dist/lib/task/skill-scope.js +0 -1
- package/dist/lib/task/verification-engine.js +58 -282
- package/dist/lib/task/verification.js +6 -3
- package/dist/lib/task/write.js +11 -1
- package/lib/agent-clients/adapter.ts +0 -76
- package/lib/agent-clients/adapters/antigravity-cli.ts +0 -5
- package/lib/agent-clients/adapters/claude-code-credentials.ts +0 -19
- package/lib/agent-clients/adapters/claude-code.ts +0 -9
- package/lib/agent-clients/adapters/codex.ts +0 -56
- package/lib/agent-clients/adapters/opencode.ts +0 -5
- package/lib/agent-clients/adapters/traecli.ts +0 -5
- package/lib/agent-clients/config.ts +20 -61
- package/lib/agent-clients/registry.ts +1 -34
- package/lib/agent-clients/schema.ts +0 -18
- package/lib/agent-clients/tokens.ts +1 -2
- package/lib/agent-clients/types.ts +0 -15
- package/lib/decide.ts +1 -0
- package/lib/git/worktree-identity.ts +0 -10
- package/lib/internal/agent-client.ts +2 -70
- package/lib/internal/cli-route-inventory.ts +1 -4
- package/lib/internal/manual-validation.ts +28 -27
- package/lib/internal/platform-comment.ts +46 -4
- package/lib/internal/task-create.ts +0 -1
- package/lib/internal/task-event.ts +1 -5
- package/lib/internal/task-finalization.ts +0 -1
- package/lib/internal/task-lifecycle.ts +3 -5
- package/lib/internal/task-operation-registry.ts +3 -19
- package/lib/internal/task-review.ts +4 -4
- package/lib/platform/comment-safety.ts +0 -10
- package/lib/platform/github-provider.ts +0 -2
- package/lib/platform/in-label-sync.ts +0 -16
- package/lib/platform/issue-comments.ts +478 -301
- package/lib/platform/issue-summary-content.ts +132 -0
- package/lib/platform/issues.ts +0 -2
- package/lib/platform/operation-coordinator.ts +4 -2
- package/lib/platform/pr-change-report.ts +165 -25
- package/lib/platform/pr-checks.ts +1 -10
- package/lib/platform/pr-review.ts +1 -1
- package/lib/platform/pr-summary-content.ts +60 -0
- package/lib/platform/pr-summary.ts +364 -257
- package/lib/platform/provider-bridge.ts +0 -1
- package/lib/platform/provider-loader.ts +1 -5
- package/lib/platform/provider-validation.ts +1 -49
- package/lib/platform/pull-requests.ts +64 -99
- package/lib/platform/releases.ts +1 -40
- package/lib/platform/summary-content-pipeline.ts +23 -0
- package/lib/platform/verification-required.ts +0 -2
- package/lib/platform/verification-sync.ts +0 -94
- package/lib/process-data/normalize.ts +1 -186
- package/lib/process-data/privacy.ts +2 -19
- package/lib/process-data/sources.ts +3 -283
- package/lib/render.ts +0 -15
- package/lib/run/index.ts +13 -7
- package/lib/run/skills.ts +0 -4
- package/lib/sandbox/commands/create.ts +37 -74
- package/lib/sandbox/commands/list-running.ts +0 -19
- package/lib/sandbox/commands/start.ts +7 -10
- package/lib/sandbox/constants.ts +0 -8
- package/lib/sandbox/control/client.ts +0 -1
- package/lib/sandbox/control/container-identity.ts +1 -16
- package/lib/sandbox/control/executor.ts +1 -5
- package/lib/sandbox/control/identity-sentinel.ts +0 -8
- package/lib/sandbox/control/lifecycle.ts +18 -51
- package/lib/sandbox/control/native-file-lock.ts +0 -8
- package/lib/sandbox/control/protocol.ts +0 -2
- package/lib/sandbox/control/server.ts +13 -39
- package/lib/sandbox/control/state.ts +1 -10
- package/lib/sandbox/dockerfile.ts +0 -11
- package/lib/sandbox/engine.ts +0 -17
- package/lib/sandbox/engines/docker-exact-discovery.ts +1 -5
- package/lib/sandbox/engines/wsl2-paths.ts +0 -4
- package/lib/sandbox/recovery.ts +24 -26
- package/lib/sandbox/removal.ts +58 -687
- package/lib/sandbox/shell.ts +1 -1
- package/lib/sandbox/task-resolver.ts +0 -48
- package/lib/sandbox/tools.ts +1 -5
- package/lib/sandbox/workspace-view.ts +2 -4
- package/lib/server/display.ts +0 -14
- package/lib/server/process-control.ts +1 -1
- package/lib/task/activity-intent.ts +36 -44
- package/lib/task/activity-log.ts +9 -22
- package/lib/task/artifact-command.ts +1 -1
- package/lib/task/artifact-lifecycle.ts +58 -67
- package/lib/task/artifact-name.ts +0 -7
- package/lib/task/artifact-operations.ts +3 -3
- package/lib/task/capabilities.ts +5 -6
- package/lib/task/commands/log.ts +0 -7
- package/lib/task/commands/status.ts +14 -79
- package/lib/task/commit-operation.ts +29 -51
- package/lib/task/completion-facts.ts +45 -42
- package/lib/task/control-authority.ts +27 -317
- package/lib/task/control-recovery.ts +2 -5
- package/lib/task/create.ts +2 -5
- package/lib/task/decision-intents.ts +5 -5
- package/lib/task/delivery-target.ts +0 -40
- package/lib/task/events.ts +89 -123
- package/lib/task/finalization.ts +52 -15
- package/lib/task/ledger-intents.ts +1 -1
- package/lib/task/lifecycle-execution.ts +37 -89
- package/lib/task/lifecycle.ts +48 -44
- package/lib/task/local-artifact-finalization.ts +0 -7
- package/lib/task/manual-validation-evidence.ts +1 -47
- package/lib/task/platform-operation-recovery.ts +117 -104
- package/lib/task/pr-delivery-fact.ts +2 -11
- package/lib/task/qualification-confirmation.ts +6 -6
- package/lib/task/resolve-ref.ts +0 -23
- package/lib/task/review-command.ts +2 -2
- package/lib/task/review-finalization.ts +1 -27
- package/lib/task/review-fingerprint.ts +0 -8
- package/lib/task/secure-fs.ts +0 -42
- package/lib/task/short-id.ts +0 -43
- package/lib/task/skill-scope.ts +0 -1
- package/lib/task/verification-engine.ts +56 -287
- package/lib/task/verification.ts +5 -5
- package/lib/task/write.ts +12 -1
- package/package.json +2 -2
- package/templates/.agents/README.en.md +1 -3
- package/templates/.agents/README.zh-CN.md +0 -2
- package/templates/.agents/rules/README.en.md +0 -1
- package/templates/.agents/rules/README.zh-CN.md +0 -1
- package/templates/.agents/rules/commit-and-pr.en.md +1 -1
- package/templates/.agents/rules/commit-and-pr.zh-CN.md +1 -1
- package/templates/.agents/rules/no-mid-flow-questions.en.md +0 -10
- package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +0 -10
- package/templates/.agents/rules/pr-sync.en.md +4 -2
- package/templates/.agents/rules/pr-sync.zh-CN.md +6 -9
- package/templates/.agents/rules/task-management.en.md +3 -3
- package/templates/.agents/rules/task-management.zh-CN.md +3 -3
- package/templates/.agents/skills/analyze-task/SKILL.en.md +3 -3
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/cancel-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/code-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/commit/SKILL.en.md +2 -2
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +6 -6
- package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +6 -6
- package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +1 -1
- package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +1 -1
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +2 -2
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +2 -2
- package/templates/.agents/skills/complete-task/SKILL.en.md +10 -25
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +11 -26
- package/templates/.agents/skills/create-pr/SKILL.en.md +1 -1
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/create-pr/reference/change-report.en.md +9 -2
- package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +9 -2
- package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +2 -2
- package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +2 -2
- package/templates/.agents/skills/create-task/SKILL.en.md +0 -18
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +0 -18
- package/templates/.agents/skills/plan-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/review-analysis/SKILL.en.md +3 -3
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/review-code/SKILL.en.md +5 -5
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/review-plan/SKILL.en.md +3 -3
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/review-pr/SKILL.en.md +4 -4
- package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/run-manual-validation/SKILL.en.md +1 -1
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +3 -75
- package/templates/.agents/skills/watch-pr/SKILL.en.md +1 -1
- package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +3 -3
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +3 -3
- package/templates/.agents/templates/task.en.md +1 -0
- package/templates/.agents/templates/task.zh-CN.md +1 -0
- package/templates/.claude/settings.json +0 -24
- package/templates/.codex/hooks.json +0 -50
- package/dist/lib/agent-clients/adapters/codex-lifecycle/app-server.js +0 -582
- package/dist/lib/agent-clients/adapters/codex-lifecycle/binding.js +0 -114
- package/dist/lib/agent-clients/adapters/codex-lifecycle/build-identity.js +0 -237
- package/dist/lib/agent-clients/adapters/codex-lifecycle/cli.js +0 -443
- package/dist/lib/agent-clients/adapters/codex-lifecycle/evidence.js +0 -236
- package/dist/lib/agent-clients/adapters/codex-lifecycle/recovery.js +0 -292
- package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +0 -267
- package/dist/lib/agent-clients/adapters/codex-orchestration.js +0 -466
- package/dist/lib/internal/task-orchestration.js +0 -71
- package/dist/lib/platform/verification.js +0 -6
- package/dist/lib/run/prompt.js +0 -2
- package/dist/lib/sandbox/engines/authority.js +0 -289
- package/dist/lib/task/delegation-receipts.js +0 -410
- package/dist/lib/task/orchestration.js +0 -1233
- package/dist/lib/task/verification-checks.js +0 -9
- package/dist/lib/task/workspace-snapshot.js +0 -121
- package/dist/lifecycle-build-manifest.json +0 -6
- package/lib/agent-clients/adapters/codex-lifecycle/app-server.ts +0 -688
- package/lib/agent-clients/adapters/codex-lifecycle/binding.ts +0 -147
- package/lib/agent-clients/adapters/codex-lifecycle/build-identity.ts +0 -349
- package/lib/agent-clients/adapters/codex-lifecycle/cli.ts +0 -506
- package/lib/agent-clients/adapters/codex-lifecycle/evidence.ts +0 -385
- package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +0 -41
- package/lib/agent-clients/adapters/codex-lifecycle/recovery.ts +0 -418
- package/lib/agent-clients/adapters/codex-lifecycle/store.ts +0 -354
- package/lib/agent-clients/adapters/codex-orchestration.ts +0 -630
- package/lib/internal/task-orchestration.ts +0 -74
- package/lib/platform/verification.ts +0 -11
- package/lib/run/prompt.ts +0 -1
- package/lib/sandbox/engines/authority.ts +0 -365
- package/lib/task/delegation-receipts.ts +0 -547
- package/lib/task/orchestration.ts +0 -1651
- package/lib/task/verification-checks.ts +0 -10
- package/lib/task/workspace-snapshot.ts +0 -144
- package/templates/.agents/hooks/lifecycle-delegation.js +0 -140
- package/templates/.agents/rules/lifecycle-orchestration.en.md +0 -44
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +0 -44
- package/templates/.agents/skills/run-task/SKILL.en.md +0 -29
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +0 -29
- package/templates/.agents/skills/run-task/config/verify.en.json +0 -10
- package/templates/.agents/skills/run-task/config/verify.zh-CN.json +0 -10
- package/templates/.agents/skills/run-task/reference/host-validation.en.md +0 -24
- package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +0 -24
- package/templates/.claude/agents/agent-infra-lifecycle-executor.en.md +0 -6
- package/templates/.claude/agents/agent-infra-lifecycle-executor.zh-CN.md +0 -6
- package/templates/.claude/agents/agent-infra-lifecycle-reviewer.en.md +0 -6
- package/templates/.claude/agents/agent-infra-lifecycle-reviewer.zh-CN.md +0 -6
- package/templates/.claude/commands/run-task.en.md +0 -8
- package/templates/.claude/commands/run-task.zh-CN.md +0 -8
- package/templates/.codex/agents/agent-infra-lifecycle-executor.en.toml +0 -3
- package/templates/.codex/agents/agent-infra-lifecycle-executor.zh-CN.toml +0 -3
- package/templates/.codex/agents/agent-infra-lifecycle-reviewer.en.toml +0 -3
- package/templates/.codex/agents/agent-infra-lifecycle-reviewer.zh-CN.toml +0 -3
- package/templates/.opencode/commands/run-task.en.md +0 -11
- package/templates/.opencode/commands/run-task.zh-CN.md +0 -11
|
@@ -1,37 +1,11 @@
|
|
|
1
|
-
import { spawnSync } from 'node:child_process';
|
|
2
1
|
import fs from 'node:fs';
|
|
3
2
|
import path from 'node:path';
|
|
4
|
-
import { isRemovedHashShortIdInput } from '../task/short-id.js';
|
|
5
3
|
import { resolveProjectTaskWorkspaceRoot } from '../task/workspace-root.js';
|
|
6
4
|
const TASK_ID_RE = /^TASK-\d{8}-\d{6}$/;
|
|
7
|
-
const SHORT_ID_RE = /^\d+$/;
|
|
8
5
|
export const TASK_WORKSPACE_STATES = ['active', 'completed', 'blocked', 'archive'];
|
|
9
|
-
function resolveShortIdStrict(arg, repoRoot) {
|
|
10
|
-
const scriptPath = path.join(repoRoot, '.agents', 'scripts', 'task-short-id.js');
|
|
11
|
-
if (!fs.existsSync(scriptPath)) {
|
|
12
|
-
throw new Error(`Short id '${arg}' provided but task-short-id.js script is missing at ${scriptPath}`);
|
|
13
|
-
}
|
|
14
|
-
const result = spawnSync('node', [scriptPath, 'resolve', arg], { encoding: 'utf8', cwd: repoRoot });
|
|
15
|
-
if (result.status !== 0) {
|
|
16
|
-
throw new Error(`Short id '${arg}' not found in active task registry: ${(result.stderr || '').trim()}`);
|
|
17
|
-
}
|
|
18
|
-
return result.stdout.trim();
|
|
19
|
-
}
|
|
20
6
|
function stripQuotes(value) {
|
|
21
7
|
return value.replace(/^(["'])(.*)\1$/, '$2');
|
|
22
8
|
}
|
|
23
|
-
function readTaskContent(repoRoot, taskId) {
|
|
24
|
-
const taskRoot = resolveProjectTaskWorkspaceRoot(repoRoot);
|
|
25
|
-
for (const state of TASK_WORKSPACE_STATES) {
|
|
26
|
-
const taskPath = state === 'archive'
|
|
27
|
-
? path.join(taskRoot, state, ...findArchiveTaskParts(repoRoot, taskId), 'local', 'task.md')
|
|
28
|
-
: path.join(taskRoot, state, taskId, 'task.md');
|
|
29
|
-
if (fs.existsSync(taskPath)) {
|
|
30
|
-
return { content: fs.readFileSync(taskPath, 'utf8'), state, taskMd: taskPath };
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
throw new Error(`Task not found: ${taskId}`);
|
|
34
|
-
}
|
|
35
9
|
function taskWorkspaceCandidates(repoRoot, taskId) {
|
|
36
10
|
const taskRoot = resolveProjectTaskWorkspaceRoot(repoRoot);
|
|
37
11
|
const hot = TASK_WORKSPACE_STATES.filter((state) => state !== 'archive').flatMap((state) => {
|
|
@@ -89,21 +63,6 @@ function resolveBranchFromTaskContent(content, taskId) {
|
|
|
89
63
|
}
|
|
90
64
|
throw new Error(`Task ${taskId} has no branch field in task.md`);
|
|
91
65
|
}
|
|
92
|
-
export function resolveTaskBranch(arg, repoRoot) {
|
|
93
|
-
if (isRemovedHashShortIdInput(arg)) {
|
|
94
|
-
throw new Error(`Invalid task short id '${arg}': task short ids must use bare digits`);
|
|
95
|
-
}
|
|
96
|
-
if (SHORT_ID_RE.test(arg)) {
|
|
97
|
-
const taskId = resolveShortIdStrict(arg, repoRoot);
|
|
98
|
-
const { content } = readTaskContent(repoRoot, taskId);
|
|
99
|
-
return resolveBranchFromTaskContent(content, taskId);
|
|
100
|
-
}
|
|
101
|
-
if (!TASK_ID_RE.test(arg)) {
|
|
102
|
-
return arg;
|
|
103
|
-
}
|
|
104
|
-
const { content } = readTaskContent(repoRoot, arg);
|
|
105
|
-
return resolveBranchFromTaskContent(content, arg);
|
|
106
|
-
}
|
|
107
66
|
export function resolveTaskWorkspace(taskId, repoRoot) {
|
|
108
67
|
if (!TASK_ID_RE.test(taskId))
|
|
109
68
|
throw new Error(`Invalid task id: ${taskId}`);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { createSandboxCapabilityPlan } from './agent-client-reconciler.js';
|
|
3
|
-
import { safeNameCandidates
|
|
3
|
+
import { safeNameCandidates } from './constants.js';
|
|
4
4
|
import { hostJoin } from './engines/wsl2-paths.js';
|
|
5
5
|
export function tmpfsSeedStagingPath(toolId, index) {
|
|
6
6
|
return `/run/agent-infra/tmpfs-seeds/${toolId}/${index}`;
|
|
@@ -233,9 +233,6 @@ export function parseCustomTools(value, options) {
|
|
|
233
233
|
export function resolveTools(config) {
|
|
234
234
|
return [...createSandboxCapabilityPlan(config).tools];
|
|
235
235
|
}
|
|
236
|
-
export function toolConfigDir(tool, project, branch) {
|
|
237
|
-
return hostJoin(tool.sandboxBase, project, sanitizeBranchName(branch));
|
|
238
|
-
}
|
|
239
236
|
export function toolConfigDirCandidates(tool, project, branch) {
|
|
240
237
|
return safeNameCandidates(branch).map((name) => hostJoin(tool.sandboxBase, project, name));
|
|
241
238
|
}
|
|
@@ -295,8 +295,7 @@ export function finalizeSandboxControlManifest(setup, identity) {
|
|
|
295
295
|
const manifest = {
|
|
296
296
|
...setup.manifestDraft,
|
|
297
297
|
engine: identity.engine,
|
|
298
|
-
containerIdentity: { id: identity.id, labels: { ...identity.labels } }
|
|
299
|
-
authorityEvidence: identity.authorityEvidence
|
|
298
|
+
containerIdentity: { id: identity.id, labels: { ...identity.labels } }
|
|
300
299
|
};
|
|
301
300
|
const persistedManifest = {
|
|
302
301
|
...manifest,
|
|
@@ -4,9 +4,6 @@ export function textMessage(text) {
|
|
|
4
4
|
export function markdownMessage(markdown) {
|
|
5
5
|
return { kind: 'markdown', markdown };
|
|
6
6
|
}
|
|
7
|
-
export function tableMessage(columns, rows, title) {
|
|
8
|
-
return { kind: 'table', title, columns, rows };
|
|
9
|
-
}
|
|
10
7
|
export function statusCard(title, tone, fields, body) {
|
|
11
8
|
return { kind: 'status-card', title, tone, fields, body };
|
|
12
9
|
}
|
|
@@ -20,9 +17,6 @@ export function streamEvent(title, phase, text, exitCode, signal) {
|
|
|
20
17
|
message.signal = signal;
|
|
21
18
|
return message;
|
|
22
19
|
}
|
|
23
|
-
export function commandResult(title, exitCode, signal, stdout, stderr) {
|
|
24
|
-
return { kind: 'command-result', title, exitCode, signal, stdout, stderr };
|
|
25
|
-
}
|
|
26
20
|
export function normalizeOutbound(message) {
|
|
27
21
|
return typeof message === 'string' ? textMessage(message) : message;
|
|
28
22
|
}
|
|
@@ -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
|