@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
@@ -0,0 +1,335 @@
1
+ import fs from 'node:fs';
2
+ import { execFileSync } from 'node:child_process';
3
+ import { commitExplicitPaths, inspectGitWorkflow, pushGitRefs } from '../git/workflow.js';
4
+ import { parseTaskFrontmatter } from './frontmatter.js';
5
+ import { resolveTaskContext, resolveTaskRef } from './resolve-ref.js';
6
+ import { commitPushDecision } from './commit-policy.js';
7
+ import { mergeOperationWarnings } from './operation-outcome.js';
8
+ import { TaskExecutionLockError, withRepositoryMutationLock, withTaskExecutionLock } from './task-execution-lock.js';
9
+ import { appendActivityEntry, locateActivityLog } from './activity-log.js';
10
+ import { captureTaskWriteMetadata, writeTask } from './write.js';
11
+ import { commitOrchestrationStageCompletion, planOrchestrationStageCompletion } from './orchestration.js';
12
+ const HEAD_REF = /^refs\/heads\/(.+)$/;
13
+ function isCommitExecutionMode(value) {
14
+ return value === 'direct' || value === 'orchestrated';
15
+ }
16
+ function gitText(repoRoot, args) {
17
+ return execFileSync('git', [...args], {
18
+ cwd: repoRoot,
19
+ encoding: 'utf8',
20
+ stdio: ['ignore', 'pipe', 'pipe']
21
+ }).trim();
22
+ }
23
+ function canonicalRepositoryRoot(cwd) {
24
+ return gitText(cwd, ['rev-parse', '--show-toplevel']);
25
+ }
26
+ function failure(input, mode, taskId, code, message, status = 'failed', snapshot = null) {
27
+ return {
28
+ status,
29
+ changed: false,
30
+ result: status,
31
+ taskId,
32
+ mode,
33
+ warnings: [],
34
+ snapshot: snapshot ?? inspectGitWorkflow(input.cwd).snapshot,
35
+ operations: [],
36
+ error: { code, message }
37
+ };
38
+ }
39
+ function warning(code, message, retryable, step, target, severity) {
40
+ return { code, message, retryable, step, target, severity };
41
+ }
42
+ function resolveBoundTask(input) {
43
+ const mode = input.mode ?? 'direct';
44
+ if (input.taskRef !== undefined) {
45
+ const resolved = resolveTaskRef(input.taskRef, { repoRoot: input.cwd });
46
+ if (!resolved.ok)
47
+ return {
48
+ kind: 'error',
49
+ result: failure(input, mode, resolved.taskId, resolved.code, resolved.message)
50
+ };
51
+ return boundTask(input, resolved.taskId, resolved.taskDir, resolved.taskMdPath, resolved.repoRoot, resolved.state);
52
+ }
53
+ const context = resolveTaskContext(undefined, { repoRoot: input.cwd });
54
+ if (context.ok)
55
+ return boundTask(input, context.taskId, context.taskDir, context.taskMdPath, context.repoRoot, context.state);
56
+ if (context.code === 'TASK_CONTEXT_NOT_FOUND')
57
+ return { kind: 'none' };
58
+ return {
59
+ kind: 'error',
60
+ result: failure(input, mode, context.taskId, context.code, context.message)
61
+ };
62
+ }
63
+ function boundTask(input, taskId, taskDir, taskMdPath, repoRoot, state) {
64
+ let branch;
65
+ try {
66
+ const frontmatter = parseTaskFrontmatter(fs.readFileSync(taskMdPath, 'utf8'));
67
+ branch = frontmatter.branch ?? '';
68
+ }
69
+ catch (error) {
70
+ return {
71
+ kind: 'error',
72
+ result: failure(input, input.mode ?? 'direct', taskId, 'TASK_CONTEXT_UNREADABLE', error instanceof Error ? error.message : String(error))
73
+ };
74
+ }
75
+ if (!branch)
76
+ return {
77
+ kind: 'error',
78
+ result: failure(input, input.mode ?? 'direct', taskId, 'TASK_CONTEXT_UNREADABLE', 'task branch is missing')
79
+ };
80
+ return { kind: 'bound', task: { repoRoot, taskId, taskDir, taskMdPath, state, branch } };
81
+ }
82
+ function validateCommon(input, branch) {
83
+ if (!input.message.trim())
84
+ return { code: 'GIT_COMMIT_INPUT_INVALID', message: 'Commit message is required' };
85
+ if (input.paths.length === 0 && !input.push)
86
+ return { code: 'GIT_COMMIT_INPUT_INVALID', message: 'At least one explicit path is required unless this is a push-only retry' };
87
+ if (!/^[a-f0-9]{40,64}$/.test(input.expectedHead))
88
+ return { code: 'GIT_HEAD_EXPECTATION_REQUIRED', message: 'A valid expected HEAD is required' };
89
+ if (!/^[a-f0-9]{40,64}$/.test(input.expectedTree))
90
+ return { code: 'GIT_TREE_EXPECTATION_REQUIRED', message: 'A valid expected tree is required' };
91
+ if (input.paths.some((candidate) => !candidate || candidate.startsWith('/') || candidate.split(/[\\/]/).includes('..'))) {
92
+ return { code: 'GIT_COMMIT_INPUT_INVALID', message: 'Commit paths must stay inside the repository' };
93
+ }
94
+ if (input.paths.some((candidate) => /(^|\/)(?:\.env|credentials\.json|id_rsa)(?:$|\/)/i.test(candidate))) {
95
+ return { code: 'GIT_COMMIT_INPUT_INVALID', message: 'Sensitive paths cannot be committed' };
96
+ }
97
+ if (branch !== null && branch === '')
98
+ return { code: 'GIT_BRANCH_INVALID', message: 'A named branch is required' };
99
+ if (input.push) {
100
+ if (!input.push.remote || input.push.refs.length !== 1)
101
+ return { code: 'GIT_PUSH_INPUT_INVALID', message: 'Push requires one remote and one ref' };
102
+ const ref = input.push.refs[0] ?? '';
103
+ if (!HEAD_REF.test(ref) || HEAD_REF.exec(ref)?.[1] !== branch) {
104
+ return { code: 'GIT_PUSH_INPUT_INVALID', message: 'Push ref must be the current full heads ref' };
105
+ }
106
+ }
107
+ return null;
108
+ }
109
+ function validateOrchestrated(input, task) {
110
+ if (!input.agent)
111
+ return { error: { code: 'ORCHESTRATION_PROVENANCE_MISMATCH', message: 'orchestrated commit requires an agent' } };
112
+ const planned = planOrchestrationStageCompletion(task.taskId, {
113
+ stage: 'commit',
114
+ round: 1,
115
+ artifact: 'commit',
116
+ role: 'executor',
117
+ agent: input.agent
118
+ }, { repoRoot: task.repoRoot });
119
+ const run = planned.result.run;
120
+ if (!planned.plan
121
+ || !run
122
+ || run.status !== 'running'
123
+ || !run.commitAuthorization.issuedAt
124
+ || run.commitAuthorization.consumedAt)
125
+ return {
126
+ error: {
127
+ code: planned.result.error?.code ?? 'ORCHESTRATION_PROVENANCE_MISMATCH',
128
+ message: planned.result.error?.message ?? 'orchestrated commit requires one matching activated commit delegation'
129
+ }
130
+ };
131
+ return { plan: planned.plan };
132
+ }
133
+ function syncTaskCommit(input, task, committedHead) {
134
+ let content;
135
+ try {
136
+ content = fs.readFileSync(task.taskMdPath, 'utf8');
137
+ const activity = locateActivityLog(content);
138
+ if (!activity)
139
+ return warning('TASK_STATUS_SYNC_FAILED', 'task has no unique Activity Log section', true, 'task', task.taskId, 'ACTION_REQUIRED');
140
+ const metadata = captureTaskWriteMetadata();
141
+ const commitNote = gitText(task.repoRoot, ['show', '-s', '--format=%h %s', committedHead]);
142
+ const alreadyLogged = activity.entries.some((entry) => entry.step === 'Commit' && entry.note === commitNote);
143
+ const mutations = [];
144
+ if (!alreadyLogged)
145
+ mutations.push({
146
+ kind: 'section',
147
+ aliases: ['活动日志', 'Activity Log'],
148
+ heading: activity.heading,
149
+ body: appendActivityEntry(activity, { time: metadata.timestamp, step: 'Commit', agent: input.agent, note: commitNote })
150
+ });
151
+ const frontmatter = { assigned_to: input.agent };
152
+ mutations.push({ kind: 'frontmatter', set: frontmatter });
153
+ if (mutations.length === 0)
154
+ return null;
155
+ const written = writeTask({
156
+ taskRef: task.taskId,
157
+ expectedState: 'active',
158
+ mutations
159
+ }, { repoRoot: task.repoRoot, metadataProvider: () => metadata });
160
+ if (written.status === 'failed')
161
+ return warning('TASK_STATUS_SYNC_FAILED', written.error.message, true, 'task', task.taskId, 'ACTION_REQUIRED');
162
+ return null;
163
+ }
164
+ catch (error) {
165
+ return warning('TASK_STATUS_SYNC_FAILED', error instanceof Error ? error.message : String(error), true, 'task', task.taskId, 'ACTION_REQUIRED');
166
+ }
167
+ }
168
+ function executeUnlocked(input, task, mode) {
169
+ const inspected = inspectGitWorkflow(input.cwd);
170
+ if (!inspected.snapshot)
171
+ return failure(input, mode, task?.taskId ?? null, 'GIT_INSPECT_FAILED', 'Unable to inspect Git repository');
172
+ const branch = inspected.snapshot.branch;
173
+ const commonError = validateCommon(input, branch);
174
+ if (commonError)
175
+ return failure(input, mode, task?.taskId ?? null, commonError.code, commonError.message, 'blocked', inspected.snapshot);
176
+ if (task && task.state !== 'active')
177
+ return failure(input, mode, task.taskId, 'TASK_STATE_INVALID', 'task-bound commit requires an active task', 'blocked', inspected.snapshot);
178
+ if (task && task.branch !== branch)
179
+ return failure(input, mode, task.taskId, 'GIT_BRANCH_MISMATCH', `Task branch '${task.branch}' does not match current branch '${branch}'`, 'blocked', inspected.snapshot);
180
+ if (task && !input.agent)
181
+ return failure(input, mode, task.taskId, 'COMMIT_AGENT_REQUIRED', 'task-bound commit requires an agent', 'blocked', inspected.snapshot);
182
+ const orchestrationValidation = mode === 'orchestrated'
183
+ ? (task
184
+ ? validateOrchestrated(input, task)
185
+ : { error: { code: 'ORCHESTRATION_TASK_REQUIRED', message: 'orchestrated commit requires a task context' } })
186
+ : null;
187
+ if (orchestrationValidation && 'error' in orchestrationValidation) {
188
+ const error = orchestrationValidation.error;
189
+ return failure(input, mode, task?.taskId ?? null, error.code, error.message, 'blocked', inspected.snapshot);
190
+ }
191
+ const orchestrationCompletion = orchestrationValidation && 'plan' in orchestrationValidation
192
+ ? orchestrationValidation.plan
193
+ : null;
194
+ const committed = input.paths.length === 0
195
+ ? (() => {
196
+ if (inspected.snapshot.worktree.length > 0 || inspected.snapshot.staged.length > 0)
197
+ return {
198
+ status: 'failed',
199
+ changed: false,
200
+ snapshot: inspected.snapshot,
201
+ operations: [],
202
+ error: { code: 'GIT_COMMIT_INPUT_INVALID', message: 'Push-only retry requires a clean working tree' }
203
+ };
204
+ if (inspected.snapshot.head !== input.expectedHead)
205
+ return {
206
+ status: 'failed',
207
+ changed: false,
208
+ snapshot: inspected.snapshot,
209
+ operations: [],
210
+ error: { code: 'GIT_HEAD_MISMATCH', message: `Expected HEAD ${input.expectedHead}, received ${inspected.snapshot.head}` }
211
+ };
212
+ const currentTree = gitText(input.cwd, ['rev-parse', 'HEAD^{tree}']);
213
+ if (currentTree !== input.expectedTree)
214
+ return {
215
+ status: 'failed',
216
+ changed: false,
217
+ snapshot: inspected.snapshot,
218
+ operations: [],
219
+ error: { code: 'GIT_TREE_MISMATCH', message: `Expected current tree ${input.expectedTree}, received ${currentTree}` }
220
+ };
221
+ return {
222
+ status: 'no-op',
223
+ changed: false,
224
+ snapshot: inspected.snapshot,
225
+ operations: [{ name: 'commit', status: 'no-op' }],
226
+ error: null
227
+ };
228
+ })()
229
+ : commitExplicitPaths({
230
+ cwd: input.cwd,
231
+ paths: input.paths,
232
+ message: input.message,
233
+ expectedHead: input.expectedHead,
234
+ expectedTree: input.expectedTree
235
+ });
236
+ if (committed.status === 'failed')
237
+ return {
238
+ ...committed,
239
+ result: 'failed',
240
+ taskId: task?.taskId ?? null,
241
+ mode,
242
+ warnings: [],
243
+ snapshot: committed.snapshot
244
+ };
245
+ const warnings = [];
246
+ if (orchestrationCompletion) {
247
+ try {
248
+ commitOrchestrationStageCompletion(orchestrationCompletion);
249
+ }
250
+ catch (error) {
251
+ warnings.push(warning('ORCHESTRATION_COMPLETION_FAILED', error instanceof Error ? error.message : String(error), true, 'orchestration', task?.taskId ?? 'orchestration', 'ACTION_REQUIRED'));
252
+ }
253
+ }
254
+ let status = committed.status;
255
+ let result = committed.status === 'applied' ? 'committed' : 'no_op';
256
+ if (input.push) {
257
+ const target = `${input.push.remote}:${input.push.refs[0]}`;
258
+ const decision = commitPushDecision({ branch, automatic: input.push.automatic }, target);
259
+ if (!decision.shouldPush) {
260
+ warnings.push(decision.warning);
261
+ }
262
+ else {
263
+ const pushed = pushGitRefs({
264
+ cwd: input.cwd,
265
+ remote: input.push.remote,
266
+ refs: input.push.refs,
267
+ expectedSha: committed.snapshot?.head ?? gitText(input.cwd, ['rev-parse', 'HEAD'])
268
+ });
269
+ if (pushed.status !== 'applied')
270
+ warnings.push(warning('COMMIT_PUSH_FAILED', pushed.error?.message ?? 'Git push failed', true, 'push', target, 'ACTION_REQUIRED'));
271
+ }
272
+ }
273
+ if (warnings.length > 0) {
274
+ status = 'applied';
275
+ result = 'committed_with_warnings';
276
+ }
277
+ if (task && (committed.status === 'applied' || committed.status === 'no-op')) {
278
+ const taskWarning = syncTaskCommit(input, task, committed.snapshot?.head ?? gitText(task.repoRoot, ['rev-parse', 'HEAD']));
279
+ if (taskWarning) {
280
+ warnings.push(taskWarning);
281
+ status = 'applied';
282
+ result = 'committed_with_warnings';
283
+ }
284
+ }
285
+ return {
286
+ status,
287
+ changed: committed.changed,
288
+ result,
289
+ taskId: task?.taskId ?? null,
290
+ mode,
291
+ warnings: mergeOperationWarnings(warnings),
292
+ snapshot: committed.snapshot,
293
+ operations: committed.operations,
294
+ error: null
295
+ };
296
+ }
297
+ function executeCommitOperation(input) {
298
+ if (input.mode !== undefined && !isCommitExecutionMode(input.mode))
299
+ return {
300
+ status: 'blocked',
301
+ changed: false,
302
+ result: 'blocked',
303
+ taskId: null,
304
+ mode: 'direct',
305
+ warnings: [],
306
+ snapshot: null,
307
+ operations: [],
308
+ error: { code: 'COMMIT_MODE_INVALID', message: 'commit mode must be direct or orchestrated' }
309
+ };
310
+ const mode = input.mode ?? 'direct';
311
+ let normalizedInput;
312
+ try {
313
+ normalizedInput = { ...input, cwd: canonicalRepositoryRoot(input.cwd) };
314
+ }
315
+ catch (error) {
316
+ return failure(input, mode, null, 'GIT_INSPECT_FAILED', error instanceof Error ? error.message : 'Unable to resolve Git repository root', 'blocked');
317
+ }
318
+ const resolved = resolveBoundTask(normalizedInput);
319
+ if (resolved.kind === 'error')
320
+ return resolved.result;
321
+ const task = resolved.kind === 'bound' ? resolved.task : null;
322
+ if (mode === 'orchestrated' && !task)
323
+ return failure(normalizedInput, mode, null, 'ORCHESTRATION_TASK_REQUIRED', 'orchestrated commit requires a task context', 'blocked');
324
+ try {
325
+ return task
326
+ ? withRepositoryMutationLock(normalizedInput.cwd, () => withTaskExecutionLock(normalizedInput.cwd, task.taskId, 'commit-operation', () => executeUnlocked(normalizedInput, task, mode)))
327
+ : withRepositoryMutationLock(normalizedInput.cwd, () => executeUnlocked(normalizedInput, null, mode));
328
+ }
329
+ catch (error) {
330
+ const code = error instanceof TaskExecutionLockError ? error.code : 'COMMIT_OPERATION_FAILED';
331
+ return failure(normalizedInput, mode, task?.taskId ?? null, code, error instanceof Error ? error.message : String(error), 'blocked');
332
+ }
333
+ }
334
+ export { executeCommitOperation };
335
+ //# sourceMappingURL=commit-operation.js.map
@@ -0,0 +1,18 @@
1
+ function commitPushDecision(policy, target) {
2
+ const branch = policy.branch.trim();
3
+ if (policy.automatic && (branch === 'main' || branch === 'master'))
4
+ return {
5
+ shouldPush: false,
6
+ warning: {
7
+ code: 'COMMIT_AUTOPUSH_PROTECTED_BRANCH',
8
+ message: `Automatic commit push is disabled for protected branch '${branch}'`,
9
+ retryable: false,
10
+ step: 'push',
11
+ target,
12
+ severity: 'IMPORTANT'
13
+ }
14
+ };
15
+ return { shouldPush: true, warning: null };
16
+ }
17
+ export { commitPushDecision };
18
+ //# sourceMappingURL=commit-policy.js.map
@@ -6,6 +6,7 @@ import { LEDGER_COLUMNS, LEDGER_HEADINGS, parseLedger } from './ledger.js';
6
6
  import { resolveTaskContext } from './resolve-ref.js';
