@fitlab-ai/agent-infra 0.9.3 → 0.9.5

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 (203) hide show
  1. package/README.md +3 -1
  2. package/README.zh-CN.md +3 -1
  3. package/bin/cli.ts +12 -0
  4. package/dist/bin/cli.js +14 -0
  5. package/dist/bin/internal-cli.js +144 -123
  6. package/dist/lib/agent-clients/adapter.js +94 -4
  7. package/dist/lib/{sandbox/credentials.js → agent-clients/adapters/claude-code-credentials.js} +4 -14
  8. package/dist/lib/agent-clients/adapters/claude-code-refresh.js +85 -0
  9. package/dist/lib/agent-clients/adapters/claude-code-sandbox.js +247 -0
  10. package/dist/lib/agent-clients/adapters/claude-code.js +17 -3
  11. package/dist/lib/agent-clients/adapters/codex-lifecycle/app-server.js +382 -0
  12. package/dist/lib/agent-clients/adapters/codex-lifecycle/evidence.js +163 -0
  13. package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +211 -0
  14. package/dist/lib/agent-clients/adapters/codex.js +2 -2
  15. package/dist/lib/agent-clients/adapters/opencode-sandbox.js +108 -0
  16. package/dist/lib/agent-clients/adapters/opencode.js +15 -3
  17. package/dist/lib/agent-clients/adapters/runtimes/claude-code.dockerfile +65 -0
  18. package/dist/lib/agent-clients/registry.js +9 -1
  19. package/dist/lib/git/worktree-identity.js +64 -0
  20. package/dist/lib/internal/codex-lifecycle.js +202 -0
  21. package/dist/lib/internal/sandbox-control.js +24 -0
  22. package/dist/lib/internal/task-activity.js +45 -13
  23. package/dist/lib/internal/task-create.js +48 -0
  24. package/dist/lib/internal/task-ledger.js +12 -3
  25. package/dist/lib/internal/task-lifecycle.js +19 -1
  26. package/dist/lib/internal/task-orchestration.js +170 -27
  27. package/dist/lib/platform/github-client.js +19 -2
  28. package/dist/lib/platform/pr-checks.js +1 -1
  29. package/dist/lib/platform/pull-requests.js +47 -1
  30. package/dist/lib/platform/releases.js +13 -5
  31. package/dist/lib/process-data/index.js +239 -0
  32. package/dist/lib/process-data/normalize.js +198 -0
  33. package/dist/lib/process-data/privacy.js +33 -0
  34. package/dist/lib/process-data/reconcile.js +95 -0
  35. package/dist/lib/process-data/repair.js +58 -0
  36. package/dist/lib/process-data/sources.js +345 -0
  37. package/dist/lib/process-data/store.js +282 -0
  38. package/dist/lib/process-data/types.js +2 -0
  39. package/dist/lib/run/index.js +4 -3
  40. package/dist/lib/run/tui.js +7 -8
  41. package/dist/lib/sandbox/agent-client-reconciler.js +26 -2
  42. package/dist/lib/sandbox/capture.js +7 -2
  43. package/dist/lib/sandbox/commands/create.js +110 -228
  44. package/dist/lib/sandbox/commands/enter.js +15 -47
  45. package/dist/lib/sandbox/commands/list-running.js +16 -6
  46. package/dist/lib/sandbox/commands/ls.js +10 -6
  47. package/dist/lib/sandbox/commands/rebuild.js +4 -3
  48. package/dist/lib/sandbox/commands/refresh.js +4 -84
  49. package/dist/lib/sandbox/commands/rm.js +24 -3
  50. package/dist/lib/sandbox/commands/show.js +12 -3
  51. package/dist/lib/sandbox/commands/start.js +7 -4
  52. package/dist/lib/sandbox/config.js +2 -0
  53. package/dist/lib/sandbox/constants.js +6 -0
  54. package/dist/lib/sandbox/control/client.js +58 -0
  55. package/dist/lib/sandbox/control/protocol.js +54 -0
  56. package/dist/lib/sandbox/control/server.js +144 -0
  57. package/dist/lib/sandbox/dockerfile.js +36 -13
  58. package/dist/lib/sandbox/mounts.js +17 -4
  59. package/dist/lib/sandbox/recovery.js +128 -5
  60. package/dist/lib/sandbox/redaction.js +12 -0
  61. package/dist/lib/sandbox/runtimes/base.dockerfile +24 -74
  62. package/dist/lib/sandbox/workspace-identity.js +95 -0
  63. package/dist/lib/sandbox/workspace-view.js +109 -0
  64. package/dist/lib/task/activity-intent.js +257 -51
  65. package/dist/lib/task/activity-log.js +32 -5
  66. package/dist/lib/task/commit-finalization.js +278 -0
  67. package/dist/lib/task/commit-intent.js +165 -0
  68. package/dist/lib/task/create-service.js +137 -0
  69. package/dist/lib/task/create.js +333 -0
  70. package/dist/lib/task/decision-intents.js +31 -17
  71. package/dist/lib/task/delegation-receipts.js +2 -2
  72. package/dist/lib/task/implementation-inputs.js +54 -7
  73. package/dist/lib/task/ledger-intents.js +35 -1
  74. package/dist/lib/task/orchestration.js +505 -34
  75. package/dist/lib/task/resolve-ref.js +41 -1
  76. package/dist/lib/task/review-fingerprint.js +4 -0
  77. package/dist/lib/task/workspace-snapshot.js +78 -3
  78. package/lib/agent-clients/adapter.ts +130 -6
  79. package/lib/{sandbox/credentials.ts → agent-clients/adapters/claude-code-credentials.ts} +3 -18
  80. package/lib/agent-clients/adapters/claude-code-refresh.ts +128 -0
  81. package/lib/agent-clients/adapters/claude-code-sandbox.ts +295 -0
  82. package/lib/agent-clients/adapters/claude-code.ts +21 -3
  83. package/lib/agent-clients/adapters/codex-lifecycle/app-server.ts +442 -0
  84. package/lib/agent-clients/adapters/codex-lifecycle/evidence.ts +307 -0
  85. package/lib/agent-clients/adapters/codex-lifecycle/store.ts +250 -0
  86. package/lib/agent-clients/adapters/codex.ts +2 -2
  87. package/lib/agent-clients/adapters/opencode-sandbox.ts +136 -0
  88. package/lib/agent-clients/adapters/opencode.ts +18 -3
  89. package/lib/agent-clients/adapters/runtimes/claude-code.dockerfile +65 -0
  90. package/lib/agent-clients/registry.ts +9 -1
  91. package/lib/git/worktree-identity.ts +86 -0
  92. package/lib/internal/codex-lifecycle.ts +204 -0
  93. package/lib/internal/sandbox-control.ts +24 -0
  94. package/lib/internal/task-activity.ts +50 -14
  95. package/lib/internal/task-create.ts +49 -0
  96. package/lib/internal/task-ledger.ts +12 -3
  97. package/lib/internal/task-lifecycle.ts +22 -1
  98. package/lib/internal/task-orchestration.ts +117 -21
  99. package/lib/platform/github-client.ts +20 -2
  100. package/lib/platform/pr-checks.ts +1 -1
  101. package/lib/platform/pull-requests.ts +49 -1
  102. package/lib/platform/releases.ts +16 -4
  103. package/lib/process-data/index.ts +224 -0
  104. package/lib/process-data/normalize.ts +202 -0
  105. package/lib/process-data/privacy.ts +41 -0
  106. package/lib/process-data/reconcile.ts +110 -0
  107. package/lib/process-data/repair.ts +64 -0
  108. package/lib/process-data/sources.ts +354 -0
  109. package/lib/process-data/store.ts +315 -0
  110. package/lib/process-data/types.ts +135 -0
  111. package/lib/run/index.ts +5 -3
  112. package/lib/run/tui.ts +11 -8
  113. package/lib/sandbox/agent-client-reconciler.ts +44 -2
  114. package/lib/sandbox/capture.ts +9 -2
  115. package/lib/sandbox/commands/create.ts +127 -260
  116. package/lib/sandbox/commands/enter.ts +13 -59
  117. package/lib/sandbox/commands/list-running.ts +23 -6
  118. package/lib/sandbox/commands/ls.ts +22 -6
  119. package/lib/sandbox/commands/rebuild.ts +4 -3
  120. package/lib/sandbox/commands/refresh.ts +4 -126
  121. package/lib/sandbox/commands/rm.ts +24 -3
  122. package/lib/sandbox/commands/show.ts +29 -3
  123. package/lib/sandbox/commands/start.ts +6 -4
  124. package/lib/sandbox/config.ts +4 -0
  125. package/lib/sandbox/constants.ts +8 -0
  126. package/lib/sandbox/control/client.ts +79 -0
  127. package/lib/sandbox/control/protocol.ts +110 -0
  128. package/lib/sandbox/control/server.ts +155 -0
  129. package/lib/sandbox/dockerfile.ts +66 -13
  130. package/lib/sandbox/mounts.ts +24 -4
  131. package/lib/sandbox/recovery.ts +163 -6
  132. package/lib/sandbox/redaction.ts +14 -0
  133. package/lib/sandbox/runtimes/base.dockerfile +24 -74
  134. package/lib/sandbox/tool-types.ts +16 -0
  135. package/lib/sandbox/workspace-identity.ts +123 -0
  136. package/lib/sandbox/workspace-view.ts +150 -0
  137. package/lib/task/activity-intent.ts +350 -61
  138. package/lib/task/activity-log.ts +46 -7
  139. package/lib/task/commit-finalization.ts +376 -0
  140. package/lib/task/commit-intent.ts +230 -0
  141. package/lib/task/create-service.ts +171 -0
  142. package/lib/task/create.ts +372 -0
  143. package/lib/task/decision-intents.ts +32 -12
  144. package/lib/task/delegation-receipts.ts +2 -2
  145. package/lib/task/implementation-inputs.ts +62 -8
  146. package/lib/task/ledger-intents.ts +43 -3
  147. package/lib/task/orchestration.ts +673 -41
  148. package/lib/task/resolve-ref.ts +46 -1
  149. package/lib/task/review-fingerprint.ts +9 -0
  150. package/lib/task/workspace-snapshot.ts +98 -4
  151. package/package.json +7 -7
  152. package/templates/.agents/hooks/lifecycle-delegation.js +47 -3
  153. package/templates/.agents/rules/README.en.md +1 -1
  154. package/templates/.agents/rules/README.zh-CN.md +1 -1
  155. package/templates/.agents/rules/human-decision-context.en.md +11 -2
  156. package/templates/.agents/rules/human-decision-context.zh-CN.md +11 -2
  157. package/templates/.agents/rules/pr-checks-commands.en.md +1 -1
  158. package/templates/.agents/rules/pr-checks-commands.github.en.md +1 -1
  159. package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +2 -2
  160. package/templates/.agents/rules/pr-checks-commands.zh-CN.md +1 -1
  161. package/templates/.agents/rules/review-handshake.zh-CN.md +1 -1
  162. package/templates/.agents/rules/task-management.en.md +3 -0
  163. package/templates/.agents/rules/task-management.zh-CN.md +3 -0
  164. package/templates/.agents/skills/code-task/SKILL.en.md +1 -1
  165. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +1 -1
  166. package/templates/.agents/skills/commit/SKILL.en.md +21 -17
  167. package/templates/.agents/skills/commit/SKILL.zh-CN.md +28 -16
  168. package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +50 -0
  169. package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +56 -0
  170. package/templates/.agents/skills/commit/reference/task-status-update.en.md +4 -4
  171. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +4 -4
  172. package/templates/.agents/skills/complete-task/SKILL.en.md +1 -1
  173. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +1 -1
  174. package/templates/.agents/skills/create-pr/SKILL.en.md +4 -4
  175. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +4 -4
  176. package/templates/.agents/skills/create-task/SKILL.en.md +26 -43
  177. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +26 -43
  178. package/templates/.agents/skills/create-task/reference/context-capture.en.md +34 -0
  179. package/templates/.agents/skills/create-task/reference/context-capture.zh-CN.md +34 -0
  180. package/templates/.agents/skills/review-code/SKILL.en.md +2 -2
  181. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +2 -2
  182. package/templates/.agents/skills/review-code/reference/output-templates.en.md +1 -1
  183. package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +1 -1
  184. package/templates/.agents/skills/review-pr/SKILL.en.md +36 -8
  185. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +36 -8
  186. package/templates/.agents/skills/review-pr/reference/report-template.en.md +1 -1
  187. package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +1 -1
  188. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +67 -50
  189. package/templates/.agents/skills/watch-pr/SKILL.en.md +4 -4
  190. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +4 -4
  191. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +2 -2
  192. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +2 -2
  193. package/templates/.agents/templates/task.en.md +1 -1
  194. package/templates/.agents/templates/task.zh-CN.md +1 -1
  195. package/templates/.claude/commands/watch-pr.en.md +1 -1
  196. package/templates/.claude/commands/watch-pr.zh-CN.md +1 -1
  197. package/templates/.claude/rules/tool-preferences.en.md +20 -0
  198. package/templates/.claude/rules/tool-preferences.zh-CN.md +20 -0
  199. package/templates/.codex/hooks.json +50 -0
  200. package/templates/.opencode/commands/watch-pr.en.md +1 -1
  201. package/templates/.opencode/commands/watch-pr.zh-CN.md +1 -1
  202. package/templates/.gemini/commands/_project_/review-pr.en.toml +0 -10
  203. package/templates/.gemini/commands/_project_/review-pr.zh-CN.toml +0 -10
