@fitlab-ai/agent-infra 0.9.13 → 0.9.14

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 (280) hide show
  1. package/bin/cli.ts +26 -9
  2. package/dist/bin/cli.js +173 -157
  3. package/dist/bin/internal-cli.js +42 -21
  4. package/dist/lib/agent-client.js +5 -0
  5. package/dist/lib/internal/agent-client.js +5 -2
  6. package/dist/lib/internal/cli-route-inventory.js +152 -0
  7. package/dist/lib/internal/codex-lifecycle.js +9 -6
  8. package/dist/lib/internal/codex-sandbox-controller.js +8 -2
  9. package/dist/lib/internal/git-workflow.js +10 -6
  10. package/dist/lib/internal/platform-checks.js +16 -4
  11. package/dist/lib/internal/platform-comment.js +16 -4
  12. package/dist/lib/internal/platform-context.js +4 -1
  13. package/dist/lib/internal/platform-issue.js +12 -4
  14. package/dist/lib/internal/platform-metadata.js +88 -0
  15. package/dist/lib/internal/platform-pr-review.js +16 -3
  16. package/dist/lib/internal/platform-pr.js +24 -10
  17. package/dist/lib/internal/platform-release-notes.js +6 -3
  18. package/dist/lib/internal/platform-security.js +93 -0
  19. package/dist/lib/internal/pr-review-grade.js +14 -3
  20. package/dist/lib/internal/release-workflow.js +19 -5
  21. package/dist/lib/internal/sandbox-control.js +22 -5
  22. package/dist/lib/internal/task-activity.js +13 -4
  23. package/dist/lib/internal/task-artifact.js +186 -27
  24. package/dist/lib/internal/task-context.js +4 -1
  25. package/dist/lib/internal/task-create.js +48 -15
  26. package/dist/lib/internal/task-delivery.js +4 -1
  27. package/dist/lib/internal/task-event.js +4 -1
  28. package/dist/lib/internal/task-finalization.js +4 -1
  29. package/dist/lib/internal/task-invalidation.js +4 -1
  30. package/dist/lib/internal/task-ledger.js +12 -1
  31. package/dist/lib/internal/task-lifecycle.js +4 -1
  32. package/dist/lib/internal/task-operation-registry.js +421 -0
  33. package/dist/lib/internal/task-orchestration.js +12 -0
  34. package/dist/lib/internal/task-override.js +10 -3
  35. package/dist/lib/internal/task-qualification.js +90 -0
  36. package/dist/lib/internal/task-review.js +4 -1
  37. package/dist/lib/internal/task-short-id.js +11 -1
  38. package/dist/lib/internal/task-snapshot.js +4 -1
  39. package/dist/lib/internal/task-validate.js +7 -2
  40. package/dist/lib/internal/task-verify.js +5 -1
  41. package/dist/lib/internal/task-warning.js +8 -1
  42. package/dist/lib/platform/comment-safety.js +226 -0
  43. package/dist/lib/platform/github-provider.js +233 -6
  44. package/dist/lib/platform/issue-comments.js +146 -34
  45. package/dist/lib/platform/pr-change-report.js +6 -12
  46. package/dist/lib/platform/pr-summary.js +28 -7
  47. package/dist/lib/platform/provider-contract.d.ts +67 -1
  48. package/dist/lib/platform/provider-contract.js +6 -2
  49. package/dist/lib/platform/provider-validation.js +76 -3
  50. package/dist/lib/platform/pull-requests.js +115 -170
  51. package/dist/lib/platform/repository-metadata.js +377 -0
  52. package/dist/lib/platform/security-alerts.js +155 -0
  53. package/dist/lib/platform/verification-sync.js +33 -26
  54. package/dist/lib/process-data/index.js +7 -0
  55. package/dist/lib/run/index.js +5 -0
  56. package/dist/lib/sandbox/commands/control-status.js +22 -0
  57. package/dist/lib/sandbox/commands/create.js +32 -6
  58. package/dist/lib/sandbox/commands/ls.js +5 -0
  59. package/dist/lib/sandbox/commands/rm.js +827 -120
  60. package/dist/lib/sandbox/commands/show.js +16 -0
  61. package/dist/lib/sandbox/control/client.js +83 -9
  62. package/dist/lib/sandbox/control/completed-reentry.js +85 -0
  63. package/dist/lib/sandbox/control/container-identity.js +28 -31
  64. package/dist/lib/sandbox/control/executor.js +149 -14
  65. package/dist/lib/sandbox/control/lifecycle.js +621 -127
  66. package/dist/lib/sandbox/control/native-file-lock.js +177 -0
  67. package/dist/lib/sandbox/control/server.js +305 -35
  68. package/dist/lib/sandbox/control/state.js +5 -3
  69. package/dist/lib/sandbox/control/task-view.js +183 -0
  70. package/dist/lib/sandbox/engines/authority.js +289 -0
  71. package/dist/lib/sandbox/engines/docker-exact-discovery.js +97 -0
  72. package/dist/lib/sandbox/index.js +5 -0
  73. package/dist/lib/sandbox/recovery.js +21 -1
  74. package/dist/lib/sandbox/workspace-view.js +2 -1
  75. package/dist/lib/sandbox/worktree-safety.js +4 -1
  76. package/dist/lib/server/index.js +8 -0
  77. package/dist/lib/task/artifact-lifecycle.js +42 -13
  78. package/dist/lib/task/artifact-operations.js +520 -0
  79. package/dist/lib/task/artifact-repair-intent.js +59 -0
  80. package/dist/lib/task/artifact-schema.js +135 -0
  81. package/dist/lib/task/capabilities.js +72 -1
  82. package/dist/lib/task/control-authority.js +4 -0
  83. package/dist/lib/task/create-service.js +103 -4
  84. package/dist/lib/task/create.js +25 -0
  85. package/dist/lib/task/events.js +186 -67
  86. package/dist/lib/task/index.js +11 -3
  87. package/dist/lib/task/local-artifact-finalization.js +75 -150
  88. package/dist/lib/task/orchestration.js +192 -52
  89. package/dist/lib/task/qualification-audit.js +490 -0
  90. package/dist/lib/task/qualification-confirmation.js +109 -0
  91. package/dist/lib/task/qualification-intents.js +148 -0
  92. package/dist/lib/task/review-artifacts.js +22 -23
  93. package/dist/lib/task/review-finalization.js +121 -4
  94. package/dist/lib/task/sections.js +6 -4
  95. package/dist/lib/task/verification-config.js +11 -0
  96. package/dist/lib/task/verification-engine.js +54 -4
  97. package/dist/lifecycle-build-manifest.json +3 -3
  98. package/lib/agent-client.ts +9 -0
  99. package/lib/internal/agent-client.ts +4 -2
  100. package/lib/internal/cli-route-inventory.ts +140 -0
  101. package/lib/internal/codex-lifecycle.ts +8 -6
  102. package/lib/internal/codex-sandbox-controller.ts +7 -2
  103. package/lib/internal/git-workflow.ts +9 -6
  104. package/lib/internal/platform-checks.ts +12 -4
  105. package/lib/internal/platform-comment.ts +12 -4
  106. package/lib/internal/platform-context.ts +3 -1
  107. package/lib/internal/platform-issue.ts +11 -4
  108. package/lib/internal/platform-metadata.ts +70 -0
  109. package/lib/internal/platform-pr-review.ts +14 -3
  110. package/lib/internal/platform-pr.ts +23 -10
  111. package/lib/internal/platform-release-notes.ts +5 -3
  112. package/lib/internal/platform-security.ts +83 -0
  113. package/lib/internal/pr-review-grade.ts +10 -3
  114. package/lib/internal/release-workflow.ts +17 -5
  115. package/lib/internal/sandbox-control.ts +19 -5
  116. package/lib/internal/task-activity.ts +12 -4
  117. package/lib/internal/task-artifact.ts +164 -25
  118. package/lib/internal/task-context.ts +3 -1
  119. package/lib/internal/task-create.ts +76 -15
  120. package/lib/internal/task-delivery.ts +3 -1
  121. package/lib/internal/task-event.ts +3 -1
  122. package/lib/internal/task-finalization.ts +3 -1
  123. package/lib/internal/task-invalidation.ts +3 -1
  124. package/lib/internal/task-ledger.ts +11 -1
  125. package/lib/internal/task-lifecycle.ts +3 -1
  126. package/lib/internal/task-operation-registry.ts +482 -0
  127. package/lib/internal/task-orchestration.ts +12 -0
  128. package/lib/internal/task-override.ts +9 -3
  129. package/lib/internal/task-qualification.ts +61 -0
  130. package/lib/internal/task-review.ts +3 -1
  131. package/lib/internal/task-short-id.ts +10 -1
  132. package/lib/internal/task-snapshot.ts +3 -1
  133. package/lib/internal/task-validate.ts +6 -2
  134. package/lib/internal/task-verify.ts +4 -1
  135. package/lib/internal/task-warning.ts +7 -1
  136. package/lib/platform/comment-safety.ts +250 -0
  137. package/lib/platform/github-provider.ts +229 -7
  138. package/lib/platform/issue-comments.ts +160 -35
  139. package/lib/platform/pr-change-report.ts +6 -12
  140. package/lib/platform/pr-summary.ts +27 -6
  141. package/lib/platform/provider-contract.ts +78 -3
  142. package/lib/platform/provider-validation.ts +85 -3
  143. package/lib/platform/pull-requests.ts +126 -178
  144. package/lib/platform/repository-metadata.ts +453 -0
  145. package/lib/platform/security-alerts.ts +191 -0
  146. package/lib/platform/verification-sync.ts +32 -28
  147. package/lib/process-data/index.ts +7 -0
  148. package/lib/run/index.ts +5 -0
  149. package/lib/sandbox/commands/control-status.ts +26 -0
  150. package/lib/sandbox/commands/create.ts +46 -6
  151. package/lib/sandbox/commands/ls.ts +7 -0
  152. package/lib/sandbox/commands/rm.ts +1000 -87
  153. package/lib/sandbox/commands/show.ts +16 -0
  154. package/lib/sandbox/control/client.ts +103 -9
  155. package/lib/sandbox/control/completed-reentry.ts +98 -0
  156. package/lib/sandbox/control/container-identity.ts +27 -43
  157. package/lib/sandbox/control/executor.ts +177 -12
  158. package/lib/sandbox/control/lifecycle.ts +629 -17
  159. package/lib/sandbox/control/native-file-lock.ts +209 -0
  160. package/lib/sandbox/control/protocol.ts +5 -2
  161. package/lib/sandbox/control/server.ts +319 -37
  162. package/lib/sandbox/control/state.ts +6 -3
  163. package/lib/sandbox/control/task-view.ts +240 -0
  164. package/lib/sandbox/engines/authority.ts +365 -0
  165. package/lib/sandbox/engines/docker-exact-discovery.ts +132 -0
  166. package/lib/sandbox/index.ts +7 -0
  167. package/lib/sandbox/recovery.ts +21 -1
  168. package/lib/sandbox/workspace-view.ts +9 -3
  169. package/lib/sandbox/worktree-safety.ts +4 -1
  170. package/lib/server/index.ts +10 -0
  171. package/lib/task/artifact-lifecycle.ts +38 -16
  172. package/lib/task/artifact-operations.ts +626 -0
  173. package/lib/task/artifact-repair-intent.ts +71 -0
  174. package/lib/task/artifact-schema.ts +192 -0
  175. package/lib/task/capabilities.ts +70 -1
  176. package/lib/task/control-authority.ts +11 -1
  177. package/lib/task/create-service.ts +131 -6
  178. package/lib/task/create.ts +27 -0
  179. package/lib/task/events.ts +161 -65
  180. package/lib/task/index.ts +16 -3
  181. package/lib/task/local-artifact-finalization.ts +87 -218
  182. package/lib/task/orchestration.ts +172 -49
  183. package/lib/task/qualification-audit.ts +599 -0
  184. package/lib/task/qualification-confirmation.ts +117 -0
  185. package/lib/task/qualification-intents.ts +150 -0
  186. package/lib/task/review-artifacts.ts +21 -22
  187. package/lib/task/review-finalization.ts +133 -4
  188. package/lib/task/sections.ts +6 -4
  189. package/lib/task/verification-config.ts +12 -0
  190. package/lib/task/verification-engine.ts +55 -4
  191. package/package.json +6 -1
  192. package/templates/.agents/rules/README.en.md +2 -0
  193. package/templates/.agents/rules/README.zh-CN.md +2 -0
  194. package/templates/.agents/rules/decision-qualification.en.md +22 -0
  195. package/templates/.agents/rules/decision-qualification.zh-CN.md +22 -0
  196. package/templates/.agents/rules/evidence-reporting.en.md +28 -0
  197. package/templates/.agents/rules/evidence-reporting.zh-CN.md +28 -0
  198. package/templates/.agents/rules/label-milestone-setup.en.md +7 -7
  199. package/templates/.agents/rules/label-milestone-setup.zh-CN.md +7 -7
  200. package/templates/.agents/rules/local-artifact-repair.en.md +5 -1
  201. package/templates/.agents/rules/local-artifact-repair.zh-CN.md +5 -1
  202. package/templates/.agents/rules/security-alerts.en.md +8 -8
  203. package/templates/.agents/rules/security-alerts.zh-CN.md +8 -8
  204. package/templates/.agents/skills/analyze-task/SKILL.en.md +15 -2
  205. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +19 -2
  206. package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -12
  207. package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -12
  208. package/templates/.agents/skills/close-codescan/SKILL.en.md +2 -2
  209. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +2 -2
  210. package/templates/.agents/skills/close-dependabot/SKILL.en.md +2 -2
  211. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +2 -2
  212. package/templates/.agents/skills/code-task/SKILL.en.md +14 -1
  213. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +14 -1
  214. package/templates/.agents/skills/code-task/config/verify.en.json +5 -14
  215. package/templates/.agents/skills/code-task/config/verify.zh-CN.json +5 -14
  216. package/templates/.agents/skills/code-task/reference/code-rules.en.md +5 -4
  217. package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +5 -4
  218. package/templates/.agents/skills/code-task/reference/dual-mode.en.md +1 -1
  219. package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +1 -1
  220. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +3 -1
  221. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +3 -1
  222. package/templates/.agents/skills/code-task/reference/report-template.en.md +42 -15
  223. package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +39 -12
  224. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +5 -1
  225. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +5 -1
  226. package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +2 -0
  227. package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +2 -0
  228. package/templates/.agents/skills/complete-task/SKILL.en.md +9 -22
  229. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +9 -22
  230. package/templates/.agents/skills/create-task/SKILL.en.md +8 -0
  231. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +7 -0
  232. package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
  233. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
  234. package/templates/.agents/skills/import-dependabot/SKILL.en.md +1 -1
  235. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
  236. package/templates/.agents/skills/init-labels/SKILL.en.md +8 -8
  237. package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +8 -8
  238. package/templates/.agents/skills/init-milestones/SKILL.en.md +9 -11
  239. package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +9 -11
  240. package/templates/.agents/skills/plan-task/SKILL.en.md +14 -1
  241. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +16 -1
  242. package/templates/.agents/skills/plan-task/config/verify.en.json +4 -14
  243. package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +4 -14
  244. package/templates/.agents/skills/review-analysis/SKILL.en.md +14 -1
  245. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +14 -1
  246. package/templates/.agents/skills/review-analysis/config/verify.en.json +1 -18
  247. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -18
  248. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +50 -23
  249. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +45 -18
  250. package/templates/.agents/skills/review-code/SKILL.en.md +14 -1
  251. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +14 -1
  252. package/templates/.agents/skills/review-code/config/verify.en.json +1 -23
  253. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -23
  254. package/templates/.agents/skills/review-code/reference/report-template.en.md +49 -22
  255. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +45 -18
  256. package/templates/.agents/skills/review-plan/SKILL.en.md +14 -1
  257. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +14 -1
  258. package/templates/.agents/skills/review-plan/config/verify.en.json +1 -18
  259. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -18
  260. package/templates/.agents/skills/review-plan/reference/report-template.en.md +49 -22
  261. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +45 -18
  262. package/templates/.agents/skills/review-pr/SKILL.en.md +5 -1
  263. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +5 -1
  264. package/templates/.agents/skills/review-pr/reference/report-template.en.md +4 -3
  265. package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +4 -3
  266. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +5 -1
  267. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +5 -1
  268. package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +3 -1
  269. package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +3 -1
  270. package/templates/.agents/skills/test/SKILL.en.md +13 -2
  271. package/templates/.agents/skills/test/SKILL.zh-CN.md +13 -2
  272. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +14 -0
  273. package/templates/.agents/templates/task.en.md +6 -0
  274. package/templates/.agents/templates/task.zh-CN.md +6 -0
  275. package/templates/.agents/scripts/security-alerts.github.sh +0 -151
  276. package/templates/.agents/scripts/security-alerts.sh +0 -31
  277. package/templates/.agents/skills/init-labels/scripts/init-labels.github.sh +0 -146
  278. package/templates/.agents/skills/init-labels/scripts/init-labels.sh +0 -32
  279. package/templates/.agents/skills/init-milestones/scripts/init-milestones.github.sh +0 -294
  280. package/templates/.agents/skills/init-milestones/scripts/init-milestones.sh +0 -6