7
7
  import { extractSection, extractSubSection, findSectionHeading } from './sections.js';
8
8
  import { captureTaskWriteMetadata, writeTask } from './write.js';
9
+ import { allowsManualOverride } from './guard-override.js';
9
10
  const DECISION_ALIASES = ['人工裁决', 'Human Rulings', 'Human Decisions', 'Human Decision'];
10
11
  const ACTIVITY_ALIASES = ['活动日志', 'Activity Log'];
11
12
  function failed(code, message, taskId = null, ledgerId = null) {
@@ -56,7 +57,8 @@ function applyHumanDecision(request, options = {}) {
56
57
  const resolved = resolveTaskContext(request.taskRef, { repoRoot: options.repoRoot });
57
58
  if (!resolved.ok)
58
59
  return failed(resolved.code, resolved.message, resolved.taskId);
59
- if (resolved.state !== 'active')
60
+ const stateOverride = allowsManualOverride(options.manualOverride, 'decision-intent', 'TASK_STATE_MISMATCH');
61
+ if (resolved.state !== 'active' && !stateOverride)
60
62
  return failed('TASK_STATE_MISMATCH', `task ${resolved.taskId} is ${resolved.state}, expected active`, resolved.taskId);
61
63
  let content;
62
64
  let rows;
@@ -155,7 +157,7 @@ function applyHumanDecision(request, options = {}) {
155
157
  kind: 'section', aliases: ACTIVITY_ALIASES, heading: activity.heading,
156
158
  body: appendActivityEntry(activity, { time: metadata.timestamp, step: 'Human Decision', agent: 'human', note: `${row.id} decided → ${recordId}` })
157
159
  });
158
- const writeResult = writeTask({ taskRef: resolved.taskId, expectedState: 'active', mutations, dryRun: request.dryRun }, {
160
+ const writeResult = writeTask({ taskRef: resolved.taskId, expectedState: stateOverride ? resolved.state : 'active', mutations, dryRun: request.dryRun }, {
159
161
  ...options,
160
162
  taskLocation: { repoRoot: resolved.repoRoot, taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, state: resolved.state },
161
163
  metadataProvider: () => metadata