@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,37 +1,42 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
agent
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
return failure(request.mode, planned.result.error?.code ?? 'ORCHESTRATION_PROVENANCE_MISMATCH', planned.result.error?.message ?? 'orchestration provenance validation failed');
|
|
1
|
+
import { parseTypedTaskFrontmatter } from './frontmatter.js';
|
|
2
|
+
const labels = {
|
|
3
|
+
'Analyze Task': 'analyze', 'Review Analysis': 'review-analysis', 'Plan Task': 'plan',
|
|
4
|
+
'Review Plan': 'review-plan', 'Code Task': 'code', 'Review Code': 'review-code',
|
|
5
|
+
'Run Manual Validation': 'validation-run'
|
|
6
|
+
};
|
|
7
|
+
export function lifecycleExecutions(content) {
|
|
8
|
+
const value = parseTypedTaskFrontmatter(content).lifecycle_execution;
|
|
9
|
+
if (value !== undefined) {
|
|
10
|
+
if (typeof value !== 'string')
|
|
11
|
+
throw new Error('invalid lifecycle execution state');
|
|
12
|
+
const state = JSON.parse(value);
|
|
13
|
+
if (!state || typeof state !== 'object' || !('version' in state) || state.version !== 1 || !('open' in state) || !Array.isArray(state.open))
|
|
14
|
+
throw new Error('invalid lifecycle execution state');
|
|
15
|
+
return state.open.map((item) => {
|
|
16
|
+
if (!item || typeof item !== 'object' || !('family' in item) || typeof item.family !== 'string' || ![...Object.values(labels), 'manual-validation', 'other'].includes(item.family) || !('agent' in item) || typeof item.agent !== 'string' || !('startedAt' in item) || typeof item.startedAt !== 'string')
|
|
17
|
+
throw new Error('invalid lifecycle execution identity');
|
|
18
|
+
return item;
|
|
19
|
+
});
|
|
22
20
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
export function prReviewExecution(content) {
|
|
24
|
+
const value = parseTypedTaskFrontmatter(content).lifecycle_execution;
|
|
25
|
+
if (value === undefined)
|
|
26
|
+
return { open: null, terminals: [] };
|
|
27
|
+
if (typeof value !== 'string')
|
|
28
|
+
throw new Error('invalid lifecycle execution state');
|
|
29
|
+
const state = JSON.parse(value);
|
|
30
|
+
if (state.version !== 1 || !Array.isArray(state.open))
|
|
31
|
+
throw new Error('invalid lifecycle execution state');
|
|
32
|
+
const pr = state.prReview ?? { open: null, terminals: [] };
|
|
33
|
+
const valid = (item) => item && typeof item.artifact === 'string' && typeof item.head === 'string' && typeof item.agent === 'string';
|
|
34
|
+
if (!Array.isArray(pr.terminals) || (pr.open !== null && (!valid(pr.open) || typeof pr.open.startedAt !== 'string')) || !pr.terminals.every((item) => valid(item) && typeof item.note === 'string'))
|
|
35
|
+
throw new Error('invalid PR review execution state');
|
|
36
|
+
return pr;
|
|
28
37
|
}
|
|
29
|
-
function
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
return inspected;
|
|
33
|
-
const paused = pauseOrchestration(taskRef, inspected.error?.code ?? 'ORCHESTRATION_PROVENANCE_MISMATCH', inspected.error?.message ?? 'orchestration provenance validation failed', true, options);
|
|
34
|
-
return failure(request.mode, paused.run?.pause?.code ?? inspected.error?.code ?? 'ORCHESTRATION_PROVENANCE_MISMATCH', paused.run?.pause?.message ?? inspected.error?.message ?? 'orchestration provenance validation failed');
|
|
38
|
+
export function serializeLifecycleExecution(open, content, prReview) {
|
|
39
|
+
const pr = prReview ?? (content ? prReviewExecution(content) : { open: null, terminals: [] });
|
|
40
|
+
return JSON.stringify({ version: 1, open, prReview: pr });
|
|
35
41
|
}
|
|
36
|
-
export { inspectLifecycleExecution, validateLifecycleExecution };
|
|
37
42
|
//# sourceMappingURL=lifecycle-execution.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
-
import { appendActivityEntry, locateActivityLog } from './activity-log.js';
|
|
4
|
+
import { activityWarnings, appendActivityEntry, locateActivityLog } from './activity-log.js';
|
|
5
5
|
import { artifactFamilyCatalog, inspectArtifactDirectory } from './artifact-lifecycle.js';
|
|
6
6
|
import { parseArtifactName } from './artifact-name.js';
|
|
7
7
|
import { parseTypedTaskFrontmatter, updateTaskFrontmatter } from './frontmatter.js';
|
|
@@ -15,7 +15,7 @@ import { taskIssueIdentity } from '../platform/task-identities.js';
|
|
|
15
15
|
import { resourceIdentityEquals } from '../platform/resource-identity.js';
|
|
16
16
|
import { resolveProjectTaskWorkspaceRoot } from './workspace-root.js';
|
|
17
17
|
const lifecycleIntentCatalog = [
|
|
18
|
-
'block', 'activate', 'cancel', 'complete', 'close-codescan', 'close-dependabot', 'restore'
|
|
18
|
+
'block', 'activate', 'cancel', 'complete', 'close-codescan', 'close-dependabot', 'restore'
|
|
19
19
|
];
|
|
20
20
|
const lifecycleFailureCatalog = [
|
|
21
21
|
'LIFECYCLE_DIRECTORY_TRANSFER_FAILED',
|
|
@@ -82,9 +82,6 @@ function failed(request, error, extra = {}) {
|
|
|
82
82
|
error, ...extra
|
|
83
83
|
};
|
|
84
84
|
}
|
|
85
|
-
export function taskLifecycleFailure(request, error, taskId = null) {
|
|
86
|
-
return failed(request, error, { taskId });
|
|
87
|
-
}
|
|
88
85
|
function normalizedRequest(request) {
|
|
89
86
|
if (!request || typeof request !== 'object' || !lifecycleIntentCatalog.includes(request.intent)) {
|
|
90
87
|
return { code: 'LIFECYCLE_PAYLOAD_INVALID', message: 'intent is not in the lifecycle catalog' };
|
|
@@ -300,26 +297,11 @@ function taskBoundControlMoveSafety(request, controlRoot, options, taskId, repoR
|
|
|
300
297
|
}
|
|
301
298
|
return null;
|
|
302
299
|
}
|
|
303
|
-
function
|
|
304
|
-
const orchestrationPath = path.join(sourcePath, '.runtime', 'orchestration.json');
|
|
305
|
-
if (!pathExists(orchestrationPath))
|
|
306
|
-
return null;
|
|
307
|
-
try {
|
|
308
|
-
const run = JSON.parse(fs.readFileSync(orchestrationPath, 'utf8'));
|
|
309
|
-
if (run.status === 'running' || run.pendingDelegation !== null && run.pendingDelegation !== undefined) {
|
|
310
|
-
return { code: 'LIFECYCLE_RUNTIME_MOVE_UNSAFE', message: 'task orchestration has an active or pending delegation; settle it before moving the task directory' };
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
catch {
|
|
314
|
-
return { code: 'LIFECYCLE_RUNTIME_MOVE_UNSAFE', message: 'task orchestration state is unreadable; refusing to move the task directory' };
|
|
315
|
-
}
|
|
316
|
-
return null;
|
|
317
|
-
}
|
|
318
|
-
function runtimeMoveSafety(request, movingTaskDirectory, options, taskId, repoRoot, sourcePath, validateControlManifestIdentity) {
|
|
300
|
+
function runtimeMoveSafety(request, movingTaskDirectory, options, taskId, repoRoot, validateControlManifestIdentity) {
|
|
319
301
|
if (!movingTaskDirectory)
|
|
320
302
|
return null;
|
|
321
303
|
const controlSafety = taskBoundControlMoveSafety(request, options.controlRoot, options, taskId, repoRoot, validateControlManifestIdentity);
|
|
322
|
-
return controlSafety
|
|
304
|
+
return controlSafety;
|
|
323
305
|
}
|
|
324
306
|
function targetContainsTask(targetPath, taskId, request) {
|
|
325
307
|
try {
|
|
@@ -356,16 +338,26 @@ function actionAndNote(request, restoredFiles = 0) {
|
|
|
356
338
|
return { action: 'Close Codescan', note: `Code Scanning alert #${request.alertNumber} dismissed: ${request.reason}` };
|
|
357
339
|
if (request.intent === 'close-dependabot')
|
|
358
340
|
return { action: 'Close Dependabot', note: `Dependabot alert #${request.alertNumber} dismissed: ${request.reason}` };
|
|
359
|
-
if (request.intent === 'recover-started')
|
|
360
|
-
return { action: 'Recover Started', note: 'automatic recovery' };
|
|
361
341
|
return { action: 'Restore Task', note: `Restored ${restoredFiles} files from Issue #${request.issueNumber}` };
|
|
362
342
|
}
|
|
343
|
+
function completionKeys(content) {
|
|
344
|
+
const value = parseTypedTaskFrontmatter(content).lifecycle_transition;
|
|
345
|
+
if (value === undefined)
|
|
346
|
+
return [];
|
|
347
|
+
if (typeof value !== 'string')
|
|
348
|
+
throw new Error('invalid lifecycle transition');
|
|
349
|
+
const state = JSON.parse(value);
|
|
350
|
+
if (!state || typeof state !== 'object' || !('completedKeys' in state) || !Array.isArray(state.completedKeys))
|
|
351
|
+
throw new Error('invalid lifecycle transition');
|
|
352
|
+
return state.completedKeys.map((key) => {
|
|
353
|
+
if (!key || typeof key !== 'object' || !('action' in key) || typeof key.action !== 'string' || !('agent' in key) || typeof key.agent !== 'string' || !('note' in key) || typeof key.note !== 'string')
|
|
354
|
+
throw new Error('invalid lifecycle completion identity');
|
|
355
|
+
return key;
|
|
356
|
+
});
|
|
357
|
+
}
|
|
363
358
|
function matchingCompletion(content, request, restoredFiles = 0) {
|
|
364
|
-
const section = locateActivityLog(content);
|
|
365
|
-
if (!section)
|
|
366
|
-
return false;
|
|
367
359
|
const identity = actionAndNote(request, restoredFiles);
|
|
368
|
-
return
|
|
360
|
+
return completionKeys(content).some((entry) => entry.action === identity.action && entry.agent === request.agent && entry.note === identity.note);
|
|
369
361
|
}
|
|
370
362
|
function validateRestoreStaging(request, repoRoot, taskId) {
|
|
371
363
|
let workspace;
|
|
@@ -424,13 +416,17 @@ function validateRestoreStaging(request, repoRoot, taskId) {
|
|
|
424
416
|
}
|
|
425
417
|
return { stagingDir, fileCount: entries.filter((entry) => !entry.name.startsWith('.')).length };
|
|
426
418
|
}
|
|
427
|
-
function
|
|
428
|
-
const section = locateActivityLog(content) ?? (
|
|
419
|
+
function lifecycleActivityMutation(content, request, metadata, identity, allowMissing) {
|
|
420
|
+
const section = locateActivityLog(content) ?? (allowMissing ? { heading: 'Activity Log', body: '', entries: [] } : null);
|
|
429
421
|
if (!section)
|
|
430
|
-
return
|
|
431
|
-
const identity = actionAndNote(request, restoredFiles);
|
|
422
|
+
return [];
|
|
432
423
|
let body = appendActivityEntry(section, { time: metadata.timestamp, step: `${identity.action} [started]`, agent: request.agent, note: 'started' });
|
|
433
424
|
body = appendActivityEntry({ ...section, body }, { time: metadata.timestamp, step: identity.action, agent: request.agent, note: identity.note });
|
|
425
|
+
return [{ kind: 'section', aliases: ['活动日志', 'Activity Log'], heading: section.heading, body }];
|
|
426
|
+
}
|
|
427
|
+
function mutationsFor(request, content, metadata, restoredFiles, allowMissingActivityLog = false) {
|
|
428
|
+
const identity = actionAndNote(request, restoredFiles);
|
|
429
|
+
const activityMutation = lifecycleActivityMutation(content, request, metadata, identity, allowMissingActivityLog);
|
|
434
430
|
const set = {};
|
|
435
431
|
const remove = [];
|
|
436
432
|
if (request.intent === 'block') {
|
|
@@ -458,9 +454,13 @@ function mutationsFor(request, content, metadata, restoredFiles, allowMissingAct
|
|
|
458
454
|
if (frontmatter.target_date === '')
|
|
459
455
|
set.target_date = metadata.timestamp.slice(0, 10);
|
|
460
456
|
}
|
|
457
|
+
const completedKeys = completionKeys(content);
|
|
458
|
+
if (!matchingCompletion(content, request, restoredFiles))
|
|
459
|
+
completedKeys.push({ ...identity, agent: request.agent });
|
|
460
|
+
set.lifecycle_transition = JSON.stringify({ completedKeys });
|
|
461
461
|
const mutations = [
|
|
462
462
|
{ kind: 'frontmatter', set, remove: [...new Set(remove)] },
|
|
463
|
-
|
|
463
|
+
...activityMutation
|
|
464
464
|
];
|
|
465
465
|
if (request.intent === 'block') {
|
|
466
466
|
mutations.splice(1, 0, {
|
|
@@ -595,9 +595,6 @@ export function inspectTaskLifecycleProgress(repoRoot, taskId, agent) {
|
|
|
595
595
|
}
|
|
596
596
|
}
|
|
597
597
|
function applyTaskLifecycle(requestInput, options = {}) {
|
|
598
|
-
if (requestInput.intent === 'recover-started') {
|
|
599
|
-
return failed(requestInput, { code: 'LIFECYCLE_RECOVERY_REQUIRES_AUTHORITY', message: 'recover-started must be dispatched through task control authority' });
|
|
600
|
-
}
|
|
601
598
|
const normalized = normalizedRequest(requestInput);
|
|
602
599
|
if ('code' in normalized)
|
|
603
600
|
return failed(requestInput, normalized);
|
|
@@ -674,7 +671,7 @@ function applyTaskLifecycle(requestInput, options = {}) {
|
|
|
674
671
|
&& !(request.intent === 'complete' && targetContainsTask(targetPath, taskId, request))) {
|
|
675
672
|
return failed(request, { code: 'LIFECYCLE_TARGET_CONFLICT', message: `target directory already exists: ${targetPath}` }, { taskId, sourceState, targetState: spec.target, sourcePath, targetPath });
|
|
676
673
|
}
|
|
677
|
-
const moveSafety = runtimeMoveSafety(request, movingTaskDirectory, options, taskId, repoRoot,
|
|
674
|
+
const moveSafety = runtimeMoveSafety(request, movingTaskDirectory, options, taskId, repoRoot, true);
|
|
678
675
|
if (moveSafety)
|
|
679
676
|
return failed(request, moveSafety, { taskId, sourceState, targetState: spec.target, sourcePath, targetPath });
|
|
680
677
|
const content = io.readFileSync(currentTaskFile);
|
|
@@ -687,8 +684,6 @@ function applyTaskLifecycle(requestInput, options = {}) {
|
|
|
687
684
|
}
|
|
688
685
|
if (frontmatter.id !== taskId)
|
|
689
686
|
return failed(request, { code: 'LIFECYCLE_IDENTITY_INVALID', message: 'task.md id does not match its lifecycle task id' }, { taskId, sourceState, targetState: spec.target, sourcePath, targetPath });
|
|
690
|
-
if (!locateActivityLog(content))
|
|
691
|
-
return failed(request, { code: 'LIFECYCLE_LOG_MISSING', message: 'task has no unique Activity Log section' }, { taskId, sourceState, targetState: spec.target, sourcePath, targetPath });
|
|
692
687
|
if (spec.target === 'active') {
|
|
693
688
|
const contract = validateCurrentTaskContract(content);
|
|
694
689
|
if (!contract.ok)
|
|
@@ -832,7 +827,7 @@ function applyTaskLifecycle(requestInput, options = {}) {
|
|
|
832
827
|
if (fs.existsSync(targetPath) && !fs.existsSync(path.join(sourcePath, 'task.md')))
|
|
833
828
|
completed.add('directory-moved');
|
|
834
829
|
if (!completed.has('directory-moved')) {
|
|
835
|
-
const moveSafety = runtimeMoveSafety(request, movingTaskDirectory, options, taskId, repoRoot,
|
|
830
|
+
const moveSafety = runtimeMoveSafety(request, movingTaskDirectory, options, taskId, repoRoot, false);
|
|
836
831
|
if (moveSafety)
|
|
837
832
|
return failed(request, moveSafety, { taskId, sourceState, targetState: spec.target, sourcePath, targetPath, journalPath, completedSteps: [...completed], changed: completed.size > 0, timestamp: journal.metadata.timestamp, agentInfraVersion: journal.metadata.agentInfraVersion });
|
|
838
833
|
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
|
@@ -967,5 +962,18 @@ function applyTaskLifecycle(requestInput, options = {}) {
|
|
|
967
962
|
journalPath, completedSteps: [...completed], pendingSteps: []
|
|
968
963
|
};
|
|
969
964
|
}
|
|
970
|
-
|
|
965
|
+
function applyTaskLifecycleWithWarnings(request, options = {}) {
|
|
966
|
+
const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
|
|
967
|
+
const taskFile = resolved.ok ? resolved.taskMdPath : request.intent === 'restore' ? path.join(request.stagingDir, 'task.md') : null;
|
|
968
|
+
let warnings = [];
|
|
969
|
+
if (taskFile) {
|
|
970
|
+
try {
|
|
971
|
+
warnings = activityWarnings(fs.readFileSync(taskFile, 'utf8'));
|
|
972
|
+
}
|
|
973
|
+
catch { /* The lifecycle operation reports its own read failure. */ }
|
|
974
|
+
}
|
|
975
|
+
const result = applyTaskLifecycle(request, options);
|
|
976
|
+
return result.status === 'failed' || !warnings.length ? result : { ...result, warnings };
|
|
977
|
+
}
|
|
978
|
+
export { lifecycleIntentCatalog, lifecycleFailureCatalog, lifecycleProducerCatalog, applyTaskLifecycleWithWarnings as applyTaskLifecycle, previewTaskCompletion };
|
|
971
979
|
//# sourceMappingURL=lifecycle.js.map
|
|
@@ -113,9 +113,6 @@ function prepareLocalArtifact(request, candidate) {
|
|
|
113
113
|
repoRoot: resolved.repoRoot
|
|
114
114
|
};
|
|
115
115
|
}
|
|
116
|
-
function commitLocalArtifactProvenance(prepared) {
|
|
117
|
-
return prepared.result;
|
|
118
|
-
}
|
|
119
116
|
function finalizeLocalArtifact(request) {
|
|
120
117
|
return prepareLocalArtifact(request).result;
|
|
121
118
|
}
|
|
@@ -124,5 +121,5 @@ function preflightLocalArtifact(request) {
|
|
|
124
121
|
const prepared = prepareLocalArtifact(request);
|
|
125
122
|
return prepared.result;
|
|
126
123
|
}
|
|
127
|
-
export { LOCAL_ARTIFACT_REQUIRED_SECTIONS, finalizeLocalArtifact, preflightLocalArtifact, prepareLocalArtifact,
|
|
124
|
+
export { LOCAL_ARTIFACT_REQUIRED_SECTIONS, finalizeLocalArtifact, preflightLocalArtifact, prepareLocalArtifact, canonicalSemanticDigest as semanticDigest, sha256Content, validateLocalArtifact };
|
|
128
125
|
//# sourceMappingURL=local-artifact-finalization.js.map
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import { createHash } from 'node:crypto';
|
|
3
1
|
import { MANUAL_VALIDATION_SHA40 as SHA40, MANUAL_VALIDATION_TASK_ID as TASK_ID, exactKeys, isRecord, validTimestamp } from './manual-validation-shared.js';
|
|
4
2
|
const MANUAL_VALIDATION_EVIDENCE_SCHEMA = 'agent-infra/branch-only-validation-evidence';
|
|
5
3
|
const MANUAL_VALIDATION_EVIDENCE_VERSION = 1;
|
|
@@ -92,39 +90,5 @@ function manualValidationEvidenceSummary(evidence) {
|
|
|
92
90
|
cleanup: evidence.result.cleanup
|
|
93
91
|
};
|
|
94
92
|
}
|
|
95
|
-
|
|
96
|
-
const shape = validateShape(value);
|
|
97
|
-
if (!shape.ok)
|
|
98
|
-
return shape;
|
|
99
|
-
const evidence = shape.value;
|
|
100
|
-
if (evidence.result.exitCode !== 0 || evidence.result.signal !== null || evidence.result.cleanup !== 'completed') {
|
|
101
|
-
return { ok: false, error: { code: 'MANUAL_VALIDATION_EVIDENCE_UNSUCCESSFUL', message: 'validation must exit 0 without a signal and complete cleanup' } };
|
|
102
|
-
}
|
|
103
|
-
if (expected) {
|
|
104
|
-
if (evidence.taskId !== expected.taskId || evidence.branch !== expected.branch) {
|
|
105
|
-
return { ok: false, error: { code: 'MANUAL_VALIDATION_EVIDENCE_IDENTITY_MISMATCH', message: 'evidence task or branch does not match the expected identity' } };
|
|
106
|
-
}
|
|
107
|
-
if (expected.commit !== undefined && evidence.commit !== expected.commit) {
|
|
108
|
-
return { ok: false, error: { code: 'MANUAL_VALIDATION_EVIDENCE_STALE', message: 'evidence commit does not match the current head' } };
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
return shape;
|
|
112
|
-
}
|
|
113
|
-
function readManualValidationEvidence(file, expected) {
|
|
114
|
-
let parsed;
|
|
115
|
-
try {
|
|
116
|
-
parsed = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
117
|
-
}
|
|
118
|
-
catch (error) {
|
|
119
|
-
const code = error.code === 'ENOENT'
|
|
120
|
-
? 'MANUAL_VALIDATION_EVIDENCE_MISSING'
|
|
121
|
-
: 'MANUAL_VALIDATION_EVIDENCE_INVALID';
|
|
122
|
-
return { ok: false, error: { code, message: error instanceof Error ? error.message : String(error) } };
|
|
123
|
-
}
|
|
124
|
-
return validateManualValidationEvidence(parsed, expected);
|
|
125
|
-
}
|
|
126
|
-
function manualValidationEvidenceDigest(evidence) {
|
|
127
|
-
return createHash('sha256').update(JSON.stringify(evidence), 'utf8').digest('hex');
|
|
128
|
-
}
|
|
129
|
-
export { MANUAL_VALIDATION_EVIDENCE_SCHEMA, MANUAL_VALIDATION_EVIDENCE_VERSION, createManualValidationEvidence, manualValidationEvidenceSummary, manualValidationEvidenceDigest, readManualValidationEvidence, validateManualValidationEvidence };
|
|
93
|
+
export { MANUAL_VALIDATION_EVIDENCE_SCHEMA, MANUAL_VALIDATION_EVIDENCE_VERSION, createManualValidationEvidence, manualValidationEvidenceSummary };
|
|
130
94
|
//# sourceMappingURL=manual-validation-evidence.js.map
|
|
@@ -6,8 +6,8 @@ import { inspectPlatformCommentOperation, syncPlatformComment } from '../platfor
|
|
|
6
6
|
import { parseDeliverySummaryContent, renderDeliverySummaryContent, parseCancelSummaryContent, renderCancelSummaryContent } from '../platform/issue-summary-content.js';
|
|
7
7
|
import { enumerateArtifacts } from './artifacts.js';
|
|
8
8
|
import { inspectPlatformIssue, syncPlatformIssue } from '../platform/issues.js';
|
|
9
|
-
import
|
|
10
|
-
import
|
|
9
|
+
import '../platform/context.js';
|
|
10
|
+
import '../platform/provider-bridge.js';
|
|
11
11
|
import { inLabelMappingDigest } from '../platform/in-label-sync.js';
|
|
12
12
|
import { bindPlatformPullRequest, recoverCreatedPullRequest, syncPlatformPullRequest } from '../platform/pull-requests.js';
|
|
13
13
|
import { replayPullRequestSummary } from '../platform/pr-summary.js';
|
|
@@ -18,9 +18,10 @@ import { parseResourceIdentity, resourceIdentityEquals } from '../platform/resou
|
|
|
18
18
|
import { operationId } from './platform-operation-journal.js';
|
|
19
19
|
import { canonicalizeSummaryBody } from '../platform/comment-safety.js';
|
|
20
20
|
import { platformResult } from '../platform/types.js';
|
|
21
|
+
import { mergeOperationWarnings } from './operation-outcome.js';
|
|
21
22
|
import { resolveTaskRef } from './resolve-ref.js';
|
|
22
23
|
import { readPlatformOperationJournal, recordPlatformOperation } from './platform-operation-journal.js';
|
|
23
|
-
import
|
|
24
|
+
import '../platform/provider-validation.js';
|
|
24
25
|
const DEFAULT_RECOVERY_ATTEMPTS = 3;
|
|
25
26
|
function labelsMatchOwnedPrefix(actual, expected, prefix) {
|
|
26
27
|
return actual.filter((label) => label.startsWith(prefix)).sort().join('\0')
|
|
@@ -29,8 +30,8 @@ function labelsMatchOwnedPrefix(actual, expected, prefix) {
|
|
|
29
30
|
function fieldsMatchExpected(actual, expected) {
|
|
30
31
|
return Object.entries(expected).every(([name, value]) => actual[name] === value);
|
|
31
32
|
}
|
|
32
|
-
function result(status, recovered, pending, error = null) {
|
|
33
|
-
return { status, changed: recovered.length > 0, recovered, pending, error: error ? { code: error.code, message: error.message } : null };
|
|
33
|
+
function result(status, recovered, pending, error = null, warnings = []) {
|
|
34
|
+
return { status, changed: recovered.length > 0, recovered, pending, error: error ? { code: error.code, message: error.message } : null, ...(warnings.length ? { warnings } : {}) };
|
|
34
35
|
}
|
|
35
36
|
function summaryPayload(taskDir, taskId) {
|
|
36
37
|
const file = path.join(taskDir, '.delivery-summary.json');
|
|
@@ -170,7 +171,8 @@ async function replayIssueMetadata(taskId, operation, agent, cwd, client) {
|
|
|
170
171
|
}
|
|
171
172
|
const issue = after.issue;
|
|
172
173
|
const metadata = operation.issueMetadata;
|
|
173
|
-
const failedOperation = sync.operations.find((item) => item.status === 'failed' || item.status === 'skipped'
|
|
174
|
+
const failedOperation = sync.operations.find((item) => item.status === 'failed' || (item.status === 'skipped'
|
|
175
|
+
&& !(sync.capabilities.push === false && ['fields', 'issue-type'].includes(item.name) && item.reasonCode === 'PUSH_REQUIRED')));
|
|
174
176
|
if (failedOperation)
|
|
175
177
|
return platformResult('blocked', { error: {
|
|
176
178
|
code: failedOperation.reasonCode || 'PLATFORM_OPERATION_METADATA_UNCONFIRMED',
|
|
@@ -204,7 +206,7 @@ async function replayIssueMetadata(taskId, operation, agent, cwd, client) {
|
|
|
204
206
|
code: 'PLATFORM_OPERATION_METADATA_UNCONFIRMED',
|
|
205
207
|
message: 'Issue metadata differs from the requested recovery target after reread', retryable: true
|
|
206
208
|
} });
|
|
207
|
-
return platformResult('no-op', { changed: sync.changed || after.changed });
|
|
209
|
+
return platformResult('no-op', { changed: sync.changed || after.changed, operations: sync.operations });
|
|
208
210
|
}
|
|
209
211
|
async function verifyIssueCreate(taskId, operation, cwd, client) {
|
|
210
212
|
if (!operation.issueCreate)
|
|
@@ -291,6 +293,12 @@ function isRecoveryEligible(operation, excludeId) {
|
|
|
291
293
|
return operation.state === 'failed'
|
|
292
294
|
&& operation.lastCode !== 'PLATFORM_OPERATION_SUPERSEDED';
|
|
293
295
|
}
|
|
296
|
+
function recoveryCandidates(journal, options) {
|
|
297
|
+
const boundary = options.beforeId ? journal.operations.findIndex((item) => item.id === options.beforeId) : journal.operations.length;
|
|
298
|
+
if (boundary < 0)
|
|
299
|
+
throw Object.assign(new Error('Current platform operation boundary is unavailable'), { code: 'PLATFORM_OPERATION_BOUNDARY_MISSING' });
|
|
300
|
+
return journal.operations.slice(0, boundary).filter((item) => isRecoveryEligible(item, options.excludeId));
|
|
301
|
+
}
|
|
294
302
|
async function recoverPlatformOperationsOnce(taskRef, selection, options) {
|
|
295
303
|
const resolved = resolveTaskRef(taskRef, options.cwd ? { repoRoot: options.cwd } : {});
|
|
296
304
|
if (!resolved.ok)
|
|
@@ -303,7 +311,14 @@ async function recoverPlatformOperationsOnce(taskRef, selection, options) {
|
|
|
303
311
|
const value = error;
|
|
304
312
|
return result('failed', [], [], { code: value.code || 'PLATFORM_OPERATION_JOURNAL_INVALID', message: value.message || String(error), retryable: false });
|
|
305
313
|
}
|
|
306
|
-
|
|
314
|
+
let candidates;
|
|
315
|
+
try {
|
|
316
|
+
candidates = recoveryCandidates(journal, options);
|
|
317
|
+
}
|
|
318
|
+
catch (error) {
|
|
319
|
+
const value = error;
|
|
320
|
+
return result('blocked', [], [], value);
|
|
321
|
+
}
|
|
307
322
|
if (!candidates.length)
|
|
308
323
|
return result('no-op', [], []);
|
|
309
324
|
const head = candidates[0];
|
|
@@ -317,8 +332,9 @@ async function recoverPlatformOperationsOnce(taskRef, selection, options) {
|
|
|
317
332
|
const limit = options.limit === undefined ? candidates.length : Math.max(1, options.limit);
|
|
318
333
|
const recovered = [];
|
|
319
334
|
const pending = [];
|
|
335
|
+
let warnings = [];
|
|
320
336
|
const selected = candidates.slice(0, limit);
|
|
321
|
-
for (const
|
|
337
|
+
for (const operation of selected) {
|
|
322
338
|
{
|
|
323
339
|
try {
|
|
324
340
|
recordPlatformOperation({
|
|
@@ -437,7 +453,7 @@ async function recoverPlatformOperationsOnce(taskRef, selection, options) {
|
|
|
437
453
|
...(operation.pullRequestReview ? { pullRequestReview: operation.pullRequestReview } : {}),
|
|
438
454
|
dependency: operation.dependency,
|
|
439
455
|
state: succeeded ? 'succeeded' : 'unknown',
|
|
440
|
-
lastCode: remote.error?.code ?? latestOperation?.lastCode ?? null
|
|
456
|
+
lastCode: remote.error?.code ?? remote.operations.find((item) => item.status === 'skipped' && item.reasonCode === 'PUSH_REQUIRED')?.reasonCode ?? (succeeded ? null : latestOperation?.lastCode) ?? null
|
|
441
457
|
});
|
|
442
458
|
}
|
|
443
459
|
catch (error) {
|
|
@@ -448,11 +464,12 @@ async function recoverPlatformOperationsOnce(taskRef, selection, options) {
|
|
|
448
464
|
pending.push(targetOperation.id);
|
|
449
465
|
return result(remote.status === 'failed' ? 'failed' : 'blocked', recovered, pending, remote.error ?? { code: 'PLATFORM_OPERATION_RECOVERY_UNKNOWN', message: 'Platform operation outcome remains unknown', retryable: true });
|
|
450
466
|
}
|
|
467
|
+
warnings = mergeOperationWarnings(warnings, remote.warnings ?? []);
|
|
451
468
|
recovered.push(targetOperation.id);
|
|
452
469
|
}
|
|
453
470
|
const remaining = candidates.slice(limit).map((operation) => operation.id);
|
|
454
471
|
pending.push(...remaining);
|
|
455
|
-
return result(pending.length ? 'blocked' : recovered.length ? 'applied' : 'no-op', recovered, pending, pending.length ? { code: 'PLATFORM_OPERATION_RECOVERY_PENDING', message: 'Platform operations remain pending after the recovery budget', retryable: true } : null);
|
|
472
|
+
return result(pending.length ? 'blocked' : recovered.length ? 'applied' : 'no-op', recovered, pending, pending.length ? { code: 'PLATFORM_OPERATION_RECOVERY_PENDING', message: 'Platform operations remain pending after the recovery budget', retryable: true } : null, warnings);
|
|
456
473
|
}
|
|
457
474
|
async function recoverPlatformOperations(taskRef, selection, options) {
|
|
458
475
|
const resolved = resolveTaskRef(taskRef, options.cwd ? { repoRoot: options.cwd } : {});
|
|
@@ -466,8 +483,14 @@ async function recoverPlatformOperations(taskRef, selection, options) {
|
|
|
466
483
|
const value = error;
|
|
467
484
|
return result('failed', [], [], { code: value.code || 'PLATFORM_OPERATION_JOURNAL_INVALID', message: value.message || String(error), retryable: false });
|
|
468
485
|
}
|
|
469
|
-
|
|
470
|
-
|
|
486
|
+
let first;
|
|
487
|
+
try {
|
|
488
|
+
first = recoveryCandidates(initial, options);
|
|
489
|
+
}
|
|
490
|
+
catch (error) {
|
|
491
|
+
const value = error;
|
|
492
|
+
return result('blocked', [], [], value);
|
|
493
|
+
}
|
|
471
494
|
if (!first.length)
|
|
472
495
|
return result('no-op', [], []);
|
|
473
496
|
const operationLimit = options.limit === undefined ? first.length : Math.max(1, options.limit);
|
|
@@ -476,6 +499,7 @@ async function recoverPlatformOperations(taskRef, selection, options) {
|
|
|
476
499
|
return result('failed', [], [], { code: 'PLATFORM_OPERATION_RECOVERY_PAYLOAD_INVALID', message: 'Recovery attempts must be a positive safe integer', retryable: false });
|
|
477
500
|
}
|
|
478
501
|
const recovered = [];
|
|
502
|
+
let warnings = [];
|
|
479
503
|
for (let operationIndex = 0; operationIndex < operationLimit; operationIndex += 1) {
|
|
480
504
|
let latest;
|
|
481
505
|
try {
|
|
@@ -483,23 +507,32 @@ async function recoverPlatformOperations(taskRef, selection, options) {
|
|
|
483
507
|
}
|
|
484
508
|
catch (error) {
|
|
485
509
|
const value = error;
|
|
486
|
-
return result('failed', recovered, [], { code: value.code || 'PLATFORM_OPERATION_JOURNAL_INVALID', message: value.message || String(error), retryable: false });
|
|
510
|
+
return result('failed', recovered, [], { code: value.code || 'PLATFORM_OPERATION_JOURNAL_INVALID', message: value.message || String(error), retryable: false }, warnings);
|
|
511
|
+
}
|
|
512
|
+
let candidates;
|
|
513
|
+
try {
|
|
514
|
+
candidates = recoveryCandidates(latest, options);
|
|
515
|
+
}
|
|
516
|
+
catch (error) {
|
|
517
|
+
const value = error;
|
|
518
|
+
return result('blocked', recovered, [], value, warnings);
|
|
487
519
|
}
|
|
488
|
-
const head =
|
|
520
|
+
const head = candidates[0];
|
|
489
521
|
if (!head)
|
|
490
522
|
break;
|
|
491
523
|
if (selection !== 'all' && head.dependency !== selection) {
|
|
492
|
-
const pending =
|
|
524
|
+
const pending = candidates.map((operation) => operation.id);
|
|
493
525
|
return result('blocked', recovered, pending, {
|
|
494
526
|
code: 'PLATFORM_OPERATION_RECOVERY_PENDING',
|
|
495
527
|
message: 'The first unresolved platform operation belongs to another recovery selection',
|
|
496
528
|
retryable: true
|
|
497
|
-
});
|
|
529
|
+
}, warnings);
|
|
498
530
|
}
|
|
499
531
|
let last = null;
|
|
500
532
|
for (let attempt = 0; attempt < attemptLimit; attempt += 1) {
|
|
501
533
|
last = await recoverPlatformOperationsOnce(taskRef, selection, { ...options, limit: 1 });
|
|
502
534
|
recovered.push(...last.recovered.filter((id) => !recovered.includes(id)));
|
|
535
|
+
warnings = mergeOperationWarnings(warnings, last.warnings ?? []);
|
|
503
536
|
if (last.recovered.length > 0 || last.status === 'applied' || last.status === 'no-op')
|
|
504
537
|
break;
|
|
505
538
|
}
|
|
@@ -509,24 +542,34 @@ async function recoverPlatformOperations(taskRef, selection, options) {
|
|
|
509
542
|
current = readPlatformOperationJournal(resolved.taskId, resolved.repoRoot);
|
|
510
543
|
}
|
|
511
544
|
catch {
|
|
512
|
-
return result('blocked', recovered, [head.id], last?.error ?? null);
|
|
545
|
+
return result('blocked', recovered, [head.id], last?.error ?? null, warnings);
|
|
546
|
+
}
|
|
547
|
+
let pending;
|
|
548
|
+
try {
|
|
549
|
+
pending = recoveryCandidates(current, options).map((operation) => operation.id);
|
|
550
|
+
}
|
|
551
|
+
catch (error) {
|
|
552
|
+
const value = error;
|
|
553
|
+
return result('blocked', recovered, [], value, warnings);
|
|
513
554
|
}
|
|
514
|
-
const pending = current.operations.filter(eligible).map((operation) => operation.id);
|
|
515
555
|
return result(last?.status === 'failed' ? 'failed' : 'blocked', recovered, pending, last?.error ?? {
|
|
516
556
|
code: 'PLATFORM_OPERATION_RECOVERY_PENDING',
|
|
517
557
|
message: 'The first queued platform operation remains unresolved after this recovery run',
|
|
518
558
|
retryable: true
|
|
519
|
-
});
|
|
559
|
+
}, warnings);
|
|
520
560
|
}
|
|
521
561
|
}
|
|
522
562
|
let remaining;
|
|
523
563
|
try {
|
|
524
|
-
remaining = readPlatformOperationJournal(resolved.taskId, resolved.repoRoot)
|
|
564
|
+
remaining = recoveryCandidates(readPlatformOperationJournal(resolved.taskId, resolved.repoRoot), options).map((operation) => operation.id);
|
|
525
565
|
}
|
|
526
|
-
catch {
|
|
527
|
-
|
|
566
|
+
catch (error) {
|
|
567
|
+
const value = error;
|
|
568
|
+
return result('blocked', recovered, [], { code: value.code || 'PLATFORM_OPERATION_JOURNAL_INVALID', message: value.message || 'Unable to read platform operations' }, warnings);
|
|
528
569
|
}
|
|
529
|
-
|
|
570
|
+
const output = result(remaining.length ? 'blocked' : recovered.length ? 'applied' : 'no-op', recovered, remaining, remaining.length ? { code: 'PLATFORM_OPERATION_RECOVERY_PENDING', message: 'Platform operations remain queued after this recovery run', retryable: true } : null, warnings);
|
|
571
|
+
const degraded = readPlatformOperationJournal(resolved.taskId, resolved.repoRoot).operations.filter((item) => recovered.includes(item.id) && item.lastCode === 'PUSH_REQUIRED').map((item) => ({ id: item.id, reasonCode: item.lastCode }));
|
|
572
|
+
return degraded.length ? { ...output, degraded } : output;
|
|
530
573
|
}
|
|
531
574
|
export { fieldsMatchExpected, labelsMatchOwnedPrefix, recoverPlatformOperations };
|
|
532
575
|
//# sourceMappingURL=platform-operation-recovery.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { parseResourceIdentity, serializeResourceIdentity } from '../platform/resource-identity.js';
|
|
2
2
|
const PR_DELIVERY_FACT_KEY = 'pr_delivery_fact';
|
|
3
3
|
function factError(message) {
|
|
4
4
|
return Object.assign(new Error(`PR_DELIVERY_FACT_INVALID: ${message}`), { code: 'PR_DELIVERY_FACT_INVALID' });
|
|
@@ -132,8 +132,5 @@ function buildBoundFact(input) {
|
|
|
132
132
|
}, provenance: { establishedBy: provenanceForSource(input.source) } });
|
|
133
133
|
}
|
|
134
134
|
function factFrontmatterMutation(fact) { return { set: { [PR_DELIVERY_FACT_KEY]: encodePrDeliveryFact(fact) } }; }
|
|
135
|
-
|
|
136
|
-
return canonicalIdentity(pullRequest);
|
|
137
|
-
}
|
|
138
|
-
export { PR_DELIVERY_FACT_KEY, buildBoundFact, buildSkippedFact, buildUnboundFact, decodePrDeliveryFact, encodePrDeliveryFact, factFrontmatterMutation, identityFromPullRequest, readPrDeliveryFact, serializeResourceIdentity };
|
|
135
|
+
export { PR_DELIVERY_FACT_KEY, buildBoundFact, buildSkippedFact, buildUnboundFact, decodePrDeliveryFact, encodePrDeliveryFact, factFrontmatterMutation, readPrDeliveryFact, serializeResourceIdentity };
|
|
139
136
|
//# sourceMappingURL=pr-delivery-fact.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import fs from 'node:fs';
|
|
3
|
-
import { appendActivityEntry, locateActivityLog } from './activity-log.js';
|
|
3
|
+
import { activityWarnings, appendActivityEntry, locateActivityLog } from './activity-log.js';
|
|
4
4
|
import { CONFIRMATION_COLUMNS, CONFIRMATION_HEADINGS, constraintDigest, parseQualificationConfirmations, parseTaskQualification } from './qualification-audit.js';
|
|
5
5
|
import { findSectionHeading } from './sections.js';
|
|
6
6
|
import { resolveTaskRef } from './resolve-ref.js';
|
|
@@ -58,13 +58,13 @@ function applyQualificationConfirmation(request, options = {}) {
|
|
|
58
58
|
const previous = existing.confirmations.find((row) => row.qcrId === constraint.approvalEvidence);
|
|
59
59
|
if (operation === 'confirm' && constraint.status === 'confirmed') {
|
|
60
60
|
if (previous?.constraintId === constraint.constraintId && previous.approvedDigest === constraint.digest && previous.rationale === request.rationale.trim()) {
|
|
61
|
-
return { status: 'no-op', changed: false, taskId: resolved.taskId, qcrId: previous.qcrId, requestId: previous.requestId, operations: [], error: null };
|
|
61
|
+
return { status: 'no-op', changed: false, taskId: resolved.taskId, qcrId: previous.qcrId, requestId: previous.requestId, operations: [], error: null, warnings: activityWarnings(content) };
|
|
62
62
|
}
|
|
63
63
|
return failed('QUALIFICATION_CONFIRMATION_CONFLICT', `constraint '${request.constraintId}' is already confirmed with different evidence`, resolved.taskId);
|
|
64
64
|
}
|
|
65
65
|
const transitionStatus = operation === 'supersede' ? 'superseded' : 'open';
|
|
66
66
|
if (operation !== 'confirm' && constraint.status === transitionStatus && !constraint.approvalEvidence) {
|
|
67
|
-
return { status: 'no-op', changed: false, taskId: resolved.taskId, qcrId: null, requestId: null, operations: [], error: null };
|
|
67
|
+
return { status: 'no-op', changed: false, taskId: resolved.taskId, qcrId: null, requestId: null, operations: [], error: null, warnings: activityWarnings(content) };
|
|
68
68
|
}
|
|
69
69
|
if (operation !== 'confirm' && constraint.status !== 'confirmed')
|
|
70
70
|
return failed('QUALIFICATION_CONFIRMATION_REQUIRED', `constraint '${request.constraintId}' is not confirmed`, resolved.taskId);
|
|
@@ -90,20 +90,18 @@ function applyQualificationConfirmation(request, options = {}) {
|
|
|
90
90
|
} : null;
|
|
91
91
|
const confirmations = confirmation ? [...existing.confirmations, confirmation] : existing.confirmations;
|
|
92
92
|
const activity = locateActivityLog(content);
|
|
93
|
-
if (!activity)
|
|
94
|
-
return failed('QUALIFICATION_ACTIVITY_MISSING', 'task has no unique Activity Log section', resolved.taskId);
|
|
95
93
|
const mutations = [
|
|
96
94
|
{
|
|
97
95
|
kind: 'table-row', action: 'upsert', sectionAliases: ['约束', 'Constraints'], columns: ['constraint_id', 'statement', 'status', 'authority', 'source', 'evidence', 'derived_from', 'approval_evidence'], keyColumn: 'constraint_id', key: constraint.constraintId,
|
|
98
96
|
values: { statement: constraint.statement, status: operation === 'confirm' ? 'confirmed' : transitionStatus, authority: operation === 'confirm' ? 'human-declared' : constraint.authority, source: constraint.source, evidence: constraint.evidence, derived_from: constraint.derivedFrom.join(','), approval_evidence: qcrId ?? '' }
|
|
99
97
|
},
|
|
100
98
|
...(operation === 'confirm' ? [{ kind: 'section', aliases: CONFIRMATION_HEADINGS, heading: findSectionHeading(content, [...CONFIRMATION_HEADINGS]), body: renderConfirmations(confirmations) }] : []),
|
|
101
|
-
{ kind: 'section', aliases: ['活动日志', 'Activity Log'], heading: activity.heading, body: appendActivityEntry(activity, { time: metadata.timestamp, step: 'Qualification Confirmation', agent: 'human', note: operation === 'confirm' ? `${request.constraintId} confirmed → ${qcrId}` : `${request.constraintId} ${operation}d` }) }
|
|
99
|
+
...(activity ? [{ kind: 'section', aliases: ['活动日志', 'Activity Log'], heading: activity.heading, body: appendActivityEntry(activity, { time: metadata.timestamp, step: 'Qualification Confirmation', agent: 'human', note: operation === 'confirm' ? `${request.constraintId} confirmed → ${qcrId}` : `${request.constraintId} ${operation}d` }) }] : [])
|
|
102
100
|
];
|
|
103
101
|
const result = writeTask({ taskRef: resolved.taskId, expectedState: 'active', mutations, dryRun: request.dryRun }, { ...options, taskLocation: { repoRoot: resolved.repoRoot, taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, state: resolved.state }, metadataProvider: () => metadata });
|
|
104
102
|
if (result.status === 'failed')
|
|
105
103
|
return failed(result.error.code, result.error.message, result.taskId);
|
|
106
|
-
return { status: result.status, changed: result.changed, taskId: result.taskId, qcrId, requestId, operations: result.operations, error: null };
|
|
104
|
+
return { status: result.status, changed: result.changed, taskId: result.taskId, qcrId, requestId, operations: result.operations, error: null, warnings: activityWarnings(content) };
|
|
107
105
|
}
|
|
108
106
|
export { applyQualificationConfirmation };
|
|
109
107
|
//# sourceMappingURL=qualification-confirmation.js.map
|