@bevel-software/platform-core-backend 0.25.0 → 0.26.0

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 (254) hide show
  1. package/agent-guide/access-control.md +234 -0
  2. package/agent-guide/conventions.md +27 -0
  3. package/agent-guide/directory-structure.md +145 -0
  4. package/agent-guide/finding-things.md +7 -0
  5. package/agent-guide/introduction.md +27 -0
  6. package/agent-guide/skills.md +47 -0
  7. package/agent-guide/tool-manuals.md +217 -0
  8. package/agent-guide/where-a-new-file-goes.md +36 -0
  9. package/dist/assets.d.ts +7 -0
  10. package/dist/assets.d.ts.map +1 -1
  11. package/dist/assets.js +9 -0
  12. package/dist/assets.js.map +1 -1
  13. package/dist/core/core-ports.d.ts +11 -0
  14. package/dist/core/core-ports.d.ts.map +1 -1
  15. package/dist/core/core-ports.js.map +1 -1
  16. package/dist/core/create-core-server.d.ts.map +1 -1
  17. package/dist/core/create-core-server.js +13 -2
  18. package/dist/core/create-core-server.js.map +1 -1
  19. package/dist/core/create-core-services.d.ts +9 -0
  20. package/dist/core/create-core-services.d.ts.map +1 -1
  21. package/dist/core/create-core-services.js +14 -4
  22. package/dist/core/create-core-services.js.map +1 -1
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +2 -2
  26. package/dist/index.js.map +1 -1
  27. package/dist/modules/access/access-control.interface.d.ts +9 -0
  28. package/dist/modules/access/access-control.interface.d.ts.map +1 -1
  29. package/dist/modules/access/access-control.service.d.ts +1 -0
  30. package/dist/modules/access/access-control.service.d.ts.map +1 -1
  31. package/dist/modules/access/access-control.service.js +16 -0
  32. package/dist/modules/access/access-control.service.js.map +1 -1
  33. package/dist/modules/agent-guide/agent-guide.d.ts +139 -0
  34. package/dist/modules/agent-guide/agent-guide.d.ts.map +1 -0
  35. package/dist/modules/agent-guide/agent-guide.js +191 -0
  36. package/dist/modules/agent-guide/agent-guide.js.map +1 -0
  37. package/dist/modules/agent-guide/agent-guide.tools.d.ts +24 -0
  38. package/dist/modules/agent-guide/agent-guide.tools.d.ts.map +1 -0
  39. package/dist/modules/agent-guide/agent-guide.tools.js +100 -0
  40. package/dist/modules/agent-guide/agent-guide.tools.js.map +1 -0
  41. package/dist/modules/agent-guide/index.d.ts +4 -0
  42. package/dist/modules/agent-guide/index.d.ts.map +1 -0
  43. package/dist/modules/agent-guide/index.js +4 -0
  44. package/dist/modules/agent-guide/index.js.map +1 -0
  45. package/dist/modules/agent-instructions/agent-instructions.routes.d.ts +3 -2
  46. package/dist/modules/agent-instructions/agent-instructions.routes.d.ts.map +1 -1
  47. package/dist/modules/agent-instructions/agent-instructions.routes.js +3 -2
  48. package/dist/modules/agent-instructions/agent-instructions.routes.js.map +1 -1
  49. package/dist/modules/agent-instructions/compose.d.ts +9 -6
  50. package/dist/modules/agent-instructions/compose.d.ts.map +1 -1
  51. package/dist/modules/agent-instructions/compose.js +9 -6
  52. package/dist/modules/agent-instructions/compose.js.map +1 -1
  53. package/dist/modules/agent-instructions/index.d.ts +1 -1
  54. package/dist/modules/agent-instructions/index.d.ts.map +1 -1
  55. package/dist/modules/agent-instructions/index.js +1 -1
  56. package/dist/modules/agent-instructions/index.js.map +1 -1
  57. package/dist/modules/agent-instructions/shared-file-rules.d.ts +10 -50
  58. package/dist/modules/agent-instructions/shared-file-rules.d.ts.map +1 -1
  59. package/dist/modules/agent-instructions/shared-file-rules.js +32 -85
  60. package/dist/modules/agent-instructions/shared-file-rules.js.map +1 -1
  61. package/dist/modules/mcp/mcp.service.d.ts +29 -2
  62. package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
  63. package/dist/modules/mcp/mcp.service.js +113 -16
  64. package/dist/modules/mcp/mcp.service.js.map +1 -1
  65. package/dist/modules/mcp/tool-schema-guard.d.ts +105 -0
  66. package/dist/modules/mcp/tool-schema-guard.d.ts.map +1 -0
  67. package/dist/modules/mcp/tool-schema-guard.js +171 -0
  68. package/dist/modules/mcp/tool-schema-guard.js.map +1 -0
  69. package/dist/modules/plugins/plugins.tools.d.ts +36 -2
  70. package/dist/modules/plugins/plugins.tools.d.ts.map +1 -1
  71. package/dist/modules/plugins/plugins.tools.js +71 -14
  72. package/dist/modules/plugins/plugins.tools.js.map +1 -1
  73. package/dist/modules/settings/deployment-settings.service.d.ts +0 -7
  74. package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
  75. package/dist/modules/settings/deployment-settings.service.js +14 -53
  76. package/dist/modules/settings/deployment-settings.service.js.map +1 -1
  77. package/dist/modules/settings/setup.routes.d.ts.map +1 -1
  78. package/dist/modules/settings/setup.routes.js +3 -6
  79. package/dist/modules/settings/setup.routes.js.map +1 -1
  80. package/dist/modules/skills/skills.tools.d.ts.map +1 -1
  81. package/dist/modules/skills/skills.tools.js +58 -16
  82. package/dist/modules/skills/skills.tools.js.map +1 -1
  83. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts +23 -4
  84. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts.map +1 -1
  85. package/dist/modules/tool-manuals/tool-manuals.contract.js.map +1 -1
  86. package/dist/modules/tool-manuals/tool-manuals.service.d.ts +4 -0
  87. package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
  88. package/dist/modules/tool-manuals/tool-manuals.service.js +14 -0
  89. package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
  90. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts +7 -0
  91. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
  92. package/dist/modules/tool-manuals/tool-manuals.tools.js +66 -36
  93. package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
  94. package/dist/modules/tool-registry/description-length.d.ts +14 -14
  95. package/dist/modules/tool-registry/description-length.d.ts.map +1 -1
  96. package/dist/modules/tool-registry/description-length.js +24 -26
  97. package/dist/modules/tool-registry/description-length.js.map +1 -1
  98. package/dist/modules/tool-registry/guide-first.d.ts +23 -0
  99. package/dist/modules/tool-registry/guide-first.d.ts.map +1 -0
  100. package/dist/modules/tool-registry/guide-first.js +32 -0
  101. package/dist/modules/tool-registry/guide-first.js.map +1 -0
  102. package/dist/modules/tool-registry/tool-registry.d.ts +6 -0
  103. package/dist/modules/tool-registry/tool-registry.d.ts.map +1 -1
  104. package/dist/modules/tool-registry/tool-registry.js +9 -2
  105. package/dist/modules/tool-registry/tool-registry.js.map +1 -1
  106. package/dist/modules/workflow/agent-tools/change-request-read-shape.d.ts +449 -0
  107. package/dist/modules/workflow/agent-tools/change-request-read-shape.d.ts.map +1 -0
  108. package/dist/modules/workflow/agent-tools/change-request-read-shape.js +481 -0
  109. package/dist/modules/workflow/agent-tools/change-request-read-shape.js.map +1 -0
  110. package/dist/modules/workflow/agent-tools/change-request-read.tools.d.ts +73 -0
  111. package/dist/modules/workflow/agent-tools/change-request-read.tools.d.ts.map +1 -0
  112. package/dist/modules/workflow/agent-tools/change-request-read.tools.js +582 -0
  113. package/dist/modules/workflow/agent-tools/change-request-read.tools.js.map +1 -0
  114. package/dist/modules/workflow/agent-tools/change-request-summary.d.ts +12 -1
  115. package/dist/modules/workflow/agent-tools/change-request-summary.d.ts.map +1 -1
  116. package/dist/modules/workflow/agent-tools/change-request-summary.js +5 -1
  117. package/dist/modules/workflow/agent-tools/change-request-summary.js.map +1 -1
  118. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
  119. package/dist/modules/workflow/agent-tools/workflow.tools.js +9 -0
  120. package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
  121. package/dist/modules/workflow/git/git.service.d.ts +210 -13
  122. package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
  123. package/dist/modules/workflow/git/git.service.js +456 -91
  124. package/dist/modules/workflow/git/git.service.js.map +1 -1
  125. package/dist/modules/workflow/git/merge-commit.d.ts +73 -0
  126. package/dist/modules/workflow/git/merge-commit.d.ts.map +1 -0
  127. package/dist/modules/workflow/git/merge-commit.js +89 -0
  128. package/dist/modules/workflow/git/merge-commit.js.map +1 -0
  129. package/dist/modules/workflow/git/pull-request.service.d.ts +94 -1
  130. package/dist/modules/workflow/git/pull-request.service.d.ts.map +1 -1
  131. package/dist/modules/workflow/git/pull-request.service.js +332 -37
  132. package/dist/modules/workflow/git/pull-request.service.js.map +1 -1
  133. package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts +35 -0
  134. package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -1
  135. package/dist/modules/workflow/review-workflow/review-workflow.service.js +178 -12
  136. package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -1
  137. package/dist/modules/workflow/workflow.routes.d.ts +6 -2
  138. package/dist/modules/workflow/workflow.routes.d.ts.map +1 -1
  139. package/dist/modules/workflow/workflow.routes.js +7 -2
  140. package/dist/modules/workflow/workflow.routes.js.map +1 -1
  141. package/dist/modules/workflow/workflow.service.d.ts +4 -0
  142. package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
  143. package/dist/modules/workflow/workflow.service.js +3 -0
  144. package/dist/modules/workflow/workflow.service.js.map +1 -1
  145. package/dist/modules/workspace/startup/kb-startup-runner.d.ts +70 -0
  146. package/dist/modules/workspace/startup/kb-startup-runner.d.ts.map +1 -1
  147. package/dist/modules/workspace/startup/kb-startup-runner.js +213 -20
  148. package/dist/modules/workspace/startup/kb-startup-runner.js.map +1 -1
  149. package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
  150. package/dist/modules/workspace/startup/steps/seed-tree.js +22 -27
  151. package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
  152. package/dist/modules/workspace/startup/steps/template-files.step.d.ts +58 -52
  153. package/dist/modules/workspace/startup/steps/template-files.step.d.ts.map +1 -1
  154. package/dist/modules/workspace/startup/steps/template-files.step.js +209 -223
  155. package/dist/modules/workspace/startup/steps/template-files.step.js.map +1 -1
  156. package/dist/modules/workspace/startup/steps/template-source.d.ts +5 -3
  157. package/dist/modules/workspace/startup/steps/template-source.d.ts.map +1 -1
  158. package/dist/modules/workspace/startup/steps/template-source.js +5 -3
  159. package/dist/modules/workspace/startup/steps/template-source.js.map +1 -1
  160. package/dist/modules/workspace/workspace.tools.d.ts +10 -1
  161. package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
  162. package/dist/modules/workspace/workspace.tools.js +211 -18
  163. package/dist/modules/workspace/workspace.tools.js.map +1 -1
  164. package/dist/shared/domain-errors.d.ts +11 -0
  165. package/dist/shared/domain-errors.d.ts.map +1 -1
  166. package/dist/shared/domain-errors.js +14 -0
  167. package/dist/shared/domain-errors.js.map +1 -1
  168. package/dist/shared/hidden-tools.d.ts +44 -0
  169. package/dist/shared/hidden-tools.d.ts.map +1 -0
  170. package/dist/shared/hidden-tools.js +13 -0
  171. package/dist/shared/hidden-tools.js.map +1 -0
  172. package/kb-template/.bevelignore +0 -5
  173. package/package.json +4 -3
  174. package/src/__tests__/kb-layout-config.test.ts +10 -100
  175. package/src/__tests__/packaged-assets-ship.test.ts +54 -0
  176. package/src/assets.ts +10 -0
  177. package/src/core/core-ports.ts +11 -0
  178. package/src/core/create-core-server.ts +13 -2
  179. package/src/core/create-core-services.ts +28 -4
  180. package/src/index.ts +2 -2
  181. package/src/modules/access/__tests__/access-control.atref-batch.test.ts +58 -0
  182. package/src/modules/access/__tests__/access-control.platform-restore.test.ts +8 -7
  183. package/src/modules/access/__tests__/access-personal-plugin.test.ts +1 -18
  184. package/src/modules/access/access-control.interface.ts +15 -0
  185. package/src/modules/access/access-control.service.ts +21 -0
  186. package/src/modules/agent-guide/__tests__/agent-guide.test.ts +328 -0
  187. package/src/modules/agent-guide/__tests__/agent-guide.tools.test.ts +189 -0
  188. package/src/modules/agent-guide/agent-guide.tools.ts +122 -0
  189. package/src/modules/agent-guide/agent-guide.ts +291 -0
  190. package/src/modules/agent-guide/index.ts +21 -0
  191. package/src/modules/agent-instructions/__tests__/shared-file-rules.test.ts +28 -121
  192. package/src/modules/agent-instructions/agent-instructions.routes.ts +3 -2
  193. package/src/modules/agent-instructions/compose.ts +9 -6
  194. package/src/modules/agent-instructions/index.ts +0 -3
  195. package/src/modules/agent-instructions/shared-file-rules.ts +31 -93
  196. package/src/modules/mcp/__tests__/fake-downstream-mcp-server.ts +14 -3
  197. package/src/modules/mcp/__tests__/mcp.e2e.test.ts +250 -0
  198. package/src/modules/mcp/__tests__/mcp.service.test.ts +31 -23
  199. package/src/modules/mcp/__tests__/tool-schema-guard.test.ts +266 -0
  200. package/src/modules/mcp/mcp.service.ts +137 -19
  201. package/src/modules/mcp/tool-schema-guard.ts +196 -0
  202. package/src/modules/plugins/__tests__/plugins.tools.test.ts +154 -4
  203. package/src/modules/plugins/plugins.tools.ts +75 -15
  204. package/src/modules/settings/__tests__/deployment-settings.service.test.ts +26 -55
  205. package/src/modules/settings/deployment-settings.service.ts +13 -54
  206. package/src/modules/settings/setup.routes.ts +3 -6
  207. package/src/modules/skills/__tests__/skills.tools.description.test.ts +91 -0
  208. package/src/modules/skills/skills.tools.ts +62 -16
  209. package/src/modules/tool-manuals/__tests__/tool-manuals.detail.route.test.ts +57 -0
  210. package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +73 -4
  211. package/src/modules/tool-manuals/tool-manuals.contract.ts +24 -4
  212. package/src/modules/tool-manuals/tool-manuals.service.ts +17 -0
  213. package/src/modules/tool-manuals/tool-manuals.tools.ts +74 -36
  214. package/src/modules/tool-registry/__tests__/own-tool-schemas.test.ts +160 -0
  215. package/src/modules/tool-registry/__tests__/tool-description-length.test.ts +61 -59
  216. package/src/modules/tool-registry/description-length.ts +24 -26
  217. package/src/modules/tool-registry/guide-first.ts +34 -0
  218. package/src/modules/tool-registry/tool-registry.ts +9 -2
  219. package/src/modules/workflow/__tests__/apply-failure.test.ts +6 -1
  220. package/src/modules/workflow/agent-tools/__tests__/change-request-read-shape.test.ts +705 -0
  221. package/src/modules/workflow/agent-tools/__tests__/change-request-read.tools.test.ts +1518 -0
  222. package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +23 -2
  223. package/src/modules/workflow/agent-tools/change-request-read-shape.ts +712 -0
  224. package/src/modules/workflow/agent-tools/change-request-read.tools.ts +724 -0
  225. package/src/modules/workflow/agent-tools/change-request-summary.ts +5 -1
  226. package/src/modules/workflow/agent-tools/workflow.tools.ts +8 -0
  227. package/src/modules/workflow/git/__tests__/git.service.appliedChange.test.ts +285 -0
  228. package/src/modules/workflow/git/__tests__/git.service.changedFilesForPr.test.ts +124 -0
  229. package/src/modules/workflow/git/__tests__/git.service.mergeChangeRequest.test.ts +334 -0
  230. package/src/modules/workflow/git/__tests__/pull-request.service.list-fetch.test.ts +72 -2
  231. package/src/modules/workflow/git/__tests__/pull-request.service.placeholder.test.ts +24 -2
  232. package/src/modules/workflow/git/__tests__/pull-request.service.test.ts +620 -1
  233. package/src/modules/workflow/git/git.service.ts +537 -94
  234. package/src/modules/workflow/git/merge-commit.ts +88 -0
  235. package/src/modules/workflow/git/pull-request.service.ts +380 -54
  236. package/src/modules/workflow/review-workflow/__tests__/approval-states.test.ts +7 -1
  237. package/src/modules/workflow/review-workflow/__tests__/merge-records-own-commit.test.ts +407 -0
  238. package/src/modules/workflow/review-workflow/review-workflow.service.ts +189 -11
  239. package/src/modules/workflow/workflow.routes.ts +7 -2
  240. package/src/modules/workflow/workflow.service.ts +7 -0
  241. package/src/modules/workspace/__tests__/escape-sequences.routes.test.ts +4 -3
  242. package/src/modules/workspace/__tests__/workspace.routes.move-platform-files.test.ts +21 -10
  243. package/src/modules/workspace/__tests__/workspace.tools.agents-file.test.ts +33 -55
  244. package/src/modules/workspace/__tests__/workspace.tools.test.ts +255 -22
  245. package/src/modules/workspace/startup/__tests__/kb-startup-runner.test.ts +231 -1
  246. package/src/modules/workspace/startup/kb-startup-runner.ts +216 -19
  247. package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +191 -489
  248. package/src/modules/workspace/startup/steps/seed-tree.ts +21 -27
  249. package/src/modules/workspace/startup/steps/template-files.step.ts +217 -249
  250. package/src/modules/workspace/startup/steps/template-source.ts +5 -3
  251. package/src/modules/workspace/workspace.tools.ts +226 -16
  252. package/src/shared/domain-errors.ts +15 -0
  253. package/src/shared/hidden-tools.ts +45 -0
  254. package/kb-template/AGENTS.md +0 -730
