@wardby/cli 0.2.1 → 0.4.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 (555) hide show
  1. package/.env.example +53 -4
  2. package/README.md +52 -13
  3. package/dist/claude-coding-worker/driver.d.ts +6 -1
  4. package/dist/claude-coding-worker/driver.js +27 -1
  5. package/dist/claude-coding-worker/main.js +2 -0
  6. package/dist/claude-coding-worker/tool-socket.d.ts +9 -0
  7. package/dist/claude-coding-worker/tool-socket.js +26 -0
  8. package/dist/cli-help.d.ts +1 -1
  9. package/dist/cli-help.js +14 -4
  10. package/dist/cli.d.ts +1 -1
  11. package/dist/cli.js +284 -36
  12. package/dist/coding/base-commit.d.ts +6 -0
  13. package/dist/coding/base-commit.js +12 -0
  14. package/dist/coding/collect-exclude.d.ts +25 -0
  15. package/dist/coding/collect-exclude.js +76 -0
  16. package/dist/coding/profile.d.ts +67 -22
  17. package/dist/coding/profile.js +58 -25
  18. package/dist/coding/protected-path-wording.d.ts +24 -0
  19. package/dist/coding/protected-path-wording.js +55 -0
  20. package/dist/coding/protected-paths.d.ts +31 -0
  21. package/dist/coding/protected-paths.js +48 -0
  22. package/dist/coding/protocol.d.ts +91 -4
  23. package/dist/coding/protocol.js +123 -12
  24. package/dist/coding/provider.d.ts +6 -1
  25. package/dist/coding/provider.js +16 -9
  26. package/dist/coding/registry/adapters.d.ts +2 -0
  27. package/dist/coding/registry/adapters.js +9 -0
  28. package/dist/coding/registry/allowlist.d.ts +9 -0
  29. package/dist/coding/registry/allowlist.js +28 -0
  30. package/dist/coding/registry/json-scan.d.ts +55 -0
  31. package/dist/coding/registry/json-scan.js +191 -0
  32. package/dist/coding/registry/lockfiles.d.ts +6 -0
  33. package/dist/coding/registry/lockfiles.js +89 -0
  34. package/dist/coding/registry/npm-lockfile.d.ts +9 -0
  35. package/dist/coding/registry/npm-lockfile.js +73 -0
  36. package/dist/coding/registry/npm-plan.d.ts +29 -0
  37. package/dist/coding/registry/npm-plan.js +289 -0
  38. package/dist/coding/registry/npm.d.ts +7 -0
  39. package/dist/coding/registry/npm.js +252 -0
  40. package/dist/coding/registry/pypi.d.ts +4 -0
  41. package/dist/coding/registry/pypi.js +210 -0
  42. package/dist/coding/registry/report.d.ts +37 -0
  43. package/dist/coding/registry/report.js +31 -0
  44. package/dist/coding/registry/token.d.ts +4 -0
  45. package/dist/coding/registry/token.js +7 -0
  46. package/dist/coding/registry/types.d.ts +286 -0
  47. package/dist/coding/registry/types.js +19 -0
  48. package/dist/coding/registry/worker-config.d.ts +14 -0
  49. package/dist/coding/registry/worker-config.js +31 -0
  50. package/dist/coding/services/builtins.d.ts +22 -0
  51. package/dist/coding/services/builtins.js +85 -0
  52. package/dist/coding/services/catalog.d.ts +443 -0
  53. package/dist/coding/services/catalog.js +159 -0
  54. package/dist/coding/services/declaration.d.ts +11 -0
  55. package/dist/coding/services/declaration.js +114 -0
  56. package/dist/coding/services/note.d.ts +8 -0
  57. package/dist/coding/services/note.js +15 -0
  58. package/dist/coding/services/resolve.d.ts +25 -0
  59. package/dist/coding/services/resolve.js +50 -0
  60. package/dist/coding/services/wording.d.ts +25 -0
  61. package/dist/coding/services/wording.js +70 -0
  62. package/dist/coding-proxy/main.js +24 -4
  63. package/dist/coding-worker/artifact.d.ts +6 -0
  64. package/dist/coding-worker/debug-trace.d.ts +37 -0
  65. package/dist/coding-worker/debug-trace.js +117 -0
  66. package/dist/coding-worker/driver.d.ts +13 -1
  67. package/dist/coding-worker/driver.js +102 -13
  68. package/dist/coding-worker/errors.js +8 -0
  69. package/dist/coding-worker/main.js +10 -2
  70. package/dist/coding-worker/sdk.d.ts +2 -2
  71. package/dist/coding-worker/sdk.js +7 -2
  72. package/dist/coding-worker/types.d.ts +3 -0
  73. package/dist/config/providers.d.ts +66 -0
  74. package/dist/config/providers.js +137 -0
  75. package/dist/core/attribution.d.ts +101 -0
  76. package/dist/core/attribution.js +208 -0
  77. package/dist/core/budget-groups.d.ts +120 -10
  78. package/dist/core/budget-groups.js +133 -24
  79. package/dist/core/budget-wording.d.ts +22 -0
  80. package/dist/core/budget-wording.js +55 -0
  81. package/dist/core/coding-queue.d.ts +3 -0
  82. package/dist/core/coding-queue.js +6 -2
  83. package/dist/core/coding-service-status.d.ts +11 -0
  84. package/dist/core/coding-service-status.js +17 -0
  85. package/dist/core/cost-report.d.ts +88 -0
  86. package/dist/core/cost-report.js +248 -0
  87. package/dist/core/datastores.js +18 -2
  88. package/dist/core/db.d.ts +5 -1
  89. package/dist/core/db.js +8 -2
  90. package/dist/core/dispatch.d.ts +74 -7
  91. package/dist/core/dispatch.js +382 -47
  92. package/dist/core/engine-native.js +44 -14
  93. package/dist/core/glob.d.ts +10 -0
  94. package/dist/core/glob.js +33 -0
  95. package/dist/core/grants.d.ts +86 -0
  96. package/dist/core/grants.js +126 -0
  97. package/dist/core/host-events.d.ts +72 -0
  98. package/dist/core/host-events.js +597 -0
  99. package/dist/core/host-identity-links.d.ts +54 -0
  100. package/dist/core/host-identity-links.js +189 -0
  101. package/dist/core/host-status.d.ts +78 -0
  102. package/dist/core/host-status.js +228 -0
  103. package/dist/core/in-flight-runs.d.ts +8 -0
  104. package/dist/core/in-flight-runs.js +56 -0
  105. package/dist/core/issue-bridge.d.ts +60 -0
  106. package/dist/core/issue-bridge.js +189 -0
  107. package/dist/core/issue-dedupe.d.ts +70 -0
  108. package/dist/core/issue-dedupe.js +255 -0
  109. package/dist/core/issue-events.d.ts +42 -0
  110. package/dist/core/issue-events.js +155 -0
  111. package/dist/core/issue-status.d.ts +29 -0
  112. package/dist/core/issue-status.js +241 -0
  113. package/dist/core/issue-tracker-tools.d.ts +64 -0
  114. package/dist/core/issue-tracker-tools.js +850 -0
  115. package/dist/core/model-usage.d.ts +10 -0
  116. package/dist/core/model-usage.js +24 -0
  117. package/dist/core/provider-wording.d.ts +12 -0
  118. package/dist/core/provider-wording.js +44 -0
  119. package/dist/core/reconciler.d.ts +42 -2
  120. package/dist/core/reconciler.js +97 -2
  121. package/dist/core/repo-access.d.ts +99 -0
  122. package/dist/core/repo-access.js +136 -0
  123. package/dist/core/review-host-checks.d.ts +11 -0
  124. package/dist/core/review-host-checks.js +41 -0
  125. package/dist/core/review-host-tools.d.ts +47 -0
  126. package/dist/core/review-host-tools.js +354 -0
  127. package/dist/core/run-heartbeat.d.ts +27 -0
  128. package/dist/core/run-heartbeat.js +54 -0
  129. package/dist/core/run-pricing.d.ts +61 -0
  130. package/dist/core/run-pricing.js +56 -0
  131. package/dist/core/runner.d.ts +33 -8
  132. package/dist/core/runner.js +410 -62
  133. package/dist/core/scheduler.d.ts +4 -1
  134. package/dist/core/scheduler.js +3 -2
  135. package/dist/core/secrets.d.ts +11 -2
  136. package/dist/core/secrets.js +25 -6
  137. package/dist/core/self-defects.d.ts +80 -0
  138. package/dist/core/self-defects.js +180 -0
  139. package/dist/core/subagent-memory-tools.d.ts +1 -1
  140. package/dist/core/subagent-memory-tools.js +16 -3
  141. package/dist/core/tool-admin.d.ts +81 -0
  142. package/dist/core/tool-admin.js +129 -0
  143. package/dist/core/tool-names.d.ts +42 -0
  144. package/dist/core/tool-names.js +67 -0
  145. package/dist/core/untrusted-content.d.ts +32 -0
  146. package/dist/core/untrusted-content.js +72 -0
  147. package/dist/core/webhooks.d.ts +17 -2
  148. package/dist/core/webhooks.js +42 -3
  149. package/dist/generated/prisma/browser.d.ts +166 -0
  150. package/dist/generated/prisma/client.d.ts +166 -0
  151. package/dist/generated/prisma/commonInputTypes.d.ts +152 -52
  152. package/dist/generated/prisma/enums.d.ts +13 -0
  153. package/dist/generated/prisma/enums.js +12 -1
  154. package/dist/generated/prisma/internal/class.d.ts +242 -0
  155. package/dist/generated/prisma/internal/class.js +4 -4
  156. package/dist/generated/prisma/internal/prismaNamespace.d.ts +2571 -577
  157. package/dist/generated/prisma/internal/prismaNamespace.js +312 -6
  158. package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +328 -0
  159. package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +312 -6
  160. package/dist/generated/prisma/models/Agent.d.ts +682 -1
  161. package/dist/generated/prisma/models/AgentIssueProject.d.ts +1838 -0
  162. package/dist/generated/prisma/models/AgentIssueProject.js +1 -0
  163. package/dist/generated/prisma/models/AgentRepository.d.ts +1425 -0
  164. package/dist/generated/prisma/models/AgentRepository.js +1 -0
  165. package/dist/generated/prisma/models/AgentTool.d.ts +95 -1
  166. package/dist/generated/prisma/models/AuthUser.d.ts +56 -1
  167. package/dist/generated/prisma/models/CodingAgentProfile.d.ts +258 -7
  168. package/dist/generated/prisma/models/CodingProxySession.d.ts +195 -2
  169. package/dist/generated/prisma/models/CodingRun.d.ts +1405 -95
  170. package/dist/generated/prisma/models/CodingRunServiceStatus.d.ts +1404 -0
  171. package/dist/generated/prisma/models/CodingRunServiceStatus.js +1 -0
  172. package/dist/generated/prisma/models/CodingService.d.ts +1348 -0
  173. package/dist/generated/prisma/models/CodingService.js +1 -0
  174. package/dist/generated/prisma/models/HostEventDelivery.d.ts +946 -0
  175. package/dist/generated/prisma/models/HostEventDelivery.js +1 -0
  176. package/dist/generated/prisma/models/HostIdentity.d.ts +1232 -0
  177. package/dist/generated/prisma/models/HostIdentity.js +1 -0
  178. package/dist/generated/prisma/models/HostIdentityLinkRequest.d.ts +1473 -0
  179. package/dist/generated/prisma/models/HostIdentityLinkRequest.js +1 -0
  180. package/dist/generated/prisma/models/IssueFingerprint.d.ts +1183 -0
  181. package/dist/generated/prisma/models/IssueFingerprint.js +1 -0
  182. package/dist/generated/prisma/models/IssuePullRequest.d.ts +1255 -0
  183. package/dist/generated/prisma/models/IssuePullRequest.js +1 -0
  184. package/dist/generated/prisma/models/ModelCatalogEntry.d.ts +1322 -0
  185. package/dist/generated/prisma/models/ModelCatalogEntry.js +1 -0
  186. package/dist/generated/prisma/models/Principal.d.ts +455 -0
  187. package/dist/generated/prisma/models/RegistryAllowance.d.ts +1148 -0
  188. package/dist/generated/prisma/models/RegistryAllowance.js +1 -0
  189. package/dist/generated/prisma/models/RegistryApprovedVersion.d.ts +1219 -0
  190. package/dist/generated/prisma/models/RegistryApprovedVersion.js +1 -0
  191. package/dist/generated/prisma/models/RegistryFetch.d.ts +1428 -0
  192. package/dist/generated/prisma/models/RegistryFetch.js +1 -0
  193. package/dist/generated/prisma/models/RegistryPlanRefusal.d.ts +1294 -0
  194. package/dist/generated/prisma/models/RegistryPlanRefusal.js +1 -0
  195. package/dist/generated/prisma/models/RegistryVersionFact.d.ts +1085 -0
  196. package/dist/generated/prisma/models/RegistryVersionFact.js +1 -0
  197. package/dist/generated/prisma/models/ResourceGrant.d.ts +1437 -0
  198. package/dist/generated/prisma/models/ResourceGrant.js +1 -0
  199. package/dist/generated/prisma/models/Run.d.ts +1402 -82
  200. package/dist/generated/prisma/models/RunAttribution.d.ts +1259 -0
  201. package/dist/generated/prisma/models/RunAttribution.js +1 -0
  202. package/dist/generated/prisma/models/RunHostCheck.d.ts +1239 -0
  203. package/dist/generated/prisma/models/RunHostCheck.js +1 -0
  204. package/dist/generated/prisma/models/RunHostStatus.d.ts +1315 -0
  205. package/dist/generated/prisma/models/RunHostStatus.js +1 -0
  206. package/dist/generated/prisma/models/RunIssueStatus.d.ts +1199 -0
  207. package/dist/generated/prisma/models/RunIssueStatus.js +1 -0
  208. package/dist/generated/prisma/models/RunModelUsage.d.ts +1316 -0
  209. package/dist/generated/prisma/models/RunModelUsage.js +1 -0
  210. package/dist/generated/prisma/models/Tool.d.ts +15 -3
  211. package/dist/generated/prisma/models/WorkItem.d.ts +1408 -0
  212. package/dist/generated/prisma/models/WorkItem.js +1 -0
  213. package/dist/generated/prisma/models.d.ts +22 -0
  214. package/dist/help/build.d.ts +1 -0
  215. package/dist/help/build.js +9 -0
  216. package/dist/help/catalog.d.ts +24 -0
  217. package/dist/help/catalog.js +160 -0
  218. package/dist/help/cli.d.ts +2 -0
  219. package/dist/help/cli.js +65 -0
  220. package/dist/help/runtime.d.ts +3 -0
  221. package/dist/help/runtime.js +44 -0
  222. package/dist/help/search.d.ts +9 -0
  223. package/dist/help/search.js +104 -0
  224. package/dist/help-index.json +999 -0
  225. package/dist/import/cli-args.js +3 -2
  226. package/dist/import/create.d.ts +5 -0
  227. package/dist/import/create.js +67 -13
  228. package/dist/import/index.js +19 -9
  229. package/dist/import/neutral-schema.d.ts +18 -18
  230. package/dist/knowledge/check.d.ts +13 -0
  231. package/dist/knowledge/check.js +69 -0
  232. package/dist/knowledge/cli.d.ts +14 -0
  233. package/dist/knowledge/cli.js +67 -0
  234. package/dist/knowledge/concept.d.ts +54 -0
  235. package/dist/knowledge/concept.js +78 -0
  236. package/dist/knowledge/note.d.ts +11 -0
  237. package/dist/knowledge/note.js +39 -0
  238. package/dist/knowledge/relevance.d.ts +11 -0
  239. package/dist/knowledge/relevance.js +14 -0
  240. package/dist/knowledge/span-hash.d.ts +3 -0
  241. package/dist/knowledge/span-hash.js +16 -0
  242. package/dist/mcp/auth/access.d.ts +72 -0
  243. package/dist/mcp/auth/access.js +58 -0
  244. package/dist/mcp/auth/grants-cli.d.ts +149 -0
  245. package/dist/mcp/auth/grants-cli.js +518 -0
  246. package/dist/mcp/auth/host-account-cli.d.ts +2 -0
  247. package/dist/mcp/auth/host-account-cli.js +47 -0
  248. package/dist/mcp/auth/ownership.d.ts +25 -51
  249. package/dist/mcp/auth/ownership.js +19 -14
  250. package/dist/mcp/auth/repo-authorization.d.ts +22 -0
  251. package/dist/mcp/auth/repo-authorization.js +51 -0
  252. package/dist/mcp/auth/resource-server.d.ts +33 -2
  253. package/dist/mcp/auth/resource-server.js +99 -3
  254. package/dist/mcp/auth/self-hosted/browser.js +2 -2
  255. package/dist/mcp/auth/self-hosted/cli.js +47 -13
  256. package/dist/mcp/auth/self-hosted/credentials.d.ts +23 -5
  257. package/dist/mcp/auth/self-hosted/credentials.js +62 -4
  258. package/dist/mcp/auth/self-hosted/session.d.ts +7 -6
  259. package/dist/mcp/context.d.ts +30 -1
  260. package/dist/mcp/errors.d.ts +25 -6
  261. package/dist/mcp/errors.js +98 -0
  262. package/dist/mcp/host-events/deliveries.d.ts +9 -0
  263. package/dist/mcp/host-events/deliveries.js +17 -0
  264. package/dist/mcp/host-events/github-ingress.d.ts +38 -0
  265. package/dist/mcp/host-events/github-ingress.js +83 -0
  266. package/dist/mcp/host-events/github-user-callback.d.ts +18 -0
  267. package/dist/mcp/host-events/github-user-callback.js +50 -0
  268. package/dist/mcp/host-events/jira-ingress.d.ts +29 -0
  269. package/dist/mcp/host-events/jira-ingress.js +92 -0
  270. package/dist/mcp/index.d.ts +10 -1
  271. package/dist/mcp/index.js +187 -19
  272. package/dist/mcp/server.js +32 -11
  273. package/dist/mcp/tools/agents.js +519 -50
  274. package/dist/mcp/tools/budget-groups.js +3 -3
  275. package/dist/mcp/tools/cost-report.d.ts +8 -0
  276. package/dist/mcp/tools/cost-report.js +60 -0
  277. package/dist/mcp/tools/datastore.js +22 -15
  278. package/dist/mcp/tools/grants.d.ts +2 -0
  279. package/dist/mcp/tools/grants.js +239 -0
  280. package/dist/mcp/tools/help.d.ts +5 -0
  281. package/dist/mcp/tools/help.js +67 -0
  282. package/dist/mcp/tools/host-accounts.d.ts +2 -0
  283. package/dist/mcp/tools/host-accounts.js +114 -0
  284. package/dist/mcp/tools/issue-projects.d.ts +2 -0
  285. package/dist/mcp/tools/issue-projects.js +238 -0
  286. package/dist/mcp/tools/memory.d.ts +7 -1
  287. package/dist/mcp/tools/memory.js +5 -5
  288. package/dist/mcp/tools/model-catalog.d.ts +22 -0
  289. package/dist/mcp/tools/model-catalog.js +423 -0
  290. package/dist/mcp/tools/repositories.d.ts +2 -0
  291. package/dist/mcp/tools/repositories.js +182 -0
  292. package/dist/mcp/tools/runs.d.ts +6 -0
  293. package/dist/mcp/tools/runs.js +60 -6
  294. package/dist/mcp/tools/scheduling.js +3 -6
  295. package/dist/mcp/tools/secrets.js +18 -6
  296. package/dist/mcp/tools/services.d.ts +2 -0
  297. package/dist/mcp/tools/services.js +222 -0
  298. package/dist/mcp/tools/subagents.js +52 -16
  299. package/dist/mcp/tools/tools.d.ts +41 -0
  300. package/dist/mcp/tools/tools.js +201 -40
  301. package/dist/mcp/tools/trigger.js +65 -7
  302. package/dist/mcp/tools/webhooks.js +15 -4
  303. package/dist/mcp/transport/streamable-http.d.ts +15 -0
  304. package/dist/mcp/transport/streamable-http.js +55 -3
  305. package/dist/mcp/webhooks/ingress.d.ts +2 -1
  306. package/dist/mcp/webhooks/ingress.js +9 -2
  307. package/dist/providers/auth/delegating.d.ts +19 -0
  308. package/dist/providers/auth/delegating.js +71 -0
  309. package/dist/providers/auth/index.d.ts +2 -0
  310. package/dist/providers/auth/index.js +11 -0
  311. package/dist/providers/auth/self-hosted.d.ts +10 -2
  312. package/dist/providers/auth/self-hosted.js +55 -6
  313. package/dist/providers/auth/types.d.ts +6 -0
  314. package/dist/providers/coding-proxy/memory-ledger.d.ts +4 -1
  315. package/dist/providers/coding-proxy/memory-ledger.js +31 -3
  316. package/dist/providers/coding-proxy/metering.d.ts +6 -1
  317. package/dist/providers/coding-proxy/metering.js +41 -4
  318. package/dist/providers/coding-proxy/prisma-ledger.d.ts +17 -0
  319. package/dist/providers/coding-proxy/prisma-ledger.js +106 -8
  320. package/dist/providers/coding-proxy/proxy.d.ts +25 -2
  321. package/dist/providers/coding-proxy/proxy.js +561 -38
  322. package/dist/providers/coding-proxy/registry/audit.d.ts +131 -0
  323. package/dist/providers/coding-proxy/registry/audit.js +380 -0
  324. package/dist/providers/coding-proxy/registry/bounded-fetch.d.ts +16 -0
  325. package/dist/providers/coding-proxy/registry/bounded-fetch.js +77 -0
  326. package/dist/providers/coding-proxy/registry/plan.d.ts +58 -0
  327. package/dist/providers/coding-proxy/registry/plan.js +304 -0
  328. package/dist/providers/coding-proxy/registry/prisma-store.d.ts +34 -0
  329. package/dist/providers/coding-proxy/registry/prisma-store.js +151 -0
  330. package/dist/providers/coding-proxy/registry/service.d.ts +213 -0
  331. package/dist/providers/coding-proxy/registry/service.js +1137 -0
  332. package/dist/providers/coding-proxy/registry/store.d.ts +127 -0
  333. package/dist/providers/coding-proxy/registry/store.js +70 -0
  334. package/dist/providers/coding-proxy/runtime.d.ts +17 -0
  335. package/dist/providers/coding-proxy/runtime.js +63 -0
  336. package/dist/providers/coding-proxy/secure-fetch.js +0 -1
  337. package/dist/providers/coding-proxy/server.d.ts +11 -0
  338. package/dist/providers/coding-proxy/server.js +163 -0
  339. package/dist/providers/coding-proxy/types.d.ts +33 -1
  340. package/dist/providers/coding-proxy/types.js +12 -1
  341. package/dist/providers/engine/types.d.ts +29 -0
  342. package/dist/providers/executor/build.d.ts +2 -2
  343. package/dist/providers/executor/composition.d.ts +3 -0
  344. package/dist/providers/executor/composition.js +28 -1
  345. package/dist/providers/executor/container.d.ts +134 -4
  346. package/dist/providers/executor/container.js +394 -37
  347. package/dist/providers/executor/dbos.d.ts +4 -3
  348. package/dist/providers/executor/dbos.js +7 -5
  349. package/dist/providers/executor/in-process.d.ts +2 -3
  350. package/dist/providers/executor/routing.d.ts +13 -0
  351. package/dist/providers/executor/routing.js +18 -0
  352. package/dist/providers/executor/types.d.ts +34 -0
  353. package/dist/providers/issue-tracker/adf.d.ts +31 -0
  354. package/dist/providers/issue-tracker/adf.js +181 -0
  355. package/dist/providers/issue-tracker/index.d.ts +5 -0
  356. package/dist/providers/issue-tracker/index.js +12 -0
  357. package/dist/providers/issue-tracker/jira-client.d.ts +41 -0
  358. package/dist/providers/issue-tracker/jira-client.js +151 -0
  359. package/dist/providers/issue-tracker/jira-events.d.ts +3 -0
  360. package/dist/providers/issue-tracker/jira-events.js +98 -0
  361. package/dist/providers/issue-tracker/jira.d.ts +116 -0
  362. package/dist/providers/issue-tracker/jira.js +502 -0
  363. package/dist/providers/issue-tracker/types.d.ts +269 -0
  364. package/dist/providers/issue-tracker/types.js +16 -0
  365. package/dist/providers/jobs/claude-tool-setup.d.ts +23 -0
  366. package/dist/providers/jobs/claude-tool-setup.js +50 -0
  367. package/dist/providers/jobs/collect-prune.d.ts +7 -0
  368. package/dist/providers/jobs/collect-prune.js +27 -0
  369. package/dist/providers/jobs/docker-isolation.d.ts +48 -3
  370. package/dist/providers/jobs/docker-isolation.js +213 -22
  371. package/dist/providers/jobs/docker-services.d.ts +35 -0
  372. package/dist/providers/jobs/docker-services.js +191 -0
  373. package/dist/providers/jobs/docker.d.ts +53 -2
  374. package/dist/providers/jobs/docker.js +307 -32
  375. package/dist/providers/jobs/fake-kubernetes-api.d.ts +1 -0
  376. package/dist/providers/jobs/fake-kubernetes-api.js +12 -3
  377. package/dist/providers/jobs/kubernetes-isolation.d.ts +17 -2
  378. package/dist/providers/jobs/kubernetes-isolation.js +238 -57
  379. package/dist/providers/jobs/kubernetes-platform.d.ts +10 -4
  380. package/dist/providers/jobs/kubernetes-platform.js +11 -5
  381. package/dist/providers/jobs/kubernetes-preflight.js +3 -0
  382. package/dist/providers/jobs/kubernetes.d.ts +24 -2
  383. package/dist/providers/jobs/kubernetes.js +153 -22
  384. package/dist/providers/jobs/service-state.d.ts +22 -0
  385. package/dist/providers/jobs/service-state.js +17 -0
  386. package/dist/providers/jobs/types.d.ts +18 -0
  387. package/dist/providers/llm/anthropic.d.ts +3 -3
  388. package/dist/providers/llm/anthropic.js +3 -5
  389. package/dist/providers/llm/bedrock.d.ts +3 -3
  390. package/dist/providers/llm/bedrock.js +3 -8
  391. package/dist/providers/llm/catalog-lookup.d.ts +10 -0
  392. package/dist/providers/llm/catalog-lookup.js +15 -0
  393. package/dist/providers/llm/catalog-shipped.d.ts +18 -0
  394. package/dist/providers/llm/catalog-shipped.js +197 -0
  395. package/dist/providers/llm/catalog-store.d.ts +58 -0
  396. package/dist/providers/llm/catalog-store.js +138 -0
  397. package/dist/providers/llm/catalog-types.d.ts +66 -0
  398. package/dist/providers/llm/catalog-types.js +64 -0
  399. package/dist/providers/llm/catalog.d.ts +61 -0
  400. package/dist/providers/llm/catalog.js +147 -0
  401. package/dist/providers/llm/claude-messages.d.ts +5 -1
  402. package/dist/providers/llm/claude-messages.js +1 -0
  403. package/dist/providers/llm/claude-provider.d.ts +10 -12
  404. package/dist/providers/llm/claude-provider.js +15 -6
  405. package/dist/providers/llm/index.d.ts +9 -6
  406. package/dist/providers/llm/index.js +8 -5
  407. package/dist/providers/llm/openai.d.ts +14 -5
  408. package/dist/providers/llm/openai.js +24 -14
  409. package/dist/providers/llm/pricing-core.d.ts +5 -3
  410. package/dist/providers/llm/registration.js +8 -12
  411. package/dist/providers/llm/routing.d.ts +21 -11
  412. package/dist/providers/llm/routing.js +47 -13
  413. package/dist/providers/llm/types.d.ts +12 -0
  414. package/dist/providers/llm/types.js +8 -1
  415. package/dist/providers/review-host/diff-lines.d.ts +16 -0
  416. package/dist/providers/review-host/diff-lines.js +59 -0
  417. package/dist/providers/review-host/github-events.d.ts +6 -0
  418. package/dist/providers/review-host/github-events.js +226 -0
  419. package/dist/providers/review-host/github-user-auth.d.ts +38 -0
  420. package/dist/providers/review-host/github-user-auth.js +128 -0
  421. package/dist/providers/review-host/github.d.ts +57 -0
  422. package/dist/providers/review-host/github.js +568 -0
  423. package/dist/providers/review-host/index.d.ts +12 -0
  424. package/dist/providers/review-host/index.js +30 -0
  425. package/dist/providers/review-host/review-format.d.ts +19 -0
  426. package/dist/providers/review-host/review-format.js +59 -0
  427. package/dist/providers/review-host/types.d.ts +309 -0
  428. package/dist/providers/review-host/types.js +24 -0
  429. package/dist/providers/vcs/git.d.ts +16 -6
  430. package/dist/providers/vcs/git.js +78 -34
  431. package/dist/providers/vcs/github.d.ts +94 -3
  432. package/dist/providers/vcs/github.js +223 -17
  433. package/dist/providers/vcs/types.d.ts +48 -4
  434. package/dist/quickstart/index.d.ts +2 -0
  435. package/dist/quickstart/index.js +36 -8
  436. package/dist/sandbox/fetch-policy.d.ts +20 -2
  437. package/dist/sandbox/fetch-policy.js +64 -3
  438. package/dist/sandbox/host-functions.d.ts +9 -1
  439. package/dist/sandbox/host-functions.js +12 -5
  440. package/dist/serve.js +8 -2
  441. package/dist/viewer/api-schema.d.ts +2757 -0
  442. package/dist/viewer/api-schema.js +165 -0
  443. package/dist/viewer/build-schemas.d.ts +2 -0
  444. package/dist/viewer/build-schemas.js +18 -0
  445. package/dist/viewer/event-bus.d.ts +38 -0
  446. package/dist/viewer/event-bus.js +232 -0
  447. package/dist/viewer/graph.d.ts +40 -0
  448. package/dist/viewer/graph.js +243 -0
  449. package/dist/viewer/http.d.ts +30 -0
  450. package/dist/viewer/http.js +133 -0
  451. package/dist/viewer/run-detail.d.ts +4 -0
  452. package/dist/viewer/run-detail.js +61 -0
  453. package/dist/wardby-bin.js +11 -0
  454. package/docs/README.md +40 -0
  455. package/docs/agent-recipes.md +383 -0
  456. package/docs/architecture-runtime.md +90 -0
  457. package/docs/assets/brand/wardby-icon-512.png +0 -0
  458. package/docs/assets/brand/wardby-icon.svg +16 -0
  459. package/docs/assets/brand/wardby-mascot-profile-512.png +0 -0
  460. package/docs/assets/brand/wardby-mascot.png +0 -0
  461. package/docs/assets/brand/wardby-mascot.svg +5 -0
  462. package/docs/assets/wardby-workflow.svg +106 -0
  463. package/docs/code-review-agents.md +508 -0
  464. package/docs/coding-agent-setup.md +175 -0
  465. package/docs/coding-packages.md +455 -0
  466. package/docs/coding-services.md +300 -0
  467. package/docs/coding-worker-byo-images.md +98 -0
  468. package/docs/coding-worker-isolation.md +1068 -0
  469. package/docs/getting-started-gke.md +632 -0
  470. package/docs/getting-started-identity-provider.md +319 -0
  471. package/docs/getting-started.md +147 -0
  472. package/docs/jira-agents.md +649 -0
  473. package/docs/knowledge.md +387 -0
  474. package/docs/models.md +221 -0
  475. package/docs/observability.md +53 -0
  476. package/docs/release-verification.md +66 -0
  477. package/docs/security-deployment.md +667 -0
  478. package/docs/viewer-api.md +142 -0
  479. package/help/admin-viewer.md +39 -0
  480. package/help/agent-recipes.md +173 -0
  481. package/help/architecture-agent.md +189 -0
  482. package/help/builder-agent.md +80 -0
  483. package/help/code-review-agents.md +37 -0
  484. package/help/coding-packages.md +31 -0
  485. package/help/coding-services.md +71 -0
  486. package/help/cost-attribution.md +67 -0
  487. package/help/creating-agents.md +90 -0
  488. package/help/deploy-gke.md +45 -0
  489. package/help/deployment-targets.md +39 -0
  490. package/help/errors/budget-group-exhausted.md +25 -0
  491. package/help/errors/docker-isolation-unsupported.md +26 -0
  492. package/help/errors/model-unavailable.md +63 -0
  493. package/help/errors/protected-path.md +45 -0
  494. package/help/errors/repo-access.md +27 -0
  495. package/help/errors/service-declaration-invalid.md +27 -0
  496. package/help/errors/service-declaration-unavailable.md +25 -0
  497. package/help/errors/service-launcher-unsupported.md +30 -0
  498. package/help/errors/service-not-allowed.md +27 -0
  499. package/help/errors/service-unknown.md +23 -0
  500. package/help/errors/service-unready.md +49 -0
  501. package/help/getting-started.md +32 -0
  502. package/help/github.md +48 -0
  503. package/help/identity-and-access.md +44 -0
  504. package/help/jira.md +135 -0
  505. package/help/knowledge.md +47 -0
  506. package/help/mcp.md +30 -0
  507. package/help/models.md +90 -0
  508. package/help/native-capabilities.md +30 -0
  509. package/help/observability.md +41 -0
  510. package/help/operating-agents.md +36 -0
  511. package/help/security.md +27 -0
  512. package/help/troubleshooting/budgets.md +32 -0
  513. package/help/troubleshooting/coding-workers.md +47 -0
  514. package/help/troubleshooting/repository-access.md +27 -0
  515. package/package.json +14 -3
  516. package/prisma/migrations/20260925010000_coding_collect_exclude/migration.sql +8 -0
  517. package/prisma/migrations/20260925015000_allowed_egress_default/migration.sql +8 -0
  518. package/prisma/migrations/20260925020000_coding_package_registry/migration.sql +55 -0
  519. package/prisma/migrations/20260925030000_tool_name_per_owner/migration.sql +11 -0
  520. package/prisma/migrations/20260926010000_run_trigger_host_event/migration.sql +7 -0
  521. package/prisma/migrations/20260926020000_code_review_hosts/migration.sql +53 -0
  522. package/prisma/migrations/20260926030000_auth_user_roles/migration.sql +9 -0
  523. package/prisma/migrations/20260926040000_agent_effort/migration.sql +6 -0
  524. package/prisma/migrations/20260926050000_registry_lockfile_plan/migration.sql +32 -0
  525. package/prisma/migrations/20260926050000_repo_access_authorization/migration.sql +82 -0
  526. package/prisma/migrations/20260926060000_registry_plan_refusal/migration.sql +19 -0
  527. package/prisma/migrations/20260926100000_registry_plan_refusal_published_at/migration.sql +5 -0
  528. package/prisma/migrations/20260926190000_run_host_status/migration.sql +18 -0
  529. package/prisma/migrations/20260926210000_run_host_status_at_dispatch/migration.sql +5 -0
  530. package/prisma/migrations/20260927010000_resource_grants/migration.sql +72 -0
  531. package/prisma/migrations/20260927020000_proxy_session_budget_exhausted/migration.sql +3 -0
  532. package/prisma/migrations/20260927030000_coding_debug_trace/migration.sql +4 -0
  533. package/prisma/migrations/20260927040000_proxy_session_upstream_failure/migration.sql +3 -0
  534. package/prisma/migrations/20260927050000_coding_run_services/migration.sql +74 -0
  535. package/prisma/migrations/20260928000000_coding_run_tool_image/migration.sql +5 -0
  536. package/prisma/migrations/20260930000000_jira_issue_projects/migration.sql +34 -0
  537. package/prisma/migrations/20261001000000_jira_phase2_allowlists/migration.sql +3 -0
  538. package/prisma/migrations/20261001010000_jira_link_types_allowlist/migration.sql +2 -0
  539. package/prisma/migrations/20261002000000_jira_coding_bridge/migration.sql +28 -0
  540. package/prisma/migrations/20261002010000_jira_issue_creation/migration.sql +25 -0
  541. package/prisma/migrations/20261003000000_issue_cost_attribution/migration.sql +56 -0
  542. package/prisma/migrations/20261003010000_coding_run_service_status/migration.sql +23 -0
  543. package/prisma/migrations/20261003020000_viewer_notify/migration.sql +54 -0
  544. package/prisma/migrations/20261003030000_viewer_notify_fixes/migration.sql +47 -0
  545. package/prisma/migrations/20261003040000_viewer_indexes/migration.sql +12 -0
  546. package/prisma/migrations/20261004000000_model_catalog/migration.sql +26 -0
  547. package/prisma/schema.prisma +663 -21
  548. package/dist/mcp/tools/models.d.ts +0 -8
  549. package/dist/mcp/tools/models.js +0 -15
  550. package/dist/providers/llm/pricing-anthropic.d.ts +0 -4
  551. package/dist/providers/llm/pricing-anthropic.js +0 -30
  552. package/dist/providers/llm/pricing-bedrock-claude.d.ts +0 -12
  553. package/dist/providers/llm/pricing-bedrock-claude.js +0 -37
  554. package/dist/providers/llm/pricing.d.ts +0 -30
  555. package/dist/providers/llm/pricing.js +0 -74
@@ -9,6 +9,7 @@
9
9
  import type { Agent } from "#prisma";
10
10
  import type { Executor } from "../providers/executor/types.js";
11
11
  import { type DispatchDb } from "./dispatch.js";
12
+ import type { SelfDefectSink } from "./self-defects.js";
12
13
  export type SchedulerDb = DispatchDb;
13
14
  /**
14
15
  * Per spec: "Executor throws synchronously on start → the run is marked
@@ -25,7 +26,7 @@ export declare function findDueCandidates(db: Pick<SchedulerDb, "agent">, now: D
25
26
  * Returns the new run's id, or null if the agent wasn't (or is no longer)
26
27
  * due, or another tick already holds its row lock.
27
28
  */
28
- export declare function claimDueRun(db: SchedulerDb, executor: Executor, agentId: string, now: Date): Promise<string | null>;
29
+ export declare function claimDueRun(db: SchedulerDb, executor: Executor, agentId: string, now: Date, selfDefects?: SelfDefectSink): Promise<string | null>;
29
30
  export interface SchedulerOptions {
30
31
  executor: Executor;
31
32
  db?: SchedulerDb;
@@ -39,6 +40,8 @@ export interface SchedulerOptions {
39
40
  * failing hook cannot stop scheduled agents from firing.
40
41
  */
41
42
  onLeaderTick?: () => Promise<void>;
43
+ /** Files a self-defect when a scheduled run's executor fails to start it. Optional. */
44
+ selfDefects?: SelfDefectSink;
42
45
  }
43
46
  export interface SchedulerHandle {
44
47
  stop(): void;
@@ -39,11 +39,12 @@ export async function findDueCandidates(db, now) {
39
39
  * Returns the new run's id, or null if the agent wasn't (or is no longer)
40
40
  * due, or another tick already holds its row lock.
41
41
  */
42
- export async function claimDueRun(db, executor, agentId, now) {
42
+ export async function claimDueRun(db, executor, agentId, now, selfDefects) {
43
43
  const dispatched = await dispatchRun({
44
44
  db,
45
45
  executor,
46
46
  agentId,
47
+ selfDefects,
47
48
  trigger: "scheduled",
48
49
  now,
49
50
  lockAgent: true,
@@ -88,7 +89,7 @@ export function startScheduler(options) {
88
89
  const due = await findDueCandidates(db, now());
89
90
  for (const agent of due) {
90
91
  try {
91
- const runId = await claimDueRun(db, options.executor, agent.id, now());
92
+ const runId = await claimDueRun(db, options.executor, agent.id, now(), options.selfDefects);
92
93
  if (runId) {
93
94
  log(`firing agent "${agent.name}" -> run ${runId}`);
94
95
  }
@@ -26,14 +26,23 @@ export declare function listSecrets(ownerId: string, db: PrismaClient): Promise<
26
26
  * (`secrets.get(boundName)`). Defaults to the secret's own name. */
27
27
  export declare function attachSecret(agentId: string, name: string, ownerId: string, db: PrismaClient, boundName?: string): Promise<void>;
28
28
  /** Detaches by point-of-use name — the pair (agentId, boundName) uniquely
29
- * identifies the edge; agent ownership is enforced by the caller. */
30
- export declare function detachSecret(agentId: string, boundName: string, db: PrismaClient): Promise<void>;
29
+ * identifies the edge — falling back to the secret's own name when no edge
30
+ * has that point-of-use name, since a secret attached under an alias is
31
+ * otherwise easy to "detach" by its real name without effect. Returns how
32
+ * many edges were removed; agent ownership is enforced by the caller. */
33
+ export declare function detachSecret(agentId: string, name: string, db: PrismaClient): Promise<number>;
31
34
  export declare function deleteSecret(secretId: string, db: PrismaClient): Promise<void>;
32
35
  /**
33
36
  * Decrypt-on-demand: only the ONE secret actually requested by name is
34
37
  * decrypted, never the agent's whole attached set eagerly — a lookup
35
38
  * that returns nothing (unattached name) is indistinguishable from one
36
39
  * that was never created, both `undefined`.
40
+ *
41
+ * Owner rule (resource-sharing grants spec §3.4.1): a binding resolves only
42
+ * while the secret's owner is the agent's CURRENT owner, both non-null. A
43
+ * binding written before that rule, left behind by make_owner, or on an
44
+ * owner-less agent behaves exactly like an unattached name, so one owner's
45
+ * secret never reaches another owner's agent (A2/S2-2, R2-1).
37
46
  */
38
47
  export declare function buildSecretsAccessor(agentId: string, cipher: SecretCipher, db: Pick<PrismaClient, "agentSecret"> & Partial<Pick<PrismaClient, "$queryRaw">>): SecretsAccessor;
39
48
  /**
@@ -41,9 +41,16 @@ export async function attachSecret(agentId, name, ownerId, db, boundName = name)
41
41
  await db.agentSecret.create({ data: { agentId, secretId: secret.id, boundName } });
42
42
  }
43
43
  /** Detaches by point-of-use name — the pair (agentId, boundName) uniquely
44
- * identifies the edge; agent ownership is enforced by the caller. */
45
- export async function detachSecret(agentId, boundName, db) {
46
- await db.agentSecret.deleteMany({ where: { agentId, boundName } });
44
+ * identifies the edge — falling back to the secret's own name when no edge
45
+ * has that point-of-use name, since a secret attached under an alias is
46
+ * otherwise easy to "detach" by its real name without effect. Returns how
47
+ * many edges were removed; agent ownership is enforced by the caller. */
48
+ export async function detachSecret(agentId, name, db) {
49
+ const byBoundName = await db.agentSecret.deleteMany({ where: { agentId, boundName: name } });
50
+ if (byBoundName.count > 0)
51
+ return byBoundName.count;
52
+ const bySecretName = await db.agentSecret.deleteMany({ where: { agentId, secret: { name } } });
53
+ return bySecretName.count;
47
54
  }
48
55
  export async function deleteSecret(secretId, db) {
49
56
  await db.secret.delete({ where: { id: secretId } });
@@ -53,16 +60,25 @@ export async function deleteSecret(secretId, db) {
53
60
  * decrypted, never the agent's whole attached set eagerly — a lookup
54
61
  * that returns nothing (unattached name) is indistinguishable from one
55
62
  * that was never created, both `undefined`.
63
+ *
64
+ * Owner rule (resource-sharing grants spec §3.4.1): a binding resolves only
65
+ * while the secret's owner is the agent's CURRENT owner, both non-null. A
66
+ * binding written before that rule, left behind by make_owner, or on an
67
+ * owner-less agent behaves exactly like an unattached name, so one owner's
68
+ * secret never reaches another owner's agent (A2/S2-2, R2-1).
56
69
  */
57
70
  export function buildSecretsAccessor(agentId, cipher, db) {
58
71
  return {
59
72
  async get(name) {
60
73
  boundedString(name, 1024);
61
74
  if (db.$queryRaw) {
75
+ // NULL-safe: "=" is never true when either owner is NULL.
62
76
  const rows = await db.$queryRaw `
63
77
  SELECT CASE WHEN octet_length(s."ciphertext") <= 262144 THEN s."ciphertext" ELSE NULL END AS "ciphertext"
64
- FROM "Secret" s JOIN "AgentSecret" a ON a."secretId" = s."id"
65
- WHERE a."agentId" = ${agentId} AND a."boundName" = ${name} LIMIT 1`;
78
+ FROM "Secret" s
79
+ JOIN "AgentSecret" a ON a."secretId" = s."id"
80
+ JOIN "Agent" g ON g."id" = a."agentId"
81
+ WHERE a."agentId" = ${agentId} AND a."boundName" = ${name} AND s."ownerId" = g."ownerId" LIMIT 1`;
66
82
  if (!rows.length)
67
83
  return undefined;
68
84
  if (rows[0].ciphertext === null)
@@ -72,10 +88,13 @@ export function buildSecretsAccessor(agentId, cipher, db) {
72
88
  // Lightweight provider doubles use the same post-read bound; production Prisma filters in SQL.
73
89
  const attachment = await db.agentSecret.findFirst({
74
90
  where: { agentId, boundName: name },
75
- include: { secret: true },
91
+ include: { secret: true, agent: { select: { ownerId: true } } },
76
92
  });
77
93
  if (!attachment)
78
94
  return undefined;
95
+ const owner = attachment.agent.ownerId;
96
+ if (owner === null || attachment.secret.ownerId !== owner)
97
+ return undefined;
79
98
  boundedString(attachment.secret.ciphertext, 256 * 1024);
80
99
  return cipher.decrypt(attachment.secret.ciphertext);
81
100
  },
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Self-defects: when a run of an opted-in agent (Agent.defectProjectKey +
3
+ * defectIssueType) ends failed, lost or budget_exhausted, the control plane
4
+ * (no model involved) files a defect for it through fileIssue, deduped by a
5
+ * structural fingerprint so a recurring failure becomes "seen again" comments
6
+ * on one issue rather than a new issue per run.
7
+ *
8
+ * fingerprint self:<agentId>:<status>:<category>
9
+ * category CodingRun.failureCategory, else the leading `code:` token of
10
+ * Run.error, else "unknown" — only ever a closed-shape token
11
+ * (lower-case letters/underscore), never the error's free text
12
+ *
13
+ * Fails closed: the agent needs a live write link to defectProjectKey whose
14
+ * creatableIssueTypes includes defectIssueType; otherwise it logs and skips.
15
+ * Self-defects are not counted against the link's maxNewIssuesPerRun: that cap
16
+ * bounds what a run's model may create, while this is a control-plane action
17
+ * whose volume the fingerprint dedupe already bounds (one open issue per
18
+ * agent/status/category).
19
+ *
20
+ * Filed by whichever write made the run's row terminal (its update count says so, so a run files once): the
21
+ * runner, the container store, the reconciler, the coding queue's timeout, a failed executor start
22
+ * (markRunFailedFromExecutorError) and DBOS recovery's mark-failed.
23
+ *
24
+ * Best effort and never throws. No recursion: this is only ever called after a
25
+ * run's row is final, outside any run, and a failure to file only logs — it
26
+ * never fails a run, so it can never trigger another filing.
27
+ */
28
+ import type { PrismaClient } from "#prisma";
29
+ import { type IssueTrackerRegistry } from "../providers/issue-tracker/types.js";
30
+ import { type FileIssueInput, type FileIssueResult } from "./issue-dedupe.js";
31
+ /** Run statuses that file a defect; succeeded, cancelled and refused never do. */
32
+ export declare const SELF_DEFECT_STATUSES: ReadonlySet<string>;
33
+ /** How long a caller waits for the filing; past this it carries on in the background (and still only logs). */
34
+ export declare const SELF_DEFECT_WAIT_MS = 15000;
35
+ export type SelfDefectDb = Pick<PrismaClient, "agent" | "agentIssueProject" | "codingRun" | "$transaction">;
36
+ /** The finished run, as its final row has it. */
37
+ export interface SelfDefectRun {
38
+ id: string;
39
+ agentId: string;
40
+ status: string;
41
+ error: string | null;
42
+ finishedAt: Date | null;
43
+ }
44
+ export interface SelfDefectOptions {
45
+ /** Injected for tests; defaults to issue-dedupe's fileIssue on `db`. */
46
+ fileIssue?: (input: FileIssueInput) => Promise<FileIssueResult>;
47
+ waitMs?: number;
48
+ }
49
+ /**
50
+ * Where a write that ends a run files its self-defect: the database to read the run and file through, and the
51
+ * configured issue trackers. Absent, or with no tracker configured, the write files nothing and makes no extra query.
52
+ */
53
+ export interface SelfDefectSink {
54
+ db: SelfDefectDb & Pick<PrismaClient, "run">;
55
+ issueTrackers?: IssueTrackerRegistry;
56
+ /** Injected for tests; the wait defaults to SELF_DEFECT_SHORT_WAIT_MS. */
57
+ options?: SelfDefectOptions;
58
+ }
59
+ /** The bound for callers on a dispatch, queue or executor path: past it the filing carries on detached. */
60
+ export declare const SELF_DEFECT_SHORT_WAIT_MS = 2000;
61
+ /** True when at least one issue tracker is configured (no Jira site configured yields an empty registry). */
62
+ export declare function hasIssueTrackers(trackers: IssueTrackerRegistry | undefined): trackers is IssueTrackerRegistry;
63
+ /**
64
+ * The leading `code:` token of a run error (lower-cased) when it is a safe category (CATEGORY_PATTERN), else
65
+ * "unknown". Never any of the free text after it.
66
+ */
67
+ export declare function errorClass(error: string | null | undefined): string;
68
+ export declare function selfDefectFingerprint(agentId: string, status: string, category: string): string;
69
+ /**
70
+ * Files (or re-sights) the defect for a finished run. Resolves to the filing's
71
+ * result, or null when nothing was filed (not a filing status, not opted in,
72
+ * no live link, an error, or still in flight after `waitMs`). Never throws.
73
+ */
74
+ export declare function fileSelfDefect(db: SelfDefectDb, trackers: IssueTrackerRegistry | undefined, run: SelfDefectRun, opts?: SelfDefectOptions): Promise<FileIssueResult | null>;
75
+ /**
76
+ * For a write that just made `runId` terminal (its update count said so, so this files once): reads the final row
77
+ * and files its self-defect, waiting at most SELF_DEFECT_SHORT_WAIT_MS. No-op, with no query, without a configured
78
+ * tracker. Never throws.
79
+ */
80
+ export declare function fileSelfDefectForRun(sink: SelfDefectSink | undefined, runId: string): Promise<FileIssueResult | null>;
@@ -0,0 +1,180 @@
1
+ import { agentFooter } from "../providers/issue-tracker/jira.js";
2
+ import { ISSUE_TRACKER_PROVIDERS, } from "../providers/issue-tracker/types.js";
3
+ import { fileIssue } from "./issue-dedupe.js";
4
+ import { propertyKey } from "./issue-tracker-tools.js";
5
+ import { logger } from "./logger.js";
6
+ const log = logger.child({ module: "self-defects" });
7
+ /** Run statuses that file a defect; succeeded, cancelled and refused never do. */
8
+ export const SELF_DEFECT_STATUSES = new Set(["failed", "lost", "budget_exhausted"]);
9
+ /** How long a caller waits for the filing; past this it carries on in the background (and still only logs). */
10
+ export const SELF_DEFECT_WAIT_MS = 15_000;
11
+ const SUMMARY_MAX_LENGTH = 255;
12
+ /**
13
+ * What a category may look like to be published in the issue and fingerprint: lower-case letters and underscores,
14
+ * at most 32. No digits, dots or dashes, so secret-shaped (ghp_…, sk-ant-…), host-shaped (db.internal.corp) and
15
+ * id-shaped (run-8f3a…) prefixes never reach Jira and fingerprints stay a small closed set.
16
+ */
17
+ const CATEGORY_PATTERN = /^[a-z][a-z_]{0,31}$/;
18
+ /** The bound for callers on a dispatch, queue or executor path: past it the filing carries on detached. */
19
+ export const SELF_DEFECT_SHORT_WAIT_MS = 2_000;
20
+ /** True when at least one issue tracker is configured (no Jira site configured yields an empty registry). */
21
+ export function hasIssueTrackers(trackers) {
22
+ return !!trackers && Object.values(trackers).some(Boolean);
23
+ }
24
+ /**
25
+ * The leading `code:` token of a run error (lower-cased) when it is a safe category (CATEGORY_PATTERN), else
26
+ * "unknown". Never any of the free text after it.
27
+ */
28
+ export function errorClass(error) {
29
+ const match = /^([^:\s]{1,64}):/.exec(error ?? "");
30
+ return safeCategory(match?.[1]) ?? "unknown";
31
+ }
32
+ export function selfDefectFingerprint(agentId, status, category) {
33
+ return `self:${agentId}:${status}:${category}`;
34
+ }
35
+ function safeCategory(value) {
36
+ const lowered = value?.trim().toLowerCase();
37
+ return lowered && CATEGORY_PATTERN.test(lowered) ? lowered : null;
38
+ }
39
+ /**
40
+ * Files (or re-sights) the defect for a finished run. Resolves to the filing's
41
+ * result, or null when nothing was filed (not a filing status, not opted in,
42
+ * no live link, an error, or still in flight after `waitMs`). Never throws.
43
+ */
44
+ export async function fileSelfDefect(db, trackers, run, opts = {}) {
45
+ if (!SELF_DEFECT_STATUSES.has(run.status) || !trackers)
46
+ return null;
47
+ const filing = attempt(db, trackers, run, opts).catch((err) => {
48
+ log.warn({ err, runId: run.id, agentId: run.agentId }, "could not file the run's self-defect");
49
+ return null;
50
+ });
51
+ const waitMs = opts.waitMs ?? SELF_DEFECT_WAIT_MS;
52
+ let timer;
53
+ const timedOut = new Promise((resolve) => {
54
+ timer = setTimeout(() => {
55
+ log.warn({ runId: run.id, waitMs }, "self-defect filing still in progress; no longer waiting for it");
56
+ resolve(null);
57
+ }, waitMs);
58
+ timer.unref?.();
59
+ });
60
+ try {
61
+ return await Promise.race([filing, timedOut]);
62
+ }
63
+ finally {
64
+ clearTimeout(timer);
65
+ }
66
+ }
67
+ /**
68
+ * For a write that just made `runId` terminal (its update count said so, so this files once): reads the final row
69
+ * and files its self-defect, waiting at most SELF_DEFECT_SHORT_WAIT_MS. No-op, with no query, without a configured
70
+ * tracker. Never throws.
71
+ */
72
+ export async function fileSelfDefectForRun(sink, runId) {
73
+ if (!sink || !hasIssueTrackers(sink.issueTrackers))
74
+ return null;
75
+ let row;
76
+ try {
77
+ row = await sink.db.run.findUnique({
78
+ where: { id: runId },
79
+ select: { id: true, agentId: true, status: true, error: true, finishedAt: true },
80
+ });
81
+ }
82
+ catch (err) {
83
+ log.warn({ err, runId }, "could not read the run to file its self-defect");
84
+ return null;
85
+ }
86
+ if (!row)
87
+ return null;
88
+ return fileSelfDefect(sink.db, sink.issueTrackers, row, {
89
+ waitMs: SELF_DEFECT_SHORT_WAIT_MS,
90
+ ...sink.options,
91
+ });
92
+ }
93
+ async function attempt(db, trackers, run, opts) {
94
+ const configured = ISSUE_TRACKER_PROVIDERS.filter((p) => trackers[p]);
95
+ if (configured.length === 0)
96
+ return null;
97
+ const agent = await db.agent.findUnique({
98
+ where: { id: run.agentId },
99
+ select: { id: true, name: true, defectProjectKey: true, defectIssueType: true },
100
+ });
101
+ if (!agent?.defectProjectKey || !agent.defectIssueType)
102
+ return null;
103
+ const projectKey = agent.defectProjectKey;
104
+ const issueType = agent.defectIssueType;
105
+ let tracker;
106
+ let link;
107
+ for (const provider of configured) {
108
+ // Live, read now: an unlink, downgrade or allowlist change since the run started applies here.
109
+ const row = await db.agentIssueProject.findUnique({
110
+ where: { agentId_provider_projectKey: { agentId: agent.id, provider, projectKey } },
111
+ select: {
112
+ provider: true,
113
+ projectKey: true,
114
+ access: true,
115
+ commentVisibilityRole: true,
116
+ creatableIssueTypes: true,
117
+ },
118
+ });
119
+ if (!row)
120
+ continue;
121
+ const typeAllowed = row.creatableIssueTypes.some((t) => t.trim().toLowerCase() === issueType.trim().toLowerCase());
122
+ if (row.access !== "write" || !typeAllowed) {
123
+ log.warn({ runId: run.id, agentId: agent.id, projectKey, access: row.access, typeAllowed }, "self-defects skipped: the agent's link to the defect project is not writable or does not allow the issue type");
124
+ return null;
125
+ }
126
+ tracker = trackers[provider];
127
+ link = row;
128
+ break;
129
+ }
130
+ if (!tracker || !link) {
131
+ log.warn({ runId: run.id, agentId: agent.id, projectKey }, "self-defects skipped: no link to the defect project");
132
+ return null;
133
+ }
134
+ let codingCategory = null;
135
+ try {
136
+ const coding = await db.codingRun.findUnique({ where: { runId: run.id }, select: { failureCategory: true } });
137
+ codingCategory = safeCategory(coding?.failureCategory);
138
+ }
139
+ catch (err) {
140
+ log.debug({ err, runId: run.id }, "no coding failure category for the self-defect");
141
+ }
142
+ const category = codingCategory ?? errorClass(run.error);
143
+ const finished = (run.finishedAt ?? new Date()).toISOString();
144
+ const summary = `wardby agent "${agent.name}": ${run.status}${category === "unknown" ? "" : ` (${category})`}`;
145
+ const description = [
146
+ `A run of wardby agent "${agent.name}" ended ${run.status}.`,
147
+ "",
148
+ `- Run: ${run.id}`,
149
+ `- Agent: ${agent.id}`,
150
+ `- Status: ${run.status}`,
151
+ `- Failure category: ${category}`,
152
+ `- Finished: ${finished}`,
153
+ "",
154
+ "Filed by wardby itself. The run's error text is not included; see the run in wardby for details.",
155
+ ].join("\n");
156
+ const file = opts.fileIssue ?? ((input) => fileIssue({ db }, input));
157
+ // Not subject to maxNewIssuesPerRun (control plane; dedupe bounds volume), so createAllowed stays at its default.
158
+ const result = await file({
159
+ agentId: agent.id,
160
+ runId: run.id,
161
+ link,
162
+ tracker,
163
+ fingerprint: selfDefectFingerprint(agent.id, run.status, category),
164
+ create: {
165
+ issueType,
166
+ summary: summary.length > SUMMARY_MAX_LENGTH ? `${summary.slice(0, SUMMARY_MAX_LENGTH - 1)}…` : summary,
167
+ descriptionMarkdown: description,
168
+ properties: { [propertyKey(agent.id, "self-defect")]: { runId: run.id } },
169
+ },
170
+ footerMarkdown: agentFooter(agent.id),
171
+ seenAgainMarkdown: `Run ${run.id} ended ${run.status} at ${finished}.\n\n${agentFooter(agent.id)}`,
172
+ });
173
+ if ("error" in result) {
174
+ log.warn({ runId: run.id, agentId: agent.id, error: result.error }, "self-defect filing failed");
175
+ }
176
+ else {
177
+ log.info({ runId: run.id, agentId: agent.id, outcome: result.outcome, issueKey: result.issueKey }, "self-defect filed");
178
+ }
179
+ return result;
180
+ }
@@ -4,7 +4,7 @@ import type { AgentMemoryStore } from "../providers/memory/types.js";
4
4
  export declare const SUBAGENT_MEMORY_TOOL_NAMES: ReadonlySet<string>;
5
5
  export declare const SUBAGENT_MEMORY_GET_TOOL: LoadedTool;
6
6
  export declare const PARENT_MEMORY_GET_TOOL: LoadedTool;
7
- type SubAgentMemoryDb = Pick<PrismaClient, "agentSubAgent" | "run">;
7
+ type SubAgentMemoryDb = Pick<PrismaClient, "agentSubAgent" | "run" | "agent">;
8
8
  /** `subagent_memory_get` — callable by a parent, gated by the AgentSubAgent edge itself. */
9
9
  export declare function handleSubAgentMemoryGet(argsJson: string, callingAgentId: string, db: SubAgentMemoryDb, memory: AgentMemoryStore): Promise<string>;
10
10
  /**
@@ -4,9 +4,9 @@
4
4
  * sandboxed, the same treatment memory-tools.ts gives the own-memory
5
5
  * built-ins:
6
6
  *
7
- * - subagent_memory_get: a parent can always read a declared child's
8
- * memory. The AgentSubAgent edge itself is the grant -- no reference
9
- * needed each time.
7
+ * - subagent_memory_get: a parent can read a declared child's memory when
8
+ * both have the same owner. The AgentSubAgent edge itself is the grant --
9
+ * no reference needed each time; a cross-owner edge never carries it.
10
10
  * - parent_memory_get: a child can read a specific key of its dispatching
11
11
  * parent's memory ONLY when that exact run was handed a grant for that
12
12
  * key at dispatch time (Run.grantedParentMemoryKeys) -- never a standing
@@ -74,6 +74,19 @@ export async function handleSubAgentMemoryGet(argsJson, callingAgentId, db, memo
74
74
  message: `No sub-agent is bound to name "${args.boundName}".`,
75
75
  });
76
76
  }
77
+ // Memory inspection is owner-level (resource-sharing grants spec §3.4.4):
78
+ // an edge to another owner's child carries execute, never its memory.
79
+ // Owners are read live, so a make_owner transfer takes effect at once.
80
+ const [parent, child] = await Promise.all([
81
+ db.agent.findUnique({ where: { id: callingAgentId }, select: { ownerId: true } }),
82
+ db.agent.findUnique({ where: { id: edge.childAgentId }, select: { ownerId: true } }),
83
+ ]);
84
+ if (!parent || !child || (parent.ownerId ?? null) !== (child.ownerId ?? null)) {
85
+ return JSON.stringify({
86
+ error: "subagent_not_authorized",
87
+ message: `The "${args.boundName}" sub-agent belongs to another owner; its memory is not readable from here.`,
88
+ });
89
+ }
77
90
  const content = await memory.get(edge.childAgentId, args.key);
78
91
  return JSON.stringify({ content: content ?? null });
79
92
  }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Updating and deleting a Tool, shared by MCP update_tool/delete_tool (the
3
+ * owner, over MCP) and `wardby tool update|delete` (the operator, over the
4
+ * CLI). Each caller brings its own authorization -- MCP is strictly
5
+ * owner-only and never touches public tools; the operator may change any
6
+ * tool -- but the attachment rules are the same for both, and are always
7
+ * judged against the *tool's* owner:
8
+ *
9
+ * - An update is refused while the tool is attached to any agent owned by
10
+ * someone other than the tool's owner (a public agent counts, unless the
11
+ * tool is public too). An attachment's grants hand whatever code the row
12
+ * holds to that agent owner's secrets and hosts, and the description
13
+ * reaches their model context.
14
+ * - A delete is refused while any attachment remains; `detach` first removes
15
+ * the attachments to the tool owner's own agents (for a public tool, the
16
+ * public agents), never anyone else's. The check runs before any detach,
17
+ * so a refusal changes nothing.
18
+ *
19
+ * Both run in one Serializable transaction, the same isolation as MCP
20
+ * attach_tool, so an attach that commits between the check and the write
21
+ * aborts one side instead of letting new code reach a newly attached agent
22
+ * (pinned in core/prisma-adapter.database.test.ts). That guarantee covers
23
+ * MCP attach_tool only: `wardby tool attach` and the importer attach with a
24
+ * plain check-then-upsert, acceptable because both are operator-only.
25
+ */
26
+ import { Prisma, type PrismaClient, type Tool } from "#prisma";
27
+ export type AttachedAgent = {
28
+ id: string;
29
+ name: string;
30
+ ownerId: string | null;
31
+ };
32
+ export interface ToolChanges {
33
+ description?: string;
34
+ paramsZod?: string;
35
+ code?: string;
36
+ }
37
+ /**
38
+ * Why a tool change was refused because of its attachments:
39
+ * - `other_owners`: attached to agents owned by someone other than the
40
+ * tool's owner (`agents` lists them; callers decide how much to reveal).
41
+ * - `needs_detach`: a delete without `detach`, still attached to the tool
42
+ * owner's own agents.
43
+ * - `race`: an attachment committed after the check, and the RESTRICT
44
+ * foreign key stopped the delete (`agents` is empty).
45
+ */
46
+ export declare class ToolAttachedError extends Error {
47
+ readonly reason: "other_owners" | "needs_detach" | "race";
48
+ readonly agents: AttachedAgent[];
49
+ constructor(reason: "other_owners" | "needs_detach" | "race", agents: AttachedAgent[]);
50
+ }
51
+ /** Whether `changes` names at least one field to change. */
52
+ export declare function hasToolChanges(changes: ToolChanges): boolean;
53
+ /**
54
+ * The row update for `changes`, with jsonSchema re-derived exactly as tool
55
+ * creation does whenever paramsZod changes, so the cached schema never goes
56
+ * stale. An invalid paramsZod is returned, not thrown -- the caller reports
57
+ * it like create_tool does and writes nothing. Run it before the transaction
58
+ * so a QuickJS compile never holds one open.
59
+ */
60
+ export declare function prepareToolUpdate(changes: ToolChanges): Promise<{
61
+ ok: true;
62
+ data: Prisma.ToolUpdateInput;
63
+ } | {
64
+ ok: false;
65
+ errorKind: string;
66
+ errorMessage: string;
67
+ }>;
68
+ /** The agents `toolId` is attached to, read inside the caller's transaction. */
69
+ export declare function attachedAgents(tx: Pick<Prisma.TransactionClient, "agentTool">, toolId: string): Promise<AttachedAgent[]>;
70
+ /** Refuses (by throwing) unless the caller may change this tool; receives the row read inside the transaction. */
71
+ export type AuthorizeTool = (tool: Tool | null) => void;
72
+ export declare function updateToolGuarded(db: Pick<PrismaClient, "$transaction">, toolId: string, data: Prisma.ToolUpdateInput, authorize: AuthorizeTool): Promise<Tool>;
73
+ /** Deletes the tool and returns the ids of the agents it was detached from. */
74
+ export declare function deleteToolGuarded(db: Pick<PrismaClient, "$transaction">, toolId: string, options: {
75
+ detach: boolean;
76
+ authorize: AuthorizeTool;
77
+ }): Promise<string[]>;
78
+ /** One `wardby tool list` line: names are only unique per owner, so the id and owner disambiguate. */
79
+ export declare function formatToolLine(tool: Pick<Tool, "id" | "name" | "description" | "ownerId">): string;
80
+ /** Attached agents for an operator-facing refusal: unlike MCP's, nothing is redacted. */
81
+ export declare function formatAttachedAgents(agents: AttachedAgent[]): string;
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Updating and deleting a Tool, shared by MCP update_tool/delete_tool (the
3
+ * owner, over MCP) and `wardby tool update|delete` (the operator, over the
4
+ * CLI). Each caller brings its own authorization -- MCP is strictly
5
+ * owner-only and never touches public tools; the operator may change any
6
+ * tool -- but the attachment rules are the same for both, and are always
7
+ * judged against the *tool's* owner:
8
+ *
9
+ * - An update is refused while the tool is attached to any agent owned by
10
+ * someone other than the tool's owner (a public agent counts, unless the
11
+ * tool is public too). An attachment's grants hand whatever code the row
12
+ * holds to that agent owner's secrets and hosts, and the description
13
+ * reaches their model context.
14
+ * - A delete is refused while any attachment remains; `detach` first removes
15
+ * the attachments to the tool owner's own agents (for a public tool, the
16
+ * public agents), never anyone else's. The check runs before any detach,
17
+ * so a refusal changes nothing.
18
+ *
19
+ * Both run in one Serializable transaction, the same isolation as MCP
20
+ * attach_tool, so an attach that commits between the check and the write
21
+ * aborts one side instead of letting new code reach a newly attached agent
22
+ * (pinned in core/prisma-adapter.database.test.ts). That guarantee covers
23
+ * MCP attach_tool only: `wardby tool attach` and the importer attach with a
24
+ * plain check-then-upsert, acceptable because both are operator-only.
25
+ */
26
+ import { Prisma } from "#prisma";
27
+ import { deriveJsonSchema } from "../sandbox/zod-params.js";
28
+ /**
29
+ * Why a tool change was refused because of its attachments:
30
+ * - `other_owners`: attached to agents owned by someone other than the
31
+ * tool's owner (`agents` lists them; callers decide how much to reveal).
32
+ * - `needs_detach`: a delete without `detach`, still attached to the tool
33
+ * owner's own agents.
34
+ * - `race`: an attachment committed after the check, and the RESTRICT
35
+ * foreign key stopped the delete (`agents` is empty).
36
+ */
37
+ export class ToolAttachedError extends Error {
38
+ reason;
39
+ agents;
40
+ constructor(reason, agents) {
41
+ super(`tool_attached_${reason}`);
42
+ this.reason = reason;
43
+ this.agents = agents;
44
+ this.name = "ToolAttachedError";
45
+ }
46
+ }
47
+ /** Whether `changes` names at least one field to change. */
48
+ export function hasToolChanges(changes) {
49
+ return changes.description !== undefined || changes.paramsZod !== undefined || changes.code !== undefined;
50
+ }
51
+ /**
52
+ * The row update for `changes`, with jsonSchema re-derived exactly as tool
53
+ * creation does whenever paramsZod changes, so the cached schema never goes
54
+ * stale. An invalid paramsZod is returned, not thrown -- the caller reports
55
+ * it like create_tool does and writes nothing. Run it before the transaction
56
+ * so a QuickJS compile never holds one open.
57
+ */
58
+ export async function prepareToolUpdate(changes) {
59
+ const data = {
60
+ ...(changes.description !== undefined ? { description: changes.description } : {}),
61
+ ...(changes.code !== undefined ? { code: changes.code } : {}),
62
+ };
63
+ if (changes.paramsZod !== undefined) {
64
+ const schemaResult = await deriveJsonSchema(changes.paramsZod);
65
+ if (!schemaResult.ok) {
66
+ return { ok: false, errorKind: schemaResult.errorKind, errorMessage: schemaResult.errorMessage };
67
+ }
68
+ data.paramsZod = changes.paramsZod;
69
+ data.jsonSchema = schemaResult.value;
70
+ }
71
+ return { ok: true, data };
72
+ }
73
+ /** The agents `toolId` is attached to, read inside the caller's transaction. */
74
+ export async function attachedAgents(tx, toolId) {
75
+ const rows = await tx.agentTool.findMany({
76
+ where: { toolId },
77
+ select: { agent: { select: { id: true, name: true, ownerId: true } } },
78
+ });
79
+ return rows.map((row) => row.agent);
80
+ }
81
+ export async function updateToolGuarded(db, toolId, data, authorize) {
82
+ return db.$transaction(async (tx) => {
83
+ const tool = await tx.tool.findUnique({ where: { id: toolId } });
84
+ authorize(tool);
85
+ const others = (await attachedAgents(tx, toolId)).filter((agent) => agent.ownerId !== tool.ownerId);
86
+ if (others.length > 0)
87
+ throw new ToolAttachedError("other_owners", others);
88
+ return tx.tool.update({ where: { id: toolId }, data });
89
+ }, { isolationLevel: Prisma.TransactionIsolationLevel.Serializable });
90
+ }
91
+ /** Deletes the tool and returns the ids of the agents it was detached from. */
92
+ export async function deleteToolGuarded(db, toolId, options) {
93
+ try {
94
+ return await db.$transaction(async (tx) => {
95
+ const tool = await tx.tool.findUnique({ where: { id: toolId } });
96
+ options.authorize(tool);
97
+ const agents = await attachedAgents(tx, toolId);
98
+ const own = agents.filter((agent) => agent.ownerId === tool.ownerId);
99
+ const others = agents.filter((agent) => agent.ownerId !== tool.ownerId);
100
+ if (others.length > 0)
101
+ throw new ToolAttachedError("other_owners", others);
102
+ if (own.length > 0 && !options.detach)
103
+ throw new ToolAttachedError("needs_detach", own);
104
+ if (own.length > 0) {
105
+ await tx.agentTool.deleteMany({ where: { toolId, agentId: { in: own.map((agent) => agent.id) } } });
106
+ }
107
+ await tx.tool.delete({ where: { id: toolId } });
108
+ return own.map((agent) => agent.id);
109
+ }, { isolationLevel: Prisma.TransactionIsolationLevel.Serializable });
110
+ }
111
+ catch (err) {
112
+ // AgentTool.toolId is ON DELETE RESTRICT: an attachment that raced in
113
+ // past the check above still stops the delete, as P2003.
114
+ if (err instanceof Prisma.PrismaClientKnownRequestError && err.code === "P2003") {
115
+ throw new ToolAttachedError("race", []);
116
+ }
117
+ throw err;
118
+ }
119
+ }
120
+ /** One `wardby tool list` line: names are only unique per owner, so the id and owner disambiguate. */
121
+ export function formatToolLine(tool) {
122
+ return `${tool.id} ${tool.name} owner:${tool.ownerId ?? "public"} ${tool.description}`;
123
+ }
124
+ /** Attached agents for an operator-facing refusal: unlike MCP's, nothing is redacted. */
125
+ export function formatAttachedAgents(agents) {
126
+ return agents
127
+ .map((agent) => `"${agent.name}" (${agent.id}, ${agent.ownerId === null ? "public" : `owner ${agent.ownerId}`})`)
128
+ .join(", ");
129
+ }