@fitlab-ai/agent-infra 0.9.7 → 0.9.9

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 (195) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/dist/bin/internal-cli.js +11 -1
  4. package/dist/lib/agent-clients/adapters/claude-code.js +3 -3
  5. package/dist/lib/agent-clients/adapters/codex-lifecycle/app-server.js +60 -22
  6. package/dist/lib/agent-clients/adapters/codex-lifecycle/build-identity.js +8 -1
  7. package/dist/lib/agent-clients/adapters/codex-lifecycle/capability-store.js +175 -11
  8. package/dist/lib/agent-clients/adapters/codex-lifecycle/controller-context.js +147 -0
  9. package/dist/lib/agent-clients/adapters/codex-lifecycle/evidence.js +14 -0
  10. package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +86 -69
  11. package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +2 -1
  12. package/dist/lib/decide.js +68 -14
  13. package/dist/lib/git/workflow.js +10 -1
  14. package/dist/lib/init.js +1 -1
  15. package/dist/lib/internal/codex-lifecycle.js +19 -5
  16. package/dist/lib/internal/codex-sandbox-controller.js +6 -13
  17. package/dist/lib/internal/git-workflow.js +5 -7
  18. package/dist/lib/internal/platform-pr.js +20 -7
  19. package/dist/lib/internal/release-workflow.js +3 -4
  20. package/dist/lib/internal/sandbox-control.js +79 -2
  21. package/dist/lib/internal/task-activity.js +57 -7
  22. package/dist/lib/internal/task-event.js +57 -4
  23. package/dist/lib/internal/task-finalization.js +54 -0
  24. package/dist/lib/internal/task-ledger.js +59 -5
  25. package/dist/lib/internal/task-lifecycle.js +59 -8
  26. package/dist/lib/internal/task-orchestration.js +161 -288
  27. package/dist/lib/internal/task-override.js +131 -0
  28. package/dist/lib/internal/task-review.js +64 -6
  29. package/dist/lib/internal/task-verify.js +65 -3
  30. package/dist/lib/internal/task-warning.js +57 -4
  31. package/dist/lib/platform/pr-summary.js +53 -13
  32. package/dist/lib/platform/pull-requests.js +205 -41
  33. package/dist/lib/runtime/agent-runtime.js +56 -0
  34. package/dist/lib/sandbox/commands/create.js +389 -311
  35. package/dist/lib/sandbox/commands/rm.js +316 -55
  36. package/dist/lib/sandbox/control/client.js +190 -6
  37. package/dist/lib/sandbox/control/container-identity.js +1 -1
  38. package/dist/lib/sandbox/control/controller-registration.js +273 -0
  39. package/dist/lib/sandbox/control/executor.js +145 -5
  40. package/dist/lib/sandbox/control/lifecycle.js +395 -73
  41. package/dist/lib/sandbox/control/protocol.js +67 -6
  42. package/dist/lib/sandbox/control/state.js +27 -11
  43. package/dist/lib/sandbox/engine.js +14 -7
  44. package/dist/lib/sandbox/index.js +5 -3
  45. package/dist/lib/sandbox/managed-fs.js +5 -0
  46. package/dist/lib/sandbox/mounts.js +20 -5
  47. package/dist/lib/sandbox/recovery.js +78 -10
  48. package/dist/lib/sandbox/task-resolver.js +50 -6
  49. package/dist/lib/sandbox/workspace-identity.js +27 -0
  50. package/dist/lib/sandbox/workspace-view.js +62 -40
  51. package/dist/lib/sandbox/worktree-safety.js +215 -2
  52. package/dist/lib/server/process-state.js +51 -1
  53. package/dist/lib/task/activity-intent.js +4 -1
  54. package/dist/lib/task/codex-orchestration.js +158 -33
  55. package/dist/lib/task/commands/status.js +59 -1
  56. package/dist/lib/task/commit-operation.js +335 -0
  57. package/dist/lib/task/commit-policy.js +18 -0
  58. package/dist/lib/task/decision-intents.js +4 -2
  59. package/dist/lib/task/delegation-receipts.js +279 -17
  60. package/dist/lib/task/events.js +9 -5
  61. package/dist/lib/task/finalization.js +567 -0
  62. package/dist/lib/task/guard-override.js +31 -0
  63. package/dist/lib/task/human-override.js +1240 -0
  64. package/dist/lib/task/ledger-intents.js +6 -3
  65. package/dist/lib/task/lifecycle.js +69 -14
  66. package/dist/lib/task/operation-outcome.js +33 -0
  67. package/dist/lib/task/orchestration.js +199 -719
  68. package/dist/lib/task/review-finalization.js +3 -2
  69. package/dist/lib/task/short-id.js +59 -1
  70. package/dist/lib/task/task-execution-lock.js +6 -1
  71. package/dist/lib/task/verification-engine.js +138 -59
  72. package/dist/lib/task/verification.js +15 -2
  73. package/dist/lib/task/workflow-warning-intents.js +54 -3
  74. package/dist/lib/task/write.js +2 -1
  75. package/dist/lifecycle-build-manifest.json +3 -3
  76. package/lib/agent-clients/adapters/claude-code.ts +3 -3
  77. package/lib/agent-clients/adapters/codex-lifecycle/app-server.ts +63 -20
  78. package/lib/agent-clients/adapters/codex-lifecycle/build-identity.ts +12 -0
  79. package/lib/agent-clients/adapters/codex-lifecycle/capability-store.ts +278 -13
  80. package/lib/agent-clients/adapters/codex-lifecycle/controller-context.ts +180 -0
  81. package/lib/agent-clients/adapters/codex-lifecycle/evidence.ts +19 -0
  82. package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +9 -1
  83. package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +112 -93
  84. package/lib/agent-clients/adapters/codex-lifecycle/store.ts +2 -1
  85. package/lib/decide.ts +59 -14
  86. package/lib/git/workflow.ts +11 -2
  87. package/lib/init.ts +1 -1
  88. package/lib/internal/codex-lifecycle.ts +18 -5
  89. package/lib/internal/codex-sandbox-controller.ts +6 -12
  90. package/lib/internal/git-workflow.ts +5 -6
  91. package/lib/internal/platform-pr.ts +14 -7
  92. package/lib/internal/release-workflow.ts +3 -4
  93. package/lib/internal/sandbox-control.ts +92 -2
  94. package/lib/internal/task-activity.ts +46 -6
  95. package/lib/internal/task-event.ts +53 -4
  96. package/lib/internal/task-finalization.ts +68 -0
  97. package/lib/internal/task-ledger.ts +48 -4
  98. package/lib/internal/task-lifecycle.ts +56 -12
  99. package/lib/internal/task-orchestration.ts +32 -107
  100. package/lib/internal/task-override.ts +138 -0
  101. package/lib/internal/task-review.ts +51 -6
  102. package/lib/internal/task-verify.ts +52 -3
  103. package/lib/internal/task-warning.ts +44 -3
  104. package/lib/platform/pr-summary.ts +65 -14
  105. package/lib/platform/pull-requests.ts +211 -41
  106. package/lib/runtime/agent-runtime.ts +76 -0
  107. package/lib/sandbox/commands/create.ts +88 -4
  108. package/lib/sandbox/commands/rm.ts +413 -61
  109. package/lib/sandbox/config.ts +2 -1
  110. package/lib/sandbox/control/client.ts +255 -6
  111. package/lib/sandbox/control/container-identity.ts +3 -3
  112. package/lib/sandbox/control/controller-registration.ts +347 -0
  113. package/lib/sandbox/control/executor.ts +172 -6
  114. package/lib/sandbox/control/lifecycle.ts +465 -77
  115. package/lib/sandbox/control/protocol.ts +85 -9
  116. package/lib/sandbox/control/state.ts +35 -18
  117. package/lib/sandbox/engine.ts +20 -9
  118. package/lib/sandbox/index.ts +5 -3
  119. package/lib/sandbox/managed-fs.ts +5 -0
  120. package/lib/sandbox/mounts.ts +23 -5
  121. package/lib/sandbox/recovery.ts +90 -9
  122. package/lib/sandbox/task-resolver.ts +58 -7
  123. package/lib/sandbox/workspace-identity.ts +50 -2
  124. package/lib/sandbox/workspace-view.ts +73 -43
  125. package/lib/sandbox/worktree-safety.ts +236 -2
  126. package/lib/server/process-state.ts +48 -1
  127. package/lib/task/activity-intent.ts +4 -2
  128. package/lib/task/codex-orchestration.ts +167 -33
  129. package/lib/task/commands/status.ts +78 -1
  130. package/lib/task/commit-operation.ts +430 -0
  131. package/lib/task/commit-policy.ts +30 -0
  132. package/lib/task/decision-intents.ts +4 -2
  133. package/lib/task/delegation-receipts.ts +304 -19
  134. package/lib/task/events.ts +10 -5
  135. package/lib/task/finalization.ts +719 -0
  136. package/lib/task/guard-override.ts +50 -0
  137. package/lib/task/human-override.ts +1503 -0
  138. package/lib/task/ledger-intents.ts +6 -3
  139. package/lib/task/lifecycle.ts +71 -14
  140. package/lib/task/operation-outcome.ts +48 -0
  141. package/lib/task/orchestration.ts +239 -922
  142. package/lib/task/review-finalization.ts +6 -2
  143. package/lib/task/short-id.ts +65 -1
  144. package/lib/task/task-execution-lock.ts +10 -1
  145. package/lib/task/verification-engine.ts +145 -64
  146. package/lib/task/verification.ts +18 -3
  147. package/lib/task/workflow-warning-intents.ts +61 -4
  148. package/lib/task/write.ts +4 -1
  149. package/package.json +2 -2
  150. package/templates/.agents/QUICKSTART.en.md +2 -2
  151. package/templates/.agents/QUICKSTART.zh-CN.md +2 -2
  152. package/templates/.agents/hooks/lifecycle-delegation.js +9 -24
  153. package/templates/.agents/rules/lifecycle-orchestration.en.md +4 -3
  154. package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +4 -3
  155. package/templates/.agents/rules/task-management.en.md +2 -2
  156. package/templates/.agents/rules/task-management.zh-CN.md +2 -2
  157. package/templates/.agents/skills/block-task/SKILL.en.md +2 -4
  158. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +2 -4
  159. package/templates/.agents/skills/cancel-task/SKILL.en.md +3 -3
  160. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +3 -3
  161. package/templates/.agents/skills/close-codescan/SKILL.en.md +6 -2
  162. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +6 -2
  163. package/templates/.agents/skills/close-dependabot/SKILL.en.md +6 -2
  164. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +6 -2
  165. package/templates/.agents/skills/commit/SKILL.en.md +41 -125
  166. package/templates/.agents/skills/commit/SKILL.zh-CN.md +52 -123
  167. package/templates/.agents/skills/commit/reference/commit-message.en.md +1 -1
  168. package/templates/.agents/skills/commit/reference/commit-message.zh-CN.md +1 -1
  169. package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +14 -43
  170. package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +14 -49
  171. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +1 -1
  172. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +1 -1
  173. package/templates/.agents/skills/commit/reference/task-status-update.en.md +2 -35
  174. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +2 -35
  175. package/templates/.agents/skills/complete-task/SKILL.en.md +31 -38
  176. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +31 -38
  177. package/templates/.agents/skills/complete-task/config/verify.en.json +1 -0
  178. package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +1 -0
  179. package/templates/.agents/skills/complete-task/reference/external-delivery.en.md +1 -1
  180. package/templates/.agents/skills/complete-task/reference/external-delivery.zh-CN.md +1 -1
  181. package/templates/.agents/skills/create-pr/SKILL.en.md +6 -4
  182. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +6 -4
  183. package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +2 -2
  184. package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +2 -2
  185. package/templates/.agents/skills/run-task/SKILL.en.md +5 -5
  186. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +5 -5
  187. package/templates/.agents/skills/run-task/reference/host-validation.en.md +3 -1
  188. package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +3 -1
  189. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +1 -1
  190. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +1 -1
  191. package/templates/.codex/hooks.json +4 -4
  192. package/dist/lib/task/commit-finalization.js +0 -305
  193. package/dist/lib/task/commit-intent.js +0 -165
  194. package/lib/task/commit-finalization.ts +0 -419
  195. package/lib/task/commit-intent.ts +0 -230