@@ -0,0 +1,582 @@
1
+ import { ToolError } from '../../tool-helpers/tool.contract.js';
2
+ import { toolDef } from '../../tool-helpers/tool-def.js';
3
+ import { PER_PAGE_DEFAULT, PER_PAGE_MAX, fileIsReadable, isAuthor, matchesAuthor, pathsOf, maySeeChangeRequest, pageOf, pagingOf, statesFor, toCrComment, toCrDetail, toCrFile, toCrReviews, toCrSummary, toCrViewer, visibleBlockers, visibleComments, } from './change-request-read-shape.js';
4
+ /**
5
+ * The five read tools over change requests, named and shaped after GitHub's
6
+ * pull-request API: `list_change_requests`, `get_change_request`,
7
+ * `list_change_request_files`, `list_change_request_reviews` and
8
+ * `list_change_request_comments`. The mapping lives in
9
+ * `change-request-read-shape.ts`; this file does the IO and the access
10
+ * filtering.
11
+ *
12
+ * They ANSWER in Hexis's own vocabulary, not GitHub's field names (Razvan's
13
+ * decision on the review of PR #347, 2026-10-02): every field shared with
14
+ * `open_change_request`'s summary takes that summary's name, and the rest follow
15
+ * its style, so an agent opens a change request and reads it back in one
16
+ * vocabulary. Their INPUTS keep GitHub's filter names, which the ticket pins.
17
+ * The shape module's header says what that changed, field by field.
18
+ *
19
+ * None of them writes anything — every handler is registered `write: false`,
20
+ * so a read-scoped connection key may call all five, and every service call
21
+ * below is a read.
22
+ *
23
+ * ## What the caller may see
24
+ *
25
+ * The app's own change-request routes serve the whole list and the whole
26
+ * detail to any signed-in viewer; only the file CONTENT routes gate per path
27
+ * (`canReadAtRef` at `origin/<base>`, with an unresolvable verdict as a
28
+ * denial). These tools apply that same content gate to the whole payload,
29
+ * because an agent's answer is the content: a file list, a reviewer's comment
30
+ * and a gate warning all name paths, and an agent hands what it reads to
31
+ * whoever it is talking to.
32
+ *
33
+ * So, per request:
34
+ *
35
+ * - every path is resolved at `origin/<base>` — the target's access tree, the
36
+ * one the request is asking to be judged against — in ONE batched lookup;
37
+ * - BOTH names of a moved file are resolved, and a file is readable only if
38
+ * both are: the diff of a move shows what was at the old path, so a file
39
+ * moved out of a closed folder stays closed, however open its new home.
40
+ * The LIST decides this over the same `touchedNodeFiles` pairs the detail
41
+ * does — a list that judged the flat `touchedNodePaths` could not see a
42
+ * move's old side, and advertised requests its own by-number tools
43
+ * answered 404 for;
44
+ * - files the caller may not read are left out and counted in
45
+ * `withheldFiles`, never named (decision 2 on the ticket);
46
+ * - comments on a withheld file, and gate blockers naming one, go the same
47
+ * way, with their own counts; a REPLY goes when the comment it replies to
48
+ * does, up the whole chain;
49
+ * - `body` is the author's own description, with the generated
50
+ * `## Affected owners` block cut off the end — see `authorsDescription`;
51
+ * - a request with no readable file and no claim of authorship answers 404,
52
+ * indistinguishable from a number that was never issued.
53
+ *
54
+ * ## Reading a request that is no longer open
55
+ *
56
+ * A MERGED request is read from the merge commit its row records: its branch is
57
+ * retired, but the commit holds exactly the change that landed, so its file list
58
+ * is recovered from there and filtered by access like an open request's (the
59
+ * 2026-10-02 decision). Nothing in that path touches the network — the commit is
60
+ * in the clone or it is not.
61
+ *
62
+ * A DECLINED request has no merge commit and no branch left to diff, so its file
63
+ * set cannot be resolved at all; it fails closed, and is therefore readable by
64
+ * its author alone. "We cannot tell what this request touched" is not "you may
65
+ * see it", and an empty path set is the same answer `scopeApplyFailures` already
66
+ * refuses to grant anything on. The same holds for any request whose file set
67
+ * does not resolve — an access tree that will not load at `origin/<base>`, or a
68
+ * clone that does not have the merge commit yet.
69
+ */
70
+ export function registerChangeRequestReadTools(registry, router, toolAuth, toolHandler, accessControl, kb) {
71
+ /**
72
+ * Mount one read tool. Every one of them is keyed by a change-request number
73
+ * (or by nothing at all), never by a draft, so none declares the injected
74
+ * `branch` input — the clone a verdict is resolved in is a scratch clone of
75
+ * the one shared origin, not anybody's working branch.
76
+ */
77
+ const mount = (spec) => {
78
+ const path = `/api/agent/tools/${spec.name}`;
79
+ const def = toolDef({
80
+ name: spec.name,
81
+ description: spec.description,
82
+ path,
83
+ inputs: spec.inputs,
84
+ outputs: spec.outputs,
85
+ tags: ['workflow'],
86
+ });
87
+ registry.registerInternalTool(def);
88
+ registry.registerExternalTool(def);
89
+ router.post(path.slice('/api'.length), toolAuth, toolHandler(spec.handler, { write: false }));
90
+ };
91
+ /**
92
+ * A clone to resolve access verdicts in. All clones track the same origin and
93
+ * every verdict here is read at `origin/<base>`, so any existing one answers
94
+ * identically — reusing one avoids cloning a branch just to read a ref.
95
+ */
96
+ const repoGlobalWorkspaceId = async (ctx) => (await ctx.workspaceService.findAnyWorkspaceId()) ?? kb.defaultWorkspaceId();
97
+ /** A change-request number as the tools accept it. */
98
+ const numberArg = (args) => {
99
+ const n = args.number;
100
+ // A SAFE integer: JSON carries numbers a double cannot hold exactly, and
101
+ // one of those would reach the database rounded, or as an error the
102
+ // caller could not have predicted — not as the 400 a wrong number earns.
103
+ if (typeof n !== 'number' || !Number.isSafeInteger(n) || n <= 0) {
104
+ throw new ToolError('`number` is required and must be a positive integer.', 400);
105
+ }
106
+ return n;
107
+ };
108
+ /**
109
+ * Read verdicts for `paths` at `origin/<base>`, as a membership set of what
110
+ * the caller MAY read. A null answer (the ref or its `roles.yaml` does not
111
+ * resolve) withholds everything, which is the same reading the app's
112
+ * fork-point route gives it.
113
+ */
114
+ const readablePaths = async (ctx, workspaceId, base, paths) => {
115
+ if (paths.length === 0)
116
+ return new Set();
117
+ const verdicts = await accessControl.canReadBatchAtRef(workspaceId, `origin/${base}`, ctx.user.email, [...new Set(paths)]);
118
+ if (!verdicts)
119
+ return new Set();
120
+ return new Set([...verdicts].filter(([, allowed]) => allowed).map(([p]) => p));
121
+ };
122
+ const scopedDetail = async (ctx, number, opts) => {
123
+ const workspaceId = await repoGlobalWorkspaceId(ctx);
124
+ const detail = await ctx.workflowService.getChangeRequestDetail(number, {
125
+ workspaceId,
126
+ viewerEmail: ctx.user.email,
127
+ patches: opts.patches,
128
+ });
129
+ if (!detail)
130
+ throw notFound(number);
131
+ const viewerIsAuthor = isAuthor(detail, ctx.user.email);
132
+ // Comment paths join the batch: a comment may name a file the request no
133
+ // longer changes, and without a verdict of its own it would be withheld
134
+ // from a caller who can read it perfectly well.
135
+ const commentPaths = detail.comments.map((c) => c.path).filter((p) => !!p);
136
+ // BOTH names of every file: a move is judged on its old path as well as
137
+ // its new one, because the diff of a move shows what was at the old one.
138
+ const readable = await readablePaths(ctx, workspaceId, detail.base, [
139
+ ...detail.files.flatMap(pathsOf),
140
+ ...commentPaths,
141
+ ]);
142
+ const mayRead = (path) => readable.has(path);
143
+ const readableFiles = detail.files.filter((f) => fileIsReadable(f, mayRead));
144
+ if (!maySeeChangeRequest({ readableFiles: readableFiles.length, isAuthor: viewerIsAuthor })) {
145
+ throw notFound(number);
146
+ }
147
+ // Every name a withheld file goes by, so a gate warning quoting either
148
+ // spelling is caught by the blocker filter — and so `mayShow` catches
149
+ // whichever spelling an approval or a comment happens to use.
150
+ const withheldFilePaths = detail.files
151
+ .filter((f) => !fileIsReadable(f, mayRead))
152
+ .flatMap(pathsOf);
153
+ const withheldNames = new Set(withheldFilePaths);
154
+ return {
155
+ detail,
156
+ mayRead,
157
+ mayShow: (path) => mayRead(path) && !withheldNames.has(path),
158
+ readableFiles,
159
+ withheldFilePaths,
160
+ withheldFileCount: detail.files.length - readableFiles.length,
161
+ viewerIsAuthor,
162
+ };
163
+ };
164
+ /**
165
+ * The same answer for a number that was never issued and for one the caller
166
+ * may not see — requirement 7. Says nothing a probe could tell apart.
167
+ */
168
+ const notFound = (number) => new ToolError(`Change request #${number} not found.`, 404);
169
+ /**
170
+ * The changed files of a SUMMARY, as the pairs a read gate decides over.
171
+ *
172
+ * Absent `touchedNodeFiles` means no summary builder filled it, and that is
173
+ * answered with no files rather than by falling back to `touchedNodePaths`:
174
+ * the fallback cannot pair a move, which is the whole reason this field
175
+ * exists, and a silent one would restore the list-versus-detail disagreement
176
+ * the next time a summary reached here from somewhere new. No files means
177
+ * nothing proven, which means author-only — the same fail-closed reading an
178
+ * empty path set already gets.
179
+ */
180
+ const filesOf = (cr) => cr.touchedNodeFiles ?? [];
181
+ /** `approvals` is one entry per file, same order; index it by path. */
182
+ const approvalsByPath = (detail) => new Map(detail.approvals.map((a) => [a.path, a]));
183
+ // ── Shared output sub-schemas ─────────────────────────────────────────────
184
+ const userSchema = {
185
+ type: 'object',
186
+ properties: {
187
+ login: { type: 'string', description: 'Hash-derived login (`user-<12 hex>`); no raw address.' },
188
+ name: { type: 'string' },
189
+ email: { type: 'string', description: 'Set for comment authors and approvers only.' },
190
+ },
191
+ required: ['login'],
192
+ };
193
+ const changeRequestSchema = {
194
+ type: 'object',
195
+ properties: {
196
+ url: { type: 'string', description: 'Link a person can open. First field: hand this to the user.' },
197
+ urlNote: { type: 'string', description: 'Present only when `url` is relative.' },
198
+ number: { type: 'integer' },
199
+ title: { type: 'string' },
200
+ state: { type: 'string', enum: ['open', 'merged', 'closed'], description: "Hexis's own state: `merged` is applied, `closed` declined." },
201
+ author: userSchema,
202
+ sourceBranch: { type: 'string', description: 'The branch the change comes from.' },
203
+ targetBranch: { type: 'string', description: 'The branch it would be applied to.' },
204
+ createdAt: { type: 'string', description: 'ISO timestamp.' },
205
+ updatedAt: { type: 'string', description: 'ISO timestamp — the close time of a closed request, else the creation time.' },
206
+ changedFiles: { type: 'integer', description: 'How many of its files YOU may read.' },
207
+ withheldFiles: { type: 'integer', description: 'How many of its files you may not read. Never named.' },
208
+ lastApplyFailure: {
209
+ type: 'object',
210
+ description: 'Present while an open request carries the refusal its last Apply met: `reason` in the gate\'s or git\'s ' +
211
+ 'words when you may read every file of the request, else a line saying the reason is withheld; ' +
212
+ '`conflicts` when git refused on conflicts with the target; `at` an ISO timestamp.',
213
+ properties: {
214
+ reason: { type: 'string' },
215
+ conflicts: { type: 'boolean' },
216
+ at: { type: 'string' },
217
+ },
218
+ required: ['reason', 'conflicts', 'at'],
219
+ },
220
+ },
221
+ required: ['url', 'number', 'title', 'state', 'author', 'sourceBranch', 'targetBranch', 'createdAt', 'updatedAt', 'changedFiles', 'withheldFiles'],
222
+ };
223
+ const pagingOutputs = {
224
+ totalCount: { type: 'integer', description: 'Entries you may read, across all pages.' },
225
+ page: { type: 'integer' },
226
+ perPage: { type: 'integer' },
227
+ hasNextPage: { type: 'boolean', description: 'True when a further page exists.' },
228
+ };
229
+ const pagingRequired = ['totalCount', 'page', 'perPage', 'hasNextPage'];
230
+ const pagingInputs = {
231
+ per_page: { type: 'integer', minimum: 1, maximum: PER_PAGE_MAX, description: `Entries per page (default ${PER_PAGE_DEFAULT}, at most ${PER_PAGE_MAX}).` },
232
+ page: { type: 'integer', minimum: 1, description: 'Page number, from 1.' },
233
+ };
234
+ // ── list_change_requests ──────────────────────────────────────────────────
235
+ mount({
236
+ name: 'list_change_requests',
237
+ description: 'List change requests (GitHub: list pull requests), newest first. Filter by `state` ' +
238
+ '(`open`, the default, `closed` — which covers applied and declined alike — or `all`), ' +
239
+ '`head` (source branch), `base` (target branch) and `author` (an email or a `login`). ' +
240
+ "Each answers in Hexis's own words: `url`, `number`, `title`, `state` (`open`, `merged` or " +
241
+ '`closed`), `sourceBranch`, `targetBranch`. Read-only, and limited to what you may read: a ' +
242
+ 'request whose files are all closed to you is not listed unless you opened it, and ' +
243
+ '`withheldFiles` counts the ones left out of each.',
244
+ inputs: {
245
+ type: 'object',
246
+ properties: {
247
+ state: { type: 'string', enum: ['open', 'closed', 'all'], description: 'Default `open`. `closed` covers applied and declined alike; the answer says which.' },
248
+ head: { type: 'string', description: 'Source branch — list only requests coming FROM it.' },
249
+ base: { type: 'string', description: 'Target branch — list only requests going INTO it.' },
250
+ author: { type: 'string', description: "The author's email, or their `author.login`." },
251
+ ...pagingInputs,
252
+ },
253
+ additionalProperties: false,
254
+ },
255
+ outputs: {
256
+ type: 'object',
257
+ properties: {
258
+ changeRequests: { type: 'array', items: changeRequestSchema },
259
+ ...pagingOutputs,
260
+ },
261
+ required: ['changeRequests', ...pagingRequired],
262
+ },
263
+ handler: async (args, ctx) => {
264
+ const state = args.state === 'closed' || args.state === 'all' ? args.state : 'open';
265
+ const head = typeof args.head === 'string' ? args.head : undefined;
266
+ const base = typeof args.base === 'string' ? args.base : undefined;
267
+ const author = typeof args.author === 'string' ? args.author : undefined;
268
+ const { perPage, page } = pagingOf(args);
269
+ // The one clone every answer here is read in, resolved ONCE and handed
270
+ // to the listing too: the summaries' file lists are built in it, and
271
+ // the by-number tools read the same request in the same clone, so the
272
+ // list cannot hide a request the detail would serve — or the reverse —
273
+ // for want of a workspace the other path fell back to.
274
+ const workspaceId = await repoGlobalWorkspaceId(ctx);
275
+ const all = await ctx.workflowService.listChangeRequestsByState(statesFor(state), { workspaceId });
276
+ const matching = all.filter((cr) => (head === undefined || cr.branch === head) &&
277
+ (base === undefined || cr.base === base) &&
278
+ (author === undefined || matchesAuthor(cr, author)));
279
+ // One access lookup per distinct target branch, not per request: the
280
+ // access tree is read at `origin/<base>`, and a list is usually a dozen
281
+ // requests into the same two or three targets.
282
+ //
283
+ // Over `touchedNodeFiles`, NOT `touchedNodePaths`. The flat list reports a
284
+ // move under its new name alone, so a file moved out of a folder this
285
+ // caller cannot open looked readable here while the detail — which pairs
286
+ // the two names — refused it: the list advertised a change request that
287
+ // all four by-number tools answered 404 for, and counted its withheld
288
+ // file as zero. One notion of a readable file, shared with the detail
289
+ // through the same `fileIsReadable`, is what stops the two disagreeing.
290
+ const byBase = new Map();
291
+ for (const cr of matching) {
292
+ const bucket = byBase.get(cr.base) ?? [];
293
+ bucket.push(...filesOf(cr).flatMap(pathsOf));
294
+ byBase.set(cr.base, bucket);
295
+ }
296
+ const readableByBase = new Map();
297
+ await Promise.all([...byBase].map(async ([baseRef, paths]) => {
298
+ readableByBase.set(baseRef, await readablePaths(ctx, workspaceId, baseRef, paths));
299
+ }));
300
+ const visible = [];
301
+ for (const cr of matching) {
302
+ const readable = readableByBase.get(cr.base) ?? new Set();
303
+ const mayRead = (path) => readable.has(path);
304
+ const files = filesOf(cr);
305
+ const readableCount = files.filter((f) => fileIsReadable(f, mayRead)).length;
306
+ const mine = isAuthor(cr, ctx.user.email);
307
+ if (!maySeeChangeRequest({ readableFiles: readableCount, isAuthor: mine }))
308
+ continue;
309
+ visible.push(toCrSummary(cr, {
310
+ readable: readableCount,
311
+ // One per withheld FILE, whatever its move names it.
312
+ withheld: files.length - readableCount,
313
+ }));
314
+ }
315
+ // Paged AFTER the filter, so a page's length says nothing about what was
316
+ // withheld — the counts do that.
317
+ const { items, ...paging } = pageOf(visible, perPage, page);
318
+ return { changeRequests: items, ...paging };
319
+ },
320
+ });
321
+ // ── get_change_request ────────────────────────────────────────────────────
322
+ mount({
323
+ name: 'get_change_request',
324
+ description: 'Read one change request by `number` (GitHub: get a pull request) — its `url`, `title`, ' +
325
+ '`body` (what the author wrote, without the generated owners block Hexis appends), ' +
326
+ '`state`, `sourceBranch`, `targetBranch`, whether it is `mergeable`, the ' +
327
+ '`mergeBlockedReasons` holding it up, and a `viewer` block saying whether YOU may approve ' +
328
+ 'or apply it. The same field names `open_change_request` answers in. Read-only. Answers ' +
329
+ '404 both for a number that does not exist and for a request you may not see.',
330
+ inputs: {
331
+ type: 'object',
332
+ properties: { number: { type: 'integer', minimum: 1, description: 'Change request number.' } },
333
+ required: ['number'],
334
+ additionalProperties: false,
335
+ },
336
+ outputs: {
337
+ type: 'object',
338
+ properties: {
339
+ ...changeRequestSchema.properties,
340
+ body: { type: 'string', description: "What the AUTHOR wrote. The generated `## Affected owners` block Hexis appends — which names every changed path — is cut off the end; read who must approve each file from `list_change_request_files`." },
341
+ headSha: { type: 'string', description: 'The source commit this answer describes. Absent when no commit could be resolved.' },
342
+ baseSha: { type: 'string', description: 'The target commit it is read against. Absent when no commit could be resolved.' },
343
+ mergeable: { type: 'boolean', description: "Hexis's merge gate, which also waits on the per-file approvals. May be false while `mergeBlockedReasons` is empty, if a blocker names a file you may not read." },
344
+ mergeBlockedReasons: { type: 'array', items: { type: 'string' }, description: 'Why it cannot be applied yet, in the gate\'s own words. Blockers naming a file you may not read are left out.' },
345
+ withheldMergeBlockedReasons: { type: 'integer', description: 'How many blockers were left out because they name a file you may not read.' },
346
+ viewer: {
347
+ type: 'object',
348
+ description: 'What YOU, specifically, may do with this request.',
349
+ properties: {
350
+ mayApprove: { type: 'boolean', description: 'Whether you may approve at least one of the files you are shown. False on any request that is not open: approvals are given while it is.' },
351
+ mayMerge: { type: 'boolean', description: 'Whether an Apply by you would be accepted right now.' },
352
+ isAuthor: { type: 'boolean', description: 'Whether you opened it (your agent counts as you).' },
353
+ },
354
+ required: ['mayApprove', 'mayMerge', 'isAuthor'],
355
+ },
356
+ },
357
+ required: [
358
+ ...changeRequestSchema.required,
359
+ 'body',
360
+ 'mergeable',
361
+ 'mergeBlockedReasons',
362
+ 'withheldMergeBlockedReasons',
363
+ 'viewer',
364
+ ],
365
+ },
366
+ handler: async (args, ctx) => {
367
+ const number = numberArg(args);
368
+ const scoped = await scopedDetail(ctx, number, { patches: false });
369
+ const { detail, readableFiles, withheldFilePaths, withheldFileCount, viewerIsAuthor } = scoped;
370
+ // Unwrapped, as `open_change_request` answers since #349: `url` is the
371
+ // first field of the answer itself, so a truncation cannot take it.
372
+ return toCrDetail(detail, { readable: readableFiles.length, withheld: withheldFileCount }, visibleBlockers(detail.mergeBlockedReasons, withheldFilePaths), toCrViewer(detail, viewerIsAuthor,
373
+ // `mayApprove` over the approvals of the SHOWN files alone: an
374
+ // approval keyed on a withheld file must not answer for it.
375
+ detail.approvals.filter((a) => scoped.mayShow(a.path))));
376
+ },
377
+ });
378
+ // ── list_change_request_files ─────────────────────────────────────────────
379
+ mount({
380
+ name: 'list_change_request_files',
381
+ description: "List a change request's changed files (GitHub: list pull request files). Each answers " +
382
+ '`path`, `change` (`added`, `changed`, `deleted` or `moved`, a moved one with its ' +
383
+ '`previousPath`), `additions` and `deletions` — the same words ' +
384
+ '`open_change_request` uses — plus who must approve it (`requiredApprovers`) and who has ' +
385
+ '(`approvedBy`). No patch is returned unless you ask with `include: ["patches"]`. ' +
386
+ 'Read-only. Files you may not read are left out and counted in `withheldFiles`, never named.',
387
+ inputs: {
388
+ type: 'object',
389
+ properties: {
390
+ number: { type: 'integer', minimum: 1, description: 'Change request number.' },
391
+ include: {
392
+ type: 'array',
393
+ items: { type: 'string', enum: ['patches'] },
394
+ description: 'Pass `["patches"]` to get each file\'s unified diff. Omit it and no patch is returned.',
395
+ },
396
+ ...pagingInputs,
397
+ },
398
+ required: ['number'],
399
+ additionalProperties: false,
400
+ },
401
+ outputs: {
402
+ type: 'object',
403
+ properties: {
404
+ files: {
405
+ type: 'array',
406
+ items: {
407
+ type: 'object',
408
+ properties: {
409
+ path: { type: 'string', description: 'Repository-relative path.' },
410
+ previousPath: { type: 'string', description: 'Where a `moved` file came from.' },
411
+ change: { type: 'string', enum: ['added', 'changed', 'deleted', 'moved'], description: 'What happened to it.' },
412
+ additions: { type: 'integer' },
413
+ deletions: { type: 'integer' },
414
+ patch: { type: 'string', description: 'Unified diff — only on `include: ["patches"]`, and never for a binary.' },
415
+ isBinary: { type: 'boolean' },
416
+ requiredApprovers: {
417
+ type: 'object',
418
+ description: 'Who must approve this file before the request can be applied.',
419
+ properties: {
420
+ roles: { type: 'array', items: { type: 'string' } },
421
+ users: { type: 'array', items: userSchema },
422
+ },
423
+ required: ['roles', 'users'],
424
+ },
425
+ approversUnknown: { type: 'boolean', description: 'Present when the approver set could not be resolved — then an empty `requiredApprovers` means UNKNOWN, not nobody.' },
426
+ approvedBy: {
427
+ type: 'array',
428
+ description: 'The approvals standing on this file.',
429
+ items: {
430
+ type: 'object',
431
+ properties: {
432
+ user: userSchema,
433
+ approvedAt: { type: 'string', description: 'ISO timestamp.' },
434
+ stale: { type: 'boolean', description: 'True when a later push invalidated it.' },
435
+ selfApproval: { type: 'boolean', description: "True when the approver is the request's author." },
436
+ },
437
+ required: ['user', 'approvedAt', 'stale', 'selfApproval'],
438
+ },
439
+ },
440
+ approved: { type: 'boolean', description: 'A current approval by an eligible approver stands.' },
441
+ inMergeGate: { type: 'boolean', description: 'Whether the gate waits on this file at all.' },
442
+ viewerMayApprove: { type: 'boolean', description: 'Whether YOU may approve it. False on any request that is not open: approvals are given while it is.' },
443
+ },
444
+ required: ['path', 'change', 'additions', 'deletions', 'isBinary', 'requiredApprovers', 'approvedBy', 'approved', 'inMergeGate', 'viewerMayApprove'],
445
+ },
446
+ },
447
+ withheldFiles: { type: 'integer', description: 'How many of its files you may not read. Never named.' },
448
+ ...pagingOutputs,
449
+ },
450
+ required: ['files', 'withheldFiles', ...pagingRequired],
451
+ },
452
+ handler: async (args, ctx) => {
453
+ const include = Array.isArray(args.include) ? args.include : [];
454
+ const patches = include.includes('patches');
455
+ const number = numberArg(args);
456
+ const { perPage, page } = pagingOf(args);
457
+ const scoped = await scopedDetail(ctx, number, { patches });
458
+ const approvals = approvalsByPath(scoped.detail);
459
+ const { items, ...paging } = pageOf(scoped.readableFiles, perPage, page);
460
+ return {
461
+ files: items.map((f) => toCrFile(f, approvals.get(f.path), { patches, open: scoped.detail.state === 'open' })),
462
+ withheldFiles: scoped.withheldFileCount,
463
+ ...paging,
464
+ };
465
+ },
466
+ });
467
+ // ── list_change_request_reviews ───────────────────────────────────────────
468
+ mount({
469
+ name: 'list_change_request_reviews',
470
+ description: "List a change request's reviews (GitHub: list reviews): who approved what, and when. " +
471
+ 'Hexis approves per FILE, so each entry names a `reviewer`, the `files` they approved and ' +
472
+ 'the time of the latest of them; `stale` is true for approvals a later push invalidated. ' +
473
+ 'Nothing records who DECLINED a request, so no entry reports one — a reviewer\'s objection ' +
474
+ 'is a comment. Read-only: an entry keeps only the files you may read, and one with no ' +
475
+ 'readable file at all is counted in `withheldReviews` rather than named.',
476
+ inputs: {
477
+ type: 'object',
478
+ properties: {
479
+ number: { type: 'integer', minimum: 1, description: 'Change request number.' },
480
+ ...pagingInputs,
481
+ },
482
+ required: ['number'],
483
+ additionalProperties: false,
484
+ },
485
+ outputs: {
486
+ type: 'object',
487
+ properties: {
488
+ reviews: {
489
+ type: 'array',
490
+ items: {
491
+ type: 'object',
492
+ properties: {
493
+ id: { type: 'string', description: 'Stable within the request: the reviewer, and whether their approvals still stand.' },
494
+ reviewer: userSchema,
495
+ stale: { type: 'boolean', description: 'True when a later push invalidated the approvals gathered here.' },
496
+ submittedAt: { type: 'string', description: 'ISO timestamp of the latest approval in this entry.' },
497
+ files: { type: 'array', items: { type: 'string' }, description: 'The files this reviewer approved.' },
498
+ withheldFiles: { type: 'integer', description: 'Further files of this review you may not read. Never named.' },
499
+ },
500
+ required: ['id', 'reviewer', 'stale', 'submittedAt', 'files', 'withheldFiles'],
501
+ },
502
+ },
503
+ withheldReviews: { type: 'integer', description: 'Reviews every file of which you may not read. Neither the reviewer nor the files are named.' },
504
+ ...pagingOutputs,
505
+ },
506
+ required: ['reviews', 'withheldReviews', ...pagingRequired],
507
+ },
508
+ handler: async (args, ctx) => {
509
+ const number = numberArg(args);
510
+ const { perPage, page } = pagingOf(args);
511
+ const scoped = await scopedDetail(ctx, number, { patches: false });
512
+ // The read predicate goes IN rather than a pre-filtered list: a review is
513
+ // grouped over every file the reviewer approved, so that it can count the
514
+ // withheld ones under its own id and drop itself when they are all it has.
515
+ // `mayShow` keeps a withheld move out of the files a review names.
516
+ const { reviews, withheldReviews } = toCrReviews(scoped.detail.approvals, scoped.mayShow);
517
+ const { items, ...paging } = pageOf(reviews, perPage, page);
518
+ return { reviews: items, withheldReviews, ...paging };
519
+ },
520
+ });
521
+ // ── list_change_request_comments ──────────────────────────────────────────
522
+ mount({
523
+ name: 'list_change_request_comments',
524
+ description: "List a change request's comments (GitHub: list review comments and issue comments — Hexis " +
525
+ 'keeps both in one thread). Each carries its `author`, `body`, `path` and `line` when it is ' +
526
+ 'anchored to a file, `parentId` when it is a reply (the same id you pass to ' +
527
+ '`post_change_request_comment` to reply yourself), and its times. Read-only. A comment on a ' +
528
+ 'file you may not read is left out and counted in `withheldComments`, and so is a reply to ' +
529
+ 'a comment that was left out.',
530
+ inputs: {
531
+ type: 'object',
532
+ properties: {
533
+ number: { type: 'integer', minimum: 1, description: 'Change request number.' },
534
+ ...pagingInputs,
535
+ },
536
+ required: ['number'],
537
+ additionalProperties: false,
538
+ },
539
+ outputs: {
540
+ type: 'object',
541
+ properties: {
542
+ comments: {
543
+ type: 'array',
544
+ items: {
545
+ type: 'object',
546
+ properties: {
547
+ id: { type: 'string', description: 'Pass as `parentId` to `post_change_request_comment` to reply.' },
548
+ author: userSchema,
549
+ body: { type: 'string' },
550
+ path: { type: 'string', description: 'Repository-relative path, on a file-level or inline comment.' },
551
+ line: { type: 'integer', description: 'Set on an inline comment.' },
552
+ parentId: { type: 'string', description: 'The comment this one replies to.' },
553
+ headSha: { type: 'string', description: 'The commit the comment was anchored to.' },
554
+ createdAt: { type: 'string', description: 'ISO timestamp.' },
555
+ updatedAt: { type: 'string', description: 'ISO timestamp; present once edited.' },
556
+ },
557
+ required: ['id', 'author', 'body', 'headSha', 'createdAt'],
558
+ },
559
+ },
560
+ withheldComments: { type: 'integer', description: 'Comments on a file you may not read, and replies to those.' },
561
+ ...pagingOutputs,
562
+ },
563
+ required: ['comments', 'withheldComments', ...pagingRequired],
564
+ },
565
+ handler: async (args, ctx) => {
566
+ const number = numberArg(args);
567
+ const { perPage, page } = pagingOf(args);
568
+ const scoped = await scopedDetail(ctx, number, { patches: false });
569
+ // A comment with no path is about the request as a whole; one with a path
570
+ // is as readable as that path is NAMEABLE here. A reply inherits its
571
+ // parent's verdict up the chain — see `visibleComments`.
572
+ const { visible, withheld } = visibleComments(scoped.detail.comments, scoped.mayShow);
573
+ const { items, ...paging } = pageOf(visible, perPage, page);
574
+ return {
575
+ comments: items.map(toCrComment),
576
+ withheldComments: withheld,
577
+ ...paging,
578
+ };
579
+ },
580
+ });
581
+ }
582
+ //# sourceMappingURL=change-request-read.tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"change-request-read.tools.js","sourceRoot":"","sources":["../../../../src/modules/workflow/agent-tools/change-request-read.tools.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { ChangeRequestDetail, ChangeRequestState } from '@bevel-software/platform-shared';
1
+ import type { ChangeRequestDetail, ChangeRequestState, PrFileStatus } from '@bevel-software/platform-shared';
2
2
  /**
3
3
  * What `open_change_request` answers, and why it is not the detail the app's
4
4
  * dialog reads.
@@ -83,6 +83,17 @@ export interface ChangeRequestSummary {
83
83
  /** How many files the request changes in total, cut or not. */
84
84
  totalFiles: number;
85
85
  }
86
+ /**
87
+ * A copy and a rename both carry `previousPath`, and the one thing a reader
88
+ * does with either is look at where the text came from — so both read `moved`.
89
+ * `unchanged` is a file the request lists without changing (git reports it on
90
+ * a mode-only change); `changed` is the honest word for it among these four.
91
+ *
92
+ * Exported because `list_change_request_files` answers `change` under this same
93
+ * name: an agent that opens a request and reads its files back must not be told
94
+ * `moved` by one tool and `renamed` by the other.
95
+ */
96
+ export declare function changeKindOf(status: PrFileStatus | undefined): ChangeKind;
86
97
  /**
87
98
  * Shape the tool's answer out of the detail the service already returns. Pure:
88
99
  * the service and the app's routes are untouched, and the detail they serve is