@fitlab-ai/agent-infra 0.11.2 → 0.11.4
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 +17 -8
- package/README.zh-CN.md +17 -8
- package/dist/bin/internal-cli.js +7 -2
- package/dist/lib/agent-clients/adapter.js +3 -0
- package/dist/lib/agent-clients/adapters/codex-lifecycle/recovery.js +234 -0
- package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +8 -35
- package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +1 -34
- package/dist/lib/agent-clients/adapters/codex.js +10 -0
- package/dist/lib/internal/cli-route-inventory.js +1 -1
- package/dist/lib/internal/manual-validation.js +22 -27
- package/dist/lib/internal/sandbox-control.js +1 -43
- package/dist/lib/internal/task-artifact.js +1 -1
- package/dist/lib/internal/task-finalization.js +41 -1
- package/dist/lib/internal/task-ledger.js +13 -5
- package/dist/lib/internal/task-lifecycle.js +1 -1
- package/dist/lib/internal/task-operation-registry.js +7 -2
- package/dist/lib/platform/completion-backfill.js +63 -17
- package/dist/lib/platform/issue-comments.js +2 -31
- package/dist/lib/platform/pr-summary.js +7 -2
- package/dist/lib/sandbox/control/client.js +3 -44
- package/dist/lib/sandbox/control/executor.js +14 -79
- package/dist/lib/sandbox/control/protocol.js +5 -64
- package/dist/lib/sandbox/control/server.js +49 -343
- package/dist/lib/sandbox/control/state.js +1 -7
- package/dist/lib/sandbox/control/task-view.js +1 -2
- package/dist/lib/sandbox/task-cleanup.js +13 -20
- package/dist/lib/task/artifact-command.js +11 -4
- package/dist/lib/task/artifact-lifecycle.js +217 -85
- package/dist/lib/task/artifact-operations.js +1 -26
- package/dist/lib/task/artifact-receipts.js +4 -1
- package/dist/lib/task/artifact-schema.js +1 -0
- package/dist/lib/task/artifact-selection.js +25 -0
- package/dist/lib/task/capabilities.js +158 -39
- package/dist/lib/task/commands/status.js +9 -2
- package/dist/lib/task/control-authority.js +37 -38
- package/dist/lib/task/control-recovery.js +3 -42
- package/dist/lib/task/decision-intents.js +12 -0
- package/dist/lib/task/delegation-receipts.js +2 -2
- package/dist/lib/task/delivery.js +1 -43
- package/dist/lib/task/events.js +80 -64
- package/dist/lib/task/finalization-artifacts.js +1 -3
- package/dist/lib/task/finalization-state.js +1 -1
- package/dist/lib/task/finalization.js +319 -234
- package/dist/lib/task/ledger-intents.js +157 -15
- package/dist/lib/task/lifecycle-path.js +75 -0
- package/dist/lib/task/lifecycle.js +11 -1
- package/dist/lib/task/local-artifact-finalization.js +1 -20
- package/dist/lib/task/manual-validation-receipt.js +8 -3
- package/dist/lib/task/orchestration.js +29 -13
- package/dist/lib/task/review-finalization.js +3 -16
- package/dist/lib/task/rework-intent.js +70 -4
- package/dist/lib/task/verification-engine.js +20 -30
- package/dist/lib/task/verification.js +1 -0
- package/dist/lib/task/workflow-warning-intents.js +21 -6
- package/dist/lib/task/workspace-snapshot.js +7 -2
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-clients/adapter.ts +46 -0
- package/lib/agent-clients/adapters/codex-lifecycle/recovery.ts +297 -0
- package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +13 -33
- package/lib/agent-clients/adapters/codex-lifecycle/store.ts +1 -44
- package/lib/agent-clients/adapters/codex.ts +10 -0
- package/lib/internal/cli-route-inventory.ts +1 -1
- package/lib/internal/manual-validation.ts +22 -26
- package/lib/internal/sandbox-control.ts +0 -42
- package/lib/internal/task-artifact.ts +1 -1
- package/lib/internal/task-finalization.ts +40 -1
- package/lib/internal/task-ledger.ts +12 -5
- package/lib/internal/task-lifecycle.ts +2 -2
- package/lib/internal/task-operation-registry.ts +8 -4
- package/lib/platform/completion-backfill.ts +78 -16
- package/lib/platform/issue-comments.ts +1 -35
- package/lib/platform/pr-summary.ts +10 -2
- package/lib/sandbox/control/client.ts +5 -68
- package/lib/sandbox/control/executor.ts +14 -81
- package/lib/sandbox/control/protocol.ts +7 -83
- package/lib/sandbox/control/server.ts +47 -362
- package/lib/sandbox/control/state.ts +1 -9
- package/lib/sandbox/control/task-view.ts +1 -2
- package/lib/sandbox/task-cleanup.ts +12 -20
- package/lib/task/artifact-command.ts +14 -4
- package/lib/task/artifact-lifecycle.ts +236 -85
- package/lib/task/artifact-operations.ts +1 -26
- package/lib/task/artifact-receipts.ts +4 -1
- package/lib/task/artifact-schema.ts +1 -0
- package/lib/task/artifact-selection.ts +53 -0
- package/lib/task/capabilities.ts +154 -40
- package/lib/task/commands/status.ts +11 -2
- package/lib/task/control-authority.ts +41 -48
- package/lib/task/control-recovery.ts +3 -43
- package/lib/task/decision-intents.ts +9 -0
- package/lib/task/delegation-receipts.ts +2 -2
- package/lib/task/delivery.ts +1 -40
- package/lib/task/events.ts +82 -64
- package/lib/task/finalization-artifacts.ts +1 -3
- package/lib/task/finalization-state.ts +1 -1
- package/lib/task/finalization.ts +310 -216
- package/lib/task/ledger-intents.ts +155 -15
- package/lib/task/lifecycle-path.ts +98 -0
- package/lib/task/lifecycle.ts +15 -2
- package/lib/task/local-artifact-finalization.ts +2 -25
- package/lib/task/manual-validation-receipt.ts +8 -2
- package/lib/task/orchestration.ts +56 -27
- package/lib/task/review-finalization.ts +3 -16
- package/lib/task/rework-intent.ts +75 -5
- package/lib/task/verification-engine.ts +19 -30
- package/lib/task/verification.ts +2 -1
- package/lib/task/workflow-warning-intents.ts +18 -6
- package/lib/task/workspace-snapshot.ts +3 -2
- package/package.json +1 -1
- package/templates/.agents/rules/lifecycle-orchestration.en.md +19 -5
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +19 -5
- package/templates/.agents/rules/review-handshake.en.md +4 -4
- package/templates/.agents/rules/review-handshake.zh-CN.md +4 -4
- package/templates/.agents/skills/analyze-task/SKILL.en.md +11 -4
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +11 -4
- package/templates/.agents/skills/code-task/SKILL.en.md +14 -8
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +18 -13
- package/templates/.agents/skills/code-task/reference/code-rules.en.md +2 -2
- package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +2 -2
- package/templates/.agents/skills/code-task/reference/dual-mode.en.md +4 -4
- package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +4 -4
- package/templates/.agents/skills/code-task/reference/report-template.en.md +1 -1
- package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +1 -1
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +2 -2
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/complete-task/SKILL.en.md +7 -8
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +7 -8
- package/templates/.agents/skills/plan-task/SKILL.en.md +13 -10
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +13 -10
- package/templates/.agents/skills/review-analysis/SKILL.en.md +5 -1
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +5 -1
- package/templates/.agents/skills/review-code/SKILL.en.md +5 -1
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +5 -1
- package/templates/.agents/skills/review-plan/SKILL.en.md +5 -1
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +5 -1
- package/templates/.agents/skills/run-manual-validation/SKILL.en.md +2 -2
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/run-task/SKILL.en.md +9 -8
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +9 -8
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +18 -2
- package/templates/.agents/templates/task.en.md +2 -2
- package/templates/.agents/templates/task.zh-CN.md +2 -2
- package/templates/.agents/workflows/bug-fix.en.yaml +11 -6
- package/templates/.agents/workflows/bug-fix.zh-CN.yaml +11 -6
- package/templates/.agents/workflows/feature-development.en.yaml +11 -6
- package/templates/.agents/workflows/feature-development.zh-CN.yaml +11 -6
- package/templates/.agents/workflows/refactoring.en.yaml +11 -6
- package/templates/.agents/workflows/refactoring.zh-CN.yaml +11 -6
- package/dist/lib/sandbox/control/finalization-response.js +0 -35
- package/dist/lib/sandbox/control/task-workflow.js +0 -74
- package/dist/lib/sandbox/control/workflow-executor.js +0 -142
- package/dist/lib/task/lifecycle-recovery.js +0 -549
- package/dist/lib/task/recovery-warning.js +0 -19
- package/dist/lib/task/workflow-command.js +0 -21
- package/dist/lib/task/workflow-dispatch.js +0 -213
- package/lib/sandbox/control/finalization-response.ts +0 -37
- package/lib/sandbox/control/task-workflow.ts +0 -95
- package/lib/sandbox/control/workflow-executor.ts +0 -156
- package/lib/task/lifecycle-recovery.ts +0 -691
- package/lib/task/recovery-warning.ts +0 -21
- package/lib/task/workflow-command.ts +0 -22
- package/lib/task/workflow-dispatch.ts +0 -214
|
@@ -9,6 +9,11 @@
|
|
|
9
9
|
name: refactoring
|
|
10
10
|
description: Safe and structured workflow for code refactoring.
|
|
11
11
|
|
|
12
|
+
lifecycle_paths:
|
|
13
|
+
streamlined: [analysis, code, code-review]
|
|
14
|
+
standard: [analysis, design, code, code-review]
|
|
15
|
+
full: [analysis, analysis-review, design, design-review, code, code-review]
|
|
16
|
+
|
|
12
17
|
steps:
|
|
13
18
|
- name: analysis
|
|
14
19
|
description: Analyze the current code and define the refactoring scope.
|
|
@@ -28,7 +33,7 @@ steps:
|
|
|
28
33
|
outputs:
|
|
29
34
|
- name: analysis
|
|
30
35
|
pattern: "analysis.md | analysis-r{N}.md"
|
|
31
|
-
rule: "
|
|
36
|
+
rule: "Let the task-artifact selector decide: reuse a completed artifact when inputs and substantive results match; create the next round only for new inputs, rework evidence, or result changes"
|
|
32
37
|
outputs:
|
|
33
38
|
- Scope analysis with dependency map
|
|
34
39
|
- Risk assessment
|
|
@@ -55,7 +60,7 @@ steps:
|
|
|
55
60
|
outputs:
|
|
56
61
|
- name: review-analysis
|
|
57
62
|
pattern: "review-analysis.md | review-analysis-r{N}.md"
|
|
58
|
-
rule: "
|
|
63
|
+
rule: "Let the task-artifact selector decide: reuse a completed artifact when inputs and substantive results match; create the next round only for new inputs, rework evidence, or result changes"
|
|
59
64
|
outputs:
|
|
60
65
|
- Requirement analysis review report
|
|
61
66
|
- Findings to fix, if any
|
|
@@ -84,7 +89,7 @@ steps:
|
|
|
84
89
|
outputs:
|
|
85
90
|
- name: plan
|
|
86
91
|
pattern: "plan.md | plan-r{N}.md"
|
|
87
|
-
rule: "
|
|
92
|
+
rule: "Let the task-artifact selector decide: reuse a completed artifact when inputs and substantive results match; create the next round only for new inputs, rework evidence, or result changes"
|
|
88
93
|
outputs:
|
|
89
94
|
- Incremental refactoring plan
|
|
90
95
|
- Prerequisite test list
|
|
@@ -111,7 +116,7 @@ steps:
|
|
|
111
116
|
outputs:
|
|
112
117
|
- name: review-plan
|
|
113
118
|
pattern: "review-plan.md | review-plan-r{N}.md"
|
|
114
|
-
rule: "
|
|
119
|
+
rule: "Let the task-artifact selector decide: reuse a completed artifact when inputs and substantive results match; create the next round only for new inputs, rework evidence, or result changes"
|
|
115
120
|
outputs:
|
|
116
121
|
- Plan review report
|
|
117
122
|
- Findings to fix, if any
|
|
@@ -148,7 +153,7 @@ steps:
|
|
|
148
153
|
outputs:
|
|
149
154
|
- name: code
|
|
150
155
|
pattern: "code.md | code-r{N}.md"
|
|
151
|
-
rule: "
|
|
156
|
+
rule: "Let the task-artifact selector decide: reuse a completed artifact when inputs and substantive results match; create the next round only for new inputs, rework evidence, or result changes"
|
|
152
157
|
outputs:
|
|
153
158
|
- Refactoring branch with implementation or fixes
|
|
154
159
|
- Updated or new test files
|
|
@@ -177,7 +182,7 @@ steps:
|
|
|
177
182
|
outputs:
|
|
178
183
|
- name: review-code
|
|
179
184
|
pattern: "review-code.md | review-code-r{N}.md"
|
|
180
|
-
rule: "
|
|
185
|
+
rule: "Let the task-artifact selector decide: reuse a completed artifact when inputs and substantive results match; create the next round only for new inputs, rework evidence, or result changes"
|
|
181
186
|
outputs:
|
|
182
187
|
- Code review report
|
|
183
188
|
- Findings list, if any
|
|
@@ -8,6 +8,11 @@
|
|
|
8
8
|
name: refactoring
|
|
9
9
|
description: 安全且结构化的代码重构工作流。
|
|
10
10
|
|
|
11
|
+
lifecycle_paths:
|
|
12
|
+
streamlined: [analysis, code, code-review]
|
|
13
|
+
standard: [analysis, design, code, code-review]
|
|
14
|
+
full: [analysis, analysis-review, design, design-review, code, code-review]
|
|
15
|
+
|
|
11
16
|
steps:
|
|
12
17
|
- name: analysis
|
|
13
18
|
description: 分析当前代码并确定重构范围。
|
|
@@ -27,7 +32,7 @@ steps:
|
|
|
27
32
|
outputs:
|
|
28
33
|
- name: analysis
|
|
29
34
|
pattern: "analysis.md | analysis-r{N}.md"
|
|
30
|
-
rule: "
|
|
35
|
+
rule: "由 task-artifact 选择器决定:输入与实质结果未变化时复用已完成产物;仅在新输入、新返工证据或结果变化时创建下一轮"
|
|
31
36
|
outputs:
|
|
32
37
|
- 包含依赖关系图的范围分析
|
|
33
38
|
- 风险评估
|
|
@@ -54,7 +59,7 @@ steps:
|
|
|
54
59
|
outputs:
|
|
55
60
|
- name: review-analysis
|
|
56
61
|
pattern: "review-analysis.md | review-analysis-r{N}.md"
|
|
57
|
-
rule: "
|
|
62
|
+
rule: "由 task-artifact 选择器决定:输入与实质结果未变化时复用已完成产物;仅在新输入、新返工证据或结果变化时创建下一轮"
|
|
58
63
|
outputs:
|
|
59
64
|
- 需求分析审查报告
|
|
60
65
|
- 待修正问题列表(如有)
|
|
@@ -83,7 +88,7 @@ steps:
|
|
|
83
88
|
outputs:
|
|
84
89
|
- name: plan
|
|
85
90
|
pattern: "plan.md | plan-r{N}.md"
|
|
86
|
-
rule: "
|
|
91
|
+
rule: "由 task-artifact 选择器决定:输入与实质结果未变化时复用已完成产物;仅在新输入、新返工证据或结果变化时创建下一轮"
|
|
87
92
|
outputs:
|
|
88
93
|
- 包含增量步骤的重构计划
|
|
89
94
|
- 前置测试列表
|
|
@@ -110,7 +115,7 @@ steps:
|
|
|
110
115
|
outputs:
|
|
111
116
|
- name: review-plan
|
|
112
117
|
pattern: "review-plan.md | review-plan-r{N}.md"
|
|
113
|
-
rule: "
|
|
118
|
+
rule: "由 task-artifact 选择器决定:输入与实质结果未变化时复用已完成产物;仅在新输入、新返工证据或结果变化时创建下一轮"
|
|
114
119
|
outputs:
|
|
115
120
|
- 技术方案审查报告
|
|
116
121
|
- 待修正问题列表(如有)
|
|
@@ -147,7 +152,7 @@ steps:
|
|
|
147
152
|
outputs:
|
|
148
153
|
- name: code
|
|
149
154
|
pattern: "code.md | code-r{N}.md"
|
|
150
|
-
rule: "
|
|
155
|
+
rule: "由 task-artifact 选择器决定:输入与实质结果未变化时复用已完成产物;仅在新输入、新返工证据或结果变化时创建下一轮"
|
|
151
156
|
outputs:
|
|
152
157
|
- 包含变更的重构分支
|
|
153
158
|
- 更新或新增的测试文件
|
|
@@ -176,7 +181,7 @@ steps:
|
|
|
176
181
|
outputs:
|
|
177
182
|
- name: review-code
|
|
178
183
|
pattern: "review-code.md | review-code-r{N}.md"
|
|
179
|
-
rule: "
|
|
184
|
+
rule: "由 task-artifact 选择器决定:输入与实质结果未变化时复用已完成产物;仅在新输入、新返工证据或结果变化时创建下一轮"
|
|
180
185
|
outputs:
|
|
181
186
|
- 代码审查报告
|
|
182
187
|
- 问题列表(如有)
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
export function finalizationTerminalResponse(taskId, requestId, receipt) {
|
|
2
|
-
const pendingSteps = [
|
|
3
|
-
receipt.taskComment === 'pending' ? 'task-comment' : null,
|
|
4
|
-
receipt.verification === 'pending' ? 'verification' : null,
|
|
5
|
-
receipt.summary === 'pending' ? 'summary' : null,
|
|
6
|
-
receipt.postSummaryVerification === 'pending' ? 'post-summary-verification' : null
|
|
7
|
-
].filter((step) => step !== null);
|
|
8
|
-
const completedSteps = [
|
|
9
|
-
'lifecycle', receipt.taskComment === 'pending' ? null : 'task-comment',
|
|
10
|
-
receipt.verification === 'pending' ? null : 'verification', receipt.summary === 'pending' ? null : 'summary',
|
|
11
|
-
receipt.postSummaryVerification === 'pending' ? null : 'post-summary-verification'
|
|
12
|
-
]
|
|
13
|
-
.filter((step) => step !== null);
|
|
14
|
-
const warnings = receipt.warnings
|
|
15
|
-
.filter((warning) => warning.status === 'open')
|
|
16
|
-
.map(({ status: _status, resolvedAt: _resolvedAt, ...warning }) => warning);
|
|
17
|
-
const result = {
|
|
18
|
-
status: 'completed', changed: false, taskId,
|
|
19
|
-
lifecycle: { status: 'no-op', changed: false, error: null },
|
|
20
|
-
taskComment: receipt.taskComment === 'pending' ? null : { status: 'no-op', changed: false, error: null },
|
|
21
|
-
verification: receipt.verification === 'pending' ? null : { status: 'no-op', changed: false, error: null },
|
|
22
|
-
summary: receipt.summary === 'pending' ? null : { status: 'no-op', changed: false, error: null },
|
|
23
|
-
postSummaryVerification: receipt.postSummaryVerification === 'pending' ? null : { status: 'no-op', changed: false, error: null },
|
|
24
|
-
completedSteps, pendingSteps,
|
|
25
|
-
result: pendingSteps.length > 0 || receipt.warningProjection === 'pending' || warnings.length > 0
|
|
26
|
-
? 'completed_with_warnings' : 'completed',
|
|
27
|
-
warnings, error: null
|
|
28
|
-
};
|
|
29
|
-
return {
|
|
30
|
-
version: 2, id: requestId, phase: 'completed', exitCode: 0,
|
|
31
|
-
stdout: `${JSON.stringify({ version: 1, status: 'completed', changed: false, accepted: true, result, error: null })}\n`,
|
|
32
|
-
stderr: '', error: null
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
//# sourceMappingURL=finalization-response.js.map
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { randomUUID } from 'node:crypto';
|
|
4
|
-
import { readStableFile, SecureFileError, writeAtomicFile } from '../../task/secure-fs.js';
|
|
5
|
-
import { TASK_WORKFLOW_COMMANDS, TASK_WORKFLOW_OPERATIONS } from '../../task/workflow-command.js';
|
|
6
|
-
export function validateTaskWorkflowRequest(value) {
|
|
7
|
-
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
8
|
-
throw new Error('TASK_WORKFLOW_REQUEST_INVALID');
|
|
9
|
-
const request = value;
|
|
10
|
-
if (Object.keys(request).sort().join(',') !== 'args,generation,id,operation,taskId,version'
|
|
11
|
-
|| request.version !== 1 || typeof request.id !== 'string' || !/^[a-f0-9-]{16,64}$/u.test(request.id)
|
|
12
|
-
|| typeof request.taskId !== 'string' || !/^TASK-\d{8}-\d{6}$/u.test(request.taskId)
|
|
13
|
-
|| typeof request.generation !== 'string' || !request.generation
|
|
14
|
-
|| !Object.hasOwn(TASK_WORKFLOW_COMMANDS, request.operation)
|
|
15
|
-
|| !Array.isArray(request.args) || request.args.length < 2 || request.args.length > 128
|
|
16
|
-
|| !request.args.every((arg) => typeof arg === 'string' && !/[\r\n]/u.test(arg))
|
|
17
|
-
|| request.args[0] !== request.taskId)
|
|
18
|
-
throw new Error('TASK_WORKFLOW_REQUEST_INVALID');
|
|
19
|
-
const [, selector] = TASK_WORKFLOW_COMMANDS[request.operation];
|
|
20
|
-
if (selector !== null && request.args[1] !== selector)
|
|
21
|
-
throw new Error('TASK_WORKFLOW_REQUEST_INVALID');
|
|
22
|
-
return request;
|
|
23
|
-
}
|
|
24
|
-
/** Preserve argv verbatim; the domain command owns option parsing and validation. */
|
|
25
|
-
export function createTaskWorkflowRequest(command, args, taskId, generation) {
|
|
26
|
-
const operation = TASK_WORKFLOW_OPERATIONS.find((key) => {
|
|
27
|
-
const [name, selector] = TASK_WORKFLOW_COMMANDS[key];
|
|
28
|
-
return name === command && (selector === null || selector === args[1]);
|
|
29
|
-
});
|
|
30
|
-
if (!operation)
|
|
31
|
-
throw new Error('TASK_WORKFLOW_OPERATION_UNSUPPORTED');
|
|
32
|
-
return validateTaskWorkflowRequest({ version: 1, id: randomUUID(), taskId, generation, operation, args: [...args] });
|
|
33
|
-
}
|
|
34
|
-
export function canonicalArtifactName(value) {
|
|
35
|
-
return /^(?:analysis|plan|code|review-analysis|review-plan|review-code)(?:-r[1-9]\d*)?\.md$/u.test(value)
|
|
36
|
-
&& path.basename(value) === value;
|
|
37
|
-
}
|
|
38
|
-
function assertTaskArtifactDirectory(directory) {
|
|
39
|
-
const resolved = path.resolve(directory);
|
|
40
|
-
let stat;
|
|
41
|
-
try {
|
|
42
|
-
stat = fs.lstatSync(resolved);
|
|
43
|
-
}
|
|
44
|
-
catch {
|
|
45
|
-
throw new SecureFileError('TASK_ARTIFACT_WRITE_DENIED', 'task directory is unavailable');
|
|
46
|
-
}
|
|
47
|
-
if (!stat.isDirectory() || stat.isSymbolicLink()) {
|
|
48
|
-
throw new SecureFileError('TASK_ARTIFACT_WRITE_DENIED', 'task directory must be a real directory');
|
|
49
|
-
}
|
|
50
|
-
return resolved;
|
|
51
|
-
}
|
|
52
|
-
export async function readTaskArtifact(taskDir, input) {
|
|
53
|
-
if (!canonicalArtifactName(input.artifact))
|
|
54
|
-
throw new SecureFileError('TASK_ARTIFACT_WRITE_DENIED', 'artifact must be a canonical top-level basename');
|
|
55
|
-
const root = assertTaskArtifactDirectory(taskDir);
|
|
56
|
-
const candidate = path.join(root, input.artifact);
|
|
57
|
-
if (path.dirname(candidate) !== root)
|
|
58
|
-
throw new SecureFileError('TASK_ARTIFACT_WRITE_DENIED', 'artifact escapes task directory');
|
|
59
|
-
const stable = await readStableFile(candidate, {
|
|
60
|
-
maxBytes: 1024 * 1024,
|
|
61
|
-
...(input.expectedSha256 ? { expectedSha256: input.expectedSha256 } : {})
|
|
62
|
-
});
|
|
63
|
-
return { artifact: input.artifact, bytes: stable.bytes, sha256: stable.sha256 };
|
|
64
|
-
}
|
|
65
|
-
export async function writeTaskArtifact(taskDir, artifact) {
|
|
66
|
-
if (!canonicalArtifactName(artifact.artifact))
|
|
67
|
-
throw new SecureFileError('TASK_ARTIFACT_WRITE_DENIED', 'artifact must be a canonical top-level basename');
|
|
68
|
-
const root = assertTaskArtifactDirectory(taskDir);
|
|
69
|
-
const target = path.join(root, artifact.artifact);
|
|
70
|
-
if (path.dirname(target) !== root)
|
|
71
|
-
throw new SecureFileError('TASK_ARTIFACT_WRITE_DENIED', 'artifact escapes task directory');
|
|
72
|
-
await writeAtomicFile(target, artifact.bytes, 0o600, artifact.expectedSha256);
|
|
73
|
-
}
|
|
74
|
-
//# sourceMappingURL=task-workflow.js.map
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { randomUUID } from 'node:crypto';
|
|
4
|
-
import { TASK_WORKFLOW_COMMANDS } from '../../task/workflow-command.js';
|
|
5
|
-
import { parseArtifactCommand, executeArtifactCommand } from '../../task/artifact-command.js';
|
|
6
|
-
import { parseReviewCommand } from '../../task/review-command.js';
|
|
7
|
-
import { prepareLocalArtifact, preflightLocalArtifact, commitLocalArtifactProvenance } from '../../task/local-artifact-finalization.js';
|
|
8
|
-
import { prepareReviewSummaryCandidate, preflightReviewSummary } from '../../task/review-finalization.js';
|
|
9
|
-
import { withTaskExecutionLock } from '../../task/task-execution-lock.js';
|
|
10
|
-
import { dispatchWorkflowCommand } from '../../task/workflow-dispatch.js';
|
|
11
|
-
import { assertSandboxTaskSource } from '../workspace-view.js';
|
|
12
|
-
import { appendDiagnosticAudit } from './audit.js';
|
|
13
|
-
import { readTaskArtifact } from './task-workflow.js';
|
|
14
|
-
import { applyTaskEvent } from '../../task/events.js';
|
|
15
|
-
import { parseTaskEventRequest } from '../../internal/task-event.js';
|
|
16
|
-
function executionResult(result) {
|
|
17
|
-
return { exitCode: result.status === 'failed' || result.status === 'refused' ? 1 : 0, stdout: `${JSON.stringify(result)}\n`, stderr: '' };
|
|
18
|
-
}
|
|
19
|
-
function replaceCurrentArtifactAtomically(file, content) {
|
|
20
|
-
const temporary = path.join(path.dirname(file), `.${path.basename(file)}.${process.pid}.${randomUUID()}.tmp`);
|
|
21
|
-
try {
|
|
22
|
-
fs.writeFileSync(temporary, content, { encoding: 'utf8', flag: 'wx' });
|
|
23
|
-
fs.renameSync(temporary, file);
|
|
24
|
-
}
|
|
25
|
-
finally {
|
|
26
|
-
try {
|
|
27
|
-
fs.unlinkSync(temporary);
|
|
28
|
-
}
|
|
29
|
-
catch (error) {
|
|
30
|
-
if (error.code !== 'ENOENT')
|
|
31
|
-
throw error;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
/** The broker already authorized this host executor; domain operations own validation. */
|
|
36
|
-
export async function executeTaskWorkflow(manifest, request, lifecycleRecoveryAttestation = null, options = {}) {
|
|
37
|
-
let publicationCommitted = false;
|
|
38
|
-
let faultTriggered = false;
|
|
39
|
-
const fault = (window) => {
|
|
40
|
-
if (faultTriggered || options.faultWindow !== window)
|
|
41
|
-
return;
|
|
42
|
-
faultTriggered = true;
|
|
43
|
-
throw new Error(`TASK_WORKFLOW_FAULT_INJECTED:${window}`);
|
|
44
|
-
};
|
|
45
|
-
const response = (result) => {
|
|
46
|
-
fault('before-result-return');
|
|
47
|
-
return executionResult(result);
|
|
48
|
-
};
|
|
49
|
-
try {
|
|
50
|
-
fault('before-call');
|
|
51
|
-
const taskDir = assertSandboxTaskSource(manifest.repoRoot, request.taskId);
|
|
52
|
-
const [command] = TASK_WORKFLOW_COMMANDS[request.operation];
|
|
53
|
-
if (request.operation === 'event') {
|
|
54
|
-
const eventRequest = parseTaskEventRequest(request.args);
|
|
55
|
-
const boundEventRequest = lifecycleRecoveryAttestation && eventRequest.requestId === undefined
|
|
56
|
-
? { ...eventRequest, requestId: lifecycleRecoveryAttestation.lifecycleRequestId }
|
|
57
|
-
: eventRequest;
|
|
58
|
-
fault('before-domain-write');
|
|
59
|
-
const result = applyTaskEvent(boundEventRequest, {
|
|
60
|
-
repoRoot: manifest.repoRoot,
|
|
61
|
-
lifecycleRecoveryAttestation,
|
|
62
|
-
deferLifecycleRecoveryConsumption: true
|
|
63
|
-
});
|
|
64
|
-
publicationCommitted = result.changed;
|
|
65
|
-
fault('after-atomic-rename');
|
|
66
|
-
return response(result);
|
|
67
|
-
}
|
|
68
|
-
if (command !== 'task-artifact' && command !== 'task-review') {
|
|
69
|
-
// The broker owns this short-lived executor; no global service or worker
|
|
70
|
-
// credential participates in the command's authority or recovery path.
|
|
71
|
-
fault('before-domain-write');
|
|
72
|
-
const result = dispatchWorkflowCommand(manifest.repoRoot, request.operation, request.args);
|
|
73
|
-
publicationCommitted = result.changed === true;
|
|
74
|
-
fault('after-atomic-rename');
|
|
75
|
-
return response(result);
|
|
76
|
-
}
|
|
77
|
-
const input = command === 'task-artifact' ? parseArtifactCommand(request.args) : parseReviewCommand(request.args);
|
|
78
|
-
if (command === 'task-artifact' && 'operation' in input && input.operation === 'inspect') {
|
|
79
|
-
fault('before-domain-write');
|
|
80
|
-
const result = executeArtifactCommand(input, { repoRoot: manifest.repoRoot });
|
|
81
|
-
publicationCommitted = result.changed === true;
|
|
82
|
-
fault('after-atomic-rename');
|
|
83
|
-
return response(result);
|
|
84
|
-
}
|
|
85
|
-
if ('operation' in input && input.operation === 'init') {
|
|
86
|
-
fault('before-domain-write');
|
|
87
|
-
const result = executeArtifactCommand(input, { repoRoot: manifest.repoRoot, artifactDir: taskDir });
|
|
88
|
-
publicationCommitted = result.changed === true;
|
|
89
|
-
fault('after-atomic-rename');
|
|
90
|
-
return response(result);
|
|
91
|
-
}
|
|
92
|
-
return await withTaskExecutionLock(manifest.repoRoot, request.taskId, `sandbox-control.${request.operation}`, async () => {
|
|
93
|
-
const artifact = await readTaskArtifact(taskDir, { artifact: input.artifact });
|
|
94
|
-
const content = artifact.bytes.toString('utf8');
|
|
95
|
-
fault('before-domain-write');
|
|
96
|
-
let result;
|
|
97
|
-
if ('operation' in input) {
|
|
98
|
-
const { family } = input;
|
|
99
|
-
if (family !== 'analysis' && family !== 'plan' && family !== 'code')
|
|
100
|
-
throw new Error('ARTIFACT_IDENTITY_INVALID');
|
|
101
|
-
const local = { taskRef: request.taskId, family, artifact: input.artifact, repoRoot: manifest.repoRoot, lockAlreadyHeld: true };
|
|
102
|
-
if (input.operation === 'preflight') {
|
|
103
|
-
const result = preflightLocalArtifact(local);
|
|
104
|
-
return response(result);
|
|
105
|
-
}
|
|
106
|
-
const prepared = prepareLocalArtifact(local, content);
|
|
107
|
-
result = commitLocalArtifactProvenance(prepared);
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
if (input.overrideTicket)
|
|
111
|
-
throw new Error('TASK_WORKFLOW_OVERRIDE_UNSUPPORTED');
|
|
112
|
-
const family = `review-${input.stage}`;
|
|
113
|
-
if (request.operation === 'review-preflight') {
|
|
114
|
-
const result = preflightReviewSummary(input, { repoRoot: manifest.repoRoot, lockAlreadyHeld: true });
|
|
115
|
-
return response(result);
|
|
116
|
-
}
|
|
117
|
-
const prepared = prepareReviewSummaryCandidate(input, content, { repoRoot: manifest.repoRoot, lockAlreadyHeld: true });
|
|
118
|
-
if (input.dryRun || prepared.result.status === 'planned')
|
|
119
|
-
return executionResult(prepared.result);
|
|
120
|
-
if (prepared.result.status === 'failed')
|
|
121
|
-
return executionResult(prepared.result);
|
|
122
|
-
if (prepared.result.changed)
|
|
123
|
-
replaceCurrentArtifactAtomically(path.join(taskDir, input.artifact), prepared.content);
|
|
124
|
-
result = prepared.result;
|
|
125
|
-
}
|
|
126
|
-
publicationCommitted ||= result.changed === true;
|
|
127
|
-
if (result.status !== 'failed')
|
|
128
|
-
appendDiagnosticAudit(manifest, 'task-workflow-artifact-finalized', {
|
|
129
|
-
requestId: request.id, sandboxTaskId: request.taskId, workflowOperation: request.operation,
|
|
130
|
-
artifact: input.artifact, sha256: result.artifactSha256, semanticDigest: result.semanticDigest
|
|
131
|
-
});
|
|
132
|
-
fault('after-atomic-rename');
|
|
133
|
-
return response(result);
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
catch (error) {
|
|
137
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
138
|
-
const code = error?.code ?? /^([A-Z][A-Z0-9_]+)/u.exec(message)?.[1] ?? 'TASK_WORKFLOW_REQUEST_INVALID';
|
|
139
|
-
return executionResult({ status: 'failed', changed: publicationCommitted ? null : false, error: { code, message } });
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
//# sourceMappingURL=workflow-executor.js.map
|