@fitlab-ai/agent-infra 0.12.1 → 0.12.2

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 (303) hide show
  1. package/README.md +0 -2
  2. package/README.zh-CN.md +0 -2
  3. package/dist/bin/internal-cli.js +2 -17
  4. package/dist/lib/agent-clients/adapter.js +0 -13
  5. package/dist/lib/agent-clients/adapters/antigravity-cli.js +0 -5
  6. package/dist/lib/agent-clients/adapters/claude-code-credentials.js +0 -17
  7. package/dist/lib/agent-clients/adapters/claude-code.js +0 -9
  8. package/dist/lib/agent-clients/adapters/codex.js +0 -52
  9. package/dist/lib/agent-clients/adapters/opencode.js +0 -5
  10. package/dist/lib/agent-clients/adapters/traecli.js +0 -5
  11. package/dist/lib/agent-clients/config.js +19 -54
  12. package/dist/lib/agent-clients/registry.js +1 -12
  13. package/dist/lib/agent-clients/schema.js +0 -18
  14. package/dist/lib/agent-clients/tokens.js +1 -2
  15. package/dist/lib/agent-clients/types.js +0 -1
  16. package/dist/lib/decide.js +2 -0
  17. package/dist/lib/git/worktree-identity.js +1 -9
  18. package/dist/lib/internal/agent-client.js +2 -62
  19. package/dist/lib/internal/cli-route-inventory.js +1 -5
  20. package/dist/lib/internal/manual-validation.js +18 -10
  21. package/dist/lib/internal/task-create.js +1 -1
  22. package/dist/lib/internal/task-event.js +1 -8
  23. package/dist/lib/internal/task-finalization.js +0 -1
  24. package/dist/lib/internal/task-lifecycle.js +2 -2
  25. package/dist/lib/internal/task-operation-registry.js +4 -20
  26. package/dist/lib/internal/task-review.js +4 -4
  27. package/dist/lib/platform/comment-safety.js +1 -7
  28. package/dist/lib/platform/in-label-sync.js +1 -14
  29. package/dist/lib/platform/issue-comments.js +1 -16
  30. package/dist/lib/platform/issues.js +1 -1
  31. package/dist/lib/platform/operation-coordinator.js +4 -2
  32. package/dist/lib/platform/pr-change-report.js +1 -4
  33. package/dist/lib/platform/pr-checks.js +2 -8
  34. package/dist/lib/platform/provider-validation.js +0 -20
  35. package/dist/lib/platform/pull-requests.js +73 -84
  36. package/dist/lib/platform/releases.js +1 -43
  37. package/dist/lib/platform/verification-required.js +0 -2
  38. package/dist/lib/platform/verification-sync.js +1 -79
  39. package/dist/lib/process-data/normalize.js +1 -185
  40. package/dist/lib/process-data/privacy.js +1 -16
  41. package/dist/lib/process-data/sources.js +2 -279
  42. package/dist/lib/render.js +0 -12
  43. package/dist/lib/run/index.js +15 -10
  44. package/dist/lib/run/skills.js +0 -3
  45. package/dist/lib/sandbox/commands/create.js +40 -53
  46. package/dist/lib/sandbox/commands/list-running.js +0 -18
  47. package/dist/lib/sandbox/commands/start.js +7 -8
  48. package/dist/lib/sandbox/constants.js +0 -6
  49. package/dist/lib/sandbox/control/client.js +0 -1
  50. package/dist/lib/sandbox/control/container-identity.js +1 -16
  51. package/dist/lib/sandbox/control/executor.js +0 -4
  52. package/dist/lib/sandbox/control/identity-sentinel.js +0 -7
  53. package/dist/lib/sandbox/control/lifecycle.js +21 -37
  54. package/dist/lib/sandbox/control/native-file-lock.js +0 -3
  55. package/dist/lib/sandbox/control/server.js +18 -38
  56. package/dist/lib/sandbox/control/state.js +1 -9
  57. package/dist/lib/sandbox/dockerfile.js +0 -6
  58. package/dist/lib/sandbox/engine.js +0 -14
  59. package/dist/lib/sandbox/engines/docker-exact-discovery.js +1 -4
  60. package/dist/lib/sandbox/engines/wsl2-paths.js +0 -3
  61. package/dist/lib/sandbox/recovery.js +24 -26
  62. package/dist/lib/sandbox/removal.js +11 -519
  63. package/dist/lib/sandbox/task-resolver.js +0 -41
  64. package/dist/lib/sandbox/tools.js +1 -4
  65. package/dist/lib/sandbox/workspace-view.js +1 -2
  66. package/dist/lib/server/display.js +0 -6
  67. package/dist/lib/task/activity-intent.js +45 -40
  68. package/dist/lib/task/activity-log.js +9 -16
  69. package/dist/lib/task/artifact-command.js +1 -1
  70. package/dist/lib/task/artifact-lifecycle.js +61 -63
  71. package/dist/lib/task/artifact-name.js +0 -6
  72. package/dist/lib/task/artifact-operations.js +3 -3
  73. package/dist/lib/task/capabilities.js +4 -5
  74. package/dist/lib/task/commands/log.js +0 -6
  75. package/dist/lib/task/commands/status.js +17 -60
  76. package/dist/lib/task/commit-operation.js +28 -39
  77. package/dist/lib/task/completion-facts.js +56 -43
  78. package/dist/lib/task/control-authority.js +23 -256
  79. package/dist/lib/task/control-recovery.js +3 -5
  80. package/dist/lib/task/create.js +2 -4
  81. package/dist/lib/task/decision-intents.js +8 -9
  82. package/dist/lib/task/delivery-target.js +1 -40
  83. package/dist/lib/task/events.js +84 -107
  84. package/dist/lib/task/finalization.js +44 -8
  85. package/dist/lib/task/ledger-intents.js +1 -1
  86. package/dist/lib/task/lifecycle-execution.js +38 -33
  87. package/dist/lib/task/lifecycle.js +49 -41
  88. package/dist/lib/task/local-artifact-finalization.js +1 -4
  89. package/dist/lib/task/manual-validation-evidence.js +1 -37
  90. package/dist/lib/task/platform-operation-recovery.js +67 -24
  91. package/dist/lib/task/pr-delivery-fact.js +2 -5
  92. package/dist/lib/task/qualification-confirmation.js +5 -7
  93. package/dist/lib/task/resolve-ref.js +1 -25
  94. package/dist/lib/task/review-command.js +2 -2
  95. package/dist/lib/task/review-finalization.js +1 -21
  96. package/dist/lib/task/review-fingerprint.js +0 -4
  97. package/dist/lib/task/secure-fs.js +0 -56
  98. package/dist/lib/task/short-id.js +1 -39
  99. package/dist/lib/task/skill-scope.js +0 -1
  100. package/dist/lib/task/verification-engine.js +58 -282
  101. package/dist/lib/task/verification.js +6 -3
  102. package/dist/lib/task/write.js +11 -1
  103. package/lib/agent-clients/adapter.ts +0 -76
  104. package/lib/agent-clients/adapters/antigravity-cli.ts +0 -5
  105. package/lib/agent-clients/adapters/claude-code-credentials.ts +0 -19
  106. package/lib/agent-clients/adapters/claude-code.ts +0 -9
  107. package/lib/agent-clients/adapters/codex.ts +0 -56
  108. package/lib/agent-clients/adapters/opencode.ts +0 -5
  109. package/lib/agent-clients/adapters/traecli.ts +0 -5
  110. package/lib/agent-clients/config.ts +20 -61
  111. package/lib/agent-clients/registry.ts +1 -34
  112. package/lib/agent-clients/schema.ts +0 -18
  113. package/lib/agent-clients/tokens.ts +1 -2
  114. package/lib/agent-clients/types.ts +0 -15
  115. package/lib/decide.ts +1 -0
  116. package/lib/git/worktree-identity.ts +0 -10
  117. package/lib/internal/agent-client.ts +2 -70
  118. package/lib/internal/cli-route-inventory.ts +1 -4
  119. package/lib/internal/manual-validation.ts +16 -9
  120. package/lib/internal/task-create.ts +0 -1
  121. package/lib/internal/task-event.ts +1 -5
  122. package/lib/internal/task-finalization.ts +0 -1
  123. package/lib/internal/task-lifecycle.ts +3 -5
  124. package/lib/internal/task-operation-registry.ts +3 -19
  125. package/lib/internal/task-review.ts +4 -4
  126. package/lib/platform/comment-safety.ts +0 -10
  127. package/lib/platform/github-provider.ts +0 -2
  128. package/lib/platform/in-label-sync.ts +0 -16
  129. package/lib/platform/issue-comments.ts +0 -21
  130. package/lib/platform/issues.ts +0 -2
  131. package/lib/platform/operation-coordinator.ts +4 -2
  132. package/lib/platform/pr-change-report.ts +0 -5
  133. package/lib/platform/pr-checks.ts +1 -10
  134. package/lib/platform/pr-review.ts +1 -1
  135. package/lib/platform/provider-bridge.ts +0 -1
  136. package/lib/platform/provider-loader.ts +1 -5
  137. package/lib/platform/provider-validation.ts +1 -49
  138. package/lib/platform/pull-requests.ts +64 -99
  139. package/lib/platform/releases.ts +1 -40
  140. package/lib/platform/verification-required.ts +0 -2
  141. package/lib/platform/verification-sync.ts +0 -94
  142. package/lib/process-data/normalize.ts +1 -186
  143. package/lib/process-data/privacy.ts +2 -19
  144. package/lib/process-data/sources.ts +3 -283
  145. package/lib/render.ts +0 -15
  146. package/lib/run/index.ts +13 -7
  147. package/lib/run/skills.ts +0 -4
  148. package/lib/sandbox/commands/create.ts +37 -74
  149. package/lib/sandbox/commands/list-running.ts +0 -19
  150. package/lib/sandbox/commands/start.ts +7 -10
  151. package/lib/sandbox/constants.ts +0 -8
  152. package/lib/sandbox/control/client.ts +0 -1
  153. package/lib/sandbox/control/container-identity.ts +1 -16
  154. package/lib/sandbox/control/executor.ts +1 -5
  155. package/lib/sandbox/control/identity-sentinel.ts +0 -8
  156. package/lib/sandbox/control/lifecycle.ts +18 -51
  157. package/lib/sandbox/control/native-file-lock.ts +0 -8
  158. package/lib/sandbox/control/protocol.ts +0 -2
  159. package/lib/sandbox/control/server.ts +13 -39
  160. package/lib/sandbox/control/state.ts +1 -10
  161. package/lib/sandbox/dockerfile.ts +0 -11
  162. package/lib/sandbox/engine.ts +0 -17
  163. package/lib/sandbox/engines/docker-exact-discovery.ts +1 -5
  164. package/lib/sandbox/engines/wsl2-paths.ts +0 -4
  165. package/lib/sandbox/recovery.ts +24 -26
  166. package/lib/sandbox/removal.ts +11 -696
  167. package/lib/sandbox/shell.ts +1 -1
  168. package/lib/sandbox/task-resolver.ts +0 -48
  169. package/lib/sandbox/tools.ts +1 -5
  170. package/lib/sandbox/workspace-view.ts +2 -4
  171. package/lib/server/display.ts +0 -14
  172. package/lib/server/process-control.ts +1 -1
  173. package/lib/task/activity-intent.ts +36 -44
  174. package/lib/task/activity-log.ts +9 -22
  175. package/lib/task/artifact-command.ts +1 -1
  176. package/lib/task/artifact-lifecycle.ts +58 -67
  177. package/lib/task/artifact-name.ts +0 -7
  178. package/lib/task/artifact-operations.ts +3 -3
  179. package/lib/task/capabilities.ts +5 -6
  180. package/lib/task/commands/log.ts +0 -7
  181. package/lib/task/commands/status.ts +14 -79
  182. package/lib/task/commit-operation.ts +29 -51
  183. package/lib/task/completion-facts.ts +45 -42
  184. package/lib/task/control-authority.ts +27 -317
  185. package/lib/task/control-recovery.ts +2 -5
  186. package/lib/task/create.ts +2 -5
  187. package/lib/task/decision-intents.ts +5 -5
  188. package/lib/task/delivery-target.ts +0 -40
  189. package/lib/task/events.ts +89 -123
  190. package/lib/task/finalization.ts +41 -9
  191. package/lib/task/ledger-intents.ts +1 -1
  192. package/lib/task/lifecycle-execution.ts +37 -89
  193. package/lib/task/lifecycle.ts +48 -44
  194. package/lib/task/local-artifact-finalization.ts +0 -7
  195. package/lib/task/manual-validation-evidence.ts +1 -47
  196. package/lib/task/platform-operation-recovery.ts +50 -26
  197. package/lib/task/pr-delivery-fact.ts +2 -11
  198. package/lib/task/qualification-confirmation.ts +6 -6
  199. package/lib/task/resolve-ref.ts +0 -23
  200. package/lib/task/review-command.ts +2 -2
  201. package/lib/task/review-finalization.ts +1 -27
  202. package/lib/task/review-fingerprint.ts +0 -8
  203. package/lib/task/secure-fs.ts +0 -42
  204. package/lib/task/short-id.ts +0 -43
  205. package/lib/task/skill-scope.ts +0 -1
  206. package/lib/task/verification-engine.ts +56 -287
  207. package/lib/task/verification.ts +5 -5
  208. package/lib/task/write.ts +12 -1
  209. package/package.json +2 -2
  210. package/templates/.agents/README.en.md +1 -3
  211. package/templates/.agents/README.zh-CN.md +0 -2
  212. package/templates/.agents/rules/README.en.md +0 -1
  213. package/templates/.agents/rules/README.zh-CN.md +0 -1
  214. package/templates/.agents/rules/commit-and-pr.en.md +1 -1
  215. package/templates/.agents/rules/commit-and-pr.zh-CN.md +1 -1
  216. package/templates/.agents/rules/no-mid-flow-questions.en.md +0 -10
  217. package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +0 -10
  218. package/templates/.agents/rules/pr-sync.en.md +1 -1
  219. package/templates/.agents/rules/pr-sync.zh-CN.md +1 -1
  220. package/templates/.agents/rules/task-management.en.md +3 -3
  221. package/templates/.agents/rules/task-management.zh-CN.md +3 -3
  222. package/templates/.agents/skills/analyze-task/SKILL.en.md +3 -3
  223. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +3 -3
  224. package/templates/.agents/skills/cancel-task/SKILL.en.md +2 -2
  225. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +2 -2
  226. package/templates/.agents/skills/code-task/SKILL.en.md +2 -2
  227. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +4 -4
  228. package/templates/.agents/skills/commit/SKILL.en.md +2 -2
  229. package/templates/.agents/skills/commit/SKILL.zh-CN.md +2 -2
  230. package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +6 -6
  231. package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +6 -6
  232. package/templates/.agents/skills/plan-task/SKILL.en.md +2 -2
  233. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +2 -2
  234. package/templates/.agents/skills/review-analysis/SKILL.en.md +3 -3
  235. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +3 -3
  236. package/templates/.agents/skills/review-code/SKILL.en.md +5 -5
  237. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +5 -5
  238. package/templates/.agents/skills/review-plan/SKILL.en.md +3 -3
  239. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +3 -3
  240. package/templates/.agents/skills/review-pr/SKILL.en.md +4 -4
  241. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +4 -4
  242. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +1 -1
  243. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +1 -1
  244. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +3 -75
  245. package/templates/.agents/templates/task.en.md +1 -0
  246. package/templates/.agents/templates/task.zh-CN.md +1 -0
  247. package/templates/.claude/settings.json +0 -24
  248. package/templates/.codex/hooks.json +0 -50
  249. package/dist/lib/agent-clients/adapters/codex-lifecycle/app-server.js +0 -582
  250. package/dist/lib/agent-clients/adapters/codex-lifecycle/binding.js +0 -114
  251. package/dist/lib/agent-clients/adapters/codex-lifecycle/build-identity.js +0 -237
  252. package/dist/lib/agent-clients/adapters/codex-lifecycle/cli.js +0 -443
  253. package/dist/lib/agent-clients/adapters/codex-lifecycle/evidence.js +0 -236
  254. package/dist/lib/agent-clients/adapters/codex-lifecycle/recovery.js +0 -292
  255. package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +0 -267
  256. package/dist/lib/agent-clients/adapters/codex-orchestration.js +0 -466
  257. package/dist/lib/internal/task-orchestration.js +0 -71
  258. package/dist/lib/platform/verification.js +0 -6
  259. package/dist/lib/run/prompt.js +0 -2
  260. package/dist/lib/sandbox/engines/authority.js +0 -289
  261. package/dist/lib/task/delegation-receipts.js +0 -410
  262. package/dist/lib/task/orchestration.js +0 -1233
  263. package/dist/lib/task/verification-checks.js +0 -9
  264. package/dist/lib/task/workspace-snapshot.js +0 -121
  265. package/dist/lifecycle-build-manifest.json +0 -6
  266. package/lib/agent-clients/adapters/codex-lifecycle/app-server.ts +0 -688
  267. package/lib/agent-clients/adapters/codex-lifecycle/binding.ts +0 -147
  268. package/lib/agent-clients/adapters/codex-lifecycle/build-identity.ts +0 -349
  269. package/lib/agent-clients/adapters/codex-lifecycle/cli.ts +0 -506
  270. package/lib/agent-clients/adapters/codex-lifecycle/evidence.ts +0 -385
  271. package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +0 -41
  272. package/lib/agent-clients/adapters/codex-lifecycle/recovery.ts +0 -418
  273. package/lib/agent-clients/adapters/codex-lifecycle/store.ts +0 -354
  274. package/lib/agent-clients/adapters/codex-orchestration.ts +0 -630
  275. package/lib/internal/task-orchestration.ts +0 -74
  276. package/lib/platform/verification.ts +0 -11
  277. package/lib/run/prompt.ts +0 -1
  278. package/lib/sandbox/engines/authority.ts +0 -365
  279. package/lib/task/delegation-receipts.ts +0 -547
  280. package/lib/task/orchestration.ts +0 -1651
  281. package/lib/task/verification-checks.ts +0 -10
  282. package/lib/task/workspace-snapshot.ts +0 -144
  283. package/templates/.agents/hooks/lifecycle-delegation.js +0 -140
  284. package/templates/.agents/rules/lifecycle-orchestration.en.md +0 -44
  285. package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +0 -44
  286. package/templates/.agents/skills/run-task/SKILL.en.md +0 -29
  287. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +0 -29
  288. package/templates/.agents/skills/run-task/config/verify.en.json +0 -10
  289. package/templates/.agents/skills/run-task/config/verify.zh-CN.json +0 -10
  290. package/templates/.agents/skills/run-task/reference/host-validation.en.md +0 -24
  291. package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +0 -24
  292. package/templates/.claude/agents/agent-infra-lifecycle-executor.en.md +0 -6
  293. package/templates/.claude/agents/agent-infra-lifecycle-executor.zh-CN.md +0 -6
  294. package/templates/.claude/agents/agent-infra-lifecycle-reviewer.en.md +0 -6
  295. package/templates/.claude/agents/agent-infra-lifecycle-reviewer.zh-CN.md +0 -6
  296. package/templates/.claude/commands/run-task.en.md +0 -8
  297. package/templates/.claude/commands/run-task.zh-CN.md +0 -8
  298. package/templates/.codex/agents/agent-infra-lifecycle-executor.en.toml +0 -3
  299. package/templates/.codex/agents/agent-infra-lifecycle-executor.zh-CN.toml +0 -3
  300. package/templates/.codex/agents/agent-infra-lifecycle-reviewer.en.toml +0 -3
  301. package/templates/.codex/agents/agent-infra-lifecycle-reviewer.zh-CN.toml +0 -3
  302. package/templates/.opencode/commands/run-task.en.md +0 -11
  303. package/templates/.opencode/commands/run-task.zh-CN.md +0 -11
