@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.
Files changed (162) hide show
  1. package/README.md +17 -8
  2. package/README.zh-CN.md +17 -8
  3. package/dist/bin/internal-cli.js +7 -2
  4. package/dist/lib/agent-clients/adapter.js +3 -0
  5. package/dist/lib/agent-clients/adapters/codex-lifecycle/recovery.js +234 -0
  6. package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +8 -35
  7. package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +1 -34
  8. package/dist/lib/agent-clients/adapters/codex.js +10 -0
  9. package/dist/lib/internal/cli-route-inventory.js +1 -1
  10. package/dist/lib/internal/manual-validation.js +22 -27
  11. package/dist/lib/internal/sandbox-control.js +1 -43
  12. package/dist/lib/internal/task-artifact.js +1 -1
  13. package/dist/lib/internal/task-finalization.js +41 -1
  14. package/dist/lib/internal/task-ledger.js +13 -5
  15. package/dist/lib/internal/task-lifecycle.js +1 -1
  16. package/dist/lib/internal/task-operation-registry.js +7 -2
  17. package/dist/lib/platform/completion-backfill.js +63 -17
  18. package/dist/lib/platform/issue-comments.js +2 -31
  19. package/dist/lib/platform/pr-summary.js +7 -2
  20. package/dist/lib/sandbox/control/client.js +3 -44
  21. package/dist/lib/sandbox/control/executor.js +14 -79
  22. package/dist/lib/sandbox/control/protocol.js +5 -64
  23. package/dist/lib/sandbox/control/server.js +49 -343
  24. package/dist/lib/sandbox/control/state.js +1 -7
  25. package/dist/lib/sandbox/control/task-view.js +1 -2
  26. package/dist/lib/sandbox/task-cleanup.js +13 -20
  27. package/dist/lib/task/artifact-command.js +11 -4
  28. package/dist/lib/task/artifact-lifecycle.js +217 -85
  29. package/dist/lib/task/artifact-operations.js +1 -26
  30. package/dist/lib/task/artifact-receipts.js +4 -1
  31. package/dist/lib/task/artifact-schema.js +1 -0
  32. package/dist/lib/task/artifact-selection.js +25 -0
  33. package/dist/lib/task/capabilities.js +158 -39
  34. package/dist/lib/task/commands/status.js +9 -2
  35. package/dist/lib/task/control-authority.js +37 -38
  36. package/dist/lib/task/control-recovery.js +3 -42
  37. package/dist/lib/task/decision-intents.js +12 -0
  38. package/dist/lib/task/delegation-receipts.js +2 -2
  39. package/dist/lib/task/delivery.js +1 -43
  40. package/dist/lib/task/events.js +80 -64
  41. package/dist/lib/task/finalization-artifacts.js +1 -3
  42. package/dist/lib/task/finalization-state.js +1 -1
  43. package/dist/lib/task/finalization.js +319 -234
  44. package/dist/lib/task/ledger-intents.js +157 -15
  45. package/dist/lib/task/lifecycle-path.js +75 -0
  46. package/dist/lib/task/lifecycle.js +11 -1
  47. package/dist/lib/task/local-artifact-finalization.js +1 -20
  48. package/dist/lib/task/manual-validation-receipt.js +8 -3
  49. package/dist/lib/task/orchestration.js +29 -13
  50. package/dist/lib/task/review-finalization.js +3 -16
  51. package/dist/lib/task/rework-intent.js +70 -4
  52. package/dist/lib/task/verification-engine.js +20 -30
  53. package/dist/lib/task/verification.js +1 -0
  54. package/dist/lib/task/workflow-warning-intents.js +21 -6
  55. package/dist/lib/task/workspace-snapshot.js +7 -2
  56. package/dist/lifecycle-build-manifest.json +3 -3
  57. package/lib/agent-clients/adapter.ts +46 -0
  58. package/lib/agent-clients/adapters/codex-lifecycle/recovery.ts +297 -0
  59. package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +13 -33
  60. package/lib/agent-clients/adapters/codex-lifecycle/store.ts +1 -44
  61. package/lib/agent-clients/adapters/codex.ts +10 -0
  62. package/lib/internal/cli-route-inventory.ts +1 -1
  63. package/lib/internal/manual-validation.ts +22 -26
  64. package/lib/internal/sandbox-control.ts +0 -42
  65. package/lib/internal/task-artifact.ts +1 -1
  66. package/lib/internal/task-finalization.ts +40 -1
  67. package/lib/internal/task-ledger.ts +12 -5
  68. package/lib/internal/task-lifecycle.ts +2 -2
  69. package/lib/internal/task-operation-registry.ts +8 -4
  70. package/lib/platform/completion-backfill.ts +78 -16
  71. package/lib/platform/issue-comments.ts +1 -35
  72. package/lib/platform/pr-summary.ts +10 -2
  73. package/lib/sandbox/control/client.ts +5 -68
  74. package/lib/sandbox/control/executor.ts +14 -81
  75. package/lib/sandbox/control/protocol.ts +7 -83
  76. package/lib/sandbox/control/server.ts +47 -362
  77. package/lib/sandbox/control/state.ts +1 -9
  78. package/lib/sandbox/control/task-view.ts +1 -2
  79. package/lib/sandbox/task-cleanup.ts +12 -20
  80. package/lib/task/artifact-command.ts +14 -4
  81. package/lib/task/artifact-lifecycle.ts +236 -85
  82. package/lib/task/artifact-operations.ts +1 -26
  83. package/lib/task/artifact-receipts.ts +4 -1
  84. package/lib/task/artifact-schema.ts +1 -0
  85. package/lib/task/artifact-selection.ts +53 -0
  86. package/lib/task/capabilities.ts +154 -40
  87. package/lib/task/commands/status.ts +11 -2
  88. package/lib/task/control-authority.ts +41 -48
  89. package/lib/task/control-recovery.ts +3 -43
  90. package/lib/task/decision-intents.ts +9 -0
  91. package/lib/task/delegation-receipts.ts +2 -2
  92. package/lib/task/delivery.ts +1 -40
  93. package/lib/task/events.ts +82 -64
  94. package/lib/task/finalization-artifacts.ts +1 -3
  95. package/lib/task/finalization-state.ts +1 -1
  96. package/lib/task/finalization.ts +310 -216
  97. package/lib/task/ledger-intents.ts +155 -15
  98. package/lib/task/lifecycle-path.ts +98 -0
  99. package/lib/task/lifecycle.ts +15 -2
  100. package/lib/task/local-artifact-finalization.ts +2 -25
  101. package/lib/task/manual-validation-receipt.ts +8 -2
  102. package/lib/task/orchestration.ts +56 -27
  103. package/lib/task/review-finalization.ts +3 -16
  104. package/lib/task/rework-intent.ts +75 -5
  105. package/lib/task/verification-engine.ts +19 -30
  106. package/lib/task/verification.ts +2 -1
  107. package/lib/task/workflow-warning-intents.ts +18 -6
  108. package/lib/task/workspace-snapshot.ts +3 -2
  109. package/package.json +1 -1
  110. package/templates/.agents/rules/lifecycle-orchestration.en.md +19 -5
  111. package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +19 -5
  112. package/templates/.agents/rules/review-handshake.en.md +4 -4
  113. package/templates/.agents/rules/review-handshake.zh-CN.md +4 -4
  114. package/templates/.agents/skills/analyze-task/SKILL.en.md +11 -4
  115. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +11 -4
  116. package/templates/.agents/skills/code-task/SKILL.en.md +14 -8
  117. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +18 -13
  118. package/templates/.agents/skills/code-task/reference/code-rules.en.md +2 -2
  119. package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +2 -2
  120. package/templates/.agents/skills/code-task/reference/dual-mode.en.md +4 -4
  121. package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +4 -4
  122. package/templates/.agents/skills/code-task/reference/report-template.en.md +1 -1
  123. package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +1 -1
  124. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +2 -2
  125. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +2 -2
  126. package/templates/.agents/skills/complete-task/SKILL.en.md +7 -8
  127. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +7 -8
  128. package/templates/.agents/skills/plan-task/SKILL.en.md +13 -10
  129. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +13 -10
  130. package/templates/.agents/skills/review-analysis/SKILL.en.md +5 -1
  131. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +5 -1
  132. package/templates/.agents/skills/review-code/SKILL.en.md +5 -1
  133. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +5 -1
  134. package/templates/.agents/skills/review-plan/SKILL.en.md +5 -1
  135. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +5 -1
  136. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +2 -2
  137. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +2 -2
  138. package/templates/.agents/skills/run-task/SKILL.en.md +9 -8
  139. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +9 -8
  140. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +18 -2
  141. package/templates/.agents/templates/task.en.md +2 -2
  142. package/templates/.agents/templates/task.zh-CN.md +2 -2
  143. package/templates/.agents/workflows/bug-fix.en.yaml +11 -6
  144. package/templates/.agents/workflows/bug-fix.zh-CN.yaml +11 -6
  145. package/templates/.agents/workflows/feature-development.en.yaml +11 -6
  146. package/templates/.agents/workflows/feature-development.zh-CN.yaml +11 -6
  147. package/templates/.agents/workflows/refactoring.en.yaml +11 -6
  148. package/templates/.agents/workflows/refactoring.zh-CN.yaml +11 -6
  149. package/dist/lib/sandbox/control/finalization-response.js +0 -35
  150. package/dist/lib/sandbox/control/task-workflow.js +0 -74
  151. package/dist/lib/sandbox/control/workflow-executor.js +0 -142
  152. package/dist/lib/task/lifecycle-recovery.js +0 -549
  153. package/dist/lib/task/recovery-warning.js +0 -19
  154. package/dist/lib/task/workflow-command.js +0 -21
  155. package/dist/lib/task/workflow-dispatch.js +0 -213
  156. package/lib/sandbox/control/finalization-response.ts +0 -37
  157. package/lib/sandbox/control/task-workflow.ts +0 -95
  158. package/lib/sandbox/control/workflow-executor.ts +0 -156
  159. package/lib/task/lifecycle-recovery.ts +0 -691
  160. package/lib/task/recovery-warning.ts +0 -21
  161. package/lib/task/workflow-command.ts +0 -22
  162. 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: "Scan existing analysis artifacts; create analysis.md for round 1 and analysis-r{N}.md for later revisions (N = current highest round + 1)"
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: "Scan existing requirement-analysis review artifacts; create review-analysis.md for round 1 and review-analysis-r{N}.md for later rounds (N = current highest round + 1)"
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: "Scan existing plan artifacts; create plan.md for round 1 and plan-r{N}.md for later revisions (N = current highest round + 1)"
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: "Scan existing plan review artifacts; create review-plan.md for round 1 and review-plan-r{N}.md for later rounds (N = current highest round + 1)"
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: "Scan existing code artifacts; create code.md for round 1 and code-r{N}.md for later fixes or reimplementation (N = current highest round + 1)"
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: "Scan existing code review artifacts; create review-code.md for round 1 and review-code-r{N}.md for later rounds (N = current highest round + 1)"
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: "扫描现有分析产物;首轮创建 analysis.md,后续修订创建 analysis-r{N}.md(N = 当前最高轮次 + 1)"
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: "扫描现有需求分析审查产物;首轮创建 review-analysis.md,后续轮次创建 review-analysis-r{N}.md(N = 当前最高轮次 + 1)"
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: "扫描现有方案产物;首轮创建 plan.md,后续修订创建 plan-r{N}.md(N = 当前最高轮次 + 1)"
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: "扫描现有方案审查产物;首轮创建 review-plan.md,后续轮次创建 review-plan-r{N}.md(N = 当前最高轮次 + 1)"
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: "扫描现有实现产物;首轮创建 code.md,后续修复或重实现创建 code-r{N}.md(N = 当前最高轮次 + 1)"
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: "扫描现有代码审查产物;首轮创建 review-code.md,后续轮次创建 review-code-r{N}.md(N = 当前最高轮次 + 1)"
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