@fitlab-ai/agent-infra 0.9.11 → 0.9.12
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 +6 -6
- package/README.zh-CN.md +6 -6
- package/dist/bin/internal-cli.js +5 -0
- package/dist/lib/agent-clients/adapters/codex-lifecycle/build-identity.js +71 -10
- package/dist/lib/defaults.json +4 -0
- package/dist/lib/git/workflow.js +43 -1
- package/dist/lib/init.js +1 -0
- package/dist/lib/internal/git-workflow.js +8 -1
- package/dist/lib/internal/platform-pr.js +8 -2
- package/dist/lib/internal/task-delivery.js +59 -0
- package/dist/lib/platform/github-client.js +7 -1
- package/dist/lib/platform/pr-checks.js +8 -5
- package/dist/lib/platform/pr-summary.js +12 -8
- package/dist/lib/platform/pull-requests.js +393 -91
- package/dist/lib/platform/verification-required.js +13 -2
- package/dist/lib/platform/verification-sync.js +9 -4
- package/dist/lib/pr-review/evidence-grading.js +12 -4
- package/dist/lib/sandbox/config.js +5 -0
- package/dist/lib/sandbox/control/lifecycle.js +29 -7
- package/dist/lib/server/process-state.js +2 -2
- package/dist/lib/task/artifact-lifecycle.js +2 -2
- package/dist/lib/task/commit-intent.js +100 -0
- package/dist/lib/task/commit-operation.js +195 -101
- package/dist/lib/task/create.js +33 -7
- package/dist/lib/task/decision-details.js +3 -48
- package/dist/lib/task/delivery-target.js +97 -0
- package/dist/lib/task/delivery.js +153 -0
- package/dist/lib/task/human-override.js +5 -2
- package/dist/lib/task/lifecycle.js +106 -9
- package/dist/lib/task/orchestration.js +55 -62
- package/dist/lib/task/pr-delivery-fact.js +182 -0
- package/dist/lib/task/review-finalization.js +4 -8
- package/dist/lib/task/review-fingerprint.js +8 -0
- package/dist/lib/task/verification-engine.js +48 -24
- package/dist/lib/task/verification-review.js +1 -1
- package/dist/lib/update.js +9 -0
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-clients/adapters/codex-lifecycle/build-identity.ts +105 -10
- package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +12 -1
- package/lib/defaults.json +4 -0
- package/lib/git/workflow.ts +38 -1
- package/lib/init.ts +3 -0
- package/lib/internal/git-workflow.ts +7 -1
- package/lib/internal/platform-pr.ts +8 -1
- package/lib/internal/task-delivery.ts +53 -0
- package/lib/platform/github-client.ts +8 -1
- package/lib/platform/pr-checks.ts +7 -5
- package/lib/platform/pr-summary.ts +10 -7
- package/lib/platform/pull-requests.ts +425 -87
- package/lib/platform/verification-required.ts +12 -2
- package/lib/platform/verification-sync.ts +9 -4
- package/lib/pr-review/evidence-grading.ts +7 -4
- package/lib/sandbox/config.ts +7 -0
- package/lib/sandbox/control/lifecycle.ts +30 -8
- package/lib/server/process-state.ts +2 -2
- package/lib/task/artifact-lifecycle.ts +2 -2
- package/lib/task/commit-intent.ts +137 -0
- package/lib/task/commit-operation.ts +174 -87
- package/lib/task/create.ts +34 -9
- package/lib/task/decision-details.ts +2 -62
- package/lib/task/delivery-target.ts +130 -0
- package/lib/task/delivery.ts +160 -0
- package/lib/task/human-override.ts +5 -2
- package/lib/task/lifecycle.ts +93 -4
- package/lib/task/orchestration.ts +62 -65
- package/lib/task/pr-delivery-fact.ts +254 -0
- package/lib/task/review-finalization.ts +4 -14
- package/lib/task/review-fingerprint.ts +10 -0
- package/lib/task/verification-engine.ts +45 -28
- package/lib/task/verification-review.ts +2 -0
- package/lib/update.ts +10 -0
- package/package.json +1 -1
- package/templates/.agents/rules/README.en.md +4 -2
- package/templates/.agents/rules/README.zh-CN.md +4 -2
- package/templates/.agents/rules/create-issue.en.md +11 -2
- package/templates/.agents/rules/create-issue.zh-CN.md +24 -2
- package/templates/.agents/rules/issue-pr-commands.en.md +4 -17
- package/templates/.agents/rules/issue-sync.en.md +26 -5
- package/templates/.agents/rules/issue-sync.zh-CN.md +62 -5
- package/templates/.agents/rules/label-milestone-setup.en.md +15 -2
- package/templates/.agents/rules/label-milestone-setup.zh-CN.md +15 -2
- package/templates/.agents/rules/local-artifact-repair.en.md +46 -0
- package/templates/.agents/rules/local-artifact-repair.zh-CN.md +46 -0
- package/templates/.agents/rules/milestone-inference.en.md +12 -2
- package/templates/.agents/rules/milestone-inference.zh-CN.md +25 -3
- package/templates/.agents/rules/pr-sync.en.md +22 -13
- package/templates/.agents/rules/pr-sync.zh-CN.md +22 -1
- package/templates/.agents/rules/release-commands.en.md +42 -3
- package/templates/.agents/rules/release-commands.zh-CN.md +42 -3
- package/templates/.agents/rules/security-alerts.en.md +17 -2
- package/templates/.agents/rules/security-alerts.zh-CN.md +17 -2
- package/templates/.agents/rules/sync-content-generation.en.md +8 -0
- package/templates/.agents/rules/sync-content-generation.zh-CN.md +8 -0
- package/templates/.agents/rules/task-management.en.md +1 -1
- package/templates/.agents/rules/task-management.zh-CN.md +1 -1
- package/templates/.agents/scripts/security-alerts.github.sh +151 -0
- package/templates/.agents/scripts/security-alerts.sh +31 -0
- package/templates/.agents/skills/analyze-task/SKILL.en.md +1 -0
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +1 -0
- package/templates/.agents/skills/close-codescan/SKILL.en.md +2 -2
- package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/close-dependabot/SKILL.en.md +2 -2
- package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/code-task/SKILL.en.md +5 -2
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +6 -3
- package/templates/.agents/skills/commit/SKILL.en.md +3 -3
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/commit/config/verify.json +1 -1
- package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +3 -3
- package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +3 -3
- package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +1 -1
- package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +1 -1
- package/templates/.agents/skills/commit/reference/task-status-update.en.md +2 -2
- package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +2 -2
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +2 -1
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +2 -1
- package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -1
- package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +1 -1
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +1 -1
- package/templates/.agents/skills/complete-task/SKILL.en.md +10 -10
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +10 -10
- package/templates/.agents/skills/complete-task/reference/external-delivery.en.md +2 -2
- package/templates/.agents/skills/complete-task/reference/external-delivery.zh-CN.md +2 -2
- package/templates/.agents/skills/create-pr/SKILL.en.md +4 -4
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/create-task/SKILL.en.md +1 -0
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +1 -0
- package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
- package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/import-dependabot/SKILL.en.md +1 -1
- package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/init-labels/SKILL.en.md +9 -10
- package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +9 -10
- package/templates/.agents/skills/init-labels/scripts/init-labels.github.sh +57 -1
- package/templates/.agents/skills/init-labels/scripts/init-labels.sh +27 -1
- package/templates/.agents/skills/init-milestones/SKILL.en.md +3 -5
- package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +3 -5
- package/templates/.agents/skills/plan-task/SKILL.en.md +1 -0
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +1 -0
- package/templates/.agents/skills/review-analysis/SKILL.en.md +4 -3
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +4 -3
- package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +18 -0
- package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +18 -0
- package/templates/.agents/skills/review-code/SKILL.en.md +7 -6
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +7 -6
- package/templates/.agents/skills/review-code/reference/output-templates.en.md +19 -1
- package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +19 -1
- package/templates/.agents/skills/review-code/reference/report-template.en.md +4 -2
- package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +4 -2
- package/templates/.agents/skills/review-plan/SKILL.en.md +4 -3
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +4 -3
- package/templates/.agents/skills/review-plan/reference/output-templates.en.md +18 -0
- package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +18 -0
- package/templates/.agents/skills/review-pr/SKILL.en.md +1 -0
- package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +1 -0
- package/templates/.agents/skills/review-pr/reference/evidence-grading.en.md +2 -2
- package/templates/.agents/skills/review-pr/reference/evidence-grading.zh-CN.md +2 -2
- package/templates/.agents/skills/run-manual-validation/SKILL.en.md +1 -0
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +1 -0
- package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +4 -0
- package/templates/.agents/skills/watch-pr/SKILL.en.md +4 -4
- package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +4 -4
- package/templates/.agents/templates/task.en.md +5 -1
- package/templates/.agents/templates/task.zh-CN.md +5 -1
- package/templates/.agents/workflows/bug-fix.en.yaml +9 -8
- package/templates/.agents/workflows/bug-fix.zh-CN.yaml +9 -8
- package/templates/.agents/workflows/feature-development.en.yaml +9 -8
- package/templates/.agents/workflows/feature-development.zh-CN.yaml +9 -8
- package/templates/.agents/workflows/refactoring.en.yaml +9 -8
- package/templates/.agents/workflows/refactoring.zh-CN.yaml +9 -8
- package/templates/.agents/rules/create-issue.github.en.md +0 -14
- package/templates/.agents/rules/create-issue.github.zh-CN.md +0 -27
- package/templates/.agents/rules/issue-pr-commands.github.en.md +0 -34
- package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +0 -49
- package/templates/.agents/rules/issue-sync.github.en.md +0 -40
- package/templates/.agents/rules/issue-sync.github.zh-CN.md +0 -76
- package/templates/.agents/rules/label-milestone-setup.github.en.md +0 -60
- package/templates/.agents/rules/label-milestone-setup.github.zh-CN.md +0 -60
- package/templates/.agents/rules/milestone-inference.github.en.md +0 -15
- package/templates/.agents/rules/milestone-inference.github.zh-CN.md +0 -27
- package/templates/.agents/rules/pr-checks-commands.github.en.md +0 -18
- package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +0 -34
- package/templates/.agents/rules/pr-sync.github.en.md +0 -43
- package/templates/.agents/rules/pr-sync.github.zh-CN.md +0 -69
- package/templates/.agents/rules/release-commands.github.en.md +0 -44
- package/templates/.agents/rules/release-commands.github.zh-CN.md +0 -44
- package/templates/.agents/rules/security-alerts.github.en.md +0 -43
- package/templates/.agents/rules/security-alerts.github.zh-CN.md +0 -43
- /package/templates/.agents/rules/{issue-fields.github.en.md → issue-fields.en.md} +0 -0
- /package/templates/.agents/rules/{issue-fields.github.zh-CN.md → issue-fields.zh-CN.md} +0 -0
package/README.md
CHANGED
|
@@ -71,11 +71,11 @@ Just fix it at the application layer in LoginService.
|
|
|
71
71
|
> AI re-runs `/plan-task` to update the plan accordingly and confirms.
|
|
72
72
|
|
|
73
73
|
```bash
|
|
74
|
-
/code-task <task-id> # AI writes the fix,
|
|
74
|
+
/code-task <task-id> # AI writes the fix, tests it, and creates a local checkpoint commit
|
|
75
75
|
/review-code <task-id> # A fresh isolated reviewer reports one minor finding
|
|
76
|
-
/code-task <task-id> # AI fixes the minor issue
|
|
77
|
-
/
|
|
78
|
-
/create-pr <task-id> #
|
|
76
|
+
/code-task <task-id> # AI fixes the minor issue, re-validates, and creates a new checkpoint
|
|
77
|
+
/review-code <task-id> # The reviewer approves the current checkpoint
|
|
78
|
+
/create-pr <task-id> # The reviewed branch is published to its task-bound target; PR links issue #42
|
|
79
79
|
/complete-task <task-id> # task archived
|
|
80
80
|
```
|
|
81
81
|
|
|
@@ -189,8 +189,8 @@ The most-used lifecycle commands, in delivery order. The command prefix varies b
|
|
|
189
189
|
| `run-task` | Resume the lifecycle with fresh isolated executors/reviewers when the selected client exposes verified actual model/effort evidence; Codex now has an experimental Hooks + App Server evidence channel, but orchestration remains disabled until that channel is connected to delegation receipts |
|
|
190
190
|
| `analyze-task` → `review-analysis` | Capture scope and risks, then review the analysis |
|
|
191
191
|
| `plan-task` → `review-plan` | Design the approach, then review the plan |
|
|
192
|
-
| `code-task` → `review-code` | Implement and test, then
|
|
193
|
-
| `
|
|
192
|
+
| `code-task` → `review-code` | Implement and test; `code-task` creates a local checkpoint, then a structured review checks that checkpoint |
|
|
193
|
+
| `create-pr` → `complete-task` | Publish the approved checkpoint to the task-bound target branch, then archive after merge and final gates |
|
|
194
194
|
|
|
195
195
|
Start with one atomic role policy, for example: `$run-task 42 --executor-model <id> --executor-reasoning-effort <value> --reviewer-model <id> --reviewer-reasoning-effort <value>`. Both roles may use the same model. With no explicit policy, `run-task` reads the current Agent Client's optional `agentClients[].orchestration`; if neither source is complete, it shows the host model-selection guidance before creating any run. Re-entry uses the persisted run policy. Finish or clear active runs before upgrading agent-infra; unsupported disk state fails closed without rewriting.
|
|
196
196
|
|
package/README.zh-CN.md
CHANGED
|
@@ -70,11 +70,11 @@ agent-infra 的目标就是把这层共享基础设施标准化。它为所有
|
|
|
70
70
|
> AI 按你的要求重跑 `/plan-task` 更新方案并确认。
|
|
71
71
|
|
|
72
72
|
```bash
|
|
73
|
-
/code-task <task-id> # AI
|
|
73
|
+
/code-task <task-id> # AI 编写修复代码、测试,并创建本地 checkpoint commit
|
|
74
74
|
/review-code <task-id> # fresh 隔离 reviewer 报告一个次要问题
|
|
75
|
-
/code-task <task-id> # AI
|
|
76
|
-
/
|
|
77
|
-
/create-pr <task-id> # PR
|
|
75
|
+
/code-task <task-id> # AI 修复次要问题、重新验证,并创建新的 checkpoint
|
|
76
|
+
/review-code <task-id> # reviewer 审查并通过当前 checkpoint
|
|
77
|
+
/create-pr <task-id> # 将已审查分支发布到任务绑定目标分支;PR 自动关联 Issue #42
|
|
78
78
|
/complete-task <task-id> # 任务归档
|
|
79
79
|
```
|
|
80
80
|
|
|
@@ -188,8 +188,8 @@ ai agent-client configure
|
|
|
188
188
|
| `run-task` | 当所选客户端能提供已验证的 actual model/effort 证据时,用 fresh 隔离 executor/reviewer 续跑生命周期;Codex 现已具备实验性的 Hooks + App Server 证据通道,但在该通道接入 delegation receipt 前仍不会启用 orchestration |
|
|
189
189
|
| `analyze-task` → `review-analysis` | 明确范围与风险,再审查分析 |
|
|
190
190
|
| `plan-task` → `review-plan` | 设计实现路径,再审查方案 |
|
|
191
|
-
| `code-task` → `review-code` |
|
|
192
|
-
| `
|
|
191
|
+
| `code-task` → `review-code` | 实现并测试;`code-task` 创建本地 checkpoint,再由结构化审查检视该 checkpoint |
|
|
192
|
+
| `create-pr` → `complete-task` | 将已通过审查的 checkpoint 发布到任务绑定目标分支,并在合并和最终门禁通过后归档 |
|
|
193
193
|
|
|
194
194
|
启动时可提供原子角色策略,例如:`$run-task 42 --executor-model <id> --executor-reasoning-effort <值> --reviewer-model <id> --reviewer-reasoning-effort <值>`。两个角色可以使用同一模型。完全没有显式策略时,`run-task` 读取当前 Agent Client 可选的 `agentClients[].orchestration`;两个来源都不完整时,会在创建任何 run 前展示宿主模型选择指引。重入使用已持久化的 run 策略。升级 agent-infra 前必须完成或清空 active run;不受支持的磁盘状态会失败关闭且不改写。
|
|
195
195
|
|
package/dist/bin/internal-cli.js
CHANGED
|
@@ -88,6 +88,11 @@ else
|
|
|
88
88
|
gitWorkflow(process.argv.slice(3));
|
|
89
89
|
break;
|
|
90
90
|
}
|
|
91
|
+
case 'task-delivery': {
|
|
92
|
+
const { taskDelivery } = await import('../lib/internal/task-delivery.js');
|
|
93
|
+
taskDelivery(process.argv.slice(3));
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
91
96
|
case 'release-workflow': {
|
|
92
97
|
const { releaseWorkflow } = await import('../lib/internal/release-workflow.js');
|
|
93
98
|
await releaseWorkflow(process.argv.slice(3));
|
|
@@ -16,20 +16,63 @@ function isLifecycleProtocolVersion(value) {
|
|
|
16
16
|
function normalizeRelativePath(value) {
|
|
17
17
|
return value.replaceAll('\\', '/');
|
|
18
18
|
}
|
|
19
|
+
function isSafeLifecyclePath(value) {
|
|
20
|
+
return exactText(value)
|
|
21
|
+
&& value === normalizeRelativePath(value)
|
|
22
|
+
&& !path.isAbsolute(value)
|
|
23
|
+
&& !/^[A-Za-z]:[\\/]/u.test(value)
|
|
24
|
+
&& !value.split('/').includes('..');
|
|
25
|
+
}
|
|
26
|
+
function isLifecycleLauncherLine(value) {
|
|
27
|
+
return typeof value === 'string'
|
|
28
|
+
&& value.length > 1
|
|
29
|
+
&& value.slice(0, -1).trim() === value.slice(0, -1)
|
|
30
|
+
&& value.startsWith('#!')
|
|
31
|
+
&& value.endsWith('\n')
|
|
32
|
+
&& value.indexOf('\n') === value.length - 1
|
|
33
|
+
&& !value.includes('\r');
|
|
34
|
+
}
|
|
35
|
+
function readLifecycleLauncherShebang(value, executableFiles) {
|
|
36
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
37
|
+
throw new Error('Lifecycle manifest launcher shebang policy is invalid');
|
|
38
|
+
}
|
|
39
|
+
const policy = value;
|
|
40
|
+
if (!isSafeLifecyclePath(policy.sourceFile)
|
|
41
|
+
|| !isSafeLifecyclePath(policy.compiledFile)
|
|
42
|
+
|| !isLifecycleLauncherLine(policy.canonicalLine)
|
|
43
|
+
|| !Array.isArray(policy.acceptedLines)
|
|
44
|
+
|| !policy.acceptedLines.every(isLifecycleLauncherLine)
|
|
45
|
+
|| new Set(policy.acceptedLines).size !== policy.acceptedLines.length
|
|
46
|
+
|| !policy.acceptedLines.includes(policy.canonicalLine)
|
|
47
|
+
|| !executableFiles.includes(policy.sourceFile)
|
|
48
|
+
|| policy.compiledFile !== normalizeRelativePath(path.join('dist', policy.sourceFile.endsWith('.ts')
|
|
49
|
+
? policy.sourceFile.replace(/\.ts$/u, '.js')
|
|
50
|
+
: policy.sourceFile))) {
|
|
51
|
+
throw new Error('Lifecycle manifest launcher shebang policy is invalid');
|
|
52
|
+
}
|
|
53
|
+
return Object.freeze({
|
|
54
|
+
sourceFile: policy.sourceFile,
|
|
55
|
+
compiledFile: policy.compiledFile,
|
|
56
|
+
canonicalLine: policy.canonicalLine,
|
|
57
|
+
acceptedLines: Object.freeze([...policy.acceptedLines])
|
|
58
|
+
});
|
|
59
|
+
}
|
|
19
60
|
function readLifecycleManifestFiles(packageRoot) {
|
|
20
61
|
const file = path.join(packageRoot, 'lib', 'agent-clients', 'adapters', 'codex-lifecycle', 'manifest-files.json');
|
|
21
62
|
const value = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
22
63
|
if (!Array.isArray(value.executableFiles)
|
|
23
64
|
|| !Array.isArray(value.contractFiles)
|
|
24
|
-
|| !value.executableFiles.every(
|
|
25
|
-
|| !value.contractFiles.every(
|
|
65
|
+
|| !value.executableFiles.every(isSafeLifecyclePath)
|
|
66
|
+
|| !value.contractFiles.every(isSafeLifecyclePath)
|
|
26
67
|
|| new Set(value.executableFiles).size !== value.executableFiles.length
|
|
27
68
|
|| new Set(value.contractFiles).size !== value.contractFiles.length) {
|
|
28
69
|
throw new Error('Lifecycle manifest file list is invalid');
|
|
29
70
|
}
|
|
71
|
+
const executableFiles = Object.freeze([...value.executableFiles]);
|
|
30
72
|
return Object.freeze({
|
|
31
|
-
executableFiles
|
|
32
|
-
contractFiles: Object.freeze([...value.contractFiles])
|
|
73
|
+
executableFiles,
|
|
74
|
+
contractFiles: Object.freeze([...value.contractFiles]),
|
|
75
|
+
launcherShebang: readLifecycleLauncherShebang(value.launcherShebang, executableFiles)
|
|
33
76
|
});
|
|
34
77
|
}
|
|
35
78
|
function executablePackageRoot() {
|
|
@@ -47,7 +90,22 @@ function executablePackageRoot() {
|
|
|
47
90
|
current = parent;
|
|
48
91
|
}
|
|
49
92
|
}
|
|
50
|
-
function
|
|
93
|
+
function normalizeLifecycleLauncherBytes(relative, content, policy) {
|
|
94
|
+
const normalized = normalizeRelativePath(relative);
|
|
95
|
+
if (normalized !== policy.sourceFile && normalized !== policy.compiledFile)
|
|
96
|
+
return content;
|
|
97
|
+
const lineEnd = content.indexOf(0x0a);
|
|
98
|
+
if (lineEnd < 0)
|
|
99
|
+
return content;
|
|
100
|
+
const firstLine = content.subarray(0, lineEnd + 1);
|
|
101
|
+
if (!policy.acceptedLines.some((line) => Buffer.from(line).equals(firstLine)))
|
|
102
|
+
return content;
|
|
103
|
+
return Buffer.concat([
|
|
104
|
+
Buffer.from(policy.canonicalLine),
|
|
105
|
+
content.subarray(lineEnd + 1)
|
|
106
|
+
]);
|
|
107
|
+
}
|
|
108
|
+
function hashFiles(root, files, launcherShebang) {
|
|
51
109
|
const hash = crypto.createHash('sha256');
|
|
52
110
|
for (const relative of [...new Set(files.map(normalizeRelativePath))].sort()) {
|
|
53
111
|
if (path.isAbsolute(relative) || relative.split(/[\\/]/u).includes('..')) {
|
|
@@ -60,7 +118,10 @@ function hashFiles(root, files) {
|
|
|
60
118
|
}
|
|
61
119
|
hash.update(relative);
|
|
62
120
|
hash.update('\0');
|
|
63
|
-
|
|
121
|
+
const content = fs.readFileSync(file);
|
|
122
|
+
hash.update(launcherShebang
|
|
123
|
+
? normalizeLifecycleLauncherBytes(relative, content, launcherShebang)
|
|
124
|
+
: content);
|
|
64
125
|
hash.update('\0');
|
|
65
126
|
}
|
|
66
127
|
return hash.digest('hex');
|
|
@@ -107,7 +168,7 @@ function computeLifecycleBuildIdentity(repoRoot, options = {}) {
|
|
|
107
168
|
throw new Error('Lifecycle package version is invalid');
|
|
108
169
|
let internalExecutableBuildHash;
|
|
109
170
|
if (options.executableFiles) {
|
|
110
|
-
internalExecutableBuildHash = hashFiles(repoRoot, options.executableFiles);
|
|
171
|
+
internalExecutableBuildHash = hashFiles(repoRoot, options.executableFiles, defaults.launcherShebang);
|
|
111
172
|
}
|
|
112
173
|
else {
|
|
113
174
|
const manifestFile = path.join(executableRoot, 'dist', 'lifecycle-build-manifest.json');
|
|
@@ -121,17 +182,17 @@ function computeLifecycleBuildIdentity(repoRoot, options = {}) {
|
|
|
121
182
|
}
|
|
122
183
|
if (fileURLToPath(import.meta.url).split(path.sep).includes('dist')) {
|
|
123
184
|
const compiledFiles = defaults.executableFiles.map((file) => file.endsWith('.ts') ? path.join('dist', file.replace(/\.ts$/u, '.js')) : file);
|
|
124
|
-
if (hashFiles(executableRoot, resolveLifecycleExecutableFiles(executableRoot, compiledFiles)) !== manifest.internalExecutableBuildHash) {
|
|
185
|
+
if (hashFiles(executableRoot, resolveLifecycleExecutableFiles(executableRoot, compiledFiles), defaults.launcherShebang) !== manifest.internalExecutableBuildHash) {
|
|
125
186
|
throw new Error('Lifecycle compiled executable build does not match its manifest');
|
|
126
187
|
}
|
|
127
188
|
}
|
|
128
|
-
else if (hashFiles(executableRoot, resolveLifecycleExecutableFiles(executableRoot, defaults.executableFiles)) !== manifest.sourceInputHash) {
|
|
189
|
+
else if (hashFiles(executableRoot, resolveLifecycleExecutableFiles(executableRoot, defaults.executableFiles), defaults.launcherShebang) !== manifest.sourceInputHash) {
|
|
129
190
|
throw new Error('Lifecycle executable build manifest is stale or invalid');
|
|
130
191
|
}
|
|
131
192
|
internalExecutableBuildHash = manifest.internalExecutableBuildHash;
|
|
132
193
|
}
|
|
133
194
|
else
|
|
134
|
-
internalExecutableBuildHash = hashFiles(executableRoot, resolveLifecycleExecutableFiles(executableRoot, defaults.executableFiles));
|
|
195
|
+
internalExecutableBuildHash = hashFiles(executableRoot, resolveLifecycleExecutableFiles(executableRoot, defaults.executableFiles), defaults.launcherShebang);
|
|
135
196
|
}
|
|
136
197
|
return Object.freeze({
|
|
137
198
|
protocolVersion: LIFECYCLE_PROTOCOL_VERSION,
|
package/dist/lib/defaults.json
CHANGED
package/dist/lib/git/workflow.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { spawnSync } from 'node:child_process';
|
|
2
2
|
import fs from 'node:fs';
|
|
3
|
+
import os from 'node:os';
|
|
3
4
|
import path from 'node:path';
|
|
4
5
|
const defaultRunner = (args, cwd) => {
|
|
5
6
|
const result = spawnSync('git', [...args], { cwd, encoding: 'utf8' });
|
|
@@ -108,6 +109,47 @@ function commitExplicitPaths(input, runner = defaultRunner) {
|
|
|
108
109
|
return { status: 'failed', changed: false, snapshot: after.snapshot, operations: [{ name: 'commit', status: 'failed', message: commit.stderr.trim() }], error: { code: 'GIT_COMMIT_FAILED', message: commit.stderr.trim() } };
|
|
109
110
|
return { status: 'applied', changed: true, snapshot: after.snapshot, operations: [{ name: 'stage', status: 'applied' }, { name: 'commit', status: 'applied' }], error: null };
|
|
110
111
|
}
|
|
112
|
+
function previewCommitTree(input) {
|
|
113
|
+
const invalid = validatePaths(input.paths);
|
|
114
|
+
if (invalid)
|
|
115
|
+
return { status: 'failed', tree: null, error: { code: 'GIT_COMMIT_INPUT_INVALID', message: invalid } };
|
|
116
|
+
const before = inspectGitWorkflow(input.cwd);
|
|
117
|
+
if (!before.snapshot)
|
|
118
|
+
return { status: 'failed', tree: null, error: { code: 'GIT_INSPECT_FAILED', message: 'Unable to inspect Git repository' } };
|
|
119
|
+
if (before.snapshot.head !== input.expectedHead) {
|
|
120
|
+
return { status: 'failed', tree: null, error: { code: 'GIT_HEAD_MISMATCH', message: `Expected HEAD ${input.expectedHead}, received ${before.snapshot.head}` } };
|
|
121
|
+
}
|
|
122
|
+
const selected = new Set(input.paths);
|
|
123
|
+
const unrelatedStaged = before.snapshot.staged.filter((candidate) => !selected.has(candidate));
|
|
124
|
+
if (unrelatedStaged.length > 0) {
|
|
125
|
+
return { status: 'failed', tree: null, error: { code: 'GIT_STAGED_SCOPE_MISMATCH', message: `Unrelated staged paths: ${unrelatedStaged.join(', ')}` } };
|
|
126
|
+
}
|
|
127
|
+
const temporaryDirectory = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-infra-preview-index-'));
|
|
128
|
+
const indexFile = path.join(temporaryDirectory, 'index');
|
|
129
|
+
const temporaryRunner = (args, cwd) => {
|
|
130
|
+
const result = spawnSync('git', [...args], {
|
|
131
|
+
cwd,
|
|
132
|
+
env: { ...process.env, GIT_INDEX_FILE: indexFile },
|
|
133
|
+
encoding: 'utf8'
|
|
134
|
+
});
|
|
135
|
+
return { status: result.status, stdout: result.stdout ?? '', stderr: result.stderr ?? '' };
|
|
136
|
+
};
|
|
137
|
+
try {
|
|
138
|
+
const read = run(temporaryRunner, input.cwd, ['read-tree', input.expectedHead]);
|
|
139
|
+
if (read.status !== 0)
|
|
140
|
+
return { status: 'failed', tree: null, error: { code: 'GIT_PREVIEW_FAILED', message: read.stderr.trim() || 'Unable to prepare a temporary Git index' } };
|
|
141
|
+
const stage = run(temporaryRunner, input.cwd, ['add', '-A', '--', ...input.paths]);
|
|
142
|
+
if (stage.status !== 0)
|
|
143
|
+
return { status: 'failed', tree: null, error: { code: 'GIT_PREVIEW_FAILED', message: stage.stderr.trim() || 'Unable to stage the requested paths in a temporary index' } };
|
|
144
|
+
const tree = value(temporaryRunner, input.cwd, ['write-tree']);
|
|
145
|
+
if (!tree)
|
|
146
|
+
return { status: 'failed', tree: null, error: { code: 'GIT_PREVIEW_FAILED', message: 'Unable to write the temporary Git tree' } };
|
|
147
|
+
return { status: 'planned', tree, error: null };
|
|
148
|
+
}
|
|
149
|
+
finally {
|
|
150
|
+
fs.rmSync(temporaryDirectory, { recursive: true, force: true });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
111
153
|
function pushGitRefs(input, runner = defaultRunner) {
|
|
112
154
|
if (!input.remote || input.refs.length === 0)
|
|
113
155
|
return { status: 'failed', changed: false, snapshot: inspectGitWorkflow(input.cwd, runner).snapshot, operations: [], error: { code: 'GIT_PUSH_INPUT_INVALID', message: 'Remote and refs are required' } };
|
|
@@ -185,5 +227,5 @@ function pushRebasedBranch(input, runner = defaultRunner) {
|
|
|
185
227
|
}
|
|
186
228
|
return { status: 'applied', changed: true, snapshot: inspectGitWorkflow(input.cwd, runner).snapshot, operations: [{ name: 'push-rebased', status: 'applied', ref: input.branch }], error: null };
|
|
187
229
|
}
|
|
188
|
-
export { commitExplicitPaths, inspectGitWorkflow, pushGitRefs, pushRebasedBranch };
|
|
230
|
+
export { commitExplicitPaths, inspectGitWorkflow, previewCommitTree, pushGitRefs, pushRebasedBranch };
|
|
189
231
|
//# sourceMappingURL=workflow.js.map
|
package/dist/lib/init.js
CHANGED
|
@@ -175,6 +175,7 @@ async function cmdInit() {
|
|
|
175
175
|
templateVersion: VERSION,
|
|
176
176
|
sandbox: structuredClone(defaults.sandbox),
|
|
177
177
|
task: structuredClone(defaults.task),
|
|
178
|
+
delivery: structuredClone(defaults.delivery),
|
|
178
179
|
labels: structuredClone(defaults.labels),
|
|
179
180
|
files: { managed: [], merged: [], ejected: [] },
|
|
180
181
|
agentClients: serializeAgentClients(defaultState)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
-
import { inspectGitWorkflow, pushRebasedBranch } from '../git/workflow.js';
|
|
2
|
+
import { inspectGitWorkflow, previewCommitTree, pushRebasedBranch } from '../git/workflow.js';
|
|
3
3
|
import { compareReviewTrees, snapshotReview } from '../git/review-snapshot.js';
|
|
4
4
|
import { resolvePostReviewGlobs } from '../task/review-fingerprint.js';
|
|
5
5
|
import { executeCommitOperation } from '../task/commit-operation.js';
|
|
@@ -26,6 +26,13 @@ function gitWorkflow(args = []) {
|
|
|
26
26
|
const input = inputIndex >= 0 && rest[inputIndex + 1] ? JSON.parse(fs.readFileSync(rest[inputIndex + 1], 'utf8')) : null;
|
|
27
27
|
result = input ? pushRebasedBranch({ cwd: cwd ?? process.cwd(), ...input }) : { status: 'failed', changed: false, error: { code: 'GIT_INPUT_REQUIRED', message: '--input JSON file is required' } };
|
|
28
28
|
}
|
|
29
|
+
else if (action === 'preview-tree') {
|
|
30
|
+
const inputIndex = rest.indexOf('--input');
|
|
31
|
+
const input = inputIndex >= 0 && rest[inputIndex + 1] ? JSON.parse(fs.readFileSync(rest[inputIndex + 1], 'utf8')) : null;
|
|
32
|
+
result = input
|
|
33
|
+
? previewCommitTree({ cwd: cwd ?? process.cwd(), paths: input.paths, expectedHead: input.expectedHead })
|
|
34
|
+
: { status: 'failed', changed: false, error: { code: 'GIT_INPUT_REQUIRED', message: '--input JSON file is required' } };
|
|
35
|
+
}
|
|
29
36
|
else if (action === 'snapshot' || action === 'compare-trees') {
|
|
30
37
|
const inputIndex = rest.indexOf('--input');
|
|
31
38
|
const input = inputIndex >= 0 && rest[inputIndex + 1] ? JSON.parse(fs.readFileSync(rest[inputIndex + 1], 'utf8')) : null;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { normalizeAgentToken, AGENT_USAGE_HINT } from '../agent-clients/tokens.js';
|
|
4
|
-
import { bindPlatformPullRequest, createPlatformPullRequest, inspectPlatformPullRequest, resolveExternalPullRequest, syncPlatformPullRequest } from '../platform/pull-requests.js';
|
|
4
|
+
import { bindPlatformPullRequest, createPlatformPullRequest, inspectPlatformPullRequest, resolveExternalPullRequest, skipPlatformPullRequestFact, syncPlatformPullRequest } from '../platform/pull-requests.js';
|
|
5
5
|
import { summaryContext, syncPullRequestSummary } from '../platform/pr-summary.js';
|
|
6
6
|
const USAGE = `Usage: agent-infra-internal platform-pr inspect <task-ref> [--cwd <path>]
|
|
7
7
|
agent-infra-internal platform-pr resolve-external <task-ref> --agent <agent> [--pr <N>] [--dry-run] [--cwd <path>]
|
|
8
8
|
agent-infra-internal platform-pr create <task-ref> --agent <agent> --base <branch> --head <branch> --title-file <path|-> --body-file <path|-> [--draft] [--dry-run] [--cwd <path>]
|
|
9
9
|
agent-infra-internal platform-pr bind <task-ref> --pr <N> --agent <agent> [--dry-run] [--cwd <path>]
|
|
10
|
+
agent-infra-internal platform-pr skip <task-ref> --agent <agent> [--dry-run] [--cwd <path>]
|
|
10
11
|
agent-infra-internal platform-pr sync <task-ref> --agent <agent> [--metadata] [--closing-issue] --result <pr_created|pr_reused|no_op> [--dry-run] [--cwd <path>]
|
|
11
12
|
agent-infra-internal platform-pr summary-context <task-ref> [--cwd <path>]
|
|
12
13
|
agent-infra-internal platform-pr summary-sync <task-ref> --agent <agent> --body-file <path|-> --result <pr_created|pr_reused|no_op> [--dry-run] [--cwd <path>]
|
|
@@ -58,7 +59,7 @@ function platformPr(args = []) {
|
|
|
58
59
|
return;
|
|
59
60
|
}
|
|
60
61
|
const operation = args[0];
|
|
61
|
-
if (!operation || !['inspect', 'resolve-external', 'create', 'bind', 'sync', 'summary-context', 'summary-sync'].includes(operation)) {
|
|
62
|
+
if (!operation || !['inspect', 'resolve-external', 'create', 'bind', 'skip', 'sync', 'summary-context', 'summary-sync'].includes(operation)) {
|
|
62
63
|
fail('a valid operation is required');
|
|
63
64
|
return;
|
|
64
65
|
}
|
|
@@ -79,6 +80,7 @@ function platformPr(args = []) {
|
|
|
79
80
|
'resolve-external': ['cwd', 'agent', 'pr', 'dryRun'],
|
|
80
81
|
create: ['cwd', 'agent', 'base', 'head', 'titleFile', 'bodyFile', 'draft', 'dryRun'],
|
|
81
82
|
bind: ['cwd', 'agent', 'pr', 'dryRun'],
|
|
83
|
+
skip: ['cwd', 'agent', 'dryRun'],
|
|
82
84
|
sync: ['cwd', 'agent', 'metadata', 'closingIssue', 'result', 'dryRun'],
|
|
83
85
|
'summary-context': ['cwd'],
|
|
84
86
|
'summary-sync': ['cwd', 'agent', 'bodyFile', 'result', 'dryRun']
|
|
@@ -106,6 +108,10 @@ function platformPr(args = []) {
|
|
|
106
108
|
return;
|
|
107
109
|
}
|
|
108
110
|
values.agent = agent;
|
|
111
|
+
if (operation === 'skip') {
|
|
112
|
+
finish(skipPlatformPullRequestFact(taskRef, { cwd, agent, dryRun: values.dryRun === true }));
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
109
115
|
const primaryResult = values.result === undefined ? undefined : values.result;
|
|
110
116
|
if (primaryResult !== undefined && !['pr_created', 'pr_reused', 'no_op'].includes(primaryResult)) {
|
|
111
117
|
fail('--result must be pr_created, pr_reused, or no_op');
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { normalizeAgentToken, AGENT_USAGE_HINT } from '../agent-clients/tokens.js';
|
|
3
|
+
import { deliverTaskBranch } from '../task/delivery.js';
|
|
4
|
+
const USAGE = `Usage: agent-infra-internal task-delivery <task-ref> deliver --agent <agent> [--remote <name>] [--base <branch>] [--dry-run] [--cwd <path>]\n`;
|
|
5
|
+
function taskDelivery(args = []) {
|
|
6
|
+
const taskRef = args[0];
|
|
7
|
+
const operation = args[1];
|
|
8
|
+
if (!taskRef || operation !== 'deliver') {
|
|
9
|
+
process.stdout.write(`${JSON.stringify({ status: 'failed', changed: false, error: { code: 'DELIVERY_PAYLOAD_INVALID', message: 'task ref and deliver operation are required' } })}\n`);
|
|
10
|
+
process.stderr.write(USAGE);
|
|
11
|
+
process.exitCode = 1;
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
let agent = '';
|
|
15
|
+
let remote;
|
|
16
|
+
let baseRef;
|
|
17
|
+
let cwd = process.cwd();
|
|
18
|
+
let dryRun = false;
|
|
19
|
+
for (let index = 2; index < args.length; index += 1) {
|
|
20
|
+
const flag = args[index];
|
|
21
|
+
if (flag === '--dry-run') {
|
|
22
|
+
dryRun = true;
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const value = args[++index];
|
|
26
|
+
if (value === undefined || value.startsWith('--')) {
|
|
27
|
+
process.stdout.write(`${JSON.stringify({ status: 'failed', changed: false, error: { code: 'DELIVERY_PAYLOAD_INVALID', message: `${flag} requires a value` } })}\n`);
|
|
28
|
+
process.exitCode = 1;
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (flag === '--agent')
|
|
32
|
+
agent = value;
|
|
33
|
+
else if (flag === '--remote')
|
|
34
|
+
remote = value;
|
|
35
|
+
else if (flag === '--base')
|
|
36
|
+
baseRef = value;
|
|
37
|
+
else if (flag === '--cwd')
|
|
38
|
+
cwd = path.resolve(value);
|
|
39
|
+
else {
|
|
40
|
+
process.stdout.write(`${JSON.stringify({ status: 'failed', changed: false, error: { code: 'DELIVERY_PAYLOAD_INVALID', message: `unknown option '${flag}'` } })}\n`);
|
|
41
|
+
process.exitCode = 1;
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const normalized = normalizeAgentToken(agent);
|
|
46
|
+
if (!normalized) {
|
|
47
|
+
process.stdout.write(`${JSON.stringify({ status: 'failed', changed: false, error: { code: 'DELIVERY_PAYLOAD_INVALID', message: `invalid --agent '${agent}': ${AGENT_USAGE_HINT}` } })}\n`);
|
|
48
|
+
process.exitCode = 1;
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const result = deliverTaskBranch(taskRef, { repoRoot: cwd, agent: normalized, remote, baseRef, dryRun });
|
|
52
|
+
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
53
|
+
if (result.status === 'failed')
|
|
54
|
+
process.exitCode = 1;
|
|
55
|
+
if (result.status === 'blocked')
|
|
56
|
+
process.exitCode = 2;
|
|
57
|
+
}
|
|
58
|
+
export { taskDelivery };
|
|
59
|
+
//# sourceMappingURL=task-delivery.js.map
|
|
@@ -6,8 +6,14 @@ import semver from 'semver';
|
|
|
6
6
|
const MINIMUM_GITHUB_CLI_VERSION = '2.72.0';
|
|
7
7
|
const GITHUB_CLI_MAX_BUFFER = 64 * 1024 * 1024;
|
|
8
8
|
const ERROR_DETAIL_LIMIT = 4096;
|
|
9
|
+
function redactDiagnostic(value) {
|
|
10
|
+
return value
|
|
11
|
+
.replace(/\b(?:gh[pousr]_[A-Za-z0-9_]+|github_pat_[A-Za-z0-9_]+)\b/g, '[REDACTED_TOKEN]')
|
|
12
|
+
.replace(/\b(bearer|token)\s+[A-Za-z0-9._~+\/-]+/gi, '$1 [REDACTED_TOKEN]')
|
|
13
|
+
.replace(/([?&](?:access_token|token|client_secret|password)=)[^&\s]+/gi, '$1[REDACTED]');
|
|
14
|
+
}
|
|
9
15
|
function boundedFailureDetail(result) {
|
|
10
|
-
const diagnostic = `${result.stderr}\n${result.error?.message || ''}
|
|
16
|
+
const diagnostic = redactDiagnostic(`${result.stderr}\n${result.error?.message || ''}`).trim() || redactDiagnostic(result.stdout.trim());
|
|
11
17
|
return diagnostic.length <= ERROR_DETAIL_LIMIT
|
|
12
18
|
? diagnostic
|
|
13
19
|
: `${diagnostic.slice(0, ERROR_DETAIL_LIMIT)}… [truncated]`;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
-
import {
|
|
2
|
+
import { parseTypedTaskFrontmatter } from '../task/frontmatter.js';
|
|
3
3
|
import { resolveTaskRef } from '../task/resolve-ref.js';
|
|
4
4
|
import { inspectPlatformRequiredChecks, registerPlatformCapabilities } from './adapters.js';
|
|
5
5
|
import { resolvePlatformContext } from './context.js';
|
|
6
6
|
import { createGitHubClient } from './github-client.js';
|
|
7
7
|
import { inspectPlatformPullRequest } from './pull-requests.js';
|
|
8
8
|
import { platformResult } from './types.js';
|
|
9
|
+
import { readPrDeliveryFact } from '../task/pr-delivery-fact.js';
|
|
9
10
|
function classifyRequiredChecks(required) {
|
|
10
11
|
if (required.length === 0)
|
|
11
12
|
return { state: 'no-required', required };
|
|
@@ -97,11 +98,13 @@ function resolvedTask(taskRef, options) {
|
|
|
97
98
|
const resolved = resolveTaskRef(taskRef, options.cwd ? { repoRoot: options.cwd } : {});
|
|
98
99
|
if (!resolved.ok)
|
|
99
100
|
return { ok: false, output: checksResult('failed', { error: { code: resolved.code, message: resolved.message, retryable: false } }) };
|
|
100
|
-
const frontmatter =
|
|
101
|
-
const
|
|
102
|
-
|
|
101
|
+
const frontmatter = parseTypedTaskFrontmatter(fs.readFileSync(resolved.taskMdPath, 'utf8'));
|
|
102
|
+
const fact = readPrDeliveryFact(frontmatter);
|
|
103
|
+
if (fact.status === 'invalid')
|
|
104
|
+
return { ok: false, output: checksResult('failed', { error: { code: 'PR_DELIVERY_FACT_INVALID', message: fact.error.message, retryable: false } }) };
|
|
105
|
+
const prNumber = fact.status === 'valid' && fact.fact.state === 'bound' ? fact.fact.identity.number : null;
|
|
103
106
|
if (!prNumber)
|
|
104
|
-
return { ok: false, output: checksResult('failed', { error: { code: 'PR_NOT_LINKED', message: 'Task has no
|
|
107
|
+
return { ok: false, output: checksResult('failed', { error: { code: fact.status === 'missing' ? 'PR_DELIVERY_FACT_MISSING' : 'PR_NOT_LINKED', message: 'Task has no verified bound pull request', retryable: false } }) };
|
|
105
108
|
const client = options.client || createGitHubClient();
|
|
106
109
|
const context = resolvePlatformContext({ cwd: resolved.repoRoot, client });
|
|
107
110
|
if (!context.platform.repository || !['no-op', 'degraded'].includes(context.status))
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import { execFileSync } from 'node:child_process';
|
|
3
3
|
import { enumerateArtifacts } from '../task/artifacts.js';
|
|
4
|
-
import {
|
|
4
|
+
import { parseTypedTaskFrontmatter } from '../task/frontmatter.js';
|
|
5
5
|
import { renderHumanOverrideAudit } from '../task/human-override.js';
|
|
6
6
|
import { resolveTaskRef } from '../task/resolve-ref.js';
|
|
7
7
|
import { resolvePlatformContext } from './context.js';
|
|
8
8
|
import { createGitHubClient } from './github-client.js';
|
|
9
9
|
import { listRemoteComments, normalizeCommentContent, writeComment } from './issue-comments.js';
|
|
10
10
|
import { platformResult } from './types.js';
|
|
11
|
+
import { readPrDeliveryFact } from '../task/pr-delivery-fact.js';
|
|
11
12
|
function warningResultForPrimary(primaryResult) {
|
|
12
13
|
if (primaryResult === 'pr_created')
|
|
13
14
|
return 'pr_created_with_warnings';
|
|
@@ -52,9 +53,9 @@ function summaryContext(taskRef, options = {}) {
|
|
|
52
53
|
const resolved = resolveTaskRef(taskRef, options.cwd ? { repoRoot: options.cwd } : {});
|
|
53
54
|
if (!resolved.ok)
|
|
54
55
|
return { ...platformResult('failed', { error: { code: resolved.code, message: resolved.message, retryable: false } }), task: { id: resolved.taskId, prNumber: null }, artifacts: [] };
|
|
55
|
-
const frontmatter =
|
|
56
|
-
const
|
|
57
|
-
const prNumber =
|
|
56
|
+
const frontmatter = parseTypedTaskFrontmatter(fs.readFileSync(resolved.taskMdPath, 'utf8'));
|
|
57
|
+
const fact = readPrDeliveryFact(frontmatter);
|
|
58
|
+
const prNumber = fact.status === 'valid' && fact.fact.state === 'bound' ? fact.fact.identity.number : null;
|
|
58
59
|
return { ...platformResult('no-op'), task: { id: resolved.taskId, prNumber }, artifacts: canonicalArtifacts(resolved.taskDir) };
|
|
59
60
|
}
|
|
60
61
|
function syncPullRequestSummary(taskRef, options) {
|
|
@@ -90,10 +91,13 @@ function syncPullRequestSummary(taskRef, options) {
|
|
|
90
91
|
const resolved = resolveTaskRef(taskRef, options.cwd ? { repoRoot: options.cwd } : {});
|
|
91
92
|
if (!resolved.ok)
|
|
92
93
|
return softenFailure(platformResult('failed', { error: { code: resolved.code, message: resolved.message, retryable: false } }));
|
|
93
|
-
const frontmatter =
|
|
94
|
-
const
|
|
95
|
-
if (
|
|
96
|
-
return softenFailure(platformResult('failed', { error: { code: '
|
|
94
|
+
const frontmatter = parseTypedTaskFrontmatter(fs.readFileSync(resolved.taskMdPath, 'utf8'));
|
|
95
|
+
const fact = readPrDeliveryFact(frontmatter);
|
|
96
|
+
if (fact.status === 'invalid')
|
|
97
|
+
return softenFailure(platformResult('failed', { error: { code: 'PR_DELIVERY_FACT_INVALID', message: fact.error.message, retryable: false } }));
|
|
98
|
+
const prNumber = fact.status === 'valid' && fact.fact.state === 'bound' ? fact.fact.identity.number : null;
|
|
99
|
+
if (!prNumber)
|
|
100
|
+
return softenFailure(platformResult('failed', { error: { code: fact.status === 'missing' ? 'PR_DELIVERY_FACT_MISSING' : 'PR_NOT_LINKED', message: 'Task has no verified bound pull request', retryable: false } }));
|
|
97
101
|
knownPrNumber = prNumber;
|
|
98
102
|
const client = options.client || createGitHubClient();
|
|
99
103
|
const context = resolvePlatformContext({ cwd: resolved.repoRoot, client });
|