@wardby/cli 0.3.0 → 0.4.1

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 (275) hide show
  1. package/.env.example +22 -3
  2. package/README.md +11 -9
  3. package/dist/cli-help.d.ts +1 -1
  4. package/dist/cli-help.js +1 -0
  5. package/dist/cli.js +68 -10
  6. package/dist/coding/base-commit.d.ts +6 -0
  7. package/dist/coding/base-commit.js +12 -0
  8. package/dist/coding/protocol.d.ts +17 -1
  9. package/dist/coding/protocol.js +17 -6
  10. package/dist/coding/provider.d.ts +6 -1
  11. package/dist/coding/provider.js +16 -9
  12. package/dist/config/providers.d.ts +25 -0
  13. package/dist/config/providers.js +71 -0
  14. package/dist/core/attribution.d.ts +101 -0
  15. package/dist/core/attribution.js +208 -0
  16. package/dist/core/budget-groups.d.ts +17 -10
  17. package/dist/core/budget-groups.js +15 -12
  18. package/dist/core/coding-queue.d.ts +3 -0
  19. package/dist/core/coding-queue.js +6 -2
  20. package/dist/core/coding-service-status.d.ts +11 -0
  21. package/dist/core/coding-service-status.js +17 -0
  22. package/dist/core/cost-report.d.ts +88 -0
  23. package/dist/core/cost-report.js +248 -0
  24. package/dist/core/dispatch.d.ts +42 -2
  25. package/dist/core/dispatch.js +144 -26
  26. package/dist/core/engine-native.js +17 -4
  27. package/dist/core/glob.d.ts +10 -0
  28. package/dist/core/glob.js +33 -0
  29. package/dist/core/host-events.d.ts +24 -1
  30. package/dist/core/host-events.js +341 -1
  31. package/dist/core/host-status.d.ts +19 -2
  32. package/dist/core/host-status.js +47 -30
  33. package/dist/core/issue-bridge.d.ts +60 -0
  34. package/dist/core/issue-bridge.js +189 -0
  35. package/dist/core/issue-dedupe.d.ts +70 -0
  36. package/dist/core/issue-dedupe.js +255 -0
  37. package/dist/core/issue-events.d.ts +42 -0
  38. package/dist/core/issue-events.js +155 -0
  39. package/dist/core/issue-status.d.ts +29 -0
  40. package/dist/core/issue-status.js +241 -0
  41. package/dist/core/issue-tracker-tools.d.ts +64 -0
  42. package/dist/core/issue-tracker-tools.js +850 -0
  43. package/dist/core/model-usage.d.ts +10 -0
  44. package/dist/core/model-usage.js +24 -0
  45. package/dist/core/reconciler.d.ts +8 -4
  46. package/dist/core/reconciler.js +15 -4
  47. package/dist/core/review-host-tools.js +10 -3
  48. package/dist/core/run-pricing.d.ts +61 -0
  49. package/dist/core/run-pricing.js +56 -0
  50. package/dist/core/runner.d.ts +5 -2
  51. package/dist/core/runner.js +178 -27
  52. package/dist/core/scheduler.d.ts +4 -1
  53. package/dist/core/scheduler.js +3 -2
  54. package/dist/core/self-defects.d.ts +80 -0
  55. package/dist/core/self-defects.js +180 -0
  56. package/dist/core/tool-names.js +3 -0
  57. package/dist/core/webhooks.d.ts +9 -1
  58. package/dist/core/webhooks.js +19 -1
  59. package/dist/env.js +6 -1
  60. package/dist/generated/prisma/browser.d.ts +66 -0
  61. package/dist/generated/prisma/client.d.ts +66 -0
  62. package/dist/generated/prisma/commonInputTypes.d.ts +122 -52
  63. package/dist/generated/prisma/enums.d.ts +7 -0
  64. package/dist/generated/prisma/enums.js +6 -0
  65. package/dist/generated/prisma/internal/class.d.ts +99 -0
  66. package/dist/generated/prisma/internal/class.js +4 -4
  67. package/dist/generated/prisma/internal/prismaNamespace.d.ts +826 -1
  68. package/dist/generated/prisma/internal/prismaNamespace.js +135 -2
  69. package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +142 -0
  70. package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +135 -2
  71. package/dist/generated/prisma/models/Agent.d.ts +389 -1
  72. package/dist/generated/prisma/models/AgentIssueProject.d.ts +1838 -0
  73. package/dist/generated/prisma/models/AgentIssueProject.js +1 -0
  74. package/dist/generated/prisma/models/AgentRepository.d.ts +1 -1
  75. package/dist/generated/prisma/models/AuthUser.d.ts +1 -1
  76. package/dist/generated/prisma/models/CodingProxySession.d.ts +73 -1
  77. package/dist/generated/prisma/models/CodingRun.d.ts +130 -1
  78. package/dist/generated/prisma/models/CodingRunServiceStatus.d.ts +1404 -0
  79. package/dist/generated/prisma/models/CodingRunServiceStatus.js +1 -0
  80. package/dist/generated/prisma/models/IssueFingerprint.d.ts +1183 -0
  81. package/dist/generated/prisma/models/IssueFingerprint.js +1 -0
  82. package/dist/generated/prisma/models/IssuePullRequest.d.ts +1255 -0
  83. package/dist/generated/prisma/models/IssuePullRequest.js +1 -0
  84. package/dist/generated/prisma/models/ModelCatalogEntry.d.ts +1322 -0
  85. package/dist/generated/prisma/models/ModelCatalogEntry.js +1 -0
  86. package/dist/generated/prisma/models/Run.d.ts +933 -1
  87. package/dist/generated/prisma/models/RunAttribution.d.ts +1259 -0
  88. package/dist/generated/prisma/models/RunAttribution.js +1 -0
  89. package/dist/generated/prisma/models/RunIssueStatus.d.ts +1199 -0
  90. package/dist/generated/prisma/models/RunIssueStatus.js +1 -0
  91. package/dist/generated/prisma/models/RunModelUsage.d.ts +1316 -0
  92. package/dist/generated/prisma/models/RunModelUsage.js +1 -0
  93. package/dist/generated/prisma/models/WorkItem.d.ts +1408 -0
  94. package/dist/generated/prisma/models/WorkItem.js +1 -0
  95. package/dist/generated/prisma/models.d.ts +9 -0
  96. package/dist/help-index.json +355 -16
  97. package/dist/import/neutral-schema.d.ts +16 -16
  98. package/dist/knowledge/check.d.ts +13 -0
  99. package/dist/knowledge/check.js +69 -0
  100. package/dist/knowledge/cli.d.ts +14 -0
  101. package/dist/knowledge/cli.js +67 -0
  102. package/dist/knowledge/concept.d.ts +54 -0
  103. package/dist/knowledge/concept.js +78 -0
  104. package/dist/knowledge/note.d.ts +11 -0
  105. package/dist/knowledge/note.js +39 -0
  106. package/dist/knowledge/relevance.d.ts +11 -0
  107. package/dist/knowledge/relevance.js +14 -0
  108. package/dist/knowledge/span-hash.d.ts +3 -0
  109. package/dist/knowledge/span-hash.js +16 -0
  110. package/dist/mcp/auth/access.d.ts +4 -2
  111. package/dist/mcp/auth/ownership.d.ts +9 -9
  112. package/dist/mcp/auth/resource-server.d.ts +3 -1
  113. package/dist/mcp/auth/resource-server.js +18 -3
  114. package/dist/mcp/auth/self-hosted/credentials.d.ts +3 -3
  115. package/dist/mcp/auth/self-hosted/session.d.ts +5 -5
  116. package/dist/mcp/context.d.ts +3 -0
  117. package/dist/mcp/host-events/deliveries.d.ts +9 -0
  118. package/dist/mcp/host-events/deliveries.js +17 -0
  119. package/dist/mcp/host-events/github-ingress.d.ts +4 -2
  120. package/dist/mcp/host-events/github-ingress.js +4 -13
  121. package/dist/mcp/host-events/jira-ingress.d.ts +29 -0
  122. package/dist/mcp/host-events/jira-ingress.js +92 -0
  123. package/dist/mcp/index.d.ts +2 -0
  124. package/dist/mcp/index.js +87 -9
  125. package/dist/mcp/server.js +5 -2
  126. package/dist/mcp/tools/agents.js +74 -3
  127. package/dist/mcp/tools/cost-report.d.ts +8 -0
  128. package/dist/mcp/tools/cost-report.js +60 -0
  129. package/dist/mcp/tools/issue-projects.d.ts +2 -0
  130. package/dist/mcp/tools/issue-projects.js +238 -0
  131. package/dist/mcp/tools/model-catalog.d.ts +22 -0
  132. package/dist/mcp/tools/model-catalog.js +423 -0
  133. package/dist/mcp/tools/repositories.js +2 -1
  134. package/dist/mcp/tools/tools.d.ts +2 -2
  135. package/dist/mcp/tools/trigger.js +33 -5
  136. package/dist/mcp/transport/streamable-http.d.ts +5 -0
  137. package/dist/mcp/transport/streamable-http.js +23 -1
  138. package/dist/mcp/webhooks/ingress.d.ts +2 -1
  139. package/dist/mcp/webhooks/ingress.js +9 -2
  140. package/dist/providers/auth/self-hosted.d.ts +8 -1
  141. package/dist/providers/auth/self-hosted.js +39 -2
  142. package/dist/providers/coding-proxy/memory-ledger.d.ts +1 -1
  143. package/dist/providers/coding-proxy/memory-ledger.js +10 -1
  144. package/dist/providers/coding-proxy/metering.d.ts +2 -1
  145. package/dist/providers/coding-proxy/metering.js +13 -2
  146. package/dist/providers/coding-proxy/prisma-ledger.js +59 -6
  147. package/dist/providers/coding-proxy/proxy.d.ts +12 -2
  148. package/dist/providers/coding-proxy/proxy.js +92 -30
  149. package/dist/providers/coding-proxy/types.d.ts +18 -1
  150. package/dist/providers/coding-proxy/types.js +12 -1
  151. package/dist/providers/engine/types.d.ts +19 -0
  152. package/dist/providers/executor/composition.js +9 -1
  153. package/dist/providers/executor/container.d.ts +30 -2
  154. package/dist/providers/executor/container.js +98 -17
  155. package/dist/providers/executor/dbos.d.ts +2 -0
  156. package/dist/providers/executor/dbos.js +7 -5
  157. package/dist/providers/executor/routing.d.ts +6 -0
  158. package/dist/providers/executor/routing.js +5 -0
  159. package/dist/providers/executor/types.d.ts +12 -0
  160. package/dist/providers/issue-tracker/adf.d.ts +31 -0
  161. package/dist/providers/issue-tracker/adf.js +181 -0
  162. package/dist/providers/issue-tracker/index.d.ts +5 -0
  163. package/dist/providers/issue-tracker/index.js +12 -0
  164. package/dist/providers/issue-tracker/jira-client.d.ts +41 -0
  165. package/dist/providers/issue-tracker/jira-client.js +151 -0
  166. package/dist/providers/issue-tracker/jira-events.d.ts +3 -0
  167. package/dist/providers/issue-tracker/jira-events.js +98 -0
  168. package/dist/providers/issue-tracker/jira.d.ts +116 -0
  169. package/dist/providers/issue-tracker/jira.js +502 -0
  170. package/dist/providers/issue-tracker/types.d.ts +269 -0
  171. package/dist/providers/issue-tracker/types.js +16 -0
  172. package/dist/providers/jobs/docker.d.ts +5 -1
  173. package/dist/providers/jobs/docker.js +61 -33
  174. package/dist/providers/jobs/kubernetes.d.ts +3 -0
  175. package/dist/providers/jobs/kubernetes.js +44 -4
  176. package/dist/providers/jobs/service-state.d.ts +22 -0
  177. package/dist/providers/jobs/service-state.js +17 -0
  178. package/dist/providers/llm/anthropic.d.ts +3 -3
  179. package/dist/providers/llm/anthropic.js +3 -9
  180. package/dist/providers/llm/bedrock.d.ts +3 -3
  181. package/dist/providers/llm/bedrock.js +3 -9
  182. package/dist/providers/llm/catalog-lookup.d.ts +10 -0
  183. package/dist/providers/llm/catalog-lookup.js +15 -0
  184. package/dist/providers/llm/catalog-shipped.d.ts +18 -0
  185. package/dist/providers/llm/catalog-shipped.js +197 -0
  186. package/dist/providers/llm/catalog-store.d.ts +58 -0
  187. package/dist/providers/llm/catalog-store.js +138 -0
  188. package/dist/providers/llm/catalog-types.d.ts +66 -0
  189. package/dist/providers/llm/catalog-types.js +64 -0
  190. package/dist/providers/llm/catalog.d.ts +61 -0
  191. package/dist/providers/llm/catalog.js +147 -0
  192. package/dist/providers/llm/claude-provider.d.ts +10 -14
  193. package/dist/providers/llm/claude-provider.js +11 -6
  194. package/dist/providers/llm/index.d.ts +9 -6
  195. package/dist/providers/llm/index.js +8 -5
  196. package/dist/providers/llm/openai.d.ts +14 -5
  197. package/dist/providers/llm/openai.js +24 -14
  198. package/dist/providers/llm/pricing-core.d.ts +5 -3
  199. package/dist/providers/llm/registration.js +8 -12
  200. package/dist/providers/llm/routing.d.ts +18 -17
  201. package/dist/providers/llm/routing.js +40 -24
  202. package/dist/providers/review-host/github-events.js +47 -1
  203. package/dist/providers/review-host/github.js +7 -6
  204. package/dist/providers/review-host/types.d.ts +25 -0
  205. package/dist/providers/vcs/git.js +2 -22
  206. package/dist/providers/vcs/github.d.ts +20 -0
  207. package/dist/providers/vcs/github.js +28 -2
  208. package/dist/providers/vcs/types.d.ts +6 -0
  209. package/dist/quickstart/index.d.ts +8 -0
  210. package/dist/quickstart/index.js +34 -34
  211. package/dist/serve.js +8 -2
  212. package/dist/viewer/api-schema.d.ts +2757 -0
  213. package/dist/viewer/api-schema.js +165 -0
  214. package/dist/viewer/build-schemas.d.ts +2 -0
  215. package/dist/viewer/build-schemas.js +18 -0
  216. package/dist/viewer/event-bus.d.ts +38 -0
  217. package/dist/viewer/event-bus.js +232 -0
  218. package/dist/viewer/graph.d.ts +40 -0
  219. package/dist/viewer/graph.js +243 -0
  220. package/dist/viewer/http.d.ts +30 -0
  221. package/dist/viewer/http.js +133 -0
  222. package/dist/viewer/run-detail.d.ts +4 -0
  223. package/dist/viewer/run-detail.js +61 -0
  224. package/dist/wardby-bin.js +5 -0
  225. package/docs/README.md +10 -0
  226. package/docs/agent-recipes.md +383 -0
  227. package/docs/code-review-agents.md +29 -2
  228. package/docs/coding-agent-setup.md +3 -0
  229. package/docs/coding-worker-isolation.md +39 -5
  230. package/docs/getting-started-gke.md +28 -11
  231. package/docs/getting-started-identity-provider.md +49 -38
  232. package/docs/getting-started.md +14 -0
  233. package/docs/jira-agents.md +649 -0
  234. package/docs/knowledge.md +387 -0
  235. package/docs/models.md +221 -0
  236. package/docs/security-deployment.md +19 -9
  237. package/docs/viewer-api.md +142 -0
  238. package/help/admin-viewer.md +39 -0
  239. package/help/agent-recipes.md +173 -0
  240. package/help/architecture-agent.md +189 -0
  241. package/help/builder-agent.md +80 -0
  242. package/help/code-review-agents.md +6 -0
  243. package/help/cost-attribution.md +67 -0
  244. package/help/creating-agents.md +22 -0
  245. package/help/deploy-gke.md +6 -0
  246. package/help/errors/model-unavailable.md +63 -0
  247. package/help/getting-started.md +1 -0
  248. package/help/github.md +18 -0
  249. package/help/identity-and-access.md +8 -3
  250. package/help/jira.md +135 -0
  251. package/help/knowledge.md +47 -0
  252. package/help/models.md +90 -0
  253. package/help/operating-agents.md +7 -1
  254. package/help/troubleshooting/budgets.md +6 -0
  255. package/package.json +5 -2
  256. package/prisma/migrations/20260930000000_jira_issue_projects/migration.sql +34 -0
  257. package/prisma/migrations/20261001000000_jira_phase2_allowlists/migration.sql +3 -0
  258. package/prisma/migrations/20261001010000_jira_link_types_allowlist/migration.sql +2 -0
  259. package/prisma/migrations/20261002000000_jira_coding_bridge/migration.sql +28 -0
  260. package/prisma/migrations/20261002010000_jira_issue_creation/migration.sql +25 -0
  261. package/prisma/migrations/20261003000000_issue_cost_attribution/migration.sql +56 -0
  262. package/prisma/migrations/20261003010000_coding_run_service_status/migration.sql +23 -0
  263. package/prisma/migrations/20261003020000_viewer_notify/migration.sql +54 -0
  264. package/prisma/migrations/20261003030000_viewer_notify_fixes/migration.sql +47 -0
  265. package/prisma/migrations/20261003040000_viewer_indexes/migration.sql +12 -0
  266. package/prisma/migrations/20261004000000_model_catalog/migration.sql +26 -0
  267. package/prisma/schema.prisma +258 -2
  268. package/dist/mcp/tools/models.d.ts +0 -8
  269. package/dist/mcp/tools/models.js +0 -15
  270. package/dist/providers/llm/pricing-anthropic.d.ts +0 -14
  271. package/dist/providers/llm/pricing-anthropic.js +0 -48
  272. package/dist/providers/llm/pricing-bedrock-claude.d.ts +0 -20
  273. package/dist/providers/llm/pricing-bedrock-claude.js +0 -46
  274. package/dist/providers/llm/pricing.d.ts +0 -30
  275. package/dist/providers/llm/pricing.js +0 -74
