@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.
Files changed (193) hide show
  1. package/README.md +6 -6
  2. package/README.zh-CN.md +6 -6
  3. package/dist/bin/internal-cli.js +5 -0
  4. package/dist/lib/agent-clients/adapters/codex-lifecycle/build-identity.js +71 -10
  5. package/dist/lib/defaults.json +4 -0
  6. package/dist/lib/git/workflow.js +43 -1
  7. package/dist/lib/init.js +1 -0
  8. package/dist/lib/internal/git-workflow.js +8 -1
  9. package/dist/lib/internal/platform-pr.js +8 -2
  10. package/dist/lib/internal/task-delivery.js +59 -0
  11. package/dist/lib/platform/github-client.js +7 -1
  12. package/dist/lib/platform/pr-checks.js +8 -5
  13. package/dist/lib/platform/pr-summary.js +12 -8
  14. package/dist/lib/platform/pull-requests.js +393 -91
  15. package/dist/lib/platform/verification-required.js +13 -2
  16. package/dist/lib/platform/verification-sync.js +9 -4
  17. package/dist/lib/pr-review/evidence-grading.js +12 -4
  18. package/dist/lib/sandbox/config.js +5 -0
  19. package/dist/lib/sandbox/control/lifecycle.js +29 -7
  20. package/dist/lib/server/process-state.js +2 -2
  21. package/dist/lib/task/artifact-lifecycle.js +2 -2
  22. package/dist/lib/task/commit-intent.js +100 -0
  23. package/dist/lib/task/commit-operation.js +195 -101
  24. package/dist/lib/task/create.js +33 -7
  25. package/dist/lib/task/decision-details.js +3 -48
  26. package/dist/lib/task/delivery-target.js +97 -0
  27. package/dist/lib/task/delivery.js +153 -0
  28. package/dist/lib/task/human-override.js +5 -2
  29. package/dist/lib/task/lifecycle.js +106 -9
  30. package/dist/lib/task/orchestration.js +55 -62
  31. package/dist/lib/task/pr-delivery-fact.js +182 -0
  32. package/dist/lib/task/review-finalization.js +4 -8
  33. package/dist/lib/task/review-fingerprint.js +8 -0
  34. package/dist/lib/task/verification-engine.js +48 -24
  35. package/dist/lib/task/verification-review.js +1 -1
  36. package/dist/lib/update.js +9 -0
  37. package/dist/lifecycle-build-manifest.json +3 -3
  38. package/lib/agent-clients/adapters/codex-lifecycle/build-identity.ts +105 -10
  39. package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +12 -1
  40. package/lib/defaults.json +4 -0
  41. package/lib/git/workflow.ts +38 -1
  42. package/lib/init.ts +3 -0
  43. package/lib/internal/git-workflow.ts +7 -1
  44. package/lib/internal/platform-pr.ts +8 -1
  45. package/lib/internal/task-delivery.ts +53 -0
  46. package/lib/platform/github-client.ts +8 -1
  47. package/lib/platform/pr-checks.ts +7 -5
  48. package/lib/platform/pr-summary.ts +10 -7
  49. package/lib/platform/pull-requests.ts +425 -87
  50. package/lib/platform/verification-required.ts +12 -2
  51. package/lib/platform/verification-sync.ts +9 -4
  52. package/lib/pr-review/evidence-grading.ts +7 -4
  53. package/lib/sandbox/config.ts +7 -0
  54. package/lib/sandbox/control/lifecycle.ts +30 -8
  55. package/lib/server/process-state.ts +2 -2
  56. package/lib/task/artifact-lifecycle.ts +2 -2
  57. package/lib/task/commit-intent.ts +137 -0
  58. package/lib/task/commit-operation.ts +174 -87
  59. package/lib/task/create.ts +34 -9
  60. package/lib/task/decision-details.ts +2 -62
  61. package/lib/task/delivery-target.ts +130 -0
  62. package/lib/task/delivery.ts +160 -0
  63. package/lib/task/human-override.ts +5 -2
  64. package/lib/task/lifecycle.ts +93 -4
  65. package/lib/task/orchestration.ts +62 -65
  66. package/lib/task/pr-delivery-fact.ts +254 -0
  67. package/lib/task/review-finalization.ts +4 -14
  68. package/lib/task/review-fingerprint.ts +10 -0
  69. package/lib/task/verification-engine.ts +45 -28
  70. package/lib/task/verification-review.ts +2 -0
  71. package/lib/update.ts +10 -0
  72. package/package.json +1 -1
  73. package/templates/.agents/rules/README.en.md +4 -2
  74. package/templates/.agents/rules/README.zh-CN.md +4 -2
  75. package/templates/.agents/rules/create-issue.en.md +11 -2
  76. package/templates/.agents/rules/create-issue.zh-CN.md +24 -2
  77. package/templates/.agents/rules/issue-pr-commands.en.md +4 -17
  78. package/templates/.agents/rules/issue-sync.en.md +26 -5
  79. package/templates/.agents/rules/issue-sync.zh-CN.md +62 -5
  80. package/templates/.agents/rules/label-milestone-setup.en.md +15 -2
  81. package/templates/.agents/rules/label-milestone-setup.zh-CN.md +15 -2
  82. package/templates/.agents/rules/local-artifact-repair.en.md +46 -0
  83. package/templates/.agents/rules/local-artifact-repair.zh-CN.md +46 -0
  84. package/templates/.agents/rules/milestone-inference.en.md +12 -2
  85. package/templates/.agents/rules/milestone-inference.zh-CN.md +25 -3
  86. package/templates/.agents/rules/pr-sync.en.md +22 -13
  87. package/templates/.agents/rules/pr-sync.zh-CN.md +22 -1
  88. package/templates/.agents/rules/release-commands.en.md +42 -3
  89. package/templates/.agents/rules/release-commands.zh-CN.md +42 -3
  90. package/templates/.agents/rules/security-alerts.en.md +17 -2
  91. package/templates/.agents/rules/security-alerts.zh-CN.md +17 -2
  92. package/templates/.agents/rules/sync-content-generation.en.md +8 -0
  93. package/templates/.agents/rules/sync-content-generation.zh-CN.md +8 -0
  94. package/templates/.agents/rules/task-management.en.md +1 -1
  95. package/templates/.agents/rules/task-management.zh-CN.md +1 -1
  96. package/templates/.agents/scripts/security-alerts.github.sh +151 -0
  97. package/templates/.agents/scripts/security-alerts.sh +31 -0
  98. package/templates/.agents/skills/analyze-task/SKILL.en.md +1 -0
  99. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +1 -0
  100. package/templates/.agents/skills/close-codescan/SKILL.en.md +2 -2
  101. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +2 -2
  102. package/templates/.agents/skills/close-dependabot/SKILL.en.md +2 -2
  103. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +2 -2
  104. package/templates/.agents/skills/code-task/SKILL.en.md +5 -2
  105. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +6 -3
  106. package/templates/.agents/skills/commit/SKILL.en.md +3 -3
  107. package/templates/.agents/skills/commit/SKILL.zh-CN.md +3 -3
  108. package/templates/.agents/skills/commit/config/verify.json +1 -1
  109. package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +3 -3
  110. package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +3 -3
  111. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +1 -1
  112. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +1 -1
  113. package/templates/.agents/skills/commit/reference/task-status-update.en.md +2 -2
  114. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +2 -2
  115. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +2 -1
  116. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +2 -1
  117. package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -1
  118. package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -1
  119. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +1 -1
  120. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +1 -1
  121. package/templates/.agents/skills/complete-task/SKILL.en.md +10 -10
  122. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +10 -10
  123. package/templates/.agents/skills/complete-task/reference/external-delivery.en.md +2 -2
  124. package/templates/.agents/skills/complete-task/reference/external-delivery.zh-CN.md +2 -2
  125. package/templates/.agents/skills/create-pr/SKILL.en.md +4 -4
  126. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +4 -4
  127. package/templates/.agents/skills/create-task/SKILL.en.md +1 -0
  128. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +1 -0
  129. package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
  130. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
  131. package/templates/.agents/skills/import-dependabot/SKILL.en.md +1 -1
  132. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
  133. package/templates/.agents/skills/init-labels/SKILL.en.md +9 -10
  134. package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +9 -10
  135. package/templates/.agents/skills/init-labels/scripts/init-labels.github.sh +57 -1
  136. package/templates/.agents/skills/init-labels/scripts/init-labels.sh +27 -1
  137. package/templates/.agents/skills/init-milestones/SKILL.en.md +3 -5
  138. package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +3 -5
  139. package/templates/.agents/skills/plan-task/SKILL.en.md +1 -0
  140. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +1 -0
  141. package/templates/.agents/skills/review-analysis/SKILL.en.md +4 -3
  142. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +4 -3
  143. package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +18 -0
  144. package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +18 -0
  145. package/templates/.agents/skills/review-code/SKILL.en.md +7 -6
  146. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +7 -6
  147. package/templates/.agents/skills/review-code/reference/output-templates.en.md +19 -1
  148. package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +19 -1
  149. package/templates/.agents/skills/review-code/reference/report-template.en.md +4 -2
  150. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +4 -2
  151. package/templates/.agents/skills/review-plan/SKILL.en.md +4 -3
  152. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +4 -3
  153. package/templates/.agents/skills/review-plan/reference/output-templates.en.md +18 -0
  154. package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +18 -0
  155. package/templates/.agents/skills/review-pr/SKILL.en.md +1 -0
  156. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +1 -0
  157. package/templates/.agents/skills/review-pr/reference/evidence-grading.en.md +2 -2
  158. package/templates/.agents/skills/review-pr/reference/evidence-grading.zh-CN.md +2 -2
  159. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +1 -0
  160. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +1 -0
  161. package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
  162. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
  163. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +4 -0
  164. package/templates/.agents/skills/watch-pr/SKILL.en.md +4 -4
  165. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +4 -4
  166. package/templates/.agents/templates/task.en.md +5 -1
  167. package/templates/.agents/templates/task.zh-CN.md +5 -1
  168. package/templates/.agents/workflows/bug-fix.en.yaml +9 -8
  169. package/templates/.agents/workflows/bug-fix.zh-CN.yaml +9 -8
  170. package/templates/.agents/workflows/feature-development.en.yaml +9 -8
  171. package/templates/.agents/workflows/feature-development.zh-CN.yaml +9 -8
  172. package/templates/.agents/workflows/refactoring.en.yaml +9 -8
  173. package/templates/.agents/workflows/refactoring.zh-CN.yaml +9 -8
  174. package/templates/.agents/rules/create-issue.github.en.md +0 -14
  175. package/templates/.agents/rules/create-issue.github.zh-CN.md +0 -27
  176. package/templates/.agents/rules/issue-pr-commands.github.en.md +0 -34
  177. package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +0 -49
  178. package/templates/.agents/rules/issue-sync.github.en.md +0 -40
  179. package/templates/.agents/rules/issue-sync.github.zh-CN.md +0 -76
  180. package/templates/.agents/rules/label-milestone-setup.github.en.md +0 -60
  181. package/templates/.agents/rules/label-milestone-setup.github.zh-CN.md +0 -60
  182. package/templates/.agents/rules/milestone-inference.github.en.md +0 -15
  183. package/templates/.agents/rules/milestone-inference.github.zh-CN.md +0 -27
  184. package/templates/.agents/rules/pr-checks-commands.github.en.md +0 -18
  185. package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +0 -34
  186. package/templates/.agents/rules/pr-sync.github.en.md +0 -43
  187. package/templates/.agents/rules/pr-sync.github.zh-CN.md +0 -69
  188. package/templates/.agents/rules/release-commands.github.en.md +0 -44
  189. package/templates/.agents/rules/release-commands.github.zh-CN.md +0 -44
  190. package/templates/.agents/rules/security-alerts.github.en.md +0 -43
  191. package/templates/.agents/rules/security-alerts.github.zh-CN.md +0 -43
  192. /package/templates/.agents/rules/{issue-fields.github.en.md → issue-fields.en.md} +0 -0
  193. /package/templates/.agents/rules/{issue-fields.github.zh-CN.md → issue-fields.zh-CN.md} +0 -0