@@ -1,7 +1,7 @@
1
1
  import { normalizeAgentToken, AGENT_USAGE_HINT } from '../agent-clients/tokens.js';
2
- import { activateMatchingOrchestrationDelegation, activateOrchestrationDelegation, advanceOrchestration, beginOrResumeOrchestration, completeCommitOrchestrationStage, pauseOrchestration, prepareOrchestrationDelegation, routeOrchestration, sealMatchingOrchestrationDelegation, sealOrchestrationDelegation, statusOrchestration } from '../task/orchestration.js';
2
+ import { abortCommitIntent, activateMatchingOrchestrationDelegation, activateOrchestrationDelegation, advanceOrchestration, beginCommitIntent, beginOrResumeOrchestration, checkpointCommitIntent, completeCommitIntent, pauseOrchestration, prepareOrchestrationDelegation, recoverCommitIntent, routeOrchestration, sealMatchingOrchestrationDelegation, sealOrchestrationDelegation, startCommitAttempt, statusCommitIntent, statusOrchestration, terminateCommitAttempt } from '../task/orchestration.js';
3
3
  import { isAgentClientId } from '../agent-clients/types.js';
4
- const USAGE = 'Usage: agent-infra-internal task-orchestration <task-ref|auto> <begin-or-resume|route|prepare|hook-start|stage-completed|hook-stop|advance|pause|status> [options]\n';
4
+ const USAGE = 'Usage: agent-infra-internal task-orchestration <task-ref|auto> <begin-or-resume|route|prepare|hook-start|hook-stop|advance|pause|status|commit-start|commit-begin|commit-checkpoint|commit-complete|commit-recover|commit-abort|commit-terminate|commit-status> [options]\n';
5
5
  function usageFailure(message) {
6
6
  process.stdout.write(`${JSON.stringify({
7
7
  status: 'failed', changed: false,
@@ -20,21 +20,36 @@ function taskOrchestration(args = []) {
20
20
  return;
21
21
  }
22
22
  const [taskRef, intent] = args;
23
- if (!['begin-or-resume', 'route', 'prepare', 'hook-start', 'stage-completed', 'hook-stop', 'advance', 'pause', 'status'].includes(intent)) {
23
+ if (![
24
+ 'begin-or-resume', 'route', 'prepare', 'hook-start', 'hook-stop', 'advance', 'pause', 'status',
25
+ 'commit-start', 'commit-begin', 'commit-checkpoint', 'commit-complete', 'commit-recover', 'commit-abort', 'commit-terminate', 'commit-status'
26
+ ].includes(intent)) {
24
27
  usageFailure(`unknown intent '${intent}'`);
25
28
  return;
26
29
  }
27
30
  const values = {};
28
31
  const seen = new Set();
32
+ let orchestrated = false;
29
33
  for (let index = 2; index < args.length; index += 1) {
30
34
  const flag = args[index];
35
+ if (flag === '--orchestrated') {
36
+ if (seen.has(flag)) {
37
+ usageFailure(`duplicate option '${flag}'`);
38
+ return;
39
+ }
40
+ seen.add(flag);
41
+ orchestrated = true;
42
+ continue;
43
+ }
31
44
  if (![
32
45
  '--max-steps', '--executor-model', '--executor-reasoning-effort',
33
46
  '--reviewer-model', '--reviewer-reasoning-effort',
34
47
  '--client', '--requested-model', '--requested-reasoning-effort', '--parent-id', '--before-fingerprint',
35
48
  '--native-agent', '--child-id', '--spawn-mode', '--actual-model', '--actual-reasoning-effort',
36
49
  '--model-fallback-reason', '--reasoning-effort-fallback-reason',
37
- '--exit-code', '--after-fingerprint', '--changed-paths', '--code', '--message', '--recoverable', '--agent'
50
+ '--exit-code', '--after-fingerprint', '--changed-paths', '--code', '--message', '--recoverable', '--agent',
51
+ '--baseline-head', '--token', '--kind', '--head', '--remote', '--ref', '--expected-head',
52
+ '--attempt', '--git-worktree-root'
38
53
  ].includes(flag)) {
39
54
  usageFailure(`unknown option '${flag}'`);
40
55
  return;
@@ -51,13 +66,153 @@ function taskOrchestration(args = []) {
51
66
  }
52
67
  values[flag] = value;
53
68
  }
69
+ const commitIntentFlags = {
70
+ 'commit-start': ['--agent', '--git-worktree-root'],
71
+ 'commit-begin': ['--agent', '--baseline-head', '--attempt', '--orchestrated', '--git-worktree-root'],
72
+ 'commit-checkpoint': ['--token', '--kind', '--head', '--remote', '--ref', '--git-worktree-root'],
73
+ 'commit-complete': ['--token', '--agent', '--git-worktree-root'],
74
+ 'commit-recover': ['--agent', '--git-worktree-root'],
75
+ 'commit-abort': ['--token', '--expected-head', '--git-worktree-root'],
76
+ 'commit-terminate': ['--attempt', '--agent', '--code', '--git-worktree-root'],
77
+ 'commit-status': ['--git-worktree-root']
78
+ };
79
+ if (intent in commitIntentFlags) {
80
+ const allowed = commitIntentFlags[intent];
81
+ const invalid = [...seen].find((flag) => !allowed.includes(flag));
82
+ if (invalid) {
83
+ usageFailure(`intent '${intent}' does not accept '${invalid}'`);
84
+ return;
85
+ }
86
+ }
87
+ else {
88
+ const commitOnly = [...seen].find((flag) => [
89
+ '--orchestrated', '--baseline-head', '--attempt', '--token', '--kind', '--head', '--remote', '--ref', '--expected-head'
90
+ ].includes(flag));
91
+ if (commitOnly) {
92
+ usageFailure(`intent '${intent}' does not accept '${commitOnly}'`);
93
+ return;
94
+ }
95
+ }
54
96
  const requireValues = (flags) => flags.find((flag) => values[flag] === undefined);
97
+ const coreOptions = values['--git-worktree-root'] === undefined
98
+ ? {}
99
+ : { gitWorktreeRoot: values['--git-worktree-root'] };
55
100
  if (values['--client'] !== undefined && !isAgentClientId(values['--client'])) {
56
101
  usageFailure(`unknown client '${values['--client']}'`);
57
102
  return;
58
103
  }
59
104
  let result;
60
- if (intent === 'begin-or-resume') {
105
+ if (intent === 'commit-start') {
106
+ const missing = requireValues(['--agent']);
107
+ if (missing) {
108
+ usageFailure(`intent 'commit-start' requires '${missing}'`);
109
+ return;
110
+ }
111
+ const agent = normalizeAgentToken(values['--agent']);
112
+ if (!agent) {
113
+ usageFailure(`invalid --agent '${values['--agent']}': ${AGENT_USAGE_HINT}`);
114
+ return;
115
+ }
116
+ result = startCommitAttempt(taskRef, { agent }, coreOptions);
117
+ }
118
+ else if (intent === 'commit-begin') {
119
+ const missing = requireValues(['--agent', '--baseline-head', '--attempt']);
120
+ if (missing) {
121
+ usageFailure(`intent 'commit-begin' requires '${missing}'`);
122
+ return;
123
+ }
124
+ const agent = normalizeAgentToken(values['--agent']);
125
+ if (!agent) {
126
+ usageFailure(`invalid --agent '${values['--agent']}': ${AGENT_USAGE_HINT}`);
127
+ return;
128
+ }
129
+ result = beginCommitIntent(taskRef, {
130
+ agent, orchestrated, baselineHead: values['--baseline-head'], attempt: values['--attempt']
131
+ }, coreOptions);
132
+ }
133
+ else if (intent === 'commit-checkpoint') {
134
+ const missing = requireValues(['--token', '--kind', '--head']);
135
+ if (missing) {
136
+ usageFailure(`intent 'commit-checkpoint' requires '${missing}'`);
137
+ return;
138
+ }
139
+ if (!['committed', 'pushed'].includes(values['--kind'])) {
140
+ usageFailure('--kind must be committed or pushed');
141
+ return;
142
+ }
143
+ if (values['--kind'] === 'pushed') {
144
+ const pushedMissing = requireValues(['--remote', '--ref']);
145
+ if (pushedMissing) {
146
+ usageFailure(`pushed checkpoint requires '${pushedMissing}'`);
147
+ return;
148
+ }
149
+ }
150
+ else if (values['--remote'] !== undefined || values['--ref'] !== undefined) {
151
+ usageFailure('committed checkpoint does not accept --remote or --ref');
152
+ return;
153
+ }
154
+ result = checkpointCommitIntent(taskRef, {
155
+ token: values['--token'], kind: values['--kind'],
156
+ head: values['--head'], remote: values['--remote'], ref: values['--ref']
157
+ }, coreOptions);
158
+ }
159
+ else if (intent === 'commit-complete') {
160
+ const missing = requireValues(['--token', '--agent']);
161
+ if (missing) {
162
+ usageFailure(`intent 'commit-complete' requires '${missing}'`);
163
+ return;
164
+ }
165
+ const agent = normalizeAgentToken(values['--agent']);
166
+ if (!agent) {
167
+ usageFailure(`invalid --agent '${values['--agent']}': ${AGENT_USAGE_HINT}`);
168
+ return;
169
+ }
170
+ result = completeCommitIntent(taskRef, { token: values['--token'], agent }, coreOptions);
171
+ }
172
+ else if (intent === 'commit-recover') {
173
+ const missing = requireValues(['--agent']);
174
+ if (missing) {
175
+ usageFailure(`intent 'commit-recover' requires '${missing}'`);
176
+ return;
177
+ }
178
+ const agent = normalizeAgentToken(values['--agent']);
179
+ if (!agent) {
180
+ usageFailure(`invalid --agent '${values['--agent']}': ${AGENT_USAGE_HINT}`);
181
+ return;
182
+ }
183
+ result = recoverCommitIntent(taskRef, { agent }, coreOptions);
184
+ }
185
+ else if (intent === 'commit-abort') {
186
+ const missing = requireValues(['--token', '--expected-head']);
187
+ if (missing) {
188
+ usageFailure(`intent 'commit-abort' requires '${missing}'`);
189
+ return;
190
+ }
191
+ result = abortCommitIntent(taskRef, { token: values['--token'], expectedHead: values['--expected-head'] }, coreOptions);
192
+ }
193
+ else if (intent === 'commit-terminate') {
194
+ const missing = requireValues(['--attempt', '--agent', '--code']);
195
+ if (missing) {
196
+ usageFailure(`intent 'commit-terminate' requires '${missing}'`);
197
+ return;
198
+ }
199
+ const agent = normalizeAgentToken(values['--agent']);
200
+ if (!agent) {
201
+ usageFailure(`invalid --agent '${values['--agent']}': ${AGENT_USAGE_HINT}`);
202
+ return;
203
+ }
204
+ if (!/^[A-Z][A-Z0-9_]{2,63}$/.test(values['--code'])) {
205
+ usageFailure('--code must be a stable uppercase identifier');
206
+ return;
207
+ }
208
+ result = terminateCommitAttempt(taskRef, {
209
+ attempt: values['--attempt'], agent, code: values['--code']
210
+ }, coreOptions);
211
+ }
212
+ else if (intent === 'commit-status') {
213
+ result = statusCommitIntent(taskRef, coreOptions);
214
+ }
215
+ else if (intent === 'begin-or-resume') {
61
216
  const missing = requireValues(['--client']);
62
217
  if (missing) {
63
218
  usageFailure(`intent 'begin-or-resume' requires '${missing}'`);
@@ -78,6 +233,7 @@ function taskOrchestration(args = []) {
78
233
  return;
79
234
  }
80
235
  result = beginOrResumeOrchestration(taskRef, {
236
+ ...coreOptions,
81
237
  maxSteps,
82
238
  client: values['--client'],
83
239
  modelPolicy: hasAnyPolicy ? {
@@ -93,10 +249,10 @@ function taskOrchestration(args = []) {
93
249
  });
94
250
  }
95
251
  else if (intent === 'route') {
96
- result = routeOrchestration(taskRef);
252
+ result = routeOrchestration(taskRef, coreOptions);
97
253
  }
98
254
  else if (intent === 'status') {
99
- result = statusOrchestration(taskRef);
255
+ result = statusOrchestration(taskRef, coreOptions);
100
256
  }
101
257
  else if (intent === 'prepare') {
102
258
  const missing = requireValues(['--client']);
@@ -108,7 +264,7 @@ function taskOrchestration(args = []) {
108
264
  client: values['--client'],
109
265
  requestedModel: values['--requested-model'],
110
266
  requestedReasoningEffort: values['--requested-reasoning-effort']
111
- });
267
+ }, coreOptions);
112
268
  }
113
269
  else if (intent === 'hook-start') {
114
270
  const missing = requireValues([
@@ -128,8 +284,8 @@ function taskOrchestration(args = []) {
128
284
  reasoningEffortFallbackReason: values['--reasoning-effort-fallback-reason']
129
285
  };
130
286
  result = taskRef === 'auto'
131
- ? activateMatchingOrchestrationDelegation(values['--client'], event)
132
- : activateOrchestrationDelegation(taskRef, event);
287
+ ? activateMatchingOrchestrationDelegation(values['--client'], event, coreOptions)
288
+ : activateOrchestrationDelegation(taskRef, event, coreOptions);
133
289
  }
134
290
  else if (intent === 'hook-stop') {
135
291
  if (taskRef === 'auto') {
@@ -140,7 +296,7 @@ function taskOrchestration(args = []) {
140
296
  }
141
297
  result = sealMatchingOrchestrationDelegation(values['--client'], {
142
298
  nativeAgent: values['--native-agent'], childId: values['--child-id']
143
- });
299
+ }, coreOptions);
144
300
  }
145
301
  else {
146
302
  const missing = requireValues(['--child-id', '--exit-code', '--after-fingerprint']);
@@ -157,24 +313,11 @@ function taskOrchestration(args = []) {
157
313
  childId: values['--child-id'], exitCode,
158
314
  afterFingerprint: values['--after-fingerprint'],
159
315
  changedPaths: values['--changed-paths'] ? values['--changed-paths'].split(',').filter(Boolean) : []
160
- });
161
- }
162
- }
163
- else if (intent === 'stage-completed') {
164
- const missing = requireValues(['--agent']);
165
- if (missing) {
166
- usageFailure(`intent 'stage-completed' requires '${missing}'`);
167
- return;
168
- }
169
- const agent = normalizeAgentToken(values['--agent']);
170
- if (!agent) {
171
- usageFailure(`invalid --agent '${values['--agent']}': ${AGENT_USAGE_HINT}`);
172
- return;
316
+ }, coreOptions);
173
317
  }
174
- result = completeCommitOrchestrationStage(taskRef, agent);
175
318
  }
176
319
  else if (intent === 'advance') {
177
- result = advanceOrchestration(taskRef);
320
+ result = advanceOrchestration(taskRef, coreOptions);
178
321
  }
179
322
  else {
180
323
  const missing = requireValues(['--code', '--message', '--recoverable']);
@@ -186,7 +329,7 @@ function taskOrchestration(args = []) {
186
329
  usageFailure('--recoverable must be true or false');
187
330
  return;
188
331
  }
189
- result = pauseOrchestration(taskRef, values['--code'], values['--message'], values['--recoverable'] === 'true');
332
+ result = pauseOrchestration(taskRef, values['--code'], values['--message'], values['--recoverable'] === 'true', coreOptions);
190
333
  }
191
334
  process.stdout.write(`${JSON.stringify(result)}\n`);
192
335
  if (result.status === 'failed')
@@ -2,6 +2,14 @@ import process from 'node:process';
2
2
  import spawn from 'cross-spawn';
3
3
  import semver from 'semver';
4
4
  const MINIMUM_GITHUB_CLI_VERSION = '2.16.0';
5
+ const GITHUB_CLI_MAX_BUFFER = 64 * 1024 * 1024;
6
+ const ERROR_DETAIL_LIMIT = 4096;
7
+ function boundedFailureDetail(result) {
8
+ const diagnostic = `${result.stderr}\n${result.error?.message || ''}`.trim() || result.stdout.trim();
9
+ return diagnostic.length <= ERROR_DETAIL_LIMIT
10
+ ? diagnostic
11
+ : `${diagnostic.slice(0, ERROR_DETAIL_LIMIT)}… [truncated]`;
12
+ }
5
13
  function defaultRunner(args, options) {
6
14
  const command = process.env.AGENT_INFRA_GH_BIN || 'gh';
7
15
  let prefix = [];
@@ -16,6 +24,7 @@ function defaultRunner(args, options) {
16
24
  encoding: 'utf8',
17
25
  env: process.env,
18
26
  input: options.input,
27
+ maxBuffer: GITHUB_CLI_MAX_BUFFER,
19
28
  shell: false
20
29
  });
21
30
  return {
@@ -37,7 +46,15 @@ function defaultSleep(delayMs) {
37
46
  Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, delayMs);
38
47
  }
39
48
  function classifyGitHubFailure(result) {
40
- const detail = `${result.stderr}\n${result.stdout}\n${result.error?.message || ''}`.trim();
49
+ const errorCode = result.error && 'code' in result.error ? result.error.code : undefined;
50
+ if (errorCode === 'ENOBUFS') {
51
+ return {
52
+ code: 'PLATFORM_OUTPUT_TOO_LARGE',
53
+ message: 'GitHub CLI output exceeded the configured limit',
54
+ retryable: false
55
+ };
56
+ }
57
+ const detail = boundedFailureDetail(result);
41
58
  const lower = detail.toLowerCase();
42
59
  if (/\b401\b|bad credentials|authentication required|not logged into/.test(lower)) {
43
60
  return { code: 'AUTH_REQUIRED', message: detail || 'GitHub authentication is required', retryable: false };
@@ -54,7 +71,7 @@ function classifyGitHubFailure(result) {
54
71
  if (/\b422\b|validation failed/.test(lower)) {
55
72
  return { code: 'PLATFORM_REQUEST_INVALID', message: detail || 'GitHub rejected the request', retryable: false };
56
73
  }
57
- if (result.error && 'code' in result.error && result.error.code === 'ENOENT') {
74
+ if (errorCode === 'ENOENT') {
58
75
  return { code: 'PLATFORM_DEPENDENCY_MISSING', message: detail || 'GitHub CLI is unavailable', retryable: false };
59
76
  }
60
77
  return { code: 'PLATFORM_REQUEST_FAILED', message: detail || 'GitHub request failed', retryable: false };
@@ -85,7 +85,7 @@ registerPlatformCapabilities('github', {
85
85
  inspectRequiredChecks({ client, repository, number, cwd }) {
86
86
  const github = client || createGitHubClient();
87
87
  const inspected = github.json([
88
- 'pr', 'checks', String(number), '--repo', repository, '--required',
88
+ 'pr', 'checks', String(number), '--repo', repository,
89
89
  '--json', 'name,state,bucket,link,workflow,startedAt,completedAt'
90
90
  ], { cwd });
91
91
  return inspected.ok
@@ -11,6 +11,8 @@ import { inspectPlatformIssue } from './issues.js';
11
11
  import { planPullRequestMetadata } from './pull-request-metadata.js';
12
12
  import { platformResult } from './types.js';
13
13
  import { inspectCompletionArtifacts } from '../task/finalization-artifacts.js';
14
+ import { inspectCreatePrCommitGate } from '../task/commit-finalization.js';
15
+ import { TaskExecutionLockError, withTaskExecutionLock } from '../task/task-execution-lock.js';
14
16
  function result(status, taskId, issueNumber, prNumber, overrides = {}) {
15
17
  return {
16
18
  ...platformResult(status),
@@ -612,7 +614,7 @@ function resolveExternalPullRequest(taskRef, options) {
612
614
  error: null
613
615
  }), { mode: 'external', authorization: selected.source, candidates: selected.candidates, eligible: selected.eligible, selected: selected.selected });
614
616
  }
615
- function createPlatformPullRequest(taskRef, options) {
617
+ function createPlatformPullRequestUnlocked(taskRef, options) {
616
618
  const base = resolvedContext(taskRef, options);
617
619
  if (!base.ok)
618
620
  return base.output;
@@ -622,6 +624,17 @@ function createPlatformPullRequest(taskRef, options) {
622
624
  });
623
625
  if (base.prNumber)
624
626
  return inspectPlatformPullRequest(taskRef, options);
627
+ const gate = inspectCreatePrCommitGate(base.resolved.taskDir, base.resolved.repoRoot, base.resolved.taskId);
628
+ if (!gate.allowed)
629
+ return result('blocked', base.resolved.taskId, base.issueNumber, null, {
630
+ platform: base.context.platform,
631
+ capabilities: base.context.capabilities,
632
+ error: {
633
+ code: gate.code,
634
+ message: `${gate.message}; action=${gate.action}`,
635
+ retryable: gate.action === 'rerun-commit' || gate.action === 'rerun-review-code'
636
+ }
637
+ });
625
638
  const located = locatePullRequest(base, options.head, options.base);
626
639
  if (!located.ok && located.error.code === 'PR_IDENTITY_AMBIGUOUS')
627
640
  return result('failed', base.resolved.taskId, base.issueNumber, null, {
@@ -689,6 +702,39 @@ function createPlatformPullRequest(taskRef, options) {
689
702
  operations: [{ name: created ? 'pr:create' : 'pr:reuse', status: created ? 'applied' : 'no-op', reasonCode: null }, { name: 'task:bind-pr', status: 'applied', reasonCode: null }], error: null
690
703
  });
691
704
  }
705
+ function createPlatformPullRequest(taskRef, options) {
706
+ const base = resolvedContext(taskRef, options);
707
+ if (!base.ok)
708
+ return base.output;
709
+ if (!options.base || !options.head || !options.title.trim() || !options.body.trim()) {
710
+ return result('failed', base.resolved.taskId, base.issueNumber, base.prNumber, {
711
+ error: { code: 'PR_PAYLOAD_INVALID', message: 'base, head, title and body are required', retryable: false }
712
+ });
713
+ }
714
+ if (base.prNumber)
715
+ return inspectPlatformPullRequest(taskRef, options);
716
+ try {
717
+ return withTaskExecutionLock(base.resolved.repoRoot, base.resolved.taskId, 'platform-pr.create', () => createPlatformPullRequestUnlocked(taskRef, options));
718
+ }
719
+ catch (error) {
720
+ if (error instanceof TaskExecutionLockError) {
721
+ return result('blocked', base.resolved.taskId, base.issueNumber, null, {
722
+ platform: base.context.platform,
723
+ capabilities: base.context.capabilities,
724
+ error: { code: error.code, message: error.message, retryable: true }
725
+ });
726
+ }
727
+ return result('failed', base.resolved.taskId, base.issueNumber, null, {
728
+ platform: base.context.platform,
729
+ capabilities: base.context.capabilities,
730
+ error: {
731
+ code: 'PR_CREATE_FAILED',
732
+ message: error instanceof Error ? error.message : String(error),
733
+ retryable: false
734
+ }
735
+ });
736
+ }
737
+ }
692
738
  function syncPlatformPullRequest(taskRef, options) {
693
739
  const base = resolvedContext(taskRef, options);
694
740
  if (!base.ok)
@@ -55,9 +55,17 @@ function reconcileReleaseMilestones(version, options = {}) {
55
55
  const major = Number(match[1]);
56
56
  const minor = Number(match[2]);
57
57
  const patch = Number(match[3]);
58
- const ensure = [`${major}.${minor}.${patch + 1}`, `${major}.${minor}.x`];
59
- if (patch === 0)
60
- ensure.push(`${major}.${minor + 1}.0`, `${major}.${minor + 1}.x`);
58
+ const nextPatch = `${major}.${minor}.${patch + 1}`;
59
+ const currentLine = `${major}.${minor}.x`;
60
+ const ensure = [
61
+ { title: nextPatch, description: `Issues that we want to release in v${nextPatch}.` },
62
+ { title: currentLine, description: `Issues that we want to resolve in ${major}.${minor} line.` }
63
+ ];
64
+ if (patch === 0) {
65
+ const nextMinor = `${major}.${minor + 1}.0`;
66
+ const nextLine = `${major}.${minor + 1}.x`;
67
+ ensure.push({ title: nextMinor, description: `Issues that we want to release in v${nextMinor}.` }, { title: nextLine, description: `Issues that we want to resolve in ${major}.${minor + 1} line.` });
68
+ }
61
69
  const operations = [];
62
70
  const current = milestones.find((item) => item.title === version);
63
71
  if (current && current.state !== 'closed') {
@@ -66,11 +74,11 @@ function reconcileReleaseMilestones(version, options = {}) {
66
74
  }
67
75
  else
68
76
  operations.push({ name: 'close-milestone', title: version, status: 'no-op' });
69
- for (const title of ensure) {
77
+ for (const { title, description } of ensure) {
70
78
  if (milestones.some((item) => item.title === title))
71
79
  operations.push({ name: 'ensure-milestone', title, status: 'no-op' });
72
80
  else {
73
- const created = client.json(['api', '--method', 'POST', `repos/${context.platform.repository}/milestones`, '-f', `title=${title}`], { cwd: options.cwd });
81
+ const created = client.json(['api', '--method', 'POST', `repos/${context.platform.repository}/milestones`, '-f', `title=${title}`, '-f', `description=${description}`], { cwd: options.cwd });
74
82
  operations.push({ name: 'ensure-milestone', title, status: created.ok ? 'applied' : 'failed' });
75
83
  }
76
84
  }