@fitlab-ai/agent-infra 0.9.1 → 0.9.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 (283) hide show
  1. package/README.md +16 -4
  2. package/README.zh-CN.md +16 -4
  3. package/bin/cli.ts +12 -0
  4. package/dist/bin/cli.js +14 -0
  5. package/dist/bin/internal-cli.js +15 -0
  6. package/dist/lib/agent-client.js +163 -0
  7. package/dist/lib/agent-clients/adapter.js +294 -0
  8. package/dist/lib/agent-clients/adapters/claude-code.js +62 -0
  9. package/dist/lib/agent-clients/adapters/codex-sandbox.js +210 -0
  10. package/dist/lib/agent-clients/adapters/codex.js +54 -0
  11. package/dist/lib/agent-clients/adapters/gemini-cli.js +64 -0
  12. package/dist/lib/agent-clients/adapters/index.js +20 -0
  13. package/dist/lib/agent-clients/adapters/opencode.js +64 -0
  14. package/dist/lib/agent-clients/config.js +177 -0
  15. package/dist/lib/agent-clients/custom-tuis.js +99 -0
  16. package/dist/lib/agent-clients/invocation.js +9 -0
  17. package/dist/lib/agent-clients/next-steps.js +38 -0
  18. package/dist/lib/agent-clients/project-assets.js +45 -0
  19. package/dist/lib/agent-clients/reconcile.js +235 -0
  20. package/dist/lib/agent-clients/registry.js +72 -0
  21. package/dist/lib/agent-clients/schema.js +57 -0
  22. package/dist/lib/agent-clients/types.js +29 -0
  23. package/dist/lib/builtin-tuis.js +9 -14
  24. package/dist/lib/defaults.json +85 -73
  25. package/dist/lib/git/review-snapshot.js +25 -10
  26. package/dist/lib/git/reviewed-commit-equivalence.js +110 -0
  27. package/dist/lib/init.js +47 -91
  28. package/dist/lib/internal/agent-client.js +117 -0
  29. package/dist/lib/internal/git-workflow.js +1 -1
  30. package/dist/lib/internal/release-workflow.js +71 -16
  31. package/dist/lib/internal/task-orchestration.js +151 -0
  32. package/dist/lib/internal/task-review.js +65 -0
  33. package/dist/lib/merge.js +2 -1
  34. package/dist/lib/platform/adapters.js +38 -1
  35. package/dist/lib/platform/change-request-git-evidence.js +113 -0
  36. package/dist/lib/platform/merged-pr-equivalence.js +41 -11
  37. package/dist/lib/platform/pr-checks.js +38 -10
  38. package/dist/lib/platform/pull-requests.js +110 -6
  39. package/dist/lib/platform/releases.js +1 -1
  40. package/dist/lib/platform/verification-required.js +8 -10
  41. package/dist/lib/prompt.js +15 -3
  42. package/dist/lib/release/channels.js +4 -1
  43. package/dist/lib/release/workflow.js +4 -2
  44. package/dist/lib/remove-dir.js +25 -0
  45. package/dist/lib/run/tui.js +8 -2
  46. package/dist/lib/sandbox/agent-client-reconciler.js +234 -0
  47. package/dist/lib/sandbox/clipboard/linux.js +2 -1
  48. package/dist/lib/sandbox/commands/create.js +76 -180
  49. package/dist/lib/sandbox/commands/enter.js +17 -1
  50. package/dist/lib/sandbox/commands/prune.js +2 -2
  51. package/dist/lib/sandbox/commands/rm.js +3 -2
  52. package/dist/lib/sandbox/config.js +21 -4
  53. package/dist/lib/sandbox/constants.js +3 -0
  54. package/dist/lib/sandbox/dockerfile.js +2 -1
  55. package/dist/lib/sandbox/managed-fs.js +10 -5
  56. package/dist/lib/sandbox/recovery.js +52 -36
  57. package/dist/lib/sandbox/shell.js +1 -1
  58. package/dist/lib/sandbox/tool-types.js +8 -0
  59. package/dist/lib/sandbox/tools.js +2 -126
  60. package/dist/lib/task/artifact-lifecycle.js +1 -49
  61. package/dist/lib/task/commands/decisions.js +50 -20
  62. package/dist/lib/task/delegation-receipts.js +107 -0
  63. package/dist/lib/task/events.js +100 -1
  64. package/dist/lib/task/orchestration.js +420 -0
  65. package/dist/lib/task/review-artifacts.js +143 -59
  66. package/dist/lib/task/review-finalization.js +166 -0
  67. package/dist/lib/task/review-fingerprint.js +4 -0
  68. package/dist/lib/task/verification-checks.js +2 -1
  69. package/dist/lib/task/verification-engine.js +156 -28
  70. package/dist/lib/task/verification-review.js +1 -1
  71. package/dist/lib/task/verification.js +3 -1
  72. package/dist/lib/task/workspace-snapshot.js +34 -0
  73. package/dist/lib/update.js +42 -161
  74. package/lib/agent-client.ts +214 -0
  75. package/lib/agent-clients/adapter.ts +461 -0
  76. package/lib/agent-clients/adapters/claude-code.ts +70 -0
  77. package/lib/agent-clients/adapters/codex-sandbox.ts +245 -0
  78. package/lib/agent-clients/adapters/codex.ts +58 -0
  79. package/lib/agent-clients/adapters/gemini-cli.ts +65 -0
  80. package/lib/agent-clients/adapters/index.ts +27 -0
  81. package/lib/agent-clients/adapters/opencode.ts +66 -0
  82. package/lib/agent-clients/config.ts +278 -0
  83. package/lib/agent-clients/custom-tuis.ts +149 -0
  84. package/lib/agent-clients/invocation.ts +19 -0
  85. package/lib/agent-clients/next-steps.ts +72 -0
  86. package/lib/agent-clients/project-assets.ts +96 -0
  87. package/lib/agent-clients/reconcile.ts +324 -0
  88. package/lib/agent-clients/registry.ts +144 -0
  89. package/lib/agent-clients/schema.ts +62 -0
  90. package/lib/agent-clients/types.ts +78 -0
  91. package/lib/benchmark/schemas/v1.0.0/case-manifest.schema.json +120 -0
  92. package/lib/benchmark/schemas/v1.0.0/common.schema.json +109 -0
  93. package/lib/benchmark/schemas/v1.0.0/grader-result.schema.json +160 -0
  94. package/lib/benchmark/schemas/v1.0.0/run-manifest.schema.json +122 -0
  95. package/lib/benchmark/schemas/v1.0.0/subject.schema.json +227 -0
  96. package/lib/builtin-tuis.ts +16 -15
  97. package/lib/defaults.json +24 -12
  98. package/lib/git/review-snapshot.ts +39 -9
  99. package/lib/git/reviewed-commit-equivalence.ts +135 -0
  100. package/lib/init.ts +53 -121
  101. package/lib/internal/agent-client.ts +131 -0
  102. package/lib/internal/git-workflow.ts +1 -1
  103. package/lib/internal/release-workflow.ts +68 -16
  104. package/lib/internal/task-orchestration.ts +132 -0
  105. package/lib/internal/task-review.ts +65 -0
  106. package/lib/merge.ts +2 -1
  107. package/lib/platform/adapters.ts +142 -3
  108. package/lib/platform/change-request-git-evidence.ts +159 -0
  109. package/lib/platform/merged-pr-equivalence.ts +51 -14
  110. package/lib/platform/pr-checks.ts +50 -22
  111. package/lib/platform/pull-requests.ts +134 -25
  112. package/lib/platform/releases.ts +1 -1
  113. package/lib/platform/verification-required.ts +12 -10
  114. package/lib/prompt.ts +16 -3
  115. package/lib/release/channels.ts +4 -1
  116. package/lib/release/workflow.ts +4 -3
  117. package/lib/remove-dir.ts +28 -0
  118. package/lib/run/tui.ts +9 -1
  119. package/lib/sandbox/agent-client-reconciler.ts +378 -0
  120. package/lib/sandbox/clipboard/linux.ts +2 -1
  121. package/lib/sandbox/commands/create.ts +111 -192
  122. package/lib/sandbox/commands/enter.ts +23 -1
  123. package/lib/sandbox/commands/prune.ts +2 -2
  124. package/lib/sandbox/commands/rm.ts +3 -2
  125. package/lib/sandbox/config.ts +31 -4
  126. package/lib/sandbox/constants.ts +6 -0
  127. package/lib/sandbox/dockerfile.ts +2 -1
  128. package/lib/sandbox/managed-fs.ts +18 -5
  129. package/lib/sandbox/recovery.ts +98 -67
  130. package/lib/sandbox/shell.ts +1 -1
  131. package/lib/sandbox/tool-types.ts +143 -0
  132. package/lib/sandbox/tools.ts +5 -157
  133. package/lib/task/artifact-lifecycle.ts +1 -38
  134. package/lib/task/commands/decisions.ts +53 -20
  135. package/lib/task/delegation-receipts.ts +170 -0
  136. package/lib/task/events.ts +110 -2
  137. package/lib/task/orchestration.ts +543 -0
  138. package/lib/task/review-artifacts.ts +201 -69
  139. package/lib/task/review-finalization.ts +275 -0
  140. package/lib/task/review-fingerprint.ts +5 -0
  141. package/lib/task/verification-checks.ts +2 -1
  142. package/lib/task/verification-engine.ts +177 -28
  143. package/lib/task/verification-review.ts +1 -0
  144. package/lib/task/verification.ts +5 -2
  145. package/lib/task/workspace-snapshot.ts +36 -0
  146. package/lib/update.ts +48 -184
  147. package/package.json +2 -2
  148. package/templates/.agents/README.en.md +21 -20
  149. package/templates/.agents/README.zh-CN.md +21 -20
  150. package/templates/.agents/hooks/lifecycle-delegation.js +64 -0
  151. package/templates/.agents/rules/README.en.md +2 -0
  152. package/templates/.agents/rules/README.zh-CN.md +2 -0
  153. package/templates/.agents/rules/commit-and-pr.en.md +1 -0
  154. package/templates/.agents/rules/commit-and-pr.zh-CN.md +1 -0
  155. package/templates/.agents/rules/human-decision-context.en.md +14 -12
  156. package/templates/.agents/rules/human-decision-context.zh-CN.md +14 -12
  157. package/templates/.agents/rules/lifecycle-orchestration.en.md +21 -0
  158. package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +21 -0
  159. package/templates/.agents/rules/next-step-output.en.md +16 -0
  160. package/templates/.agents/rules/next-step-output.zh-CN.md +16 -0
  161. package/templates/.agents/rules/no-mid-flow-questions.en.md +2 -0
  162. package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +2 -0
  163. package/templates/.agents/rules/release-commands.github.en.md +11 -5
  164. package/templates/.agents/rules/release-commands.github.zh-CN.md +11 -5
  165. package/templates/.agents/rules/review-handshake.en.md +4 -4
  166. package/templates/.agents/rules/review-handshake.zh-CN.md +4 -4
  167. package/templates/.agents/rules/review-method.en.md +113 -0
  168. package/templates/.agents/rules/review-method.zh-CN.md +98 -0
  169. package/templates/.agents/skills/analyze-task/SKILL.en.md +5 -5
  170. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +5 -5
  171. package/templates/.agents/skills/block-task/SKILL.en.md +4 -4
  172. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +4 -4
  173. package/templates/.agents/skills/cancel-task/SKILL.en.md +4 -4
  174. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +5 -5
  175. package/templates/.agents/skills/check-task/SKILL.en.md +16 -16
  176. package/templates/.agents/skills/check-task/SKILL.zh-CN.md +16 -16
  177. package/templates/.agents/skills/close-codescan/SKILL.en.md +4 -4
  178. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +4 -4
  179. package/templates/.agents/skills/close-dependabot/SKILL.en.md +4 -4
  180. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +4 -4
  181. package/templates/.agents/skills/code-task/SKILL.en.md +1 -1
  182. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +2 -2
  183. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +14 -16
  184. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +14 -16
  185. package/templates/.agents/skills/code-task/reference/output-template.en.md +3 -3
  186. package/templates/.agents/skills/code-task/reference/output-template.zh-CN.md +3 -3
  187. package/templates/.agents/skills/commit/SKILL.en.md +11 -1
  188. package/templates/.agents/skills/commit/SKILL.zh-CN.md +11 -1
  189. package/templates/.agents/skills/commit/reference/task-status-update.en.md +24 -28
  190. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +24 -28
  191. package/templates/.agents/skills/complete-task/SKILL.en.md +2 -2
  192. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +2 -2
  193. package/templates/.agents/skills/create-pr/SKILL.en.md +10 -10
  194. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +10 -10
  195. package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +3 -3
  196. package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +3 -3
  197. package/templates/.agents/skills/create-task/SKILL.en.md +11 -11
  198. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +11 -11
  199. package/templates/.agents/skills/import-codescan/SKILL.en.md +5 -5
  200. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +5 -5
  201. package/templates/.agents/skills/import-dependabot/SKILL.en.md +5 -5
  202. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +5 -5
  203. package/templates/.agents/skills/import-issue/SKILL.en.md +5 -5
  204. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +5 -5
  205. package/templates/.agents/skills/init-labels/SKILL.en.md +4 -4
  206. package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +4 -4
  207. package/templates/.agents/skills/init-milestones/SKILL.en.md +4 -4
  208. package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +4 -4
  209. package/templates/.agents/skills/plan-task/SKILL.en.md +5 -5
  210. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +5 -5
  211. package/templates/.agents/skills/refine-title/SKILL.en.md +1 -1
  212. package/templates/.agents/skills/refine-title/SKILL.zh-CN.md +1 -1
  213. package/templates/.agents/skills/release/SKILL.en.md +1 -1
  214. package/templates/.agents/skills/review-analysis/SKILL.en.md +13 -2
  215. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +14 -3
  216. package/templates/.agents/skills/review-analysis/config/verify.en.json +6 -0
  217. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +6 -0
  218. package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +13 -15
  219. package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +13 -15
  220. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +51 -5
  221. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +52 -6
  222. package/templates/.agents/skills/review-analysis/reference/review-criteria.en.md +25 -22
  223. package/templates/.agents/skills/review-analysis/reference/review-criteria.zh-CN.md +25 -22
  224. package/templates/.agents/skills/review-code/SKILL.en.md +28 -8
  225. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +28 -8
  226. package/templates/.agents/skills/review-code/config/verify.en.json +7 -0
  227. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +7 -0
  228. package/templates/.agents/skills/review-code/reference/concurrency-risks.en.md +25 -0
  229. package/templates/.agents/skills/review-code/reference/concurrency-risks.zh-CN.md +25 -0
  230. package/templates/.agents/skills/review-code/reference/cross-platform-risks.en.md +27 -0
  231. package/templates/.agents/skills/review-code/reference/cross-platform-risks.zh-CN.md +27 -0
  232. package/templates/.agents/skills/review-code/reference/documentation-antipatterns.en.md +13 -0
  233. package/templates/.agents/skills/review-code/reference/documentation-antipatterns.zh-CN.md +13 -0
  234. package/templates/.agents/skills/review-code/reference/migration-risks.en.md +25 -0
  235. package/templates/.agents/skills/review-code/reference/migration-risks.zh-CN.md +25 -0
  236. package/templates/.agents/skills/review-code/reference/output-templates.en.md +22 -24
  237. package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +22 -24
  238. package/templates/.agents/skills/review-code/reference/report-template.en.md +54 -7
  239. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +54 -7
  240. package/templates/.agents/skills/review-code/reference/review-criteria.en.md +29 -24
  241. package/templates/.agents/skills/review-code/reference/review-criteria.zh-CN.md +29 -24
  242. package/templates/.agents/skills/review-code/reference/security-risks.en.md +25 -0
  243. package/templates/.agents/skills/review-code/reference/security-risks.zh-CN.md +25 -0
  244. package/templates/.agents/skills/review-plan/SKILL.en.md +13 -2
  245. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +14 -3
  246. package/templates/.agents/skills/review-plan/config/verify.en.json +6 -0
  247. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +6 -0
  248. package/templates/.agents/skills/review-plan/reference/output-templates.en.md +13 -15
  249. package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +13 -15
  250. package/templates/.agents/skills/review-plan/reference/report-template.en.md +61 -5
  251. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +61 -5
  252. package/templates/.agents/skills/review-plan/reference/review-criteria.en.md +21 -24
  253. package/templates/.agents/skills/review-plan/reference/review-criteria.zh-CN.md +21 -24
  254. package/templates/.agents/skills/run-task/SKILL.en.md +22 -0
  255. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +22 -0
  256. package/templates/.agents/skills/run-task/config/verify.en.json +9 -0
  257. package/templates/.agents/skills/run-task/config/verify.zh-CN.json +9 -0
  258. package/templates/.agents/skills/test/SKILL.en.md +4 -4
  259. package/templates/.agents/skills/test/SKILL.zh-CN.md +4 -4
  260. package/templates/.agents/skills/test-integration/SKILL.en.md +4 -4
  261. package/templates/.agents/skills/test-integration/SKILL.zh-CN.md +4 -4
  262. package/templates/.agents/skills/update-agent-infra/SKILL.en.md +5 -5
  263. package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +5 -5
  264. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +647 -203
  265. package/templates/.agents/skills/upgrade-dependency/SKILL.en.md +4 -4
  266. package/templates/.agents/skills/upgrade-dependency/SKILL.zh-CN.md +4 -4
  267. package/templates/.agents/skills/watch-pr/SKILL.en.md +8 -8
  268. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +8 -8
  269. package/templates/.claude/agents/agent-infra-lifecycle-executor.en.md +6 -0
  270. package/templates/.claude/agents/agent-infra-lifecycle-executor.zh-CN.md +6 -0
  271. package/templates/.claude/agents/agent-infra-lifecycle-reviewer.en.md +6 -0
  272. package/templates/.claude/agents/agent-infra-lifecycle-reviewer.zh-CN.md +6 -0
  273. package/templates/.claude/commands/run-task.en.md +8 -0
  274. package/templates/.claude/commands/run-task.zh-CN.md +8 -0
  275. package/templates/.claude/settings.json +24 -0
  276. package/templates/.codex/agents/agent-infra-lifecycle-executor.en.toml +3 -0
  277. package/templates/.codex/agents/agent-infra-lifecycle-executor.zh-CN.toml +3 -0
  278. package/templates/.codex/agents/agent-infra-lifecycle-reviewer.en.toml +3 -0
  279. package/templates/.codex/agents/agent-infra-lifecycle-reviewer.zh-CN.toml +3 -0
  280. package/templates/.gemini/commands/_project_/run-task.en.toml +8 -0
  281. package/templates/.gemini/commands/_project_/run-task.zh-CN.toml +8 -0
  282. package/templates/.opencode/commands/run-task.en.md +11 -0
  283. package/templates/.opencode/commands/run-task.zh-CN.md +11 -0
@@ -1,10 +1,16 @@
1
1
  import fs from 'node:fs';
2
+ import { execFileSync } from 'node:child_process';
2
3
 
3
4
  import { parseTaskFrontmatter } from '../task/frontmatter.ts';
4
5
  import { resolveTaskRef } from '../task/resolve-ref.ts';
5
6
  import { extractSection } from '../task/sections.ts';
6
7
  import { captureTaskWriteMetadata, writeTask } from '../task/write.ts';
7
- import { resolvePlatformContext } from './context.ts';
8
+ import {
9
+ inspectPlatformChangeRequest,
10
+ registerPlatformCapabilities
11
+ } from './adapters.ts';
12
+ import type { PlatformChangeRequestSnapshot } from './adapters.ts';
13
+ import { parseGitHubRemote, resolvePlatformContext } from './context.ts';
8
14
  import { createGitHubClient } from './github-client.ts';
9
15
  import type { GitHubClient } from './github-client.ts';
10
16
  import { inspectPlatformIssue } from './issues.ts';
@@ -12,28 +18,13 @@ import { planPullRequestMetadata } from './pull-request-metadata.ts';
12
18
  import { platformResult } from './types.ts';
13
19
  import type { PlatformOperation, PlatformResult } from './types.ts';
14
20
 
15
- type PullRequestSnapshot = {
16
- repository: string;
17
- number: number;
18
- nodeId: string;
19
- url: string;
20
- state: 'open' | 'closed';
21
- title: string;
22
- body: string;
23
- draft: boolean;
24
- head: { repository: string; ref: string; sha: string };
25
- base: { repository: string; ref: string; sha: string };
26
- mergedAt: string | null;
27
- mergeCommitSha: string | null;
28
- labels: string[];
29
- assignees: string[];
30
- milestone: string | null;
31
- };
21
+ type PullRequestSnapshot = PlatformChangeRequestSnapshot;
32
22
 
33
23
  type PullRequestResult = PlatformResult & {
34
24
  task: { id: string | null; issueNumber: number | null; prNumber: number | null };
35
25
  pullRequest: PullRequestSnapshot | null;
36
26
  };
27
+ type InspectionOptions = { cwd?: string; client?: unknown };
37
28
  type SharedOptions = { cwd?: string; client?: GitHubClient };
38
29
  type CreateOptions = SharedOptions & {
39
30
  agent: string;
@@ -126,7 +117,7 @@ function selectPullRequest(remotes: RemotePullRequest[], repository: string, hea
126
117
  return { status: matches.length === 0 ? 'missing' : 'ambiguous', pullRequest: null };
127
118
  }
128
119
 
129
- function resolvedContext(taskRef: string, options: SharedOptions) {
120
+ function resolvedContext(taskRef: string, options: InspectionOptions) {
130
121
  const resolved = resolveTaskRef(taskRef, options.cwd ? { repoRoot: options.cwd } : {});
131
122
  if (!resolved.ok) return { ok: false as const, output: result('failed', resolved.taskId, null, null, {
132
123
  error: { code: resolved.code, message: resolved.message, retryable: false }
@@ -137,7 +128,7 @@ function resolvedContext(taskRef: string, options: SharedOptions) {
137
128
  const pr = Number(frontmatter.pr_number);
138
129
  const issueNumber = Number.isInteger(issue) && issue > 0 ? issue : null;
139
130
  const prNumber = Number.isInteger(pr) && pr > 0 ? pr : null;
140
- const client = options.client || createGitHubClient();
131
+ const client = (options.client as GitHubClient | undefined) || createGitHubClient();
141
132
  const context = resolvePlatformContext({ cwd: resolved.repoRoot, client });
142
133
  const usable = (context.status === 'no-op' || context.status === 'degraded') && context.platform.repository;
143
134
  if (!usable) return { ok: false as const, output: result(context.status, resolved.taskId, issueNumber, prNumber, {
@@ -155,6 +146,111 @@ function inspectGitHubPullRequest(client: GitHubClient, repository: string, numb
155
146
  : { ok: false as const, error: { code: 'PR_IDENTITY_INVALID', message: 'Remote resource is not a valid pull request', retryable: false } };
156
147
  }
157
148
 
149
+ function configuredGitRemotes(cwd: string): Array<{ name: string; url: string; repository: string }> {
150
+ try {
151
+ return execFileSync('git', ['remote'], {
152
+ cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe']
153
+ }).split(/\r?\n/).filter(Boolean).flatMap((name) => {
154
+ try {
155
+ const url = execFileSync('git', ['config', '--get', `remote.${name}.url`], {
156
+ cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe']
157
+ }).trim();
158
+ const repository = parseGitHubRemote(url);
159
+ return repository ? [{ name, url, repository }] : [];
160
+ } catch {
161
+ return [];
162
+ }
163
+ });
164
+ } catch {
165
+ return [];
166
+ }
167
+ }
168
+
169
+ function rewriteGitHubRemote(remote: string, repository: string): string | null {
170
+ const match = remote.trim().match(
171
+ /^(https?:\/\/github\.com\/|ssh:\/\/(?:git@)?github\.com\/|git@github\.com:)[^/\s]+\/[^/\s]+(?:\.git)?$/i
172
+ );
173
+ return match ? `${match[1]}${repository}.git` : null;
174
+ }
175
+
176
+ function resolveGitHubChangeRequestGitEvidence({
177
+ cwd,
178
+ repository,
179
+ pullRequest
180
+ }: {
181
+ cwd: string;
182
+ repository: string;
183
+ pullRequest: PullRequestSnapshot;
184
+ }) {
185
+ if (
186
+ pullRequest.repository !== repository ||
187
+ pullRequest.base.repository !== repository ||
188
+ pullRequest.number <= 0
189
+ ) {
190
+ return {
191
+ ok: false as const,
192
+ error: {
193
+ code: 'PR_MERGE_EVIDENCE_SOURCE_UNAVAILABLE',
194
+ message: 'Pull request repository identity is inconsistent',
195
+ retryable: false
196
+ }
197
+ };
198
+ }
199
+ const reviewedHeadRef = `refs/pull/${pullRequest.number}/head`;
200
+ const targetHeadRef = `refs/heads/${pullRequest.base.ref}`;
201
+ const refValid = (ref: string) => {
202
+ try {
203
+ execFileSync('git', ['check-ref-format', ref], {
204
+ cwd, encoding: 'utf8', stdio: ['ignore', 'ignore', 'ignore']
205
+ });
206
+ return true;
207
+ } catch {
208
+ return false;
209
+ }
210
+ };
211
+ if (!refValid(reviewedHeadRef) || !refValid(targetHeadRef)) {
212
+ return {
213
+ ok: false as const,
214
+ error: {
215
+ code: 'PR_MERGE_EVIDENCE_SOURCE_UNAVAILABLE',
216
+ message: 'Pull request Git refs are invalid',
217
+ retryable: false
218
+ }
219
+ };
220
+ }
221
+
222
+ const remotes = configuredGitRemotes(cwd);
223
+ const exact = remotes
224
+ .filter((remote) => remote.repository === repository)
225
+ .sort((left, right) => Number(right.name === 'origin') - Number(left.name === 'origin') ||
226
+ left.name.localeCompare(right.name))[0];
227
+ const origin = remotes.find((remote) => remote.name === 'origin');
228
+ const remoteUrl = exact?.url || (origin ? rewriteGitHubRemote(origin.url, repository) : null);
229
+ if (!remoteUrl) {
230
+ return {
231
+ ok: false as const,
232
+ error: {
233
+ code: 'PR_MERGE_EVIDENCE_SOURCE_UNAVAILABLE',
234
+ message: `No GitHub remote can provide evidence for ${repository}`,
235
+ retryable: false
236
+ }
237
+ };
238
+ }
239
+ return {
240
+ ok: true as const,
241
+ value: { remoteUrl, reviewedHeadRef, targetHeadRef }
242
+ };
243
+ }
244
+
245
+ registerPlatformCapabilities('github', {
246
+ inspectChangeRequest({ client, repository, number, cwd }) {
247
+ return inspectGitHubPullRequest((client as GitHubClient | undefined) || createGitHubClient(), repository, number, cwd);
248
+ },
249
+ resolveChangeRequestGitEvidence(context) {
250
+ return resolveGitHubChangeRequestGitEvidence(context);
251
+ }
252
+ });
253
+
158
254
  function locatePullRequest(base: ReturnType<typeof resolvedContext> & { ok: true }, head: string, target: string) {
159
255
  const repository = base.context.platform.repository!;
160
256
  const listed = base.client.json<RemotePullRequest[]>([
@@ -171,18 +267,30 @@ function locatePullRequest(base: ReturnType<typeof resolvedContext> & { ok: true
171
267
  } };
172
268
  }
173
269
 
174
- function inspectPlatformPullRequest(taskRef: string, options: SharedOptions = {}): PullRequestResult {
270
+ function inspectPlatformPullRequest(taskRef: string, options: InspectionOptions = {}): PullRequestResult {
175
271
  const base = resolvedContext(taskRef, options);
176
272
  if (!base.ok) return base.output;
177
273
  if (!base.prNumber) return result('no-op', base.resolved.taskId, base.issueNumber, null, {
178
274
  platform: base.context.platform, capabilities: base.context.capabilities,
179
275
  error: { code: 'PR_NOT_LINKED', message: 'Task has no valid pr_number', retryable: false }
180
276
  });
181
- const fetched = inspectGitHubPullRequest(base.client, base.context.platform.repository!, base.prNumber, base.resolved.repoRoot);
182
- if (!fetched.ok) return result(fetched.error.retryable ? 'blocked' : 'failed', base.resolved.taskId, base.issueNumber, base.prNumber, {
183
- platform: base.context.platform, capabilities: base.context.capabilities,
184
- resource: { kind: 'pull-request', number: base.prNumber }, error: fetched.error
277
+ const fetched = inspectPlatformChangeRequest(base.context.platform.type, {
278
+ cwd: base.resolved.repoRoot,
279
+ repository: base.context.platform.repository!,
280
+ number: base.prNumber,
281
+ client: options.client || base.client
185
282
  });
283
+ if (!fetched.ok || !fetched.value) {
284
+ const error = fetched.error || {
285
+ code: 'PR_INSPECTION_INVALID',
286
+ message: 'Platform adapter returned no change-request snapshot',
287
+ retryable: false
288
+ };
289
+ return result(error.retryable ? 'blocked' : 'failed', base.resolved.taskId, base.issueNumber, base.prNumber, {
290
+ platform: base.context.platform, capabilities: base.context.capabilities,
291
+ resource: { kind: 'pull-request', number: base.prNumber }, error
292
+ });
293
+ }
186
294
  return result('no-op', base.resolved.taskId, base.issueNumber, base.prNumber, {
187
295
  platform: base.context.platform, capabilities: base.context.capabilities,
188
296
  resource: { kind: 'pull-request', number: base.prNumber }, pullRequest: fetched.value, error: null
@@ -380,6 +488,7 @@ export {
380
488
  inspectGitHubPullRequest,
381
489
  inspectPlatformPullRequest,
382
490
  normalizePullRequest,
491
+ resolveGitHubChangeRequestGitEvidence,
383
492
  selectPullRequest,
384
493
  syncPlatformPullRequest
385
494
  };
@@ -21,7 +21,7 @@ function inspectPlatformRelease(tag: string, options: ReleaseOptions = {}) {
21
21
  return { ...platformResult(result.error.retryable ? 'blocked' : 'failed'), platform: context.platform, release: null, workflows: [], error: result.error };
22
22
  }
23
23
  const release: ReleaseSnapshot = { tag: String(result.value.tagName || tag), published: !Boolean(result.value.isDraft), draft: Boolean(result.value.isDraft), url: result.value.url ? String(result.value.url) : null };
24
- const runs = client.json<unknown[]>(['run', 'list', '--repo', context.platform.repository, '--limit', '100', '--json', 'name,headBranch,status,conclusion,url'], { cwd: options.cwd });
24
+ const runs = client.json<unknown[]>(['run', 'list', '--repo', context.platform.repository, '--limit', '100', '--json', 'name,workflowName,displayTitle,event,headBranch,headSha,status,conclusion,createdAt,databaseId,attempt,url'], { cwd: options.cwd });
25
25
  return { ...platformResult(runs.ok ? 'no-op' : runs.error.retryable ? 'blocked' : 'degraded'), platform: context.platform, release, workflows: runs.ok ? runs.value : [], error: runs.ok ? null : runs.error };
26
26
  }
27
27
 
@@ -2,10 +2,10 @@ import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { execFileSync } from "node:child_process";
4
4
 
5
+ import { hasPlatformCapability } from "./adapters.ts";
5
6
  import { inspectRequiredChecks } from "./pr-checks.ts";
6
7
  import { resolvePlatformContext } from "./context.ts";
7
8
  import { resolveReviewedHeadRelation } from "./merged-pr-equivalence.ts";
8
- import { loadPostReviewConfig, resolvePostReviewGlobs } from "../task/review-fingerprint.ts";
9
9
 
10
10
  const CHECK_TYPE = "required-checks";
11
11
  const SHA_PATTERN = /^[0-9a-f]{7,40}$/i;
@@ -57,10 +57,9 @@ export function evaluateRequiredChecks(context: any, shared: any): any {
57
57
  context.gitRoot && inspection.pullRequest?.head
58
58
  ? resolveReviewedHeadRelation({
59
59
  gitRoot: context.gitRoot,
60
- localHead,
60
+ comparisonHead: localHead,
61
61
  lastReviewedCommit: reviewedHead,
62
- pullRequest: inspection.pullRequest,
63
- pathspecs: context.pathspecs || [":/"]
62
+ pullRequest: inspection.pullRequest
64
63
  })
65
64
  : localHead === reviewedHead && localHead === prHead
66
65
  ? { status: "strict" }
@@ -87,14 +86,18 @@ export function evaluateRequiredChecks(context: any, shared: any): any {
87
86
  export function check({ taskDir }: any, shared: any): any {
88
87
  const task = shared.loadTask(taskDir);
89
88
  if (!task.ok) return shared.failResult(CHECK_TYPE, task.message);
90
- const platform = resolvePlatformContext({ cwd: shared.repoRoot });
91
- if (platform.platform.type !== "github") {
92
- return shared.passResult(CHECK_TYPE, "Skipped: this code platform does not provide required checks");
93
- }
94
89
  const prFlow = readPrFlow(shared.repoRoot);
95
90
  if (prFlow === "disabled" || task.metadata.pr_status === "skipped" || !validPrNumber(task.metadata.pr_number)) {
96
91
  return evaluateRequiredChecks({ metadata: task.metadata, localHead: null, inspection: null, prFlow }, shared);
97
92
  }
93
+ const platform = resolvePlatformContext({ cwd: shared.repoRoot });
94
+ if (!hasPlatformCapability(platform.platform.type, "required-checks")) {
95
+ return shared.blockedResult(
96
+ CHECK_TYPE,
97
+ `Platform '${platform.platform.type || "none"}' does not provide required-checks inspection`,
98
+ "dependency_error"
99
+ );
100
+ }
98
101
  const localHead = readHead(shared.repoRoot);
99
102
  if (!localHead) return evaluateRequiredChecks({ metadata: task.metadata, localHead, inspection: null, prFlow }, shared);
100
103
  const inspection = inspectRequiredChecks(task.metadata.id, { cwd: shared.repoRoot });
@@ -103,7 +106,6 @@ export function check({ taskDir }: any, shared: any): any {
103
106
  localHead,
104
107
  inspection,
105
108
  prFlow,
106
- gitRoot: shared.repoRoot,
107
- pathspecs: resolvePostReviewGlobs({}, loadPostReviewConfig(shared.repoRoot))
109
+ gitRoot: shared.repoRoot
108
110
  }, shared);
109
111
  }
package/lib/prompt.ts CHANGED
@@ -88,20 +88,33 @@ async function select(question: string, choices: string[], defaultValue?: string
88
88
 
89
89
  async function multiSelect(
90
90
  question: string,
91
- choices: { id: string; label: string }[]
91
+ choices: { id: string; label: string }[],
92
+ defaultIds: readonly string[] = choices.map((choice) => choice.id)
92
93
  ): Promise<string[]> {
94
+ const choiceIds = new Set(choices.map((choice) => choice.id));
95
+ if (defaultIds.some((id) => !choiceIds.has(id))) {
96
+ throw new Error('Default selection contains an unknown id');
97
+ }
98
+ const normalizedDefaults = choices
99
+ .map((choice) => choice.id)
100
+ .filter((id) => defaultIds.includes(id));
93
101
  process.stdout.write(` ${question}:\n`);
94
102
  const idWidth = Math.max(...choices.map((c) => c.id.length));
95
103
  choices.forEach((c, i) => {
96
104
  process.stdout.write(` ${i + 1}) ${c.id.padEnd(idWidth)} (${c.label})\n`);
97
105
  });
98
- ask('Enter comma-separated numbers or ids to keep, or "none" to select nothing [default: all]: ');
106
+ const defaultLabel = normalizedDefaults.length === choices.length
107
+ ? 'all'
108
+ : normalizedDefaults.length === 0
109
+ ? 'none'
110
+ : normalizedDefaults.join(',');
111
+ ask(`Enter comma-separated numbers or ids to keep, or "none" to select nothing [default: ${defaultLabel}]: `);
99
112
 
100
113
  setupInterface();
101
114
 
102
115
  const line = await nextLine();
103
116
  // Strictly distinguish bare Enter (null/empty string) from whitespace input.
104
- if (line === null || line === '') return choices.map((c) => c.id);
117
+ if (line === null || line === '') return normalizedDefaults;
105
118
  // Explicit empty selection: "none" means deliberately zero built-in choices.
106
119
  if (line.trim().toLowerCase() === 'none') return [];
107
120
 
@@ -20,7 +20,10 @@ async function inspectHomebrewChannel(url: string, version: string, fetcher: Fet
20
20
  if (!response.ok) return { status: 'blocked' as const, published: null, version, error: { code: 'HOMEBREW_UNAVAILABLE', message: `formula endpoint returned ${response.status}` } };
21
21
  const formula = await response.text();
22
22
  const escaped = version.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
23
- return { status: 'no-op' as const, published: new RegExp(`(?:version\\s+["']${escaped}["']|/v?${escaped}\\.)`).test(formula), version, error: null };
23
+ const formulaUrl = /^\s*url\s+["']([^"']+)["']\s*$/m.exec(formula)?.[1] ?? '';
24
+ const npmTarball = new RegExp(`^https://registry\\.npmjs\\.org/.+/-/[^/]+-${escaped}\\.tgz$`).test(formulaUrl);
25
+ const bottle = /^\s*bottle do\s*$/m.test(formula);
26
+ return { status: 'no-op' as const, published: npmTarball && bottle, version, error: null };
24
27
  } catch (error) {
25
28
  return { status: 'blocked' as const, published: null, version, error: { code: 'HOMEBREW_UNAVAILABLE', message: error instanceof Error ? error.message : String(error) } };
26
29
  }
@@ -1,8 +1,8 @@
1
1
  type ReleasePhase = 'unprepared' | 'prepared' | 'partially-published' | 'published' | 'post-pending' | 'complete';
2
- type ReleaseFacts = { localTag: boolean; localTagConflict?: boolean; remoteBranch: boolean; remoteTag: boolean; githubRelease: boolean | null; npm: boolean | null; homebrew: boolean | null; smoke: 'success' | 'pending' | 'failed' | null; postCommit: boolean };
2
+ type ReleaseFacts = { localTag: boolean; localTagAncestor?: boolean; localTagConflict?: boolean; remoteBranch: boolean; remoteTag: boolean; githubRelease: boolean | null; npm: boolean | null; homebrew: boolean | null; smoke: 'success' | 'pending' | 'failed' | null; postCommit: boolean };
3
3
 
4
4
  function deriveReleasePhase(facts: ReleaseFacts): ReleasePhase {
5
- if (!facts.localTag) return 'unprepared';
5
+ if (!facts.localTag && !facts.localTagAncestor) return 'unprepared';
6
6
  if (!facts.remoteBranch && !facts.remoteTag) return 'prepared';
7
7
  if (!facts.remoteBranch || !facts.remoteTag) return 'partially-published';
8
8
  if (facts.githubRelease !== true || facts.npm !== true || facts.homebrew !== true) return 'published';
@@ -17,8 +17,9 @@ function releaseSnapshot(version: string, facts: ReleaseFacts) {
17
17
  async function runReleaseAction(input: { version: string; action: 'inspect' | 'prepare' | 'publish' | 'post'; inspect: () => Promise<ReleaseFacts>; prepare?: () => Promise<void>; publish?: () => Promise<void>; post?: () => Promise<void> }) {
18
18
  const before = releaseSnapshot(input.version, await input.inspect());
19
19
  if (input.action === 'inspect') return { status: 'no-op' as const, changed: false, before, snapshot: before, error: null };
20
+ if (before.facts.localTagConflict) return { status: 'failed' as const, changed: false, before, snapshot: before, error: { code: 'GIT_TAG_CONFLICT', message: `Tag ${before.tag} is not reachable from HEAD` } };
20
21
  const allowed = input.action === 'prepare' ? before.phase === 'unprepared'
21
- : input.action === 'publish' ? ['prepared', 'partially-published'].includes(before.phase)
22
+ : input.action === 'publish' ? before.facts.localTag && ['prepared', 'partially-published'].includes(before.phase)
22
23
  : ['published', 'post-pending'].includes(before.phase);
23
24
  if (!allowed) return { status: before.phase === 'complete' ? 'no-op' as const : 'failed' as const, changed: false, before, snapshot: before, error: before.phase === 'complete' ? null : { code: 'RELEASE_PHASE_INVALID', message: `Cannot ${input.action} from ${before.phase}` } };
24
25
  await input[input.action]?.();
@@ -0,0 +1,28 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+
4
+ export function removeDirRecursive(dir: string): void {
5
+ if (!fs.existsSync(dir)) {
6
+ return;
7
+ }
8
+
9
+ const pending = [dir];
10
+ const directories: string[] = [];
11
+ while (pending.length > 0) {
12
+ const current = pending.pop()!;
13
+ const stat = fs.lstatSync(current);
14
+ if (!stat.isDirectory() || stat.isSymbolicLink()) {
15
+ fs.unlinkSync(current);
16
+ continue;
17
+ }
18
+
19
+ directories.push(current);
20
+ for (const entry of fs.readdirSync(current)) {
21
+ pending.push(path.join(current, entry));
22
+ }
23
+ }
24
+
25
+ for (const directory of directories.reverse()) {
26
+ fs.rmdirSync(directory);
27
+ }
28
+ }
package/lib/run/tui.ts CHANGED
@@ -1,3 +1,6 @@
1
+ import { renderAgentClientInvocation } from '../agent-clients/invocation.ts';
2
+ import { getAgentClientAdapter } from '../agent-clients/registry.ts';
3
+
1
4
  export type TuiName = 'claude' | 'codex' | 'gemini' | 'opencode';
2
5
 
3
6
  const TUI_NAMES = new Set(['claude', 'codex', 'gemini', 'opencode']);
@@ -27,7 +30,12 @@ export function selectTui(
27
30
 
28
31
  export function renderPrompt(params: { tui: TuiName; skill: string; args: string[] }): string {
29
32
  const suffix = [params.skill, ...params.args].join(' ').trim();
30
- if (params.tui === 'codex') return `$${suffix}`;
33
+ if (params.tui === 'codex') {
34
+ return renderAgentClientInvocation(getAgentClientAdapter('codex').invocation, {
35
+ skillName: params.skill,
36
+ args: params.args
37
+ });
38
+ }
31
39
  if (params.tui === 'gemini') return `/agent-infra:${suffix}`;
32
40
  return `/${suffix}`;
33
41
  }