package/lib/defaults.json CHANGED
@@ -48,6 +48,10 @@
48
48
  "task": {
49
49
  "shortIdLength": 2
50
50
  },
51
+ "delivery": {
52
+ "remote": "origin",
53
+ "baseRef": "main"
54
+ },
51
55
  "labels": {
52
56
  "in": {}
53
57
  },
@@ -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
 
5
6
  type CommandResult = { status: number | null; stdout: string; stderr: string };
@@ -105,6 +106,42 @@ function commitExplicitPaths(input: { cwd: string; paths: readonly string[]; mes
105
106
  return { status: 'applied' as const, changed: true, snapshot: after.snapshot, operations: [{ name: 'stage', status: 'applied' as const }, { name: 'commit', status: 'applied' as const }], error: null };
106
107
  }
107
108
 
109
+ function previewCommitTree(input: { cwd: string; paths: readonly string[]; expectedHead: string }) {
110
+ const invalid = validatePaths(input.paths);
111
+ if (invalid) return { status: 'failed' as const, tree: null, error: { code: 'GIT_COMMIT_INPUT_INVALID', message: invalid } };
112
+ const before = inspectGitWorkflow(input.cwd);
113
+ if (!before.snapshot) return { status: 'failed' as const, tree: null, error: { code: 'GIT_INSPECT_FAILED', message: 'Unable to inspect Git repository' } };
114
+ if (before.snapshot.head !== input.expectedHead) {
115
+ return { status: 'failed' as const, tree: null, error: { code: 'GIT_HEAD_MISMATCH', message: `Expected HEAD ${input.expectedHead}, received ${before.snapshot.head}` } };
116
+ }
117
+ const selected = new Set(input.paths);
118
+ const unrelatedStaged = before.snapshot.staged.filter((candidate) => !selected.has(candidate));
119
+ if (unrelatedStaged.length > 0) {
120
+ return { status: 'failed' as const, tree: null, error: { code: 'GIT_STAGED_SCOPE_MISMATCH', message: `Unrelated staged paths: ${unrelatedStaged.join(', ')}` } };
121
+ }
122
+ const temporaryDirectory = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-infra-preview-index-'));
123
+ const indexFile = path.join(temporaryDirectory, 'index');
124
+ const temporaryRunner: GitRunner = (args, cwd) => {
125
+ const result = spawnSync('git', [...args], {
126
+ cwd,
127
+ env: { ...process.env, GIT_INDEX_FILE: indexFile },
128
+ encoding: 'utf8'
129
+ });
130
+ return { status: result.status, stdout: result.stdout ?? '', stderr: result.stderr ?? '' };
131
+ };
132
+ try {
133
+ const read = run(temporaryRunner, input.cwd, ['read-tree', input.expectedHead]);
134
+ if (read.status !== 0) return { status: 'failed' as const, tree: null, error: { code: 'GIT_PREVIEW_FAILED', message: read.stderr.trim() || 'Unable to prepare a temporary Git index' } };
135
+ const stage = run(temporaryRunner, input.cwd, ['add', '-A', '--', ...input.paths]);
136
+ if (stage.status !== 0) return { status: 'failed' as const, tree: null, error: { code: 'GIT_PREVIEW_FAILED', message: stage.stderr.trim() || 'Unable to stage the requested paths in a temporary index' } };
137
+ const tree = value(temporaryRunner, input.cwd, ['write-tree']);
138
+ if (!tree) return { status: 'failed' as const, tree: null, error: { code: 'GIT_PREVIEW_FAILED', message: 'Unable to write the temporary Git tree' } };
139
+ return { status: 'planned' as const, tree, error: null };
140
+ } finally {
141
+ fs.rmSync(temporaryDirectory, { recursive: true, force: true });
142
+ }
143
+ }
144
+
108
145
  function pushGitRefs(input: { cwd: string; remote: string; refs: readonly string[]; expectedSha?: string }, runner: GitRunner = defaultRunner) {
109
146
  if (!input.remote || input.refs.length === 0) return { status: 'failed' as const, changed: false, snapshot: inspectGitWorkflow(input.cwd, runner).snapshot, operations: [], error: { code: 'GIT_PUSH_INPUT_INVALID', message: 'Remote and refs are required' } };
110
147
  const operations: GitOperation[] = [];
@@ -192,5 +229,5 @@ function pushRebasedBranch(input: PushRebasedInput, runner: GitRunner = defaultR
192
229
  return { status: 'applied' as const, changed: true, snapshot: inspectGitWorkflow(input.cwd, runner).snapshot, operations: [{ name: 'push-rebased', status: 'applied' as const, ref: input.branch }], error: null };
193
230
  }
194
231
 
195
- export { commitExplicitPaths, inspectGitWorkflow, pushGitRefs, pushRebasedBranch };
232
+ export { commitExplicitPaths, inspectGitWorkflow, previewCommitTree, pushGitRefs, pushRebasedBranch };
196
233
  export type { CommandResult, GitRunner, PushRebasedInput };
package/lib/init.ts CHANGED
@@ -32,6 +32,7 @@ type Defaults = {
32
32
  files: FileRegistry;
33
33
  sandbox: Record<string, unknown>;
34
34
  task: { shortIdLength: number };
35
+ delivery: { remote: string; baseRef: string };
35
36
  labels: Record<string, unknown>;
36
37
  };
37
38
 
@@ -43,6 +44,7 @@ type AgentConfig = {
43
44
  templateVersion: string;
44
45
  sandbox: Record<string, unknown>;
45
46
  task: { shortIdLength: number };
47
+ delivery: { remote: string; baseRef: string };
46
48
  labels: Record<string, unknown>;
47
49
  files: FileRegistry;
48
50
  agentClients: ReturnType<typeof serializeAgentClients>;
@@ -244,6 +246,7 @@ async function cmdInit(): Promise<void> {
244
246
  templateVersion: VERSION,
245
247
  sandbox: structuredClone(defaults.sandbox),
246
248
  task: structuredClone(defaults.task),
249
+ delivery: structuredClone(defaults.delivery),
247
250
  labels: structuredClone(defaults.labels),
248
251
  files: { managed: [], merged: [], ejected: [] },
249
252
  agentClients: serializeAgentClients(defaultState)
@@ -1,5 +1,5 @@
1
1
  import fs from 'node:fs';
2
- import { inspectGitWorkflow, pushRebasedBranch } from '../git/workflow.ts';
2
+ import { inspectGitWorkflow, previewCommitTree, pushRebasedBranch } from '../git/workflow.ts';
3
3
  import { compareReviewTrees, snapshotReview } from '../git/review-snapshot.ts';
4
4
  import { resolvePostReviewGlobs } from '../task/review-fingerprint.ts';
5
5
  import { executeCommitOperation } from '../task/commit-operation.ts';
@@ -26,6 +26,12 @@ function gitWorkflow(args: string[] = []): void {
26
26
  const inputIndex = rest.indexOf('--input');
27
27
  const input = inputIndex >= 0 && rest[inputIndex + 1] ? JSON.parse(fs.readFileSync(rest[inputIndex + 1]!, 'utf8')) : null;
28
28
  result = input ? pushRebasedBranch({ cwd: cwd ?? process.cwd(), ...input }) : { status: 'failed', changed: false, error: { code: 'GIT_INPUT_REQUIRED', message: '--input JSON file is required' } };
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' } };
29
35
  } else if (action === 'snapshot' || action === 'compare-trees') {
30
36
  const inputIndex = rest.indexOf('--input');
31
37
  const input = inputIndex >= 0 && rest[inputIndex + 1] ? JSON.parse(fs.readFileSync(rest[inputIndex + 1]!, 'utf8')) : null;
@@ -7,6 +7,7 @@ import {
7
7
  createPlatformPullRequest,
8
8
  inspectPlatformPullRequest,
9
9
  resolveExternalPullRequest,
10
+ skipPlatformPullRequestFact,
10
11
  syncPlatformPullRequest
11
12
  } from '../platform/pull-requests.ts';
12
13
  import type { PullRequestResult } from '../platform/pull-requests.ts';
@@ -17,6 +18,7 @@ const USAGE = `Usage: agent-infra-internal platform-pr inspect <task-ref> [--cwd
17
18
  agent-infra-internal platform-pr resolve-external <task-ref> --agent <agent> [--pr <N>] [--dry-run] [--cwd <path>]
18
19
  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>]
19
20
  agent-infra-internal platform-pr bind <task-ref> --pr <N> --agent <agent> [--dry-run] [--cwd <path>]
21
+ agent-infra-internal platform-pr skip <task-ref> --agent <agent> [--dry-run] [--cwd <path>]
20
22
  agent-infra-internal platform-pr sync <task-ref> --agent <agent> [--metadata] [--closing-issue] --result <pr_created|pr_reused|no_op> [--dry-run] [--cwd <path>]
21
23
  agent-infra-internal platform-pr summary-context <task-ref> [--cwd <path>]
22
24
  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>]
@@ -64,7 +66,7 @@ function readFile(value: string, cwd: string): string {
64
66
  function platformPr(args: string[] = []): void {
65
67
  if (args[0] === '--help' || args[0] === '-h') { process.stdout.write(USAGE); return; }
66
68
  const operation = args[0];
67
- if (!operation || !['inspect', 'resolve-external', 'create', 'bind', 'sync', 'summary-context', 'summary-sync'].includes(operation)) { fail('a valid operation is required'); return; }
69
+ if (!operation || !['inspect', 'resolve-external', 'create', 'bind', 'skip', 'sync', 'summary-context', 'summary-sync'].includes(operation)) { fail('a valid operation is required'); return; }
68
70
  const taskRef = args[1];
69
71
  if (!taskRef || taskRef.startsWith('--')) { fail(`${operation} requires a task ref`); return; }
70
72
  const parsed = parse(args, 2);
@@ -76,6 +78,7 @@ function platformPr(args: string[] = []): void {
76
78
  'resolve-external': ['cwd', 'agent', 'pr', 'dryRun'],
77
79
  create: ['cwd', 'agent', 'base', 'head', 'titleFile', 'bodyFile', 'draft', 'dryRun'],
78
80
  bind: ['cwd', 'agent', 'pr', 'dryRun'],
81
+ skip: ['cwd', 'agent', 'dryRun'],
79
82
  sync: ['cwd', 'agent', 'metadata', 'closingIssue', 'result', 'dryRun'],
80
83
  'summary-context': ['cwd'],
81
84
  'summary-sync': ['cwd', 'agent', 'bodyFile', 'result', 'dryRun']
@@ -88,6 +91,10 @@ function platformPr(args: string[] = []): void {
88
91
  const agent = normalizeAgentToken(values.agent);
89
92
  if (!agent) { fail(`invalid --agent '${values.agent}': ${AGENT_USAGE_HINT}`); return; }
90
93
  values.agent = agent;
94
+ if (operation === 'skip') {
95
+ finish(skipPlatformPullRequestFact(taskRef, { cwd, agent, dryRun: values.dryRun === true }));
96
+ return;
97
+ }
91
98
  const primaryResult = values.result === undefined ? undefined : values.result;
92
99
  if (primaryResult !== undefined && !['pr_created', 'pr_reused', 'no_op'].includes(primaryResult as string)) {
93
100
  fail('--result must be pr_created, pr_reused, or no_op');
@@ -0,0 +1,53 @@
1
+ import path from 'node:path';
2
+
3
+ import { normalizeAgentToken, AGENT_USAGE_HINT } from '../agent-clients/tokens.ts';
4
+ import { deliverTaskBranch } from '../task/delivery.ts';
5
+
6
+ const USAGE = `Usage: agent-infra-internal task-delivery <task-ref> deliver --agent <agent> [--remote <name>] [--base <branch>] [--dry-run] [--cwd <path>]\n`;
7
+
8
+ function taskDelivery(args: string[] = []): void {
9
+ const taskRef = args[0];
10
+ const operation = args[1];
11
+ if (!taskRef || operation !== 'deliver') {
12
+ process.stdout.write(`${JSON.stringify({ status: 'failed', changed: false, error: { code: 'DELIVERY_PAYLOAD_INVALID', message: 'task ref and deliver operation are required' } })}\n`);
13
+ process.stderr.write(USAGE);
14
+ process.exitCode = 1;
15
+ return;
16
+ }
17
+ let agent = '';
18
+ let remote: string | undefined;
19
+ let baseRef: string | undefined;
20
+ let cwd = process.cwd();
21
+ let dryRun = false;
22
+ for (let index = 2; index < args.length; index += 1) {
23
+ const flag = args[index];
24
+ if (flag === '--dry-run') { dryRun = true; continue; }
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') agent = value;
32
+ else if (flag === '--remote') remote = value;
33
+ else if (flag === '--base') baseRef = value;
34
+ else if (flag === '--cwd') cwd = path.resolve(value);
35
+ else {
36
+ process.stdout.write(`${JSON.stringify({ status: 'failed', changed: false, error: { code: 'DELIVERY_PAYLOAD_INVALID', message: `unknown option '${flag}'` } })}\n`);
37
+ process.exitCode = 1;
38
+ return;
39
+ }
40
+ }
41
+ const normalized = normalizeAgentToken(agent);
42
+ if (!normalized) {
43
+ process.stdout.write(`${JSON.stringify({ status: 'failed', changed: false, error: { code: 'DELIVERY_PAYLOAD_INVALID', message: `invalid --agent '${agent}': ${AGENT_USAGE_HINT}` } })}\n`);
44
+ process.exitCode = 1;
45
+ return;
46
+ }
47
+ const result = deliverTaskBranch(taskRef, { repoRoot: cwd, agent: normalized, remote, baseRef, dryRun });
48
+ process.stdout.write(`${JSON.stringify(result)}\n`);
49
+ if (result.status === 'failed') process.exitCode = 1;
50
+ if (result.status === 'blocked') process.exitCode = 2;
51
+ }
52
+
53
+ export { taskDelivery };
@@ -37,8 +37,15 @@ const MINIMUM_GITHUB_CLI_VERSION = '2.72.0';
37
37
  const GITHUB_CLI_MAX_BUFFER = 64 * 1024 * 1024;
38
38
  const ERROR_DETAIL_LIMIT = 4096;
39
39
 
40
+ function redactDiagnostic(value: string): string {
41
+ return value
42
+ .replace(/\b(?:gh[pousr]_[A-Za-z0-9_]+|github_pat_[A-Za-z0-9_]+)\b/g, '[REDACTED_TOKEN]')
43
+ .replace(/\b(bearer|token)\s+[A-Za-z0-9._~+\/-]+/gi, '$1 [REDACTED_TOKEN]')
44
+ .replace(/([?&](?:access_token|token|client_secret|password)=)[^&\s]+/gi, '$1[REDACTED]');
45
+ }
46
+
40
47
  function boundedFailureDetail(result: RunResult): string {
41
- const diagnostic = `${result.stderr}\n${result.error?.message || ''}`.trim() || result.stdout.trim();
48
+ const diagnostic = redactDiagnostic(`${result.stderr}\n${result.error?.message || ''}`).trim() || redactDiagnostic(result.stdout.trim());
42
49
  return diagnostic.length <= ERROR_DETAIL_LIMIT
43
50
  ? diagnostic
44
51
  : `${diagnostic.slice(0, ERROR_DETAIL_LIMIT)}… [truncated]`;
@@ -1,6 +1,6 @@
1
1
  import fs from 'node:fs';
2
2
 
3
- import { parseTaskFrontmatter } from '../task/frontmatter.ts';
3
+ import { parseTypedTaskFrontmatter } from '../task/frontmatter.ts';
4
4
  import { resolveTaskRef } from '../task/resolve-ref.ts';
5
5
  import {
6
6
  inspectPlatformRequiredChecks,
@@ -14,6 +14,7 @@ import { inspectPlatformPullRequest } from './pull-requests.ts';
14
14
  import { platformResult } from './types.ts';
15
15
  import type { PlatformResult } from './types.ts';
16
16
  import type { PullRequestSnapshot } from './pull-requests.ts';
17
+ import { readPrDeliveryFact } from '../task/pr-delivery-fact.ts';
17
18
 
18
19
  type CheckBucket = 'pass' | 'fail' | 'pending' | 'cancel';
19
20
  type CheckState = 'passed' | 'failed' | 'pending' | 'timed-out' | 'cancelled' | 'no-required';
@@ -121,10 +122,11 @@ registerPlatformCapabilities('github', {
121
122
  function resolvedTask(taskRef: string, options: InspectionOptions) {
122
123
  const resolved = resolveTaskRef(taskRef, options.cwd ? { repoRoot: options.cwd } : {});
123
124
  if (!resolved.ok) return { ok: false as const, output: checksResult('failed', { error: { code: resolved.code, message: resolved.message, retryable: false } }) };
124
- const frontmatter = parseTaskFrontmatter(fs.readFileSync(resolved.taskMdPath, 'utf8'));
125
- const pr = Number(frontmatter.pr_number);
126
- const prNumber = Number.isInteger(pr) && pr > 0 ? pr : null;
127
- if (!prNumber) return { ok: false as const, output: checksResult('failed', { error: { code: 'PR_NOT_LINKED', message: 'Task has no valid pr_number', retryable: false } }) };
125
+ const frontmatter = parseTypedTaskFrontmatter(fs.readFileSync(resolved.taskMdPath, 'utf8'));
126
+ const fact = readPrDeliveryFact(frontmatter);
127
+ if (fact.status === 'invalid') return { ok: false as const, output: checksResult('failed', { error: { code: 'PR_DELIVERY_FACT_INVALID', message: fact.error.message, retryable: false } }) };
128
+ const prNumber = fact.status === 'valid' && fact.fact.state === 'bound' ? fact.fact.identity.number : null;
129
+ if (!prNumber) return { ok: false as const, 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 } }) };
128
130
  const client = (options.client as GitHubClient | undefined) || createGitHubClient();
129
131
  const context = resolvePlatformContext({ cwd: resolved.repoRoot, client });
130
132
  if (!context.platform.repository || !['no-op', 'degraded'].includes(context.status)) return { ok: false as const, output: checksResult(context.status, { platform: context.platform, capabilities: context.capabilities, error: context.error }) };
@@ -2,7 +2,7 @@ import fs from 'node:fs';
2
2
  import { execFileSync } from 'node:child_process';
3
3
 
4
4
  import { enumerateArtifacts } from '../task/artifacts.ts';
5
- import { parseTaskFrontmatter } from '../task/frontmatter.ts';
5
+ import { parseTypedTaskFrontmatter } from '../task/frontmatter.ts';
6
6
  import { renderHumanOverrideAudit } from '../task/human-override.ts';
7
7
  import { resolveTaskRef } from '../task/resolve-ref.ts';
8
8
  import { resolvePlatformContext } from './context.ts';
@@ -12,6 +12,7 @@ import { listRemoteComments, normalizeCommentContent, writeComment } from './iss
12
12
  import { platformResult } from './types.ts';
13
13
  import type { PlatformResult } from './types.ts';
14
14
  import type { OperationWarning } from '../task/operation-outcome.ts';
15
+ import { readPrDeliveryFact } from '../task/pr-delivery-fact.ts';
15
16
 
16
17
  type SummaryComment = { id: number; body: string };
17
18
  type SummaryContextResult = PlatformResult & {
@@ -67,9 +68,9 @@ function canonicalArtifacts(taskDir: string) {
67
68
  function summaryContext(taskRef: string, options: { cwd?: string; client?: GitHubClient } = {}): SummaryContextResult {
68
69
  const resolved = resolveTaskRef(taskRef, options.cwd ? { repoRoot: options.cwd } : {});
69
70
  if (!resolved.ok) return { ...platformResult('failed', { error: { code: resolved.code, message: resolved.message, retryable: false } }), task: { id: resolved.taskId, prNumber: null }, artifacts: [] };
70
- const frontmatter = parseTaskFrontmatter(fs.readFileSync(resolved.taskMdPath, 'utf8'));
71
- const value = Number(frontmatter.pr_number);
72
- const prNumber = Number.isInteger(value) && value > 0 ? value : null;
71
+ const frontmatter = parseTypedTaskFrontmatter(fs.readFileSync(resolved.taskMdPath, 'utf8'));
72
+ const fact = readPrDeliveryFact(frontmatter);
73
+ const prNumber = fact.status === 'valid' && fact.fact.state === 'bound' ? fact.fact.identity.number : null;
73
74
  return { ...platformResult('no-op'), task: { id: resolved.taskId, prNumber }, artifacts: canonicalArtifacts(resolved.taskDir) };
74
75
  }
75
76
 
@@ -105,9 +106,11 @@ function syncPullRequestSummary(taskRef: string, options: { agent: string; body:
105
106
  };
106
107
  const resolved = resolveTaskRef(taskRef, options.cwd ? { repoRoot: options.cwd } : {});
107
108
  if (!resolved.ok) return softenFailure(platformResult('failed', { error: { code: resolved.code, message: resolved.message, retryable: false } }));
108
- const frontmatter = parseTaskFrontmatter(fs.readFileSync(resolved.taskMdPath, 'utf8'));
109
- const prNumber = Number(frontmatter.pr_number);
110
- if (!Number.isInteger(prNumber) || prNumber <= 0) return softenFailure(platformResult('failed', { error: { code: 'PR_NOT_LINKED', message: 'Task has no valid pr_number', retryable: false } }));
109
+ const frontmatter = parseTypedTaskFrontmatter(fs.readFileSync(resolved.taskMdPath, 'utf8'));
110
+ const fact = readPrDeliveryFact(frontmatter);
111
+ if (fact.status === 'invalid') return softenFailure(platformResult('failed', { error: { code: 'PR_DELIVERY_FACT_INVALID', message: fact.error.message, retryable: false } }));
112
+ const prNumber = fact.status === 'valid' && fact.fact.state === 'bound' ? fact.fact.identity.number : null;
113
+ if (!prNumber) 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 } }));
111
114
  knownPrNumber = prNumber;
112
115
  const client = options.client || createGitHubClient();
113
116
  const context = resolvePlatformContext({ cwd: resolved.repoRoot, client });