@@ -1,5 +1,8 @@
1
1
  import { finalizeReviewSummary } from '../task/review-finalization.js';
2
- const USAGE = 'Usage: agent-infra-internal task-review <task-ref> finalize-summary --stage <analysis|plan|code> --artifact <review-*.md> [--orchestrated] [--dry-run]\n';
2
+ import { consumeHumanOverride, failureId, overrideDryRunConflict } from '../task/human-override.js';
3
+ import { resolveTaskRef } from '../task/resolve-ref.js';
4
+ import { TaskExecutionLockError, withTaskExecutionLock } from '../task/task-execution-lock.js';
5
+ const USAGE = 'Usage: agent-infra-internal task-review <task-ref> finalize-summary --stage <analysis|plan|code> --artifact <review-*.md> [--orchestrated] [--dry-run] [--override-ticket <ticket> --override-target <target> --override-scope <scope>]\n';
3
6
  function failUsage(message) {
4
7
  process.stdout.write(`${JSON.stringify({
5
8
  status: 'failed',
@@ -27,10 +30,13 @@ function taskReview(args = []) {
27
30
  let artifact = '';
28
31
  let dryRun = false;
29
32
  let orchestrated = false;
33
+ let overrideTicket = '';
34
+ let overrideTarget = '';
35
+ let overrideScope = '';
30
36
  const seen = new Set();
31
37
  for (let index = 2; index < args.length; index += 1) {
32
38
  const flag = args[index];
33
- if (!['--stage', '--artifact', '--orchestrated', '--dry-run'].includes(flag)) {
39
+ if (!['--stage', '--artifact', '--orchestrated', '--dry-run', '--override-ticket', '--override-target', '--override-scope'].includes(flag)) {
34
40
  failUsage(`unknown option '${flag}'`);
35
41
  return;
36
42
  }
@@ -54,16 +60,68 @@ function taskReview(args = []) {
54
60
  }
55
61
  if (flag === '--stage')
56
62
  stage = value;
57
- else
63
+ else if (flag === '--artifact')
58
64
  artifact = value;
65
+ else if (flag === '--override-ticket')
66
+ overrideTicket = value;
67
+ else if (flag === '--override-target')
68
+ overrideTarget = value;
69
+ else if (flag === '--override-scope')
70
+ overrideScope = value;
59
71
  }
60
72
  if (!stage || !artifact) {
61
73
  failUsage("options '--stage' and '--artifact' are required");
62
74
  return;
63
75
  }
64
- const result = finalizeReviewSummary({ taskRef: args[0], stage, artifact, orchestrated, dryRun });
65
- process.stdout.write(`${JSON.stringify(result)}\n`);
66
- if (result.status === 'failed')
76
+ const dryRunConflict = overrideDryRunConflict({ dryRun, overrideTicket, overrideTarget, overrideScope });
77
+ if (dryRunConflict) {
78
+ failUsage(dryRunConflict.message);
79
+ return;
80
+ }
81
+ const resolved = resolveTaskRef(args[0]);
82
+ if (!resolved.ok) {
83
+ failUsage(resolved.message);
84
+ return;
85
+ }
86
+ let result;
87
+ let humanOverride = null;
88
+ try {
89
+ result = withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'task-review.finalize-summary', () => {
90
+ let current = finalizeReviewSummary({ taskRef: args[0], stage, artifact, orchestrated, dryRun }, { lockAlreadyHeld: true });
91
+ if (current.status !== 'failed' || !overrideTicket)
92
+ return current;
93
+ if (!overrideTarget || !overrideScope) {
94
+ failUsage('override ticket requires target and scope');
95
+ return current;
96
+ }
97
+ const consumed = consumeHumanOverride({
98
+ taskRef: args[0], ticketId: overrideTicket,
99
+ failureId: failureId('review-finalization', current.error?.code ?? 'TASK_STATE_MISMATCH'),
100
+ target: overrideTarget, scope: overrideScope
101
+ }, {
102
+ effectExecutor: (capability) => {
103
+ const retried = finalizeReviewSummary({ taskRef: args[0], stage, artifact, orchestrated, dryRun }, { lockAlreadyHeld: true, manualOverride: capability });
104
+ current = retried;
105
+ return retried.status === 'failed' || retried.status === 'planned'
106
+ ? { code: 'OVERRIDE_EFFECT_FAILED', message: retried.status === 'planned' ? 'producer returned planned; no review effect was committed' : `${retried.error?.code ?? 'REVIEW_FAILED'}: ${retried.error?.message ?? 'manual review effect failed'}` }
107
+ : null;
108
+ }
109
+ });
110
+ humanOverride = consumed;
111
+ return current;
112
+ });
113
+ }
114
+ catch (error) {
115
+ if (!(error instanceof TaskExecutionLockError))
116
+ throw error;
117
+ process.stdout.write(`${JSON.stringify({ status: 'failed', changed: false, error: { code: error.code, message: error.message } })}\n`);
118
+ process.exitCode = 1;
119
+ return;
120
+ }
121
+ process.stdout.write(`${JSON.stringify(humanOverride ? { ...result, humanOverride } : result)}\n`);
122
+ const overrideFailed = Boolean(humanOverride && typeof humanOverride === 'object' &&
123
+ humanOverride.status === 'failed');
124
+ if (result.status === 'failed' || overrideFailed)
67
125
  process.exitCode = 1;
68
126
  }
69
127
  export { taskReview };
@@ -1,5 +1,8 @@
1
1
  import { renderTaskVerification, verifyTaskEvent } from '../task/verification.js';
2
- const USAGE = 'Usage: agent-infra-internal task-verify <N | TASK-id> <verification-event> [--artifact <canonical.md>] [--format json|text]\n';
2
+ import { consumeHumanOverride, failureId } from '../task/human-override.js';
3
+ import { resolveTaskRef } from '../task/resolve-ref.js';
4
+ import { TaskExecutionLockError, withTaskExecutionLock } from '../task/task-execution-lock.js';
5
+ const USAGE = 'Usage: agent-infra-internal task-verify <N | TASK-id> <verification-event> [--artifact <canonical.md>] [--format json|text] [--override-ticket <ticket> --override-target <target> --override-scope <scope>]\n';
3
6
  function fail(message) {
4
7
  process.stdout.write(`${JSON.stringify({ status: 'failed', changed: false, error: { code: 'VERIFY_PAYLOAD_INVALID', message } })}\n`);
5
8
  process.stderr.write(USAGE);
@@ -14,12 +17,17 @@ function taskVerify(args = []) {
14
17
  fail('task ref and verification event are required');
15
18
  return;
16
19
  }
20
+ const taskRef = args[0];
21
+ const event = args[1];
17
22
  let artifact;
18
23
  let format = 'json';
24
+ let overrideTicket;
25
+ let overrideTarget;
26
+ let overrideScope;
19
27
  const seen = new Set();
20
28
  for (let index = 2; index < args.length; index += 1) {
21
29
  const flag = args[index];
22
- if (flag !== '--artifact' && flag !== '--format') {
30
+ if (!['--artifact', '--format', '--override-ticket', '--override-target', '--override-scope'].includes(flag)) {
23
31
  fail(`unknown option '${flag}'`);
24
32
  return;
25
33
  }
@@ -35,6 +43,12 @@ function taskVerify(args = []) {
35
43
  seen.add(flag);
36
44
  if (flag === '--artifact')
37
45
  artifact = value;
46
+ else if (flag === '--override-ticket')
47
+ overrideTicket = value;
48
+ else if (flag === '--override-target')
49
+ overrideTarget = value;
50
+ else if (flag === '--override-scope')
51
+ overrideScope = value;
38
52
  else if (value === 'json' || value === 'text')
39
53
  format = value;
40
54
  else {
@@ -42,7 +56,55 @@ function taskVerify(args = []) {
42
56
  return;
43
57
  }
44
58
  }
45
- const result = verifyTaskEvent({ taskRef: args[0], event: args[1], ...(artifact ? { artifact } : {}) });
59
+ const resolved = resolveTaskRef(taskRef);
60
+ if (!resolved.ok) {
61
+ fail(resolved.message);
62
+ return;
63
+ }
64
+ let result;
65
+ let humanOverride = null;
66
+ try {
67
+ result = withTaskExecutionLock(resolved.repoRoot, resolved.taskId, `task-verify.${event}`, () => {
68
+ let current = verifyTaskEvent({ taskRef, event, ...(artifact ? { artifact } : {}) });
69
+ if (current.status === 'pass' || !overrideTicket)
70
+ return current;
71
+ if (!overrideTarget || !overrideScope) {
72
+ fail('override ticket requires target and scope');
73
+ return current;
74
+ }
75
+ const failureProducer = current.status === 'blocked' || current.status === 'fail'
76
+ ? 'verification-engine'
77
+ : 'task-verify';
78
+ const failureCode = current.status === 'blocked'
79
+ ? 'CHECK_BLOCKED'
80
+ : current.status === 'fail'
81
+ ? 'CHECK_FAILED'
82
+ : current.error?.code ?? 'VERIFY_TASK_STATE_MISMATCH';
83
+ const consumed = consumeHumanOverride({
84
+ taskRef, ticketId: overrideTicket,
85
+ failureId: failureId(failureProducer, failureCode),
86
+ target: overrideTarget, scope: overrideScope
87
+ }, {
88
+ effectExecutor: (capability) => {
89
+ const retried = verifyTaskEvent({ taskRef, event, ...(artifact ? { artifact } : {}) }, { manualOverride: capability });
90
+ current = retried;
91
+ return retried.status !== 'pass'
92
+ ? { code: 'OVERRIDE_EFFECT_FAILED', message: `${retried.error?.code ?? 'VERIFY_FAILED'}: ${retried.error?.message ?? 'manual verification effect failed'}` }
93
+ : null;
94
+ }
95
+ });
96
+ humanOverride = consumed;
97
+ return current;
98
+ });
99
+ }
100
+ catch (error) {
101
+ if (!(error instanceof TaskExecutionLockError))
102
+ throw error;
103
+ fail(`${error.code}: ${error.message}`);
104
+ return;
105
+ }
106
+ if (humanOverride)
107
+ result = { ...result, humanOverride };
46
108
  process.stdout.write(format === 'text' ? renderTaskVerification(result) : `${JSON.stringify(result)}\n`);
47
109
  process.exitCode = result.status === 'pass' ? 0 : result.status === 'blocked' ? 2 : 1;
48
110
  }
@@ -1,8 +1,12 @@
1
1
  import { applyWorkflowWarningIntent } from '../task/workflow-warning-intents.js';
2
+ import { consumeHumanOverride, failureId, overrideDryRunConflict } from '../task/human-override.js';
3
+ import { resolveTaskRef } from '../task/resolve-ref.js';
4
+ import { TaskExecutionLockError, withTaskExecutionLock } from '../task/task-execution-lock.js';
2
5
  const USAGE = `Usage: agent-infra-internal task-warning <task-ref> <add|set-status|list> [intent flags] [--dry-run]\n`;
3
6
  const FLAGS = {
4
7
  '--step': 'step', '--severity': 'severity', '--code': 'code', '--target': 'target',
5
- '--message': 'message', '--action': 'action', '--id': 'id', '--status': 'status', '--resolution': 'resolution'
8
+ '--message': 'message', '--action': 'action', '--id': 'id', '--status': 'status', '--resolution': 'resolution',
9
+ '--override-ticket': 'overrideTicket', '--override-target': 'overrideTarget', '--override-scope': 'overrideScope'
6
10
  };
7
11
  function usageFailure(message) {
8
12
  process.stdout.write(`${JSON.stringify({ status: 'failed', changed: false, error: { code: 'WARNING_PAYLOAD_INVALID', message } })}\n`);
@@ -55,6 +59,9 @@ function taskWarning(args = []) {
55
59
  };
56
60
  const optional = kind === 'list' ? ['status'] : [];
57
61
  const allowed = new Set(['kind', 'taskRef', 'dryRun', ...required[kind], ...optional]);
62
+ allowed.add('overrideTicket');
63
+ allowed.add('overrideTarget');
64
+ allowed.add('overrideScope');
58
65
  const unexpected = Object.keys(values).find((key) => !allowed.has(key));
59
66
  const missing = required[kind].find((key) => values[key] === undefined);
60
67
  if (unexpected) {
@@ -65,9 +72,55 @@ function taskWarning(args = []) {
65
72
  usageFailure(`${kind} requires '${missing}'`);
66
73
  return;
67
74
  }
68
- const result = applyWorkflowWarningIntent(values);
69
- process.stdout.write(`${JSON.stringify(result)}\n`);
70
- if (result.status === 'failed')
75
+ const dryRunConflict = overrideDryRunConflict(values);
76
+ if (dryRunConflict) {
77
+ usageFailure(dryRunConflict.message);
78
+ return;
79
+ }
80
+ const resolved = resolveTaskRef(taskRef);
81
+ if (!resolved.ok) {
82
+ usageFailure(resolved.message);
83
+ return;
84
+ }
85
+ let result;
86
+ let humanOverride = null;
87
+ try {
88
+ result = withTaskExecutionLock(resolved.repoRoot, resolved.taskId, `task-warning.${kind}`, () => {
89
+ let current = applyWorkflowWarningIntent(values);
90
+ if (current.status !== 'failed' || !values.overrideTicket)
91
+ return current;
92
+ if (!values.overrideTarget || !values.overrideScope) {
93
+ usageFailure('override ticket requires target and scope');
94
+ return current;
95
+ }
96
+ const consumed = consumeHumanOverride({
97
+ taskRef, ticketId: String(values.overrideTicket),
98
+ failureId: failureId('workflow-warning', current.error?.code ?? 'TASK_STATE_MISMATCH'),
99
+ target: String(values.overrideTarget), scope: String(values.overrideScope)
100
+ }, {
101
+ effectExecutor: (capability) => {
102
+ const retried = applyWorkflowWarningIntent(values, { manualOverride: capability });
103
+ current = retried;
104
+ return retried.status === 'failed' || retried.status === 'planned'
105
+ ? { code: 'OVERRIDE_EFFECT_FAILED', message: retried.status === 'planned' ? 'producer returned planned; no workflow warning effect was committed' : `${retried.error?.code ?? 'WARNING_FAILED'}: ${retried.error?.message ?? 'manual warning effect failed'}` }
106
+ : null;
107
+ }
108
+ });
109
+ humanOverride = consumed;
110
+ return current;
111
+ });
112
+ }
113
+ catch (error) {
114
+ if (!(error instanceof TaskExecutionLockError))
115
+ throw error;
116
+ process.stdout.write(`${JSON.stringify({ status: 'failed', changed: false, error: { code: error.code, message: error.message } })}\n`);
117
+ process.exitCode = 1;
118
+ return;
119
+ }
120
+ process.stdout.write(`${JSON.stringify(humanOverride ? { ...result, humanOverride } : result)}\n`);
121
+ const overrideFailed = Boolean(humanOverride && typeof humanOverride === 'object' &&
122
+ humanOverride.status === 'failed');
123
+ if (result.status === 'failed' || overrideFailed)
71
124
  process.exitCode = 1;
72
125
  }
73
126
  export { taskWarning };
@@ -2,16 +2,25 @@ import fs from 'node:fs';
2
2
  import { execFileSync } from 'node:child_process';
3
3
  import { enumerateArtifacts } from '../task/artifacts.js';
4
4
  import { parseTaskFrontmatter } from '../task/frontmatter.js';
5
+ import { renderHumanOverrideAudit } from '../task/human-override.js';
5
6
  import { resolveTaskRef } from '../task/resolve-ref.js';
6
7
  import { resolvePlatformContext } from './context.js';
7
8
  import { createGitHubClient } from './github-client.js';
8
9
  import { listRemoteComments, normalizeCommentContent, writeComment } from './issue-comments.js';
9
10
  import { platformResult } from './types.js';
11
+ function warningResultForPrimary(primaryResult) {
12
+ if (primaryResult === 'pr_created')
13
+ return 'pr_created_with_warnings';
14
+ if (primaryResult === 'pr_reused')
15
+ return 'pr_reused_with_warnings';
16
+ return 'no_op_with_warnings';
17
+ }
10
18
  function summaryMarker(taskId) {
11
19
  return `<!-- sync-pr:${taskId}:summary -->`;
12
20
  }
13
- function buildPullRequestSummary(taskId, body, headSha) {
14
- return normalizeCommentContent(`${summaryMarker(taskId)}\n<!-- last-commit: ${headSha} -->\n\n${body.replace(/\s+$/, '')}\n`);
21
+ function buildPullRequestSummary(taskId, body, headSha, humanOverrideAudit = '') {
22
+ const sections = [body.replace(/\s+$/, ''), humanOverrideAudit.trim()].filter(Boolean).join('\n\n');
23
+ return normalizeCommentContent(`${summaryMarker(taskId)}\n<!-- last-commit: ${headSha} -->\n\n${sections}\n`);
15
24
  }
16
25
  function reconcileSummaryComment(comments, taskId, desired) {
17
26
  const marker = summaryMarker(taskId);
@@ -49,40 +58,71 @@ function summaryContext(taskRef, options = {}) {
49
58
  return { ...platformResult('no-op'), task: { id: resolved.taskId, prNumber }, artifacts: canonicalArtifacts(resolved.taskDir) };
50
59
  }
51
60
  function syncPullRequestSummary(taskRef, options) {
61
+ const warningResult = warningResultForPrimary(options.primaryResult);
62
+ let knownPrNumber = null;
63
+ const softenFailure = (output) => {
64
+ const prNumber = output.resource.kind === 'pull-request' && output.resource.number
65
+ ? output.resource.number
66
+ : knownPrNumber;
67
+ const warning = output.error && prNumber
68
+ && output.error.code !== 'PR_NOT_LINKED'
69
+ ? {
70
+ code: output.error.code,
71
+ message: output.error.message,
72
+ retryable: output.error.retryable,
73
+ step: 'pr-summary',
74
+ target: `pull-request:${prNumber}`,
75
+ severity: 'ACTION_REQUIRED'
76
+ }
77
+ : null;
78
+ return warning
79
+ ? {
80
+ ...output,
81
+ status: 'applied',
82
+ changed: false,
83
+ resource: { kind: 'pull-request', number: prNumber },
84
+ error: null,
85
+ result: warningResult,
86
+ warnings: [warning]
87
+ }
88
+ : { ...output, result: null, warnings: [] };
89
+ };
52
90
  const resolved = resolveTaskRef(taskRef, options.cwd ? { repoRoot: options.cwd } : {});
53
91
  if (!resolved.ok)
54
- return platformResult('failed', { error: { code: resolved.code, message: resolved.message, retryable: false } });
92
+ return softenFailure(platformResult('failed', { error: { code: resolved.code, message: resolved.message, retryable: false } }));
55
93
  const frontmatter = parseTaskFrontmatter(fs.readFileSync(resolved.taskMdPath, 'utf8'));
56
94
  const prNumber = Number(frontmatter.pr_number);
57
95
  if (!Number.isInteger(prNumber) || prNumber <= 0)
58
- return platformResult('failed', { error: { code: 'PR_NOT_LINKED', message: 'Task has no valid pr_number', retryable: false } });
96
+ return softenFailure(platformResult('failed', { error: { code: 'PR_NOT_LINKED', message: 'Task has no valid pr_number', retryable: false } }));
97
+ knownPrNumber = prNumber;
59
98
  const client = options.client || createGitHubClient();
60
99
  const context = resolvePlatformContext({ cwd: resolved.repoRoot, client });
61
100
  if (!context.platform.repository || !['no-op', 'degraded'].includes(context.status))
62
- return context;
101
+ return softenFailure(context);
63
102
  let headSha;
64
103
  try {
65
104
  headSha = execFileSync('git', ['rev-parse', 'HEAD'], { cwd: resolved.repoRoot, encoding: 'utf8' }).trim();
66
105
  }
67
106
  catch (error) {
68
- return platformResult('failed', { platform: context.platform, capabilities: context.capabilities, error: { code: 'GIT_HEAD_UNRESOLVED', message: error instanceof Error ? error.message : String(error), retryable: false } });
107
+ return softenFailure(platformResult('failed', { platform: context.platform, capabilities: context.capabilities, error: { code: 'GIT_HEAD_UNRESOLVED', message: error instanceof Error ? error.message : String(error), retryable: false } }));
69
108
  }
70
- const desired = buildPullRequestSummary(resolved.taskId, options.body, headSha);
109
+ const desired = buildPullRequestSummary(resolved.taskId, options.body, headSha, renderHumanOverrideAudit(fs.readFileSync(resolved.taskMdPath, 'utf8')));
71
110
  const listed = listRemoteComments(client, context.platform.repository, prNumber, resolved.repoRoot);
72
111
  if (!listed.ok)
73
- return platformResult(listed.error.retryable ? 'blocked' : 'failed', { platform: context.platform, capabilities: context.capabilities, resource: { kind: 'pull-request', number: prNumber }, error: listed.error });
112
+ return softenFailure(platformResult(listed.error.retryable ? 'blocked' : 'failed', { platform: context.platform, capabilities: context.capabilities, resource: { kind: 'pull-request', number: prNumber }, error: listed.error }));
74
113
  const reconciliation = reconcileSummaryComment(listed.value, resolved.taskId, desired);
75
114
  if (reconciliation.action === 'conflict')
76
- return platformResult('failed', { platform: context.platform, capabilities: context.capabilities, resource: { kind: 'pull-request', number: prNumber }, error: { code: 'PR_SUMMARY_MARKER_AMBIGUOUS', message: 'Multiple PR comments contain the summary marker', retryable: false } });
115
+ return softenFailure(platformResult('failed', { platform: context.platform, capabilities: context.capabilities, resource: { kind: 'pull-request', number: prNumber }, error: { code: 'PR_SUMMARY_MARKER_AMBIGUOUS', message: 'Multiple PR comments contain the summary marker', retryable: false } }));
77
116
  if (reconciliation.action === 'no-op')
78
- return platformResult('no-op', { platform: context.platform, capabilities: context.capabilities, resource: { kind: 'pull-request', number: prNumber }, comment: { kind: 'summary', marker: summaryMarker(resolved.taskId), ids: [reconciliation.commentId], parts: 1 }, error: null });
117
+ return softenFailure(platformResult('no-op', { platform: context.platform, capabilities: context.capabilities, resource: { kind: 'pull-request', number: prNumber }, comment: { kind: 'summary', marker: summaryMarker(resolved.taskId), ids: [reconciliation.commentId], parts: 1 }, error: null }));
79
118
  if (options.dryRun)
80
- return platformResult('planned', { platform: context.platform, capabilities: context.capabilities, resource: { kind: 'pull-request', number: prNumber }, operations: [{ name: `summary:${reconciliation.action}`, status: 'planned', reasonCode: null }], error: null });
119
+ return softenFailure(platformResult('planned', { platform: context.platform, capabilities: context.capabilities, resource: { kind: 'pull-request', number: prNumber }, operations: [{ name: `summary:${reconciliation.action}`, status: 'planned', reasonCode: null }], error: null }));
81
120
  const written = writeComment(client, context.platform.repository, prNumber, resolved.repoRoot, desired, reconciliation.commentId || undefined);
82
121
  if (!written.ok)
83
- return platformResult(written.error.retryable ? 'blocked' : 'failed', { platform: context.platform, capabilities: context.capabilities, resource: { kind: 'pull-request', number: prNumber }, error: written.error });
122
+ return softenFailure(platformResult(written.error.retryable ? 'blocked' : 'failed', { platform: context.platform, capabilities: context.capabilities, resource: { kind: 'pull-request', number: prNumber }, error: written.error }));
84
123
  const id = Number(written.value.id || reconciliation.commentId);
85
- return platformResult('applied', { platform: context.platform, capabilities: context.capabilities, resource: { kind: 'pull-request', number: prNumber }, comment: { kind: 'summary', marker: summaryMarker(resolved.taskId), ids: Number.isInteger(id) ? [id] : [], parts: 1 }, operations: [{ name: `summary:${reconciliation.action}`, status: 'applied', reasonCode: null }], error: null });
124
+ return softenFailure(platformResult('applied', { platform: context.platform, capabilities: context.capabilities, resource: { kind: 'pull-request', number: prNumber }, comment: { kind: 'summary', marker: summaryMarker(resolved.taskId), ids: Number.isInteger(id) ? [id] : [], parts: 1 }, operations: [{ name: `summary:${reconciliation.action}`, status: 'applied', reasonCode: null }], error: null }));
86
125
  }
87
126
  export { buildPullRequestSummary, reconcileSummaryComment, summaryContext, summaryMarker, syncPullRequestSummary };
127
+ export { warningResultForPrimary };
88
128
  //# sourceMappingURL=pr-summary.js.map