@@ -0,0 +1,269 @@
1
+ /**
2
+ * Host-neutral issue-tracker surface for native agents. Jira Cloud is the
3
+ * first implementation (./jira.ts). The control plane holds the credential;
4
+ * no method takes a token. See docs/private/2026-09-30-jira-issue-tracker-design.md.
5
+ */
6
+ export type IssueTrackerProvider = "jira";
7
+ export declare const ISSUE_TRACKER_PROVIDERS: readonly IssueTrackerProvider[];
8
+ /** The product name shown to people (e.g. in a pull request's "Resolves Jira issue …" line). */
9
+ export declare const ISSUE_TRACKER_NAMES: Readonly<Record<IssueTrackerProvider, string>>;
10
+ export interface IssuePerson {
11
+ accountId: string;
12
+ displayName: string;
13
+ }
14
+ export interface IssueCommentView {
15
+ id: string;
16
+ author: IssuePerson | null;
17
+ created: string;
18
+ body: string;
19
+ /** Written by the bot and carrying this agent's footer: editable with jira_edit_own_comment. */
20
+ byThisAgent: boolean;
21
+ }
22
+ export interface IssueView {
23
+ key: string;
24
+ projectKey: string;
25
+ summary: string;
26
+ description: string;
27
+ status: string;
28
+ /** The status's category (Jira statusCategory.key): "done" is what dedupe treats as resolved. */
29
+ statusCategory: IssueStatusCategory;
30
+ issueType: string;
31
+ priority: string | null;
32
+ labels: string[];
33
+ assignee: IssuePerson | null;
34
+ reporter: IssuePerson | null;
35
+ url: string;
36
+ /** Most recent last; capped. */
37
+ comments: IssueCommentView[];
38
+ commentsTruncated: boolean;
39
+ /** Capped list; contents are read with readAttachmentText. Filenames are untrusted. */
40
+ attachments: IssueAttachmentView[];
41
+ /** Issue links (e.g. "relates to PROJ-9"), capped. Summaries are untrusted issue text. */
42
+ links: IssueLinkView[];
43
+ }
44
+ export interface IssueLinkView {
45
+ /** How this issue relates to the other, as Jira words it from this side ("relates to", "is blocked by"). */
46
+ relation: string;
47
+ key: string;
48
+ summary: string;
49
+ status: string;
50
+ }
51
+ export type IssueStatusCategory = "new" | "indeterminate" | "done";
52
+ export interface IssueAttachmentView {
53
+ id: string;
54
+ filename: string;
55
+ mimeType: string;
56
+ size: number;
57
+ }
58
+ export interface CreateIssueInput {
59
+ projectKey: string;
60
+ /** Issue type name (case-insensitive); resolved to an id from the project's create metadata. */
61
+ issueType: string;
62
+ summary: string;
63
+ descriptionMarkdown: string;
64
+ labels?: string[];
65
+ /** Priority name. */
66
+ priority?: string;
67
+ /** Component names. */
68
+ components?: string[];
69
+ parentKey?: string;
70
+ /** customfield_N -> raw JSON value. */
71
+ customFields?: Record<string, unknown>;
72
+ /** Issue properties, set in the create call itself. */
73
+ properties?: Record<string, unknown>;
74
+ /** Projects whose bare issue keys in the description become smart links. */
75
+ issueKeyProjects?: readonly string[];
76
+ }
77
+ export interface CreateMetaIssueType {
78
+ id: string;
79
+ name: string;
80
+ subtask: boolean;
81
+ }
82
+ export interface CreateMetaField {
83
+ fieldId: string;
84
+ name: string;
85
+ required: boolean;
86
+ hasDefault: boolean;
87
+ allowedValues?: string[];
88
+ }
89
+ export interface IssueSearchHit {
90
+ key: string;
91
+ summary: string;
92
+ status: string;
93
+ issueType: string;
94
+ updated: string;
95
+ url: string;
96
+ }
97
+ export interface IssueSearchResult {
98
+ issues: IssueSearchHit[];
99
+ truncated: boolean;
100
+ }
101
+ /** Who the tracker credential acts as (Jira: GET /myself). */
102
+ export interface IssueTrackerIdentity {
103
+ accountId: string;
104
+ displayName: string;
105
+ accountType: string;
106
+ }
107
+ /**
108
+ * Bounds one tracker call for callers on a latency budget (e.g. inside a database transaction).
109
+ * `timeoutMs` caps the WHOLE call, every request it makes included; with `retryOn429: false` a 429 fails
110
+ * at once instead of sleeping for Retry-After, so the call cannot outlive `timeoutMs`.
111
+ */
112
+ export interface TrackerCallOptions {
113
+ timeoutMs?: number;
114
+ retryOn429?: boolean;
115
+ }
116
+ /** What cost attribution keeps about an issue (src/core/attribution.ts): the hierarchy as of now. */
117
+ export interface IssueSnapshot {
118
+ /** The key that was asked for (WorkItem.key). */
119
+ key: string;
120
+ title?: string;
121
+ type?: string;
122
+ url: string;
123
+ /** The project (Jira) / team (Linear) the issue is in now. */
124
+ scopeKey: string;
125
+ parent?: {
126
+ key: string;
127
+ title?: string;
128
+ kind: string;
129
+ };
130
+ }
131
+ export interface IssueTracker {
132
+ readonly provider: IssueTrackerProvider;
133
+ /** The bot's own accountId (cached after the first call). */
134
+ botAccountId(): Promise<string>;
135
+ /** The account the credential acts as, from the same cached call as botAccountId. */
136
+ identity(): Promise<IssueTrackerIdentity>;
137
+ getIssue(key: string, opts: {
138
+ maxComments: number;
139
+ agentMarker: string;
140
+ } & TrackerCallOptions): Promise<IssueView>;
141
+ /** The project the issue is in now; an old key (kept as an alias after a move) resolves to its new project. */
142
+ issueProject(key: string): Promise<string>;
143
+ /** Title, type, scope and parent of `key` in one call, for cost attribution. Throws IssueTrackerError. */
144
+ snapshotIssue(key: string, opts?: {
145
+ timeoutMs?: number;
146
+ retryOn429?: boolean;
147
+ }): Promise<IssueSnapshot>;
148
+ search(jql: string, opts: {
149
+ maxResults: number;
150
+ }): Promise<IssueSearchResult>;
151
+ /** Whether issue `key` matches `jql` (used for a link's jqlFilter). Callers on a latency budget pass a short timeout and no 429 retry. */
152
+ matchesJql(key: string, jql: string, opts?: TrackerCallOptions): Promise<boolean>;
153
+ comment(key: string,
154
+ /** issueKeyProjects: projects whose bare issue keys in the text become smart links. */
155
+ input: {
156
+ markdown: string;
157
+ visibilityRole?: string;
158
+ issueKeyProjects?: readonly string[];
159
+ }, opts?: TrackerCallOptions): Promise<{
160
+ id: string;
161
+ url: string;
162
+ }>;
163
+ editComment(key: string, commentId: string, input: {
164
+ markdown: string;
165
+ issueKeyProjects?: readonly string[];
166
+ }): Promise<void>;
167
+ /** The comment's author accountId and plain text (uncapped: only for ownership checks, never shown to a model), or null when it doesn't exist. */
168
+ readComment(key: string, commentId: string): Promise<{
169
+ authorId: string | null;
170
+ body: string;
171
+ } | null>;
172
+ issueUrl(key: string): string;
173
+ /** Transitions the service account can perform now: target status name + category. */
174
+ transitions(key: string): Promise<Array<{
175
+ id: string;
176
+ name: string;
177
+ toStatus: string;
178
+ toCategory: string;
179
+ }>>;
180
+ /** Performs the transition whose target status name matches (case-insensitive). */
181
+ transitionTo(key: string, toStatus: string): Promise<{
182
+ transitionId: string;
183
+ toStatus: string;
184
+ }>;
185
+ /** Field ids the service account may edit on this issue (from editmeta). */
186
+ editableFields(key: string): Promise<string[]>;
187
+ /** Sets fields: labels (string[]), components (names), priority (name), customfield_N (raw JSON value). */
188
+ editFields(key: string, fields: Record<string, unknown>): Promise<void>;
189
+ linkTypes(opts?: TrackerCallOptions): Promise<Array<{
190
+ name: string;
191
+ inward: string;
192
+ outward: string;
193
+ }>>;
194
+ linkIssues(input: {
195
+ type: string;
196
+ inwardKey: string;
197
+ outwardKey: string;
198
+ }, opts?: TrackerCallOptions): Promise<void>;
199
+ /** Adds (or, for an existing globalId, updates) a web link on the issue: Jira's remote link, shown under "Web links". */
200
+ addRemoteLink(key: string, input: {
201
+ globalId: string;
202
+ url: string;
203
+ title: string;
204
+ status?: {
205
+ resolved: boolean;
206
+ };
207
+ }): Promise<void>;
208
+ /** The property's JSON value, or null when it does not exist. */
209
+ getProperty(key: string, property: string): Promise<unknown>;
210
+ setProperty(key: string, property: string, value: unknown): Promise<void>;
211
+ /** Issue types creatable in the project by the service account. */
212
+ createMeta(projectKey: string): Promise<{
213
+ issueTypes: CreateMetaIssueType[];
214
+ }>;
215
+ /** Create-screen fields for one issue type (by id). */
216
+ fieldMeta(projectKey: string, issueTypeId: string): Promise<CreateMetaField[]>;
217
+ /** Creates an issue; missing required fields (without defaults) fail with tracker_invalid_request naming them. */
218
+ createIssue(input: CreateIssueInput, opts?: TrackerCallOptions): Promise<{
219
+ key: string;
220
+ url: string;
221
+ }>;
222
+ /** First `maxBytes` of a text-like attachment, decoded as UTF-8; other types fail with tracker_invalid_request. */
223
+ readAttachmentText(id: string, maxBytes: number): Promise<{
224
+ filename: string;
225
+ mimeType: string;
226
+ text: string;
227
+ truncated: boolean;
228
+ }>;
229
+ }
230
+ export type IssueTrackerErrorCode = "tracker_not_found" | "tracker_permission_denied" | "tracker_rate_limited" | "tracker_invalid_request" | "tracker_api_error" | "tracker_invalid_response";
231
+ export declare class IssueTrackerError extends Error {
232
+ readonly code: IssueTrackerErrorCode;
233
+ constructor(code: IssueTrackerErrorCode, message?: string);
234
+ }
235
+ export type IssueTrackerRegistry = Partial<Record<IssueTrackerProvider, IssueTracker>>;
236
+ export type IssueEventKind = "created" | "transitioned" | "labeled" | "assigned" | "mention";
237
+ /** What a webhook adapter (jira-events.ts) normalises a payload into, for src/core/issue-events.ts. */
238
+ export interface IssueEvent {
239
+ provider: IssueTrackerProvider;
240
+ projectKey: string;
241
+ issueKey: string;
242
+ /** Every kind this one delivery represents (an update can transition AND label). */
243
+ kinds: IssueEventKind[];
244
+ actor: {
245
+ accountId: string;
246
+ displayName: string;
247
+ };
248
+ /** The new status name, with "transitioned". */
249
+ toStatus?: string;
250
+ /** Labels added by this change, with "labeled". */
251
+ addedLabels: string[];
252
+ /** The new assignee's accountId, with "assigned". */
253
+ assigneeAccountId?: string;
254
+ /** The mentioning comment, with "mention". */
255
+ comment?: {
256
+ id: string;
257
+ body: string;
258
+ };
259
+ /** Untrusted: whoever wrote them was not gated. Absent when the payload lacked the issue. */
260
+ subject?: {
261
+ summary: string;
262
+ description: string;
263
+ };
264
+ }
265
+ /** Shared by the ingress and the tools: a Jira issue key, e.g. PROJ-123. */
266
+ export declare const ISSUE_KEY: RegExp;
267
+ /** A Jira project key. */
268
+ export declare const PROJECT_KEY: RegExp;
269
+ export declare const projectOf: (issueKey: string) => string;
@@ -0,0 +1,16 @@
1
+ export const ISSUE_TRACKER_PROVIDERS = ["jira"];
2
+ /** The product name shown to people (e.g. in a pull request's "Resolves Jira issue …" line). */
3
+ export const ISSUE_TRACKER_NAMES = { jira: "Jira" };
4
+ export class IssueTrackerError extends Error {
5
+ code;
6
+ constructor(code, message = code) {
7
+ super(message);
8
+ this.code = code;
9
+ this.name = "IssueTrackerError";
10
+ }
11
+ }
12
+ /** Shared by the ingress and the tools: a Jira issue key, e.g. PROJ-123. */
13
+ export const ISSUE_KEY = /^[A-Z][A-Z0-9_]{0,254}-[1-9]\d{0,9}$/;
14
+ /** A Jira project key. */
15
+ export const PROJECT_KEY = /^[A-Z][A-Z0-9_]{0,254}$/;
16
+ export const projectOf = (issueKey) => issueKey.slice(0, issueKey.lastIndexOf("-"));
@@ -1,5 +1,6 @@
1
1
  import { type CollectExclusions } from "../../coding/collect-exclude.js";