@@ -7,8 +7,8 @@ import { inspectPlatformCommentOperation, syncPlatformComment } from '../platfor
7
7
  import { parseDeliverySummaryContent, renderDeliverySummaryContent, parseCancelSummaryContent, renderCancelSummaryContent } from '../platform/issue-summary-content.ts';
8
8
  import { enumerateArtifacts } from './artifacts.ts';
9
9
  import { inspectPlatformIssue, syncPlatformIssue } from '../platform/issues.ts';
10
- import { resolvePlatformProviderContext } from '../platform/context.ts';
11
- import { providerOperationContext, providerError, unsupportedProviderOperation } from '../platform/provider-bridge.ts';
10
+ import '../platform/context.ts';
11
+ import '../platform/provider-bridge.ts';
12
12
  import { inLabelMappingDigest } from '../platform/in-label-sync.ts';
13
13
  import { bindPlatformPullRequest, recoverCreatedPullRequest, syncPlatformPullRequest } from '../platform/pull-requests.ts';
14
14
  import { replayPullRequestSummary } from '../platform/pr-summary.ts';
@@ -21,11 +21,12 @@ import { operationId } from './platform-operation-journal.ts';
21
21
  import { canonicalizeSummaryBody } from '../platform/comment-safety.ts';
22
22
  import { platformResult } from '../platform/types.ts';
23
23
  import type { PlatformResult } from '../platform/types.ts';
24
+ import { mergeOperationWarnings, type OperationWarning } from './operation-outcome.ts';
24
25
  import { resolveTaskRef } from './resolve-ref.ts';
25
26
  import { readPlatformOperationJournal, recordPlatformOperation } from './platform-operation-journal.ts';
26
- import { providerErrorRetryable } from '../platform/provider-validation.ts';
27
+ import '../platform/provider-validation.ts';
27
28
 
28
- type RecoveryOptions = Readonly<{ agent: string; client?: PlatformClient; cwd?: string; limit?: number; attempts?: number; excludeId?: string }>;
29
+ type RecoveryOptions = Readonly<{ agent: string; client?: PlatformClient; cwd?: string; limit?: number; attempts?: number; excludeId?: string; beforeId?: string }>;
29
30
  const DEFAULT_RECOVERY_ATTEMPTS = 3;
30
31
  type RecoveryResult = Readonly<{
31
32
  status: 'applied' | 'no-op' | 'blocked' | 'failed';
@@ -33,6 +34,8 @@ type RecoveryResult = Readonly<{
33
34
  recovered: readonly string[];
34
35
  pending: readonly string[];
35
36
  error: { code: string; message: string } | null;
37
+ degraded?: readonly { id: string; reasonCode: string }[];
38
+ warnings?: readonly OperationWarning[];
36
39
  }>;
37
40
  type RecoveryError = { code: string; message: string; retryable?: boolean };
38
41
 
@@ -48,8 +51,8 @@ function fieldsMatchExpected(
48
51
  return Object.entries(expected).every(([name, value]) => actual[name] === value);
49
52
  }
50
53
 
51
- function result(status: RecoveryResult['status'], recovered: string[], pending: string[], error: RecoveryError | null = null): RecoveryResult {
52
- return { status, changed: recovered.length > 0, recovered, pending, error: error ? { code: error.code, message: error.message } : null };
54
+ function result(status: RecoveryResult['status'], recovered: string[], pending: string[], error: RecoveryError | null = null, warnings: readonly OperationWarning[] = []): RecoveryResult {
55
+ return { status, changed: recovered.length > 0, recovered, pending, error: error ? { code: error.code, message: error.message } : null, ...(warnings.length ? { warnings } : {}) };
53
56
  }
54
57
 
55
58
  function summaryPayload(taskDir: string, taskId: string): { body: string; sha256: string } | null {
@@ -164,7 +167,8 @@ async function replayIssueMetadata(taskId: string, operation: ReturnType<typeof
164
167
  }
165
168
  const issue = after.issue;
166
169
  const metadata = operation.issueMetadata;
167
- const failedOperation = sync.operations.find((item) => item.status === 'failed' || item.status === 'skipped');
170
+ const failedOperation = sync.operations.find((item) => item.status === 'failed' || (item.status === 'skipped'
171
+ && !(sync.capabilities.push === false && ['fields', 'issue-type'].includes(item.name) && item.reasonCode === 'PUSH_REQUIRED')));
168
172
  if (failedOperation) return platformResult('blocked', { error: {
169
173
  code: failedOperation.reasonCode || 'PLATFORM_OPERATION_METADATA_UNCONFIRMED',
170
174
  message: `Issue metadata recovery did not confirm operation '${failedOperation.name}'`, retryable: true
@@ -189,7 +193,7 @@ async function replayIssueMetadata(taskId: string, operation: ReturnType<typeof
189
193
  code: 'PLATFORM_OPERATION_METADATA_UNCONFIRMED',
190
194
  message: 'Issue metadata differs from the requested recovery target after reread', retryable: true
191
195
  } });
192
- return platformResult('no-op', { changed: sync.changed || after.changed });
196
+ return platformResult('no-op', { changed: sync.changed || after.changed, operations: sync.operations });
193
197
  }
194
198
 
195
199
  async function verifyIssueCreate(taskId: string, operation: ReturnType<typeof readPlatformOperationJournal>['operations'][number], cwd: string, client?: PlatformClient): Promise<PlatformResult> {
@@ -265,6 +269,12 @@ function isRecoveryEligible(operation: ReturnType<typeof readPlatformOperationJo
265
269
  ;
266
270
  }
267
271
 
272
+ function recoveryCandidates(journal: ReturnType<typeof readPlatformOperationJournal>, options: RecoveryOptions) {
273
+ const boundary = options.beforeId ? journal.operations.findIndex((item) => item.id === options.beforeId) : journal.operations.length;
274
+ if (boundary < 0) throw Object.assign(new Error('Current platform operation boundary is unavailable'), { code: 'PLATFORM_OPERATION_BOUNDARY_MISSING' });
275
+ return journal.operations.slice(0, boundary).filter((item) => isRecoveryEligible(item, options.excludeId));
276
+ }
277
+
268
278
  async function recoverPlatformOperationsOnce(
269
279
  taskRef: string,
270
280
  selection: 'required' | 'deferred' | 'all',
@@ -278,7 +288,9 @@ async function recoverPlatformOperationsOnce(
278
288
  const value = error as { code?: string; message?: string };
279
289
  return result('failed', [], [], { code: value.code || 'PLATFORM_OPERATION_JOURNAL_INVALID', message: value.message || String(error), retryable: false });
280
290
  }
281
- const candidates = journal.operations.filter((operation) => isRecoveryEligible(operation, options.excludeId));
291
+ let candidates;
292
+ try { candidates = recoveryCandidates(journal, options); }
293
+ catch (error) { const value = error as { code: string; message: string }; return result('blocked', [], [], value); }
282
294
  if (!candidates.length) return result('no-op', [], []);
283
295
  const head = candidates[0]!;
284
296
  if (selection !== 'all' && head.dependency !== selection) {
@@ -291,8 +303,9 @@ async function recoverPlatformOperationsOnce(
291
303
  const limit = options.limit === undefined ? candidates.length : Math.max(1, options.limit);
292
304
  const recovered: string[] = [];
293
305
  const pending: string[] = [];
306
+ let warnings: readonly OperationWarning[] = [];
294
307
  const selected = candidates.slice(0, limit);
295
- for (const [index, operation] of selected.entries()) {
308
+ for (const operation of selected) {
296
309
  {
297
310
  try {
298
311
  recordPlatformOperation({
@@ -368,7 +381,7 @@ async function recoverPlatformOperationsOnce(
368
381
  }
369
382
  }
370
383
  }
371
- let remote: PlatformResult;
384
+ let remote: PlatformResult & { warnings?: readonly OperationWarning[] };
372
385
  try {
373
386
  remote = operation.kind === 'issue-create'
374
387
  ? await verifyIssueCreate(resolved.taskId, operation, resolved.repoRoot)
@@ -402,7 +415,7 @@ async function recoverPlatformOperationsOnce(
402
415
  ...(operation.pullRequestReview ? { pullRequestReview: operation.pullRequestReview } : {}),
403
416
  dependency: operation.dependency,
404
417
  state: succeeded ? 'succeeded' : 'unknown',
405
- lastCode: remote.error?.code ?? latestOperation?.lastCode ?? null
418
+ lastCode: remote.error?.code ?? remote.operations.find((item) => item.status === 'skipped' && item.reasonCode === 'PUSH_REQUIRED')?.reasonCode ?? (succeeded ? null : latestOperation?.lastCode) ?? null
406
419
  });
407
420
  } catch (error) {
408
421
  const value = error as { code?: string; message?: string };
@@ -412,11 +425,12 @@ async function recoverPlatformOperationsOnce(
412
425
  pending.push(targetOperation.id);
413
426
  return result(remote.status === 'failed' ? 'failed' : 'blocked', recovered, pending, remote.error ?? { code: 'PLATFORM_OPERATION_RECOVERY_UNKNOWN', message: 'Platform operation outcome remains unknown', retryable: true });
414
427
  }
428
+ warnings = mergeOperationWarnings(warnings, remote.warnings ?? []);
415
429
  recovered.push(targetOperation.id);
416
430
  }
417
431
  const remaining = candidates.slice(limit).map((operation) => operation.id);
418
432
  pending.push(...remaining);
419
- return result(pending.length ? 'blocked' : recovered.length ? 'applied' : 'no-op', recovered, pending, pending.length ? { code: 'PLATFORM_OPERATION_RECOVERY_PENDING', message: 'Platform operations remain pending after the recovery budget', retryable: true } : null);
433
+ return result(pending.length ? 'blocked' : recovered.length ? 'applied' : 'no-op', recovered, pending, pending.length ? { code: 'PLATFORM_OPERATION_RECOVERY_PENDING', message: 'Platform operations remain pending after the recovery budget', retryable: true } : null, warnings);
420
434
  }
421
435
 
422
436
  async function recoverPlatformOperations(
@@ -432,8 +446,9 @@ async function recoverPlatformOperations(
432
446
  const value = error as { code?: string; message?: string };
433
447
  return result('failed', [], [], { code: value.code || 'PLATFORM_OPERATION_JOURNAL_INVALID', message: value.message || String(error), retryable: false });
434
448
  }
435
- const eligible = (operation: typeof initial.operations[number]) => isRecoveryEligible(operation, options.excludeId);
436
- const first = initial.operations.filter(eligible);
449
+ let first;
450
+ try { first = recoveryCandidates(initial, options); }
451
+ catch (error) { const value = error as { code: string; message: string }; return result('blocked', [], [], value); }
437
452
  if (!first.length) return result('no-op', [], []);
438
453
  const operationLimit = options.limit === undefined ? first.length : Math.max(1, options.limit);
439
454
  const attemptLimit = options.attempts ?? DEFAULT_RECOVERY_ATTEMPTS;
@@ -441,47 +456,56 @@ async function recoverPlatformOperations(
441
456
  return result('failed', [], [], { code: 'PLATFORM_OPERATION_RECOVERY_PAYLOAD_INVALID', message: 'Recovery attempts must be a positive safe integer', retryable: false });
442
457
  }
443
458
  const recovered: string[] = [];
459
+ let warnings: readonly OperationWarning[] = [];
444
460
 
445
461
  for (let operationIndex = 0; operationIndex < operationLimit; operationIndex += 1) {
446
462
  let latest;
447
463
  try { latest = readPlatformOperationJournal(resolved.taskId, resolved.repoRoot); }
448
464
  catch (error) {
449
465
  const value = error as { code?: string; message?: string };
450
- return result('failed', recovered, [], { code: value.code || 'PLATFORM_OPERATION_JOURNAL_INVALID', message: value.message || String(error), retryable: false });
466
+ return result('failed', recovered, [], { code: value.code || 'PLATFORM_OPERATION_JOURNAL_INVALID', message: value.message || String(error), retryable: false }, warnings);
451
467
  }
452
- const head = latest.operations.find(eligible);
468
+ let candidates;
469
+ try { candidates = recoveryCandidates(latest, options); }
470
+ catch (error) { const value = error as { code: string; message: string }; return result('blocked', recovered, [], value, warnings); }
471
+ const head = candidates[0];
453
472
  if (!head) break;
454
473
  if (selection !== 'all' && head.dependency !== selection) {
455
- const pending = latest.operations.filter(eligible).map((operation) => operation.id);
474
+ const pending = candidates.map((operation) => operation.id);
456
475
  return result('blocked', recovered, pending, {
457
476
  code: 'PLATFORM_OPERATION_RECOVERY_PENDING',
458
477
  message: 'The first unresolved platform operation belongs to another recovery selection',
459
478
  retryable: true
460
- });
479
+ }, warnings);
461
480
  }
462
481
  let last: RecoveryResult | null = null;
463
482
  for (let attempt = 0; attempt < attemptLimit; attempt += 1) {
464
483
  last = await recoverPlatformOperationsOnce(taskRef, selection, { ...options, limit: 1 });
465
484
  recovered.push(...last.recovered.filter((id) => !recovered.includes(id)));
485
+ warnings = mergeOperationWarnings(warnings, last.warnings ?? []);
466
486
  if (last.recovered.length > 0 || last.status === 'applied' || last.status === 'no-op') break;
467
487
  }
468
488
  if (!last || (last.recovered.length === 0 && last.status !== 'applied' && last.status !== 'no-op')) {
469
489
  let current;
470
490
  try { current = readPlatformOperationJournal(resolved.taskId, resolved.repoRoot); }
471
- catch { return result('blocked', recovered, [head.id], last?.error ?? null); }
472
- const pending = current.operations.filter(eligible).map((operation) => operation.id);
491
+ catch { return result('blocked', recovered, [head.id], last?.error ?? null, warnings); }
492
+ let pending: string[];
493
+ try { pending = recoveryCandidates(current, options).map((operation) => operation.id); }
494
+ catch (error) { const value = error as { code: string; message: string }; return result('blocked', recovered, [], value, warnings); }
473
495
  return result(last?.status === 'failed' ? 'failed' : 'blocked', recovered, pending, last?.error ?? {
474
496
  code: 'PLATFORM_OPERATION_RECOVERY_PENDING',
475
497
  message: 'The first queued platform operation remains unresolved after this recovery run',
476
498
  retryable: true
477
- });
499
+ }, warnings);
478
500
  }
479
501
  }
480
502
  let remaining: string[];
481
- try { remaining = readPlatformOperationJournal(resolved.taskId, resolved.repoRoot).operations.filter(eligible).map((operation) => operation.id); }
482
- catch { remaining = []; }
483
- return result(remaining.length ? 'blocked' : recovered.length ? 'applied' : 'no-op', recovered, remaining,
484
- remaining.length ? { code: 'PLATFORM_OPERATION_RECOVERY_PENDING', message: 'Platform operations remain queued after this recovery run', retryable: true } : null);
503
+ try { remaining = recoveryCandidates(readPlatformOperationJournal(resolved.taskId, resolved.repoRoot), options).map((operation) => operation.id); }
504
+ catch (error) { const value = error as { code?: string; message?: string }; return result('blocked', recovered, [], { code: value.code || 'PLATFORM_OPERATION_JOURNAL_INVALID', message: value.message || 'Unable to read platform operations' }, warnings); }
505
+ const output = result(remaining.length ? 'blocked' : recovered.length ? 'applied' : 'no-op', recovered, remaining,
506
+ remaining.length ? { code: 'PLATFORM_OPERATION_RECOVERY_PENDING', message: 'Platform operations remain queued after this recovery run', retryable: true } : null, warnings);
507
+ const degraded = readPlatformOperationJournal(resolved.taskId, resolved.repoRoot).operations.filter((item) => recovered.includes(item.id) && item.lastCode === 'PUSH_REQUIRED').map((item) => ({ id: item.id, reasonCode: item.lastCode! }));
508
+ return degraded.length ? { ...output, degraded } : output;
485
509
  }
486
510
 
487
511
  export { fieldsMatchExpected, labelsMatchOwnedPrefix, recoverPlatformOperations };
@@ -1,10 +1,5 @@
1
1
  import type { ResourceIdentity } from '../platform/resource-identity.ts';
2
- import {
3
- isResourceIdentity,
4
- parseResourceIdentity,
5
- resourceIdentityNumber,
6
- serializeResourceIdentity
7
- } from '../platform/resource-identity.ts';
2
+ import { parseResourceIdentity, serializeResourceIdentity } from '../platform/resource-identity.ts';
8
3
 
9
4
  const PR_DELIVERY_FACT_KEY = 'pr_delivery_fact';
10
5
 
@@ -182,9 +177,5 @@ function buildBoundFact(input: {
182
177
  }, provenance: { establishedBy: provenanceForSource(input.source) } });
183
178
  }
184
179
  function factFrontmatterMutation(fact: PrDeliveryFact): { set: { [PR_DELIVERY_FACT_KEY]: string } } { return { set: { [PR_DELIVERY_FACT_KEY]: encodePrDeliveryFact(fact) } }; }
185
- function identityFromPullRequest(pullRequest: PrDeliveryIdentityInput): PrDeliveryIdentity {
186
- return canonicalIdentity(pullRequest);
187
- }
188
-
189
- export { PR_DELIVERY_FACT_KEY, buildBoundFact, buildSkippedFact, buildUnboundFact, decodePrDeliveryFact, encodePrDeliveryFact, factFrontmatterMutation, identityFromPullRequest, readPrDeliveryFact, serializeResourceIdentity };
180
+ export { PR_DELIVERY_FACT_KEY, buildBoundFact, buildSkippedFact, buildUnboundFact, decodePrDeliveryFact, encodePrDeliveryFact, factFrontmatterMutation, readPrDeliveryFact, serializeResourceIdentity };
190
181
  export type { CreationOutcome, PrDeliveryBindingSource, PrDeliveryFact, PrDeliveryFactError, PrDeliveryFactReadResult, PrDeliveryIdentity, PrDeliveryIdentityInput, PrDeliveryProvenance };
@@ -1,7 +1,7 @@
1
1
  import { createHash } from 'node:crypto';
2
2
  import fs from 'node:fs';
3
3
 
4
- import { appendActivityEntry, locateActivityLog } from './activity-log.ts';
4
+ import { activityWarnings, appendActivityEntry, locateActivityLog } from './activity-log.ts';
5
5
  import { CONFIRMATION_COLUMNS, CONFIRMATION_HEADINGS, constraintDigest, parseQualificationConfirmations, parseTaskQualification } from './qualification-audit.ts';
6
6
  import type { QualificationConfirmation } from './qualification-audit.ts';
7
7
  import { findSectionHeading } from './sections.ts';
@@ -25,6 +25,7 @@ type QualificationConfirmationResult = {
25
25
  requestId: string | null;
26
26
  operations: readonly TaskOperationSummary[];
27
27
  error: { code: string; message: string } | null;
28
+ warnings?: readonly { code: string; message: string }[];
28
29
  };
29
30
 
30
31
  function failed(code: string, message: string, taskId: string | null = null): QualificationConfirmationResult {
@@ -73,13 +74,13 @@ function applyQualificationConfirmation(request: QualificationConfirmationReques
73
74
  const previous = existing.confirmations.find((row) => row.qcrId === constraint.approvalEvidence);
74
75
  if (operation === 'confirm' && constraint.status === 'confirmed') {
75
76
  if (previous?.constraintId === constraint.constraintId && previous.approvedDigest === constraint.digest && previous.rationale === request.rationale.trim()) {
76
- return { status: 'no-op', changed: false, taskId: resolved.taskId, qcrId: previous.qcrId, requestId: previous.requestId, operations: [], error: null };
77
+ return { status: 'no-op', changed: false, taskId: resolved.taskId, qcrId: previous.qcrId, requestId: previous.requestId, operations: [], error: null, warnings: activityWarnings(content) };
77
78
  }
78
79
  return failed('QUALIFICATION_CONFIRMATION_CONFLICT', `constraint '${request.constraintId}' is already confirmed with different evidence`, resolved.taskId);
79
80
  }
80
81
  const transitionStatus = operation === 'supersede' ? 'superseded' : 'open';
81
82
  if (operation !== 'confirm' && constraint.status === transitionStatus && !constraint.approvalEvidence) {
82
- return { status: 'no-op', changed: false, taskId: resolved.taskId, qcrId: null, requestId: null, operations: [], error: null };
83
+ return { status: 'no-op', changed: false, taskId: resolved.taskId, qcrId: null, requestId: null, operations: [], error: null, warnings: activityWarnings(content) };
83
84
  }
84
85
  if (operation !== 'confirm' && constraint.status !== 'confirmed') return failed('QUALIFICATION_CONFIRMATION_REQUIRED', `constraint '${request.constraintId}' is not confirmed`, resolved.taskId);
85
86
  if (parsed.qualification.constraintDigest !== request.expectedDigest) return failed('QUALIFICATION_DIGEST_CONFLICT', 'constraint digest changed before human confirmation', resolved.taskId);
@@ -99,18 +100,17 @@ function applyQualificationConfirmation(request: QualificationConfirmationReques
99
100
  } : null;
100
101
  const confirmations = confirmation ? [...existing.confirmations, confirmation] : existing.confirmations;
101
102
  const activity = locateActivityLog(content);
102
- if (!activity) return failed('QUALIFICATION_ACTIVITY_MISSING', 'task has no unique Activity Log section', resolved.taskId);
103
103
  const mutations: Parameters<typeof writeTask>[0]['mutations'][number][] = [
104
104
  {
105
105
  kind: 'table-row', action: 'upsert', sectionAliases: ['约束', 'Constraints'], columns: ['constraint_id', 'statement', 'status', 'authority', 'source', 'evidence', 'derived_from', 'approval_evidence'], keyColumn: 'constraint_id', key: constraint.constraintId,
106
106
  values: { statement: constraint.statement, status: operation === 'confirm' ? 'confirmed' : transitionStatus, authority: operation === 'confirm' ? 'human-declared' : constraint.authority, source: constraint.source, evidence: constraint.evidence, derived_from: constraint.derivedFrom.join(','), approval_evidence: qcrId ?? '' }
107
107
  },
108
108
  ...(operation === 'confirm' ? [{ kind: 'section' as const, aliases: CONFIRMATION_HEADINGS, heading: findSectionHeading(content, [...CONFIRMATION_HEADINGS]), body: renderConfirmations(confirmations) }] : []),
109
- { kind: 'section', aliases: ['活动日志', 'Activity Log'], heading: activity.heading, body: appendActivityEntry(activity, { time: metadata.timestamp, step: 'Qualification Confirmation', agent: 'human', note: operation === 'confirm' ? `${request.constraintId} confirmed → ${qcrId}` : `${request.constraintId} ${operation}d` }) }
109
+ ...(activity ? [{ kind: 'section' as const, aliases: ['活动日志', 'Activity Log'], heading: activity.heading, body: appendActivityEntry(activity, { time: metadata.timestamp, step: 'Qualification Confirmation', agent: 'human', note: operation === 'confirm' ? `${request.constraintId} confirmed → ${qcrId}` : `${request.constraintId} ${operation}d` }) }] : [])
110
110
  ];
111
111
  const result = writeTask({ taskRef: resolved.taskId, expectedState: 'active', mutations, dryRun: request.dryRun }, { ...options, taskLocation: { repoRoot: resolved.repoRoot, taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, state: resolved.state }, metadataProvider: () => metadata });
112
112
  if (result.status === 'failed') return failed(result.error.code, result.error.message, result.taskId);
113
- return { status: result.status, changed: result.changed, taskId: result.taskId, qcrId, requestId, operations: result.operations, error: null };
113
+ return { status: result.status, changed: result.changed, taskId: result.taskId, qcrId, requestId, operations: result.operations, error: null, warnings: activityWarnings(content) };
114
114
  }
115
115
 
116
116
  export { applyQualificationConfirmation };
@@ -114,28 +114,6 @@ function findTaskMd(
114
114
  return archived ? { taskMdPath: archived, state: 'archive' } : null;
115
115
  }
116
116
 
117
- /**
118
- * Enumerate every task directory under the flat workspace states
119
- * (active / blocked / completed) — archive is intentionally excluded so a
120
- * full-tree scan never pulls in cold data. Ordered by state, then task id
121
- * ascending, giving callers a deterministic traversal.
122
- */
123
- function enumerateTaskDirs(repoRoot: string): { taskId: string; taskDir: string }[] {
124
- const out: { taskId: string; taskDir: string }[] = [];
125
- const workspaceRoot = taskRoot(repoRoot);
126
- for (const sub of FLAT_WORKSPACE_DIRS) {
127
- const base = path.join(workspaceRoot, sub);
128
- if (!fs.existsSync(base)) continue;
129
- for (const entry of fs.readdirSync(base).sort()) {
130
- if (!TASK_ID_RE.test(entry)) continue;
131
- const taskDir = path.join(base, entry);
132
- if (!fs.existsSync(path.join(taskDir, 'task.md'))) continue;
133
- out.push({ taskId: entry, taskDir });
134
- }
135
- }
136
- return out;
137
- }
138
-
139
117
  /**
140
118
  * Enumerate every task directory, including the cold YYYY/MM/DD archive.
141
119
  * Invalid directory names, symlinks and entries without task.md are ignored;
@@ -364,7 +342,6 @@ export {
364
342
  resolveTaskRef,
365
343
  resolveTaskContext,
366
344
  detectRepoRoot,
367
- enumerateTaskDirs,
368
345
  enumerateAllTaskDirs,
369
346
  locateHotTaskDirs,
370
347
  TASK_ID_RE
@@ -4,14 +4,14 @@ export function parseReviewCommand(args: readonly string[]): ReviewFinalizationR
4
4
  if (!args[0] || !['preflight', 'finalize-summary'].includes(args[1] ?? '')) throw new Error('task ref and a supported review operation are required');
5
5
  const values: Record<string, string | boolean> = {};
6
6
  const flags = {
7
- '--stage': 'stage', '--artifact': 'artifact', '--orchestrated': 'orchestrated', '--dry-run': 'dryRun'
7
+ '--stage': 'stage', '--artifact': 'artifact', '--dry-run': 'dryRun'
8
8
  } as const;
9
9
  for (let index = 2; index < args.length; index += 1) {
10
10
  const flag = args[index]!;
11
11
  if (!Object.hasOwn(flags, flag)) throw new Error(`unknown option '${flag}'`);
12
12
  const key = flags[flag as keyof typeof flags];
13
13
  if (Object.hasOwn(values, key)) throw new Error(`duplicate option '${flag}'`);
14
- const value = flag === '--orchestrated' || flag === '--dry-run' ? true : args[++index];
14
+ const value = flag === '--dry-run' ? true : args[++index];
15
15
  if (!value || typeof value === 'string' && value.startsWith('--')) throw new Error(`option '${flag}' requires a value`);
16
16
  values[key] = value;
17
17
  }
@@ -9,7 +9,6 @@ import type { LedgerStageStatus, ReviewStage } from './ledger.ts';
9
9
  import { finalizeReviewSummaryContent } from './review-artifacts.ts';
10
10
  import { inspectDecisionDetailDuplicates } from './decision-details.ts';
11
11
  import { resolveTaskRef } from './resolve-ref.ts';
12
- import { validateLifecycleExecution } from './lifecycle-execution.ts';
13
12
  import type { ResolveTaskRefErrorCode } from './resolve-ref.ts';
14
13
  import { getArtifactSchema } from './artifact-schema.ts';
15
14
  import { validateQualificationAudit } from './qualification-audit.ts';
@@ -36,7 +35,6 @@ type ReviewFinalizationRequest = {
36
35
  taskRef: string;
37
36
  stage: string;
38
37
  artifact: string;
39
- orchestrated?: boolean;
40
38
  dryRun?: boolean;
41
39
  };
42
40
  type ReviewFinalizationResult = {
@@ -144,13 +142,6 @@ function preflightReviewSummary(
144
142
  content = fs.readFileSync(validated.artifact.path, 'utf8');
145
143
  } catch (error) { return preflightFailed(request, 'REVIEW_ARTIFACT_NOT_REGULAR', String(error), resolved.taskId); }
146
144
 
147
- const execution = validateLifecycleExecution(request.taskRef, {
148
- mode: request.orchestrated ? 'orchestrated' : 'standalone',
149
- identity: { stage: spec.family, round: parsed.round, artifact: request.artifact, role: 'reviewer' },
150
- dryRun: request.dryRun
151
- }, { repoRoot: options.repoRoot });
152
- if (!execution.ok) return preflightFailed(request, 'REVIEW_PROVENANCE_INVALID', `${execution.error?.code ?? 'ORCHESTRATION_PROVENANCE_MISMATCH'}: ${execution.error?.message ?? 'orchestration provenance validation failed'}`, resolved.taskId);
153
-
154
145
  const artifactSha256 = sha256Content(content);
155
146
  const semanticDigest = canonicalSemanticDigest(content);
156
147
  const detail = inspectDecisionDetailDuplicates(content);
@@ -211,15 +202,6 @@ function prepareReviewSummaryCandidate(
211
202
  catch (error) { return reject('REVIEW_ARTIFACT_NOT_REGULAR', String(error)); }
212
203
  const artifactSha256 = sha256Content(artifactContent);
213
204
  const semanticDigest = canonicalSemanticDigest(artifactContent);
214
- const digests = { artifactSha256, semanticDigest };
215
- const execution = validateLifecycleExecution(request.taskRef, {
216
- mode: request.orchestrated ? 'orchestrated' : 'standalone',
217
- identity: { stage: spec.family, round: parsed.round, artifact: request.artifact, role: 'reviewer' },
218
- dryRun: request.dryRun
219
- }, { repoRoot: options.repoRoot });
220
- if (!execution.ok) {
221
- return reject('REVIEW_PROVENANCE_INVALID', `${execution.error?.code ?? 'ORCHESTRATION_PROVENANCE_MISMATCH'}: ${execution.error?.message ?? 'orchestration provenance validation failed'}`);
222
- }
223
205
  try {
224
206
  const ledger = parseLedgerDocument(taskContent);
225
207
  if (!ledger.present) return reject('REVIEW_LEDGER_INVALID', `${LEDGER_SECTION_MISSING_CODE}: ${LEDGER_SECTION_MISSING_MESSAGE}`);
@@ -259,14 +241,6 @@ function prepareReviewSummaryCandidate(
259
241
  };
260
242
  }
261
243
 
262
- function commitReviewSummaryProvenance(
263
- prepared: ReviewSummaryCandidatePreparation,
264
- repoRoot: string,
265
- options: Readonly<{ afterPublish?: () => void }> = {}
266
- ): ReviewFinalizationResult {
267
- return prepared.result;
268
- }
269
-
270
244
  function replaceCurrentArtifactAtomically(file: string, content: string): void {
271
245
  const temporary = path.join(path.dirname(file), `.${path.basename(file)}.${process.pid}.${randomUUID()}.tmp`);
272
246
  try {
@@ -316,7 +290,7 @@ function finalizeReviewSummary(
316
290
  }
317
291
  }
318
292
 
319
- export { finalizeReviewSummary, preflightReviewSummary, prepareReviewSummaryCandidate, commitReviewSummaryProvenance };
293
+ export { finalizeReviewSummary, preflightReviewSummary, prepareReviewSummaryCandidate };
320
294
  export type {
321
295
  ReviewFinalizationError,
322
296
  ReviewFinalizationErrorCode,
@@ -3,13 +3,6 @@ import path from "node:path";
3
3
 
4
4
  import { inspectArtifactDirectory } from "./artifact-lifecycle.ts";
5
5
 
6
- type ReviewedGitTree = string & { readonly __reviewedGitTree: unique symbol };
7
- const REVIEWED_TREE_RE = /^[a-f0-9]{40,64}$/;
8
-
9
- export function parseReviewedGitTree(value: string): ReviewedGitTree | null {
10
- return REVIEWED_TREE_RE.test(value) ? value as ReviewedGitTree : null;
11
- }
12
-
13
6
  // Paths excluded from the post-review coverage gate. Fail-closed: the gate
14
7
  // covers ALL tracked changes by default. This default denylist is EMPTY —
15
8
  // projects opt into exclusions explicitly via review.post_review_exclude_globs.
@@ -87,7 +80,6 @@ export function extractReviewedSnapshotTree(content: string): string {
87
80
  return match ? match[1]!.trim().replace(/`/g, "") : "";
88
81
  }
89
82
 
90
- export type { ReviewedGitTree };
91
83
 
92
84
  export function parseReviewVerdict(content: string): string {
93
85
  const match = String(content).match(/^[-*]?\s*\*\*(?:总体结论|Overall Verdict)\*\*[::]\s*(.*?)\s*$/m);
@@ -3,7 +3,6 @@ import fs from 'node:fs';
3
3
  import path from 'node:path';
4
4
 
5
5
  const NO_FOLLOW = fs.constants.O_NOFOLLOW ?? 0;
6
- const DIRECTORY = fs.constants.O_DIRECTORY ?? 0;
7
6
 
8
7
  export class SecureFileError extends Error {
9
8
  readonly code: string;
@@ -40,10 +39,6 @@ function assertNoSymlinkAncestors(candidate: string): void {
40
39
  }
41
40
  }
42
41
 
43
- export async function readStableFile(candidate: string, options: Readonly<{ maxBytes: number; expectedSha256?: string }>): Promise<StableFile> {
44
- return readStableFileSync(candidate, options);
45
- }
46
-
47
42
  export function readStableFileSync(candidate: string, options: Readonly<{ maxBytes: number; expectedSha256?: string }>): StableFile {
48
43
  if (!path.isAbsolute(candidate)) conflict('candidate path must be absolute and terminal');
49
44
  assertNoSymlinkAncestors(candidate);
@@ -74,40 +69,3 @@ export function readStableFileSync(candidate: string, options: Readonly<{ maxByt
74
69
  if (descriptor !== undefined) fs.closeSync(descriptor);
75
70
  }
76
71
  }
77
-
78
- export async function writeAtomicFile(target: string, bytes: Buffer, mode = 0o600, expectedSha256?: string): Promise<void> {
79
- const parent = path.dirname(target);
80
- let current = path.resolve(parent);
81
- while (true) {
82
- let stat: fs.Stats;
83
- try { stat = await fs.promises.lstat(current); }
84
- catch { throw new SecureFileError('TASK_ARTIFACT_WRITE_CONFLICT', 'authoritative parent directory is missing'); }
85
- if (!stat.isDirectory() || stat.isSymbolicLink()) throw new SecureFileError('TASK_ARTIFACT_WRITE_CONFLICT', 'authoritative parent directory is not a real directory');
86
- const next = path.dirname(current);
87
- if (next === current) break;
88
- current = next;
89
- }
90
- try {
91
- const existing = await fs.promises.lstat(target);
92
- if (existing.isSymbolicLink() || !existing.isFile()) throw new SecureFileError('TASK_ARTIFACT_WRITE_CONFLICT', 'authoritative target is not a regular file');
93
- } catch (error) {
94
- if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;
95
- }
96
- const temporary = path.join(parent, `.${path.basename(target)}.${process.pid}.${Date.now()}.tmp`);
97
- let handle: fs.promises.FileHandle | undefined;
98
- try {
99
- handle = await fs.promises.open(temporary, fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL, mode);
100
- await handle.writeFile(bytes);
101
- await handle.sync();
102
- await handle.chmod(mode);
103
- await handle.close();
104
- handle = undefined;
105
- if (expectedSha256 !== undefined) readStableFileSync(target, { maxBytes: 1024 * 1024, expectedSha256 });
106
- fs.renameSync(temporary, target);
107
- const directory = await fs.promises.open(parent, fs.constants.O_RDONLY | DIRECTORY);
108
- try { await directory.sync(); } finally { await directory.close(); }
109
- } finally {
110
- await handle?.close().catch(() => undefined);
111
- await fs.promises.rm(temporary, { force: true }).catch(() => undefined);
112
- }
113
- }
@@ -447,15 +447,6 @@ function readRegistry(repoRoot: string): RegistrySchema | null {
447
447
  }
448
448
  }
449
449
 
450
- function readBranchFromTaskMd(repoRoot: string, taskId: string): string | null {
451
- const taskMdPath = path.join(resolveProjectTaskWorkspaceRoot(repoRoot), 'active', taskId, 'task.md');
452
- if (!fs.existsSync(taskMdPath)) return null;
453
- const content = fs.readFileSync(taskMdPath, 'utf8');
454
- const m = content.match(/^branch:\s*(.+)$/m);
455
- if (!m || !m[1]) return null;
456
- return m[1].trim().replace(/^(["'])(.*)\1$/, '$2');
457
- }
458
-
459
450
  function loadShortIdByTaskId(repoRoot: string): Map<string, string> {
460
451
  const registry = readRegistry(repoRoot);
461
452
  const map = new Map<string, string>();
@@ -527,44 +518,10 @@ function inspectShortIdRegistry(
527
518
  }
528
519
  }
529
520
 
530
- /**
531
- * Resolve a branch to its active-task short id (`NN`), or `null` when no
532
- * active task is bound to that branch.
533
- *
534
- * Two-state semantics: this only consults the active registry
535
- * (`active/.short-ids.json`) plus each `active/{taskId}/task.md`. Tasks moved
536
- * to completed/blocked/cancelled/archive have already released their short id,
537
- * so their branches return `null` — in `ai sandbox ls` that surfaces as `-`,
538
- * meaning the sandbox is free to remove.
539
- */
540
- function lookupShortIdByBranch(
541
- branch: string,
542
- repoRoot: string,
543
- _opts?: { shortIdLength?: number }
544
- ): string | null {
545
- const registry = readRegistry(repoRoot);
546
- if (!registry) return null;
547
- const matches: string[] = [];
548
- for (const [key, taskId] of Object.entries(registry.ids)) {
549
- const taskBranch = readBranchFromTaskMd(repoRoot, taskId);
550
- if (taskBranch && taskBranch === branch) {
551
- matches.push(key);
552
- }
553
- }
554
- if (matches.length === 0) return null;
555
- if (matches.length > 1) {
556
- process.stderr.write(
557
- `Warning: branch '${branch}' is bound to multiple active tasks: ${matches.join(', ')}; using ${matches[0]}\n`
558
- );
559
- }
560
- return matches[0]!;
561
- }
562
-
563
521
  export {
564
522
  normalizeShortIdInput,
565
523
  isRemovedHashShortIdInput,
566
524
  resolveShortIdReadOnly,
567
- lookupShortIdByBranch,
568
525
  loadShortIdByTaskId,
569
526
  inspectShortIdRegistry,
570
527
  configuredShortIdLength,
@@ -13,7 +13,6 @@ const TASK_SCOPE_SKILLS: ReadonlySet<string> = new Set([
13
13
  'review-code',
14
14
  'review-plan',
15
15
  'run-manual-validation',
16
- 'run-task',
17
16
  'watch-pr'
18
17
  ]);
19
18