@@ -11,6 +11,7 @@ import type { PrDeliveryFact } from '../task/pr-delivery-fact.ts';
11
11
  import { resolvePlatformProviderContext } from './context.ts';
12
12
  import type { LoadedContext, PlatformClient } from './context.ts';
13
13
  import { normalizeCommentContent } from './issue-comments.ts';
14
+ import { CONTROL_MARKER_PATTERN, escapeHtmlText, sanitizeMarkdownDocument, splitDocumentPlaceholder } from './comment-safety.ts';
14
15
  import { platformResult } from './types.ts';
15
16
  import type { PlatformResult } from './types.ts';
16
17
  import type { OperationWarning } from '../task/operation-outcome.ts';
@@ -19,6 +20,7 @@ import type { PlatformChangeRequestSnapshot } from './adapters.ts';
19
20
  import type { ChangeRequestSnapshot } from './provider-contract.ts';
20
21
  import {
21
22
  buildPrChangeReport,
23
+ CANONICAL_REPORT_PLACEHOLDER,
22
24
  readPrChangeReport,
23
25
  replaceCanonicalReportPlaceholder,
24
26
  runMechanicalChangeReport,
@@ -57,11 +59,7 @@ function summaryMarker(taskId: string): string {
57
59
  }
58
60
 
59
61
  function escapeSummaryAuditText(value: string): string {
60
- return value
61
- .replace(/&/g, '&')
62
- .replace(/</g, '&lt;')
63
- .replace(/>/g, '&gt;')
64
- .replace(/\r\n?/g, '\n');
62
+ return escapeHtmlText(value).replace(/\r\n?/g, '\n');
65
63
  }
66
64
 
67
65
  function renderSummaryAuditLine(value: string): string {
@@ -528,7 +526,30 @@ async function syncPullRequestSummary(
528
526
  if (!report.ok) return fail('failed', context, platformError(report.error));
529
527
  const checked = currentReportCheck(report.value, initial.value, taskContent, resolved.repoRoot);
530
528
  if (!checked.ok) return fail('failed', context, checked.error);
531
- const replaced = replaceCanonicalReportPlaceholder(options.body, report.value);
529
+ const placeholder = CANONICAL_REPORT_PLACEHOLDER;
530
+ const split = splitDocumentPlaceholder(options.body, placeholder);
531
+ if (!split.ok) return fail('failed', context, {
532
+ code: 'PR_SUMMARY_BODY_CONTRACT_INVALID',
533
+ message: split.error.message,
534
+ retryable: false
535
+ });
536
+ const prefix = sanitizeMarkdownDocument(split.value.prefix, { reservedMarkers: [CONTROL_MARKER_PATTERN] });
537
+ const suffix = sanitizeMarkdownDocument(split.value.suffix, { reservedMarkers: [CONTROL_MARKER_PATTERN] });
538
+ if (!prefix.ok) {
539
+ return fail('failed', context, {
540
+ code: 'PR_SUMMARY_BODY_CONTRACT_INVALID',
541
+ message: `${prefix.error.message} at offset ${prefix.error.offset}`,
542
+ retryable: false
543
+ });
544
+ }
545
+ if (!suffix.ok) {
546
+ return fail('failed', context, {
547
+ code: 'PR_SUMMARY_BODY_CONTRACT_INVALID',
548
+ message: `${suffix.error.message} at offset ${suffix.error.offset}`,
549
+ retryable: false
550
+ });
551
+ }
552
+ const replaced = replaceCanonicalReportPlaceholder(`${prefix.value}${placeholder}${suffix.value}`, report.value);
532
553
  if (!replaced.ok) return fail('failed', context, platformError(replaced.error));
533
554
  const desired = buildPullRequestSummary(resolved.taskId, replaced.value, initial.value.head.sha, renderHumanOverrideAudit(taskContent));
534
555
  if (!isSafeSummaryEnvelope(desired, resolved.taskId)) return fail('failed', context, {
@@ -22,7 +22,7 @@ type PlatformError = {
22
22
 
23
23
  type ProviderResult<T> =
24
24
  | { ok: true; value: T }
25
- | { ok: false; error: PlatformError };
25
+ | { ok: false; error: PlatformError; value?: T };
26
26
 
27
27
  type ProviderOperationContext = {
28
28
  repositoryRoot: string;
@@ -162,6 +162,41 @@ type MutationReceipt = {
162
162
  operationId?: string;
163
163
  };
164
164
 
165
+ type SecurityAlertKind = 'dependabot' | 'code-scanning';
166
+
167
+ type SecurityAlertSnapshot = {
168
+ kind: SecurityAlertKind;
169
+ number: number;
170
+ state: string;
171
+ data: JsonValue;
172
+ };
173
+
174
+ type LabelDefinition = {
175
+ name: string;
176
+ color: string;
177
+ description: string;
178
+ };
179
+
180
+ type LabelReconciliation = {
181
+ changed: boolean;
182
+ created: string[];
183
+ updated: string[];
184
+ removed: string[];
185
+ skipped: string[];
186
+ };
187
+
188
+ type MilestoneDefinition = {
189
+ title: string;
190
+ description: string;
191
+ state: 'open' | 'closed';
192
+ };
193
+
194
+ type MilestoneInitialization = {
195
+ changed: boolean;
196
+ created: string[];
197
+ skipped: string[];
198
+ };
199
+
165
200
  type RepositoryMetadataSnapshot = {
166
201
  repository: { identity: ResourceIdentity; name: string; url: string | null };
167
202
  labels: Array<{ identity: ResourceIdentity; name: string }>;
@@ -286,6 +321,8 @@ type PlatformProvider = {
286
321
  head: string;
287
322
  }): Promise<ProviderResult<{ sha: string }>>;
288
323
  inspect(input: { context: ProviderOperationContext; target: ResourceIdentity }): Promise<ProviderResult<ChangeRequestSnapshot>>;
324
+ listFiles?(input: { context: ProviderOperationContext; target: ResourceIdentity }): Promise<ProviderResult<string[]>>;
325
+ listClosingIssues?(input: { context: ProviderOperationContext; target: ResourceIdentity }): Promise<ProviderResult<ResourceIdentity[]>>;
289
326
  listClosing(input: { context: ProviderOperationContext; issue: ResourceIdentity }): Promise<ProviderResult<ChangeRequestSnapshot[]>>;
290
327
  create(input: {
291
328
  context: ProviderOperationContext;
@@ -383,6 +420,34 @@ type PlatformProvider = {
383
420
  historyLimit: number;
384
421
  }): Promise<ProviderResult<ReleaseNotesFacts>>;
385
422
  };
423
+ securityAlerts?: {
424
+ inspect(input: {
425
+ context: ProviderOperationContext;
426
+ kind: SecurityAlertKind;
427
+ number: number;
428
+ }): Promise<ProviderResult<SecurityAlertSnapshot>>;
429
+ dismiss(input: {
430
+ context: ProviderOperationContext;
431
+ kind: SecurityAlertKind;
432
+ number: number;
433
+ reason: string;
434
+ comment: string;
435
+ mutation: MutationIdentity;
436
+ }): Promise<ProviderResult<MutationReceipt>>;
437
+ };
438
+ repositoryMetadata?: {
439
+ reconcileLabels(input: {
440
+ context: ProviderOperationContext;
441
+ desired: LabelDefinition[];
442
+ cleanupStaleIn: boolean;
443
+ mutation: MutationIdentity;
444
+ }): Promise<ProviderResult<LabelReconciliation>>;
445
+ reconcileMilestones(input: {
446
+ context: ProviderOperationContext;
447
+ desired: MilestoneDefinition[];
448
+ mutation: MutationIdentity;
449
+ }): Promise<ProviderResult<MilestoneInitialization>>;
450
+ };
386
451
  verification?: {
387
452
  fetchRemoteFacts(input: {
388
453
  context: ProviderOperationContext;
@@ -414,12 +479,14 @@ function validatePlatformProvider(
414
479
  providerType: string
415
480
  ): ProviderResult<PlatformProvider> {
416
481
  const operationGroups: Record<string, { required: string[]; optional: string[] }> = {
417
- issues: { required: ['inspect', 'create', 'update', 'describeRepository'], optional: [] },
482
+ issues: { required: ['inspect', 'create', 'update', 'describeRepository'], optional: ['listLabels', 'listMilestones'] },
418
483
  comments: { required: ['list', 'write', 'delete'], optional: [] },
419
- changeRequests: { required: ['inspect', 'listClosing', 'create', 'update', 'resolveGitEvidence'], optional: ['verifyHead'] },
484
+ changeRequests: { required: ['inspect', 'listClosing', 'create', 'update', 'resolveGitEvidence'], optional: ['verifyHead', 'listFiles', 'listClosingIssues'] },
420
485
  checks: { required: ['inspectRequired', 'resolveRun', 'fetchLogs'], optional: [] },
421
486
  reviews: { required: ['list', 'publish'], optional: [] },
422
487
  releases: { required: ['inspect', 'create', 'update', 'reconcileMilestones', 'publishNotes', 'collectNotes'], optional: [] },
488
+ securityAlerts: { required: ['inspect', 'dismiss'], optional: [] },
489
+ repositoryMetadata: { required: ['reconcileLabels', 'reconcileMilestones'], optional: [] },
423
490
  verification: { required: ['fetchRemoteFacts'], optional: [] }
424
491
  };
425
492
  const resourceKindsByGroup: Record<string, PlatformResourceKind[]> = {
@@ -429,6 +496,8 @@ function validatePlatformProvider(
429
496
  checks: ['pull-request'],
430
497
  reviews: ['pull-request'],
431
498
  releases: ['release', 'issue', 'pull-request'],
499
+ securityAlerts: [],
500
+ repositoryMetadata: [],
432
501
  verification: ['issue', 'pull-request']
433
502
  };
434
503
  if (!isRecord(value)
@@ -515,6 +584,10 @@ export type {
515
584
  IssueSnapshot,
516
585
  JsonValue,
517
586
  MilestoneReconciliation,
587
+ MilestoneDefinition,
588
+ MilestoneInitialization,
589
+ LabelDefinition,
590
+ LabelReconciliation,
518
591
  MutationIdentity,
519
592
  MutationReceipt,
520
593
  PlatformCapabilities,
@@ -531,6 +604,8 @@ export type {
531
604
  RepositoryMetadataSnapshot,
532
605
  ReleaseNotesFacts,
533
606
  ResourceIdentity,
607
+ SecurityAlertKind,
608
+ SecurityAlertSnapshot,
534
609
  ReviewSnapshot,
535
610
  VerificationRemoteFacts
536
611
  };
@@ -5,7 +5,11 @@ import type {
5
5
  CheckLogSnapshot,
6
6
  CheckRunSnapshot,
7
7
  GitEvidenceSnapshot,
8
+ LabelDefinition,
9
+ LabelReconciliation,
8
10
  IssueSnapshot,
11
+ MilestoneDefinition,
12
+ MilestoneInitialization,
9
13
  MilestoneReconciliation,
10
14
  MutationReceipt,
11
15
  PlatformContextSnapshot,
@@ -18,6 +22,8 @@ import type {
18
22
  RepositoryMetadataSnapshot,
19
23
  RequiredCheckSnapshot,
20
24
  ReviewSnapshot,
25
+ SecurityAlertKind,
26
+ SecurityAlertSnapshot,
21
27
  VerificationRemoteFacts
22
28
  } from './provider-contract.ts';
23
29
  import type { JsonValue } from './provider-contract.ts';
@@ -273,6 +279,67 @@ function validateReceipt(value: unknown): MutationReceipt {
273
279
  };
274
280
  }
275
281
 
282
+ function positiveInteger(value: unknown, label: string): number {
283
+ if (!Number.isSafeInteger(value) || (value as number) <= 0) throw new Error(`${label} must be a positive integer`);
284
+ return value as number;
285
+ }
286
+
287
+ function validateSecurityAlert(value: unknown): SecurityAlertSnapshot {
288
+ const item = record(value, 'security alert');
289
+ exactKeys(item, ['kind', 'number', 'state', 'data'], 'security alert');
290
+ if (item.kind !== 'dependabot' && item.kind !== 'code-scanning') throw new Error('security alert.kind is invalid');
291
+ return {
292
+ kind: item.kind as SecurityAlertKind,
293
+ number: positiveInteger(item.number, 'security alert.number'),
294
+ state: stringValue(item.state, 'security alert.state'),
295
+ data: jsonValue(item.data, 'security alert.data')
296
+ };
297
+ }
298
+
299
+ function validateLabelDefinition(value: unknown, label: string): LabelDefinition {
300
+ const item = record(value, label);
301
+ exactKeys(item, ['name', 'color', 'description'], label);
302
+ return {
303
+ name: stringValue(item.name, `${label}.name`),
304
+ color: stringValue(item.color, `${label}.color`),
305
+ description: stringValue(item.description, `${label}.description`, true)
306
+ };
307
+ }
308
+
309
+ function validateLabelReconciliation(value: unknown): LabelReconciliation {
310
+ const item = record(value, 'label reconciliation');
311
+ exactKeys(item, ['changed', 'created', 'updated', 'removed', 'skipped'], 'label reconciliation');
312
+ const names = (field: string) => arrayValue(item[field], `label reconciliation.${field}`).map((entry) => stringValue(entry, `${field}[]`));
313
+ return {
314
+ changed: booleanValue(item.changed, 'label reconciliation.changed'),
315
+ created: names('created'),
316
+ updated: names('updated'),
317
+ removed: names('removed'),
318
+ skipped: names('skipped')
319
+ };
320
+ }
321
+
322
+ function validateMilestoneDefinition(value: unknown, label: string): MilestoneDefinition {
323
+ const item = record(value, label);
324
+ exactKeys(item, ['title', 'description', 'state'], label);
325
+ if (item.state !== 'open' && item.state !== 'closed') throw new Error(`${label}.state is invalid`);
326
+ return {
327
+ title: stringValue(item.title, `${label}.title`),
328
+ description: stringValue(item.description, `${label}.description`, true),
329
+ state: item.state
330
+ };
331
+ }
332
+
333
+ function validateMilestoneInitialization(value: unknown): MilestoneInitialization {
334
+ const item = record(value, 'milestone initialization');
335
+ exactKeys(item, ['changed', 'created', 'skipped'], 'milestone initialization');
336
+ return {
337
+ changed: booleanValue(item.changed, 'milestone initialization.changed'),
338
+ created: arrayValue(item.created, 'milestone initialization.created').map((entry) => stringValue(entry, 'created[]')),
339
+ skipped: arrayValue(item.skipped, 'milestone initialization.skipped').map((entry) => stringValue(entry, 'skipped[]'))
340
+ };
341
+ }
342
+
276
343
  function validateMetadata(value: unknown): RepositoryMetadataSnapshot {
277
344
  const item = record(value, 'repository metadata');
278
345
  exactKeys(item, ['repository', 'labels', 'milestones', 'issueTypes', 'fields'], 'repository metadata');
@@ -375,6 +442,11 @@ const PROVIDER_ERROR_CATALOG: Readonly<Record<string, { message: string; retryab
375
442
  ISSUE_NUMBER_INVALID: { message: 'The issue number is invalid', retryable: false },
376
443
  ISSUE_CREATE_RESPONSE_INVALID: { message: 'Issue creation returned an invalid response', retryable: false },
377
444
  COMMENT_ID_INVALID: { message: 'The comment identity is invalid', retryable: false },
445
+ SECURITY_KIND_INVALID: { message: 'The security alert kind is invalid', retryable: false },
446
+ SECURITY_NUMBER_INVALID: { message: 'The security alert number is invalid', retryable: false },
447
+ SECURITY_RESPONSE_INVALID: { message: 'The platform returned an invalid security alert', retryable: false },
448
+ LABEL_RESPONSE_INVALID: { message: 'The platform returned an invalid label response', retryable: false },
449
+ MILESTONE_RESPONSE_INVALID: { message: 'The platform returned an invalid milestone response', retryable: false },
378
450
  MILESTONE_IDENTITY_INVALID: { message: 'The milestone identity is invalid', retryable: false },
379
451
  CHECK_RUN_NOT_FOUND: { message: 'The check run was not found', retryable: false },
380
452
  RELEASE_NOTES_AUTHORS_TRUNCATED: { message: 'Release note commit authors exceeded the supported limit', retryable: false },
@@ -415,6 +487,8 @@ function validators(providerType: string, declaration?: ProviderIdentityDeclarat
415
487
  return { sha: stringValue(item.sha, 'change request head.sha') };
416
488
  },
417
489
  'changeRequests.inspect': (value) => validateChangeRequest(value, declaredIdentityKind(declaration, 'pull-request'), true),
490
+ 'changeRequests.listFiles': (value) => arrayValue(value, 'pull request files').map((entry) => stringValue(entry, 'pull request files[]')),
491
+ 'changeRequests.listClosingIssues': (value) => arrayValue(value, 'closing issues').map((entry) => identity(entry, 'closing issues[]', declaredIdentityKind(declaration, 'issue'))),
418
492
  'changeRequests.listClosing': (value) => arrayValue(value, 'changeRequests').map((entry) => validateChangeRequest(entry, declaredIdentityKind(declaration, 'pull-request'), true)),
419
493
  'changeRequests.create': validateReceipt,
420
494
  'changeRequests.update': validateReceipt,
@@ -458,6 +532,10 @@ function validators(providerType: string, declaration?: ProviderIdentityDeclarat
458
532
  },
459
533
  'releases.publishNotes': validateReceipt,
460
534
  'releases.collectNotes': (value) => validateReleaseNotes(value, declaration),
535
+ 'securityAlerts.inspect': validateSecurityAlert,
536
+ 'securityAlerts.dismiss': validateReceipt,
537
+ 'repositoryMetadata.reconcileLabels': validateLabelReconciliation,
538
+ 'repositoryMetadata.reconcileMilestones': validateMilestoneInitialization,
461
539
  'verification.fetchRemoteFacts': (value) => {
462
540
  const item = record(value, 'verification facts');
463
541
  exactKeys(item, ['issue', 'comments', 'changeRequest', 'commit', 'fields'], 'verification facts');
@@ -491,11 +569,15 @@ async function invokeProviderOperation<T>(
491
569
  }
492
570
  if (envelope.ok === false && envelope.error && typeof envelope.error === 'object' && !Array.isArray(envelope.error)) {
493
571
  try {
494
- exactKeys(envelope, ['ok', 'error'], `${operation} result`);
572
+ exactKeys(envelope, Object.hasOwn(envelope, 'value') ? ['ok', 'error', 'value'] : ['ok', 'error'], `${operation} result`);
495
573
  const error = envelope.error as Record<string, unknown>;
496
574
  exactKeys(error, ['code', 'message', 'retryable'], `${operation} error`);
497
575
  if (typeof error.code !== 'string' || !error.code || typeof error.message !== 'string' || !error.message || typeof error.retryable !== 'boolean') throw new Error('invalid provider error');
498
- return { ok: false, error: safeProviderError(providerType, operation, error) };
576
+ return {
577
+ ok: false,
578
+ error: safeProviderError(providerType, operation, error),
579
+ ...(Object.hasOwn(envelope, 'value') ? { value: validate(envelope.value) } : {})
580
+ };
499
581
  } catch {
500
582
  return { ok: false, error: validationError(providerType, operation, 'Provider operation returned an invalid error') };
501
583
  }
@@ -510,7 +592,7 @@ function wrapProviderOperations(provider: PlatformProvider): PlatformProvider {
510
592
  const map = validators(provider.type, provider.identity);
511
593
  const wrapped: PlatformProvider = { ...provider, context: { ...provider.context } };
512
594
  wrapped.context.resolve = (input) => invokeProviderOperation(provider.type, 'context.resolve', () => provider.context.resolve(input), map['context.resolve']! as ResultValidator<PlatformContextSnapshot>);
513
- for (const groupName of ['issues', 'comments', 'changeRequests', 'checks', 'reviews', 'releases', 'verification'] as const) {
595
+ for (const groupName of ['issues', 'comments', 'changeRequests', 'checks', 'reviews', 'releases', 'securityAlerts', 'repositoryMetadata', 'verification'] as const) {
514
596
  const group = provider[groupName];
515
597
  if (!group) continue;
516
598
  const target: Record<string, unknown> = { ...group };