2
2
  import type { CodingProvider } from "../../coding/provider.js";
3
+ import { type ServiceStateReporter } from "./service-state.js";
3
4
  import type { JobHandle, JobResult, JobSpec, JobStatus, WorkspaceJobLauncher } from "./types.js";
4
5
  /** How long one service image pull may take before the run fails as service_unready. */
5
6
  export declare const SERVICE_IMAGE_PULL_TIMEOUT_MS = 300000;
@@ -99,6 +100,8 @@ export interface DockerJobLauncherOptions {
99
100
  * DEFAULT_SERVICE_READY_TIMEOUT_MS). Start-up never runs past the run's own deadline either.
100
101
  */
101
102
  serviceReadyTimeoutMs?: number;
103
+ /** Display-only observer of each service's start-up state (the viewer); its errors are ignored. */
104
+ onServiceState?: ServiceStateReporter;
102
105
  /** Optional observer invoked after provisioning fails but before resources are cleaned up. */
103
106
  onProvisionFailure?: (context: {
104
107
  runId: string;
@@ -148,7 +151,8 @@ export declare class DockerJobLauncher implements WorkspaceJobLauncher {
148
151
  * attempt bounded by timeoutSeconds, failing after failureThreshold consecutive failures. A
149
152
  * service that exited or vanished fails at once, and so does one still unready when the start-up
150
153
  * budget runs out (each probe and wait is clipped to what is left of it). Probe output is never
151
- * logged or kept, so these errors carry no cause.
154
+ * logged or kept, so these errors carry no cause. Returns the number of probes made; records
155
+ * why it failed in `failure` for the display-only state report.
152
156
  */
153
157
  private waitForServiceReady;
154
158
  private refresh;
@@ -12,6 +12,7 @@ import { assertDockerHostSupportsIsolation, assertClaudeAgentContainerInspection
12
12
  import { serviceUnreadyError } from "../../coding/services/wording.js";
13
13
  import { assertServiceContainerInspection, buildDockerServicePlan, dockerServiceContainerNames, } from "./docker-services.js";
14
14
  import { claudeToolSetup } from "./claude-tool-setup.js";
15
+ import { reportServiceState, } from "./service-state.js";
15
16
  import { replaceDirectoryFromStaging } from "./workspace-swap.js";
16
17
  const BACKEND = "docker";
17
18
  const STATE_SCHEMA_VERSION = 1;
@@ -773,41 +774,61 @@ export class DockerJobLauncher {
773
774
  if (!keeperId)
774
775
  throw new Error("docker_resource_attestation_failed");
775
776
  await this.startContainer(keeperName);
777
+ const report = (name, update) => reportServiceState(this.options.onServiceState, { runId: record.runId, name, ...update });
778
+ for (const planned of services)
779
+ await report(planned.service.name, { state: "pending" });
776
780
  for (const planned of services) {
777
781
  const name = planned.service.name;
778
- if (budget.remainingMs() <= 0)
779
- throw serviceUnready(name);
780
- await this.ensureServiceImage(planned, budget);
781
- if (budget.remainingMs() <= 0)
782
- throw serviceUnready(name);
783
- let createFailure;
782
+ const failure = { reason: "image_unavailable" };
783
+ let attempts;
784
784
  try {
785
- await this.createAndAssert(appendLabels(planned.createArgs, labels), ["container", "inspect", planned.container], (value) => {
786
- const inspected = value;
787
- assertServiceContainerInspection(inspected, record.spec, planned.service, keeperId);
788
- if (!labelsMatch(inspected.Config?.Labels, labels))
789
- throw new Error("docker_resource_attestation_failed");
790
- }, undefined, (error) => {
791
- createFailure = error;
792
- });
785
+ if (budget.remainingMs() <= 0)
786
+ throw serviceUnready(name);
787
+ await this.ensureServiceImage(planned, budget);
788
+ if (budget.remainingMs() <= 0)
789
+ throw serviceUnready(name);
790
+ failure.reason = "start_failed";
791
+ let createFailure;
792
+ try {
793
+ await this.createAndAssert(appendLabels(planned.createArgs, labels), ["container", "inspect", planned.container], (value) => {
794
+ const inspected = value;
795
+ assertServiceContainerInspection(inspected, record.spec, planned.service, keeperId);
796
+ if (!labelsMatch(inspected.Config?.Labels, labels))
797
+ throw new Error("docker_resource_attestation_failed");
798
+ }, undefined, (error) => {
799
+ createFailure = error;
800
+ });
801
+ }
802
+ catch (error) {
803
+ // createAndAssert tolerates a failed create (a crash retry may find it made), so a service
804
+ // Docker refused to create shows up as a failed inspection; the create's own failure is the
805
+ // useful cause, not that generic "not found". Attestation failures rethrow as is.
806
+ if (error instanceof DockerCommandError)
807
+ throw serviceUnready(name, createFailure ?? error);
808
+ throw error;
809
+ }
810
+ if (budget.remainingMs() <= 0)
811
+ throw serviceUnready(name);
812
+ try {
813
+ await this.startContainer(planned.container);
814
+ }
815
+ catch (error) {
816
+ throw serviceUnready(name, error);
817
+ }
818
+ failure.reason = "probe_failed";
819
+ await report(name, { state: "probing", attempts: 0 });
820
+ attempts = await this.waitForServiceReady(planned, budget, failure, (made) => report(name, { state: "probing", attempts: made }));
793
821
  }
794
822
  catch (error) {
795
- // createAndAssert tolerates a failed create (a crash retry may find it made), so a service
796
- // Docker refused to create shows up as a failed inspection; the create's own failure is the
797
- // useful cause, not that generic "not found". Attestation failures rethrow as is.
798
- if (error instanceof DockerCommandError)
799
- throw serviceUnready(name, createFailure ?? error);
823
+ const reason = failure.reason !== "exited" && budget.remainingMs() <= 0 ? "timed_out" : failure.reason;
824
+ await report(name, {
825
+ state: "failed",
826
+ reason,
827
+ ...(failure.attempts === undefined ? {} : { attempts: failure.attempts }),
828
+ });
800
829
  throw error;
801
830
  }
802
- if (budget.remainingMs() <= 0)
803
- throw serviceUnready(name);
804
- try {
805
- await this.startContainer(planned.container);
806
- }
807
- catch (error) {
808
- throw serviceUnready(name, error);
809
- }
810
- await this.waitForServiceReady(planned, budget);
831
+ await report(name, { state: "ready", attempts });
811
832
  }
812
833
  return keeperId;
813
834
  }
@@ -844,9 +865,10 @@ export class DockerJobLauncher {
844
865
  * attempt bounded by timeoutSeconds, failing after failureThreshold consecutive failures. A
845
866
  * service that exited or vanished fails at once, and so does one still unready when the start-up
846
867
  * budget runs out (each probe and wait is clipped to what is left of it). Probe output is never
847
- * logged or kept, so these errors carry no cause.
868
+ * logged or kept, so these errors carry no cause. Returns the number of probes made; records
869
+ * why it failed in `failure` for the display-only state report.
848
870
  */
849
- async waitForServiceReady(planned, budget) {
871
+ async waitForServiceReady(planned, budget, failure, onProbeFailed) {
850
872
  const { command, periodSeconds, timeoutSeconds, failureThreshold } = planned.service.readiness;
851
873
  const name = planned.service.name;
852
874
  let failures = 0;
@@ -858,12 +880,16 @@ export class DockerJobLauncher {
858
880
  state = await this.inspect(["container", "inspect", planned.container]);
859
881
  }
860
882
  catch (error) {
861
- if (error instanceof DockerCommandError)
883
+ if (error instanceof DockerCommandError) {
884
+ failure.reason = "exited";
862
885
  throw serviceUnready(name);
886
+ }
863
887
  throw error;
864
888
  }
865
- if (state.State?.Running !== true)
889
+ if (state.State?.Running !== true) {
890
+ failure.reason = "exited";
866
891
  throw serviceUnready(name);
892
+ }
867
893
  const remaining = budget.remainingMs();
868
894
  if (remaining <= 0)
869
895
  throw serviceUnready(name);
@@ -872,13 +898,15 @@ export class DockerJobLauncher {
872
898
  timeoutMs: Math.min(timeoutSeconds * 1_000, remaining),
873
899
  maxOutputBytes: MAX_SERVICE_PROBE_OUTPUT_BYTES,
874
900
  });
875
- return;
901
+ return failures + 1;
876
902
  }
877
903
  catch {
878
904
  failures += 1;
905
+ failure.attempts = failures;
879
906
  if (failures >= failureThreshold)
880
907
  throw serviceUnready(name);
881
908
  }
909
+ await onProbeFailed(failures);
882
910
  const wait = Math.min(periodSeconds * 1_000, budget.remainingMs());
883
911
  if (wait <= 0)
884
912
  throw serviceUnready(name);
@@ -1,6 +1,7 @@
1
1
  import { type Readable } from "node:stream";
2
2
  import type { KubernetesJobConfig } from "../../config/providers.js";
3
3
  import { type KubernetesApi } from "./kubernetes-api.js";
4
+ import { type ServiceStateReporter } from "./service-state.js";
4
5
  import type { CodingProvider } from "../../coding/provider.js";
5
6
  import type { JobHandle, JobResult, JobSpec, JobStatus, WorkspaceJobLauncher } from "./types.js";
6
7
  export interface KubernetesClusterInfo {
@@ -38,6 +39,8 @@ export interface KubernetesJobLauncherOptions {
38
39
  stream: Readable;
39
40
  done: Promise<number>;
40
41
  };
42
+ /** Display-only observer of each service sidecar's start-up state (the viewer); its errors are ignored. */
43
+ onServiceState?: ServiceStateReporter;
41
44
  onWarning?: (message: string) => void;
42
45
  }
43
46
  /** Archives a trusted local directory with the host's `tar`, under a minimal environment. */
@@ -37,6 +37,7 @@ import { ENFORCEMENT_PROBE_DENY_REACHABLE, ENFORCEMENT_PROBE_PROVEN, ENFORCEMENT
37
37
  import { claudeToolSetup } from "./claude-tool-setup.js";
38
38
  import { readProxyWitness } from "./kubernetes-witness.js";
39
39
  import { safeExtract } from "./safe-extract.js";
40
+ import { reportServiceState, } from "./service-state.js";
40
41
  import { serviceUnreadyError } from "../../coding/services/wording.js";
41
42
  import { replaceDirectoryFromStaging } from "./workspace-swap.js";
42
43
  import { collectExclusions, normalizeCollectExclusions, tarExcludeArgs, } from "../../coding/collect-exclude.js";
@@ -156,6 +157,29 @@ const FATAL_WAITING_REASONS = new Set([
156
157
  "CreateContainerError",
157
158
  "CrashLoopBackOff",
158
159
  ]);
160
+ const IMAGE_WAITING_REASONS = new Set(["ErrImagePull", "ImagePullBackOff", "InvalidImageName"]);
161
+ /**
162
+ * A service sidecar's start-up state as the pod status shows it. The kubelet runs the startup
163
+ * probe, so attempt counts are unknown here; checks mirror waitForKeeper's own failure rules.
164
+ */
165
+ function observedServiceState(status) {
166
+ if (status === undefined)
167
+ return { state: "pending" };
168
+ if ((status.restartCount ?? 0) > 0)
169
+ return { state: "failed", reason: "probe_failed" };
170
+ const waiting = status.state?.waiting?.reason ?? "";
171
+ if (IMAGE_WAITING_REASONS.has(waiting))
172
+ return { state: "failed", reason: "image_unavailable" };
173
+ if (FATAL_WAITING_REASONS.has(waiting))
174
+ return { state: "failed", reason: "start_failed" };
175
+ if (status.state?.terminated !== undefined)
176
+ return { state: "failed", reason: "exited" };
177
+ if (status.started === true)
178
+ return { state: "ready" };
179
+ if (status.state?.running !== undefined)
180
+ return { state: "probing" };
181
+ return { state: "pending" };
182
+ }
159
183
  const CAPABILITY = /^rrp_[A-Za-z0-9_-]{16,512}$/;
160
184
  const TOKEN = /^[a-f0-9]{20}$/;
161
185
  const WORKSPACE_STORAGE = `${STORAGE_ROOT}/workspace`;
@@ -635,7 +659,7 @@ export class KubernetesJobLauncher {
635
659
  await this.createIfMissing(() => this.api.createSecret(this.namespace, buildCapabilitySecret(spec, this.namespace, capability, toolSetup)));
636
660
  await this.createIfMissing(() => this.api.createNetworkPolicy(this.namespace, policy));
637
661
  await this.createIfMissing(() => this.api.createPod(this.namespace, pod));
638
- await this.waitForKeeper(names, (spec.services ?? []).map((service) => service.name), spec.provider === "claude-code");
662
+ await this.waitForKeeper(names, spec.runId, (spec.services ?? []).map((service) => service.name), spec.provider === "claude-code");
639
663
  const [actualPod, actualPolicy] = await Promise.all([
640
664
  this.api.readPod(this.namespace, names.pod),
641
665
  this.api.readNetworkPolicy(this.namespace, names.policy),
@@ -679,8 +703,16 @@ export class KubernetesJobLauncher {
679
703
  throw error;
680
704
  }
681
705
  }
682
- async waitForKeeper(names, serviceNames, toolRunner = false) {
706
+ async waitForKeeper(names, runId, serviceNames, toolRunner = false) {
683
707
  const started = this.now();
708
+ const reported = new Map();
709
+ const report = async (name, observed) => {
710
+ const key = `${observed.state}:${observed.reason ?? ""}`;
711
+ if (reported.get(name) === key)
712
+ return;
713
+ reported.set(name, key);
714
+ await reportServiceState(this.options.onServiceState, { runId, name, ...observed });
715
+ };
684
716
  for (;;) {
685
717
  const pod = await this.api.readPod(this.namespace, names.pod);
686
718
  if (!pod || pod.status?.phase === "Failed")
@@ -688,6 +720,8 @@ export class KubernetesJobLauncher {
688
720
  const statuses = pod.status?.containerStatuses ?? [];
689
721
  const initStatuses = pod.status?.initContainerStatuses ?? [];
690
722
  const sidecar = (name) => initStatuses.find((status) => status.name === serviceContainerName(name));
723
+ for (const name of serviceNames)
724
+ await report(name, observedServiceState(sidecar(name)));
691
725
  // A service sidecar that restarted (its startup probe gave up), can't be pulled or created, or
692
726
  // exited will never let the keeper start. Name the service rather than a generic start failure.
693
727
  const failedService = serviceNames.find((name) => {
@@ -711,8 +745,12 @@ export class KubernetesJobLauncher {
711
745
  keeper?.state?.terminated !== undefined) {
712
746
  throw new Error("kubernetes_pod_start_failed");
713
747
  }
714
- if (keeper?.ready === true)
748
+ if (keeper?.ready === true) {
749
+ // Native sidecars start in order before the keeper, so a ready keeper means every service started.
750
+ for (const name of serviceNames)
751
+ await report(name, { state: "ready" });
715
752
  return;
753
+ }
716
754
  if (this.now() - started >= this.readyTimeoutMs) {
717
755
  if (toolRunner && toolStatus?.started !== true) {
718
756
  throw new Error("kubernetes_tool_runner_unready");
@@ -720,8 +758,10 @@ export class KubernetesJobLauncher {
720
758
  // At the bound, a service that never passed its startup probe (still pulling, still starting)
721
759
  // is why the keeper never started.
722
760
  const waiting = serviceNames.find((name) => sidecar(name)?.started !== true);
723
- if (waiting !== undefined)
761
+ if (waiting !== undefined) {
762
+ await report(waiting, { state: "failed", reason: "timed_out" });
724
763
  throw serviceUnreadyError(waiting);
764
+ }
725
765
  throw new Error("kubernetes_pod_start_timeout");
726
766
  }
727
767
  await this.sleep(READY_POLL_MS);
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Display-only observation of coding-run service start-up (docs/coding-services.md): launchers
3
+ * report each service's state as they see it, for the viewer. Never part of the launch's own
4
+ * control flow: a reporter error is swallowed. The launcher does await each report inline,
5
+ * though, so a reporter must be fast.
6
+ */
7
+ export type ServiceState = "pending" | "probing" | "ready" | "failed";
8
+ /** Fixed identifiers only: never probe output, container logs, or anything from the repository. */
9
+ export type ServiceFailureReason = "image_unavailable" | "start_failed" | "exited" | "probe_failed" | "timed_out";
10
+ export interface ServiceStateUpdate {
11
+ runId: string;
12
+ /** The catalog service name (CodingService.name). */
13
+ name: string;
14
+ state: ServiceState;
15
+ /** Readiness probes completed so far; only launchers that run the probe themselves (Docker) know it. */
16
+ attempts?: number;
17
+ /** Set only with state "failed". */
18
+ reason?: ServiceFailureReason;
19
+ }
20
+ export type ServiceStateReporter = (update: ServiceStateUpdate) => Promise<void>;
21
+ /** Calls `reporter` if there is one; any error it throws is dropped (status is display-only). */
22
+ export declare function reportServiceState(reporter: ServiceStateReporter | undefined, update: ServiceStateUpdate): Promise<void>;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Display-only observation of coding-run service start-up (docs/coding-services.md): launchers
3
+ * report each service's state as they see it, for the viewer. Never part of the launch's own
4
+ * control flow: a reporter error is swallowed. The launcher does await each report inline,
5
+ * though, so a reporter must be fast.
6
+ */
7
+ /** Calls `reporter` if there is one; any error it throws is dropped (status is display-only). */
8
+ export async function reportServiceState(reporter, update) {
9
+ if (!reporter)
10
+ return;
11
+ try {
12
+ await reporter(update);
13
+ }
14
+ catch {
15
+ // Display-only: a lost update must never fail or slow a launch.
16
+ }
17
+ }
@@ -2,12 +2,12 @@
2
2
  * Direct Anthropic (Claude) adapter for the LlmProvider seam. `@anthropic-ai/sdk`
3
3
  * is imported only here; all protocol/pricing-dispatch logic lives in the
4
4
  * shared ClaudeLlmProvider base class (claude-provider.ts) — this file's only
5
- * job is constructing the right client and pricing module.
5
+ * job is constructing the right client.
6
6
  */
7
7
  import Anthropic from "@anthropic-ai/sdk";
8
8
  import { ClaudeLlmProvider } from "./claude-provider.js";
9
- export { anthropicSupportedModels } from "./pricing-anthropic.js";
9
+ import type { CatalogLookup } from "./catalog-lookup.js";
10
10
  export declare function anthropicCredentialsPresent(env?: NodeJS.ProcessEnv): boolean;
11
11
  export declare class AnthropicLlmProvider extends ClaudeLlmProvider {
12
- constructor(apiKey?: string, client?: Anthropic);
12
+ constructor(apiKey?: string, client?: Anthropic, lookup?: CatalogLookup);
13
13
  }
@@ -2,24 +2,18 @@
2
2
  * Direct Anthropic (Claude) adapter for the LlmProvider seam. `@anthropic-ai/sdk`
3
3
  * is imported only here; all protocol/pricing-dispatch logic lives in the
4
4
  * shared ClaudeLlmProvider base class (claude-provider.ts) — this file's only
5
- * job is constructing the right client and pricing module.
5
+ * job is constructing the right client.
6
6
  */
7
7
  import Anthropic from "@anthropic-ai/sdk";
8
8
  import { ClaudeLlmProvider } from "./claude-provider.js";
9
- import { anthropicPriceUsd, anthropicSupportedEfforts, getAnthropicPricing } from "./pricing-anthropic.js";
10
- export { anthropicSupportedModels } from "./pricing-anthropic.js";
11
9
  export function anthropicCredentialsPresent(env = process.env) {
12
10
  return Boolean(env.ANTHROPIC_API_KEY);
13
11
  }
14
12
  export class AnthropicLlmProvider extends ClaudeLlmProvider {
15
- constructor(apiKey = process.env.ANTHROPIC_API_KEY ?? "", client) {
13
+ constructor(apiKey = process.env.ANTHROPIC_API_KEY ?? "", client, lookup) {
16
14
  if (!client && !apiKey) {
17
15
  throw new Error("ANTHROPIC_API_KEY is not set — required by the Anthropic LlmProvider adapter.");
18
16
  }
19
- super(client ?? new Anthropic({ apiKey }), {
20
- getPricing: getAnthropicPricing,
21
- priceUsd: anthropicPriceUsd,
22
- supportedEfforts: anthropicSupportedEfforts,
23
- });
17
+ super(client ?? new Anthropic({ apiKey }), lookup);
24
18
  }
25
19
  }