@cat-factory/node-server 0.107.10 → 0.107.12

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 (33) hide show
  1. package/dist/container-account-deps.d.ts +40 -0
  2. package/dist/container-account-deps.d.ts.map +1 -0
  3. package/dist/container-account-deps.js +142 -0
  4. package/dist/container-account-deps.js.map +1 -0
  5. package/dist/container-executor-deps.d.ts +26 -4
  6. package/dist/container-executor-deps.d.ts.map +1 -1
  7. package/dist/container-executor-deps.js +2 -13
  8. package/dist/container-executor-deps.js.map +1 -1
  9. package/dist/container-github-deps.d.ts +56 -0
  10. package/dist/container-github-deps.d.ts.map +1 -0
  11. package/dist/container-github-deps.js +275 -0
  12. package/dist/container-github-deps.js.map +1 -0
  13. package/dist/container-model-deps.d.ts +50 -0
  14. package/dist/container-model-deps.d.ts.map +1 -0
  15. package/dist/container-model-deps.js +127 -0
  16. package/dist/container-model-deps.js.map +1 -0
  17. package/dist/container-realtime-deps.d.ts +34 -0
  18. package/dist/container-realtime-deps.d.ts.map +1 -0
  19. package/dist/container-realtime-deps.js +112 -0
  20. package/dist/container-realtime-deps.js.map +1 -0
  21. package/dist/container-run-services-deps.d.ts +44 -0
  22. package/dist/container-run-services-deps.d.ts.map +1 -0
  23. package/dist/container-run-services-deps.js +148 -0
  24. package/dist/container-run-services-deps.js.map +1 -0
  25. package/dist/container-transport-deps.d.ts +72 -0
  26. package/dist/container-transport-deps.d.ts.map +1 -0
  27. package/dist/container-transport-deps.js +88 -0
  28. package/dist/container-transport-deps.js.map +1 -0
  29. package/dist/container.d.ts +2 -2
  30. package/dist/container.d.ts.map +1 -1
  31. package/dist/container.js +144 -742
  32. package/dist/container.js.map +1 -1
  33. package/package.json +12 -12
@@ -0,0 +1,275 @@
1
+ import { GitHubIssuesProvider, IssueWritebackService, JiraProvider, LinearTaskProvider, githubIssuesLogic, } from '@cat-factory/integrations';
2
+ import { FetchGitHubClient, FetchGitHubProvisioningClient, GitHubBranchUpdater, GitHubCiStatusProvider, GitHubDocQualityProvider, GitHubMergeabilityProvider, GitHubPullRequestMerger, GitHubPullRequestReviewProvider, PatPreferringAppRegistry, WebCryptoSecretCipher, WebCryptoWebhookVerifier, makeResolveRepoFilesForCoords, makeResolveRunRepoContext, } from '@cat-factory/server';
3
+ import { wireCiStatusProvider, wireDocQualityProvider, wireMergeabilityProvider, wirePullRequestReviewProvider, } from '@cat-factory/gates';
4
+ import { buildNodeGitHubIssueFiler } from './container-executor-deps.js';
5
+ import { DrizzleDocumentRepository } from './repositories/documents.js';
6
+ import { DrizzleBranchProjectionRepository, DrizzleCheckRunProjectionRepository, DrizzleCommitProjectionRepository, DrizzleIssueProjectionRepository, DrizzlePullRequestProjectionRepository, } from './repositories/github.js';
7
+ import { DrizzleTaskConnectionRepository, DrizzleTaskRepository, DrizzleTaskSourceSettingsRepository, } from './repositories/tasks.js';
8
+ import { DrizzleUserRepoAccessRepository } from './repositories/userRepoAccess.js';
9
+ // The engine's CI/mergeability gate reads never persist rate-limit snapshots (that is the
10
+ // GitHub sync/webhook path's job), so the client backing them takes a no-op rate-limit store.
11
+ class NoopRateLimitRepository {
12
+ record(_snapshot) {
13
+ return Promise.resolve();
14
+ }
15
+ deleteOlderThan(_epochMs) {
16
+ return Promise.resolve(0);
17
+ }
18
+ }
19
+ /**
20
+ * Wire the task-source integration for the Node facade (Jira + Linear always; GitHub Issues
21
+ * only when a GitHub client is available, since it reuses the workspace's App installation).
22
+ * Mirrors the Cloudflare facade's `config.github.enabled` gate (see CLAUDE.md parity rule).
23
+ * Whether a workspace OFFERS a source is the per-workspace toggle (task_source_settings), not
24
+ * a deployment env gate.
25
+ */
26
+ function selectNodeTasksDeps(config, db, githubClient, installations) {
27
+ if (!config.tasks.enabled || !config.tasks.encryptionKey)
28
+ return { deps: {} };
29
+ // Jira and Linear are always registered (their credentials are per-workspace, entered in the UI).
30
+ const providers = [new JiraProvider(), new LinearTaskProvider()];
31
+ // GitHub Issues reuse the workspace's installed GitHub App, so this provider is
32
+ // wired whenever a GitHub client is available (the App is configured) — it has no
33
+ // credentials of its own and resolves the installation per issue.
34
+ if (githubClient) {
35
+ providers.push(new GitHubIssuesProvider({ githubClient, installations }));
36
+ }
37
+ const taskConnectionRepository = new DrizzleTaskConnectionRepository(db,
38
+ // Source credentials are encrypted at rest under a tasks-scoped HKDF info (the
39
+ // same domain the Cloudflare facade uses), keyed by the shared ENCRYPTION_KEY.
40
+ new WebCryptoSecretCipher({
41
+ masterKeyBase64: config.tasks.encryptionKey,
42
+ info: 'cat-factory:tasks',
43
+ }));
44
+ return {
45
+ deps: {
46
+ taskSourceProviders: providers,
47
+ taskConnectionRepository,
48
+ taskSourceSettingsRepository: new DrizzleTaskSourceSettingsRepository(db),
49
+ taskRepository: new DrizzleTaskRepository(db),
50
+ },
51
+ taskConnectionRepository,
52
+ };
53
+ }
54
+ /**
55
+ * The GitHub-client-dependent slice of the Node composition root, lifted out of
56
+ * `buildNodeContainer` so that root stays within the file-size budget (the same reason
57
+ * `container-executor-deps.ts` / `container-content-library-deps.ts` exist). Mirrors the
58
+ * Worker's `selectGitHubDeps`: build the engine's GitHub client, wire the CI / mergeability /
59
+ * review / doc-quality gate providers onto the app-owned `providerRegistry`, and assemble the
60
+ * GitHub gate + projection/sync module deps. As a side effect it registers the gate providers;
61
+ * call it at the point the region occupied so the ordering (before `applyGateProviders`) holds.
62
+ */
63
+ export function selectNodeGitHubDeps(input) {
64
+ const { config, db, remoteRepos, sourced, idGenerator, clock, appRegistry, githubClientOverride, resolveUserGitHubToken, gitlabEngineClient, providerRegistry, resolveRepoTarget, githubInstallationRepository, repoProjectionRepository, blockRepository, trackerSettingsRepository, caches, } = input;
65
+ // GitHub-issue tracker: file the tech-debt pipeline's issue through the workspace's
66
+ // own GitHub App installation (per-tenant), resolving the service's repo from the
67
+ // github_repos projection — the same per-tenant infra the container executor uses.
68
+ const fileGitHubIssue = buildNodeGitHubIssueFiler(config, appRegistry, resolveRepoTarget);
69
+ // The GitHub client backing the CI gate + merge / mergeability providers: an injected
70
+ // one wins (the local facade supplies a PAT-backed client), else — when the GitHub App
71
+ // is configured — one minted from the shared App registry, so a stock Node deployment
72
+ // with an App ALSO gates on real GitHub Actions CI and merges the PR for real (parity
73
+ // with the Worker). Undefined → these stay unwired and the gates pass through.
74
+ // Prefer the run initiator's per-user PAT (when stored) over the App token for the
75
+ // engine's CI gate + merge reads, so those are attributed to them too. The engine
76
+ // sets the initiator in ambient context around the gate-probe / merge boundaries.
77
+ const engineRegistry = appRegistry && resolveUserGitHubToken
78
+ ? new PatPreferringAppRegistry(appRegistry, resolveUserGitHubToken)
79
+ : appRegistry;
80
+ const githubClient = githubClientOverride ??
81
+ (engineRegistry
82
+ ? new FetchGitHubClient({
83
+ registry: engineRegistry,
84
+ rateLimitRepository: new NoopRateLimitRepository(),
85
+ idGenerator,
86
+ clock,
87
+ apiBase: config.github.apiBase,
88
+ })
89
+ : undefined);
90
+ // The client the engine's gate / merge / RepoFiles seams read through: the real GitHub client
91
+ // when present, else the GitLab-backed fallback so a GitLab-only deployment still gates on real
92
+ // CI and merges for real (the GitHub App wins when both are configured). Kept SEPARATE from
93
+ // `githubClient` on purpose — the GitHub-issue-specific consumers below (the GitHub Issues task
94
+ // source, issue writeback, the App projection module) must NOT be fed the GitLab client, or a
95
+ // GitLab-only deployment would offer a non-functional "GitHub Issues" source (it resolves the
96
+ // empty github_installations projection). Parity with the Worker, which keeps the App client
97
+ // distinct from its GitLab engine fallback.
98
+ const engineVcsClient = githubClient ?? gitlabEngineClient;
99
+ // Task-source integration (Jira + GitHub issues). Tenants connect their own Jira
100
+ // site through the UI (credentials stored per-workspace, encrypted at rest); the
101
+ // tracker resolves each workspace's own credentials from this same store. GitHub
102
+ // issues reuse the workspace's installed App, so they wire only when `githubClient`
103
+ // is available — kept here, after the client is built, for parity with the Worker.
104
+ const tasks = selectNodeTasksDeps(config, db, githubClient, githubInstallationRepository);
105
+ // Issue-tracker writeback (comment-on-PR-open + close-on-merge of a task's linked
106
+ // issue), gated per workspace + per task inside the provider. GitHub uses the same
107
+ // per-tenant client + installation lookup as the tracker/CI/merge providers; Jira
108
+ // reuses the workspace's encrypted connection. Wired whenever the tracker-settings
109
+ // repo exists (always on Node) so the engine can write back when a tracker is set.
110
+ const resolveWritebackIssue = githubClient
111
+ ? async (workspaceId, externalId) => {
112
+ const parsed = githubIssuesLogic.parseGitHubIssueExternalId(externalId);
113
+ if (!parsed)
114
+ return null;
115
+ const installation = await githubInstallationRepository.getByWorkspace(workspaceId);
116
+ if (!installation)
117
+ return null;
118
+ return { installationId: installation.installationId, parsed };
119
+ }
120
+ : undefined;
121
+ const issueWritebackProvider = new IssueWritebackService({
122
+ trackerSettingsRepository,
123
+ taskRepository: sourced('taskRepository', (d) => new DrizzleTaskRepository(d)),
124
+ fetchImpl: fetch,
125
+ ...(githubClient && resolveWritebackIssue
126
+ ? {
127
+ commentOnGitHubIssue: async (workspaceId, externalId, body) => {
128
+ const target = await resolveWritebackIssue(workspaceId, externalId);
129
+ if (!target)
130
+ return;
131
+ await githubClient.comment(target.installationId, { owner: target.parsed.owner, repo: target.parsed.repo }, target.parsed.number, body);
132
+ },
133
+ closeGitHubIssue: async (workspaceId, externalId) => {
134
+ const target = await resolveWritebackIssue(workspaceId, externalId);
135
+ if (!target)
136
+ return;
137
+ await githubClient.closeIssue(target.installationId, { owner: target.parsed.owner, repo: target.parsed.repo }, target.parsed.number);
138
+ },
139
+ labelGitHubIssue: async (workspaceId, externalId, label) => {
140
+ const target = await resolveWritebackIssue(workspaceId, externalId);
141
+ if (!target)
142
+ return;
143
+ await githubClient.applyIssueLabel?.(target.installationId, { owner: target.parsed.owner, repo: target.parsed.repo }, target.parsed.number, label);
144
+ },
145
+ }
146
+ : {}),
147
+ ...(tasks.taskConnectionRepository
148
+ ? {
149
+ resolveJiraConnection: async (workspaceId) => {
150
+ const connection = await tasks.taskConnectionRepository.getByWorkspace(workspaceId, 'jira');
151
+ const { baseUrl, accountEmail, apiToken } = connection?.credentials ?? {};
152
+ if (!baseUrl || !accountEmail || !apiToken)
153
+ return null;
154
+ return { baseUrl, accountEmail, apiToken };
155
+ },
156
+ resolveLinearConnection: async (workspaceId) => {
157
+ const connection = await tasks.taskConnectionRepository.getByWorkspace(workspaceId, 'linear');
158
+ const { apiKey, token } = connection?.credentials ?? {};
159
+ return apiKey || token ? { apiKey, token } : null;
160
+ },
161
+ }
162
+ : {}),
163
+ });
164
+ let githubGateDeps = {};
165
+ if (engineVcsClient) {
166
+ // The `ci` / `conflicts` gates now live in `@cat-factory/gates`; wire their providers into
167
+ // the gate suite instead of onto the engine's CoreDependencies (single-process startup, so
168
+ // the deployment-global handles are set once here). Parity with the Worker's selectGitHubDeps.
169
+ // These read through `engineVcsClient` (GitHub App or the GitLab fallback), so a GitLab-only
170
+ // deployment gates + merges for real too.
171
+ wireCiStatusProvider(providerRegistry, new GitHubCiStatusProvider({
172
+ githubClient: engineVcsClient,
173
+ resolveRepoTarget,
174
+ blockRepository,
175
+ }));
176
+ wireMergeabilityProvider(providerRegistry, new GitHubMergeabilityProvider({
177
+ githubClient: engineVcsClient,
178
+ resolveRepoTarget,
179
+ blockRepository,
180
+ }));
181
+ wirePullRequestReviewProvider(providerRegistry, new GitHubPullRequestReviewProvider({
182
+ githubClient: engineVcsClient,
183
+ resolveRepoTarget,
184
+ blockRepository,
185
+ }));
186
+ wireDocQualityProvider(providerRegistry, new GitHubDocQualityProvider({
187
+ githubClient: engineVcsClient,
188
+ resolveRepoTarget,
189
+ blockRepository,
190
+ // The gate resolves a workspace-linked template (WS1) for the block's kind, so it checks
191
+ // against the SAME sections the doc-writer followed. In db-less mothership mode the writer
192
+ // resolves the template through the RPC-proxied documents repo (getRoleLink is run-path
193
+ // allow-listed), so the gate MUST use that same repo — not `undefined` — or a doc written
194
+ // to the workspace template would be graded against the built-in skeleton (writer/gate drift).
195
+ documentRepository: db
196
+ ? new DrizzleDocumentRepository(db)
197
+ : remoteRepos?.documentRepository,
198
+ }));
199
+ githubGateDeps = {
200
+ // The engine binds a registered custom kind's pre/post-op hooks to a run's repo
201
+ // via this checkout-free RepoFiles resolver, composed from the same client +
202
+ // repo-target walk the gates/merger use — parity with the Worker. The `repoFiles`
203
+ // cache (slice 4) makes the post-op idempotency re-reads a read-through hit.
204
+ resolveRunRepoContext: makeResolveRunRepoContext(engineVcsClient, resolveRepoTarget, caches?.repoFiles),
205
+ // Block-less repo resolver for the environments module's on-demand repo
206
+ // validation / config bootstrap (operator names owner+repo).
207
+ resolveRepoFilesForCoords: makeResolveRepoFilesForCoords(engineVcsClient, githubInstallationRepository, repoProjectionRepository),
208
+ branchUpdater: new GitHubBranchUpdater({
209
+ githubClient: engineVcsClient,
210
+ resolveRepoTarget,
211
+ blockRepository,
212
+ }),
213
+ pullRequestMerger: new GitHubPullRequestMerger({
214
+ githubClient: engineVcsClient,
215
+ resolveRepoTarget,
216
+ blockRepository,
217
+ }),
218
+ };
219
+ }
220
+ // GitHub installation + projections + sync/webhook module: wired when the App is
221
+ // configured (a real githubClient), mirroring the Worker's selectGitHubDeps. This
222
+ // turns the GitHub read endpoints + the inline webhook/backfill sync on for Node —
223
+ // the sync engine (GitHubSyncService) is runtime-neutral, so populating the
224
+ // projection repos here makes the inline ingest actually persist (parity with the
225
+ // Worker, which fans the same sync through a queue/Workflow). `canCreateRepos` /
226
+ // `workflowsGranted` come from the App registry when present (advisory).
227
+ const githubModuleDeps = config.github.enabled && githubClient
228
+ ? {
229
+ githubClient,
230
+ githubInstallationRepository,
231
+ repoProjectionRepository,
232
+ // The five GitHub projection repos share one shape (remote in mothership mode, else
233
+ // Drizzle over `db`), routed through the shared `sourced` helper.
234
+ branchProjectionRepository: sourced('branchProjectionRepository', (d) => new DrizzleBranchProjectionRepository(d)),
235
+ pullRequestProjectionRepository: sourced('pullRequestProjectionRepository', (d) => new DrizzlePullRequestProjectionRepository(d)),
236
+ issueProjectionRepository: sourced('issueProjectionRepository', (d) => new DrizzleIssueProjectionRepository(d)),
237
+ commitProjectionRepository: sourced('commitProjectionRepository', (d) => new DrizzleCommitProjectionRepository(d)),
238
+ checkRunProjectionRepository: sourced('checkRunProjectionRepository', (d) => new DrizzleCheckRunProjectionRepository(d)),
239
+ // Per-user PAT-reachable repo projection (picker expansion + redaction); Postgres-only,
240
+ // so absent in a no-DB mothership node (the picker keeps its App-only behaviour there).
241
+ userRepoAccessRepository: db ? new DrizzleUserRepoAccessRepository(db) : undefined,
242
+ webhookVerifier: new WebCryptoWebhookVerifier(config.github.webhookSecret),
243
+ // Bound the initial backfill to the commit retention horizon (0 = full).
244
+ commitBackfillHorizonMs: config.retention.commitMs || undefined,
245
+ ...(appRegistry
246
+ ? {
247
+ // Privileged App tier (ADR 0005): when configured, its client backs the
248
+ // create-repo endpoint; `canCreateRepos` flags a connection whose
249
+ // installation is owned by the privileged App. Absent → repo creation
250
+ // stays the manual flow (parity with the Worker's selectGitHubDeps).
251
+ repoProvisioningClient: config.github.privilegedApp
252
+ ? new FetchGitHubProvisioningClient({
253
+ registry: appRegistry,
254
+ apiBase: config.github.apiBase,
255
+ })
256
+ : undefined,
257
+ canCreateRepos: (installation) => appRegistry.canCreateRepos(installation),
258
+ workflowsGranted: async (installation) => {
259
+ const perms = await appRegistry.installationPermissions(installation.installationId);
260
+ return perms.workflows === 'write';
261
+ },
262
+ }
263
+ : {}),
264
+ }
265
+ : {};
266
+ return {
267
+ githubClient,
268
+ tasks,
269
+ fileGitHubIssue,
270
+ issueWritebackProvider,
271
+ githubGateDeps,
272
+ githubModuleDeps,
273
+ };
274
+ }
275
+ //# sourceMappingURL=container-github-deps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container-github-deps.js","sourceRoot":"","sources":["../src/container-github-deps.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ import { AiAgentExecutor, type AgentKindRegistry } from '@cat-factory/agents';
2
+ import type { ApiKeyService, LocalModelEndpointService, UserSecretKindRegistry } from '@cat-factory/integrations';
3
+ import type { AppCaches, LocalModelEndpointRepository, ModelProviderResolver, PersonalSubscriptionRepository, ProviderApiKeyRepository, ProviderSubscriptionTokenRepository, ResolveUserGitHubToken, SubscriptionActivationRepository, WorkspaceRepository } from '@cat-factory/kernel';
4
+ import type { Clock, IdGenerator } from '@cat-factory/kernel';
5
+ import { type AppConfig } from '@cat-factory/server';
6
+ import type { ModelProviderResolverWrapDeps } from './container.js';
7
+ import type { DrizzleDb } from './db/client.js';
8
+ /** Inputs {@link buildNodeModelDeps} needs from the composition root. */
9
+ export interface NodeModelDepsInput {
10
+ env: NodeJS.ProcessEnv;
11
+ config: AppConfig;
12
+ db: DrizzleDb;
13
+ workspaceRepository: WorkspaceRepository;
14
+ idGenerator: IdGenerator;
15
+ clock: Clock;
16
+ agentKindRegistry: AgentKindRegistry;
17
+ userSecretKindRegistry: UserSecretKindRegistry;
18
+ resolveWorkspaceModelDefault: (workspaceId: string, agentKind: string, modelPresetId?: string) => Promise<string | undefined>;
19
+ providerApiKeyRepository?: ProviderApiKeyRepository;
20
+ localModelEndpointRepository?: LocalModelEndpointRepository;
21
+ providerSubscriptionTokenRepository?: ProviderSubscriptionTokenRepository;
22
+ personalSubscriptionRepository?: PersonalSubscriptionRepository;
23
+ subscriptionActivationRepository?: SubscriptionActivationRepository;
24
+ wrapModelProviderResolver?: (inner: ModelProviderResolver, deps: ModelProviderResolverWrapDeps) => ModelProviderResolver;
25
+ cloudflareModelsEnabled?: boolean;
26
+ caches?: AppCaches;
27
+ }
28
+ /**
29
+ * The credential/token stores + the model-provisioning stack of the Node composition root,
30
+ * lifted out of `buildNodeContainer` so that root stays within the file-size budget (the same
31
+ * reason `container-executor-deps.ts` exists). Builds the direct-provider API-key pool, the
32
+ * public-API + local-model-endpoint + user-secret + OpenRouter-catalog + subscription +
33
+ * personal-subscription stores, then the trace sink, the (optionally facade-wrapped +
34
+ * vendor-limited) model-provider resolver, and the inline agent executor.
35
+ */
36
+ export declare function buildNodeModelDeps(input: NodeModelDepsInput): {
37
+ apiKeys: ApiKeyService | undefined;
38
+ publicApiKeys: import("@cat-factory/integrations").PublicApiKeyService | undefined;
39
+ localModelEndpoints: LocalModelEndpointService | undefined;
40
+ userSecrets: import("@cat-factory/integrations").UserSecretService | undefined;
41
+ resolveUserGitHubToken: ResolveUserGitHubToken | undefined;
42
+ openRouterCatalog: import("@cat-factory/integrations").OpenRouterCatalogService | undefined;
43
+ subscriptions: import("@cat-factory/integrations").ProviderSubscriptionService | undefined;
44
+ personalSubscriptions: import("@cat-factory/integrations").PersonalSubscriptionService | undefined;
45
+ traceSink: import("@cat-factory/kernel").LlmTraceSink | undefined;
46
+ modelProviderResolver: ModelProviderResolver;
47
+ cloudflareModelsEnabled: boolean;
48
+ inline: AiAgentExecutor;
49
+ };
50
+ //# sourceMappingURL=container-model-deps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container-model-deps.d.ts","sourceRoot":"","sources":["../src/container-model-deps.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,KAAK,iBAAiB,EAGvB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EACV,aAAa,EACb,yBAAyB,EACzB,sBAAsB,EACvB,MAAM,2BAA2B,CAAA;AAClC,OAAO,KAAK,EACV,SAAS,EACT,4BAA4B,EAC5B,qBAAqB,EACrB,8BAA8B,EAC9B,wBAAwB,EACxB,mCAAmC,EACnC,sBAAsB,EACtB,gCAAgC,EAChC,mBAAmB,EACpB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAC7D,OAAO,EAAE,KAAK,SAAS,EAA2B,MAAM,qBAAqB,CAAA;AAE7E,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,gBAAgB,CAAA;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAsC/C,yEAAyE;AACzE,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAA;IACtB,MAAM,EAAE,SAAS,CAAA;IACjB,EAAE,EAAE,SAAS,CAAA;IACb,mBAAmB,EAAE,mBAAmB,CAAA;IACxC,WAAW,EAAE,WAAW,CAAA;IACxB,KAAK,EAAE,KAAK,CAAA;IACZ,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,sBAAsB,EAAE,sBAAsB,CAAA;IAC9C,4BAA4B,EAAE,CAC5B,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,aAAa,CAAC,EAAE,MAAM,KACnB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IAChC,wBAAwB,CAAC,EAAE,wBAAwB,CAAA;IACnD,4BAA4B,CAAC,EAAE,4BAA4B,CAAA;IAC3D,mCAAmC,CAAC,EAAE,mCAAmC,CAAA;IACzE,8BAA8B,CAAC,EAAE,8BAA8B,CAAA;IAC/D,gCAAgC,CAAC,EAAE,gCAAgC,CAAA;IACnE,yBAAyB,CAAC,EAAE,CAC1B,KAAK,EAAE,qBAAqB,EAC5B,IAAI,EAAE,6BAA6B,KAChC,qBAAqB,CAAA;IAC1B,uBAAuB,CAAC,EAAE,OAAO,CAAA;IACjC,MAAM,CAAC,EAAE,SAAS,CAAA;CACnB;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,kBAAkB;;;;;;;;;;;;;EAiK3D"}
@@ -0,0 +1,127 @@
1
+ import { AiAgentExecutor, inlineWebSearchOptionsFromEnv, vendorConcurrencyLimiterFromEnv, } from '@cat-factory/agents';
2
+ import { wrapResolverWithLimiter } from '@cat-factory/server';
3
+ import { buildTraceSink } from './container-executor-deps.js';
4
+ import { createNodeModelProviderResolver } from './modelProvider.js';
5
+ import { buildNodeApiKeyService, buildNodeLocalModelEndpointService, buildNodeOpenRouterCatalogService, buildNodePersonalSubscriptionService, buildNodePublicApiKeyService, buildNodeSubscriptionService, buildNodeUserSecretService, } from './wireCredentialServices.js';
6
+ /**
7
+ * The Node model-provider RESOLVER (instrumented when Langfuse is on), shared per
8
+ * `(env, db)`. Builds a per-scope provider from the DB-backed API-key pool plus opt-in
9
+ * Cloudflare-REST / Bedrock registries. Mirrors the Worker's buildModelProviderResolver.
10
+ */
11
+ const modelResolverCache = new WeakMap();
12
+ function buildModelProviderResolver(env, db, apiKeys, localModelEndpoints,
13
+ // The shared inline instrument (one trace sink for the proxied path, the core AND the
14
+ // inline calls) so the OTel SDK exporter isn't rebuilt per wiring site.
15
+ instrument) {
16
+ // The cache keys on the db handle (one resolver per Drizzle client). Mothership mode has no
17
+ // db, so skip the cache entirely (WeakMap keys must be objects) and build a fresh resolver —
18
+ // a mothership node builds one container, so there is nothing to share it with anyway.
19
+ if (!db)
20
+ return createNodeModelProviderResolver(env, apiKeys, localModelEndpoints, instrument);
21
+ const cached = modelResolverCache.get(db);
22
+ if (cached)
23
+ return cached;
24
+ const resolver = createNodeModelProviderResolver(env, apiKeys, localModelEndpoints, instrument);
25
+ modelResolverCache.set(db, resolver);
26
+ return resolver;
27
+ }
28
+ /**
29
+ * The credential/token stores + the model-provisioning stack of the Node composition root,
30
+ * lifted out of `buildNodeContainer` so that root stays within the file-size budget (the same
31
+ * reason `container-executor-deps.ts` exists). Builds the direct-provider API-key pool, the
32
+ * public-API + local-model-endpoint + user-secret + OpenRouter-catalog + subscription +
33
+ * personal-subscription stores, then the trace sink, the (optionally facade-wrapped +
34
+ * vendor-limited) model-provider resolver, and the inline agent executor.
35
+ */
36
+ export function buildNodeModelDeps(input) {
37
+ const { env, config, db, workspaceRepository, idGenerator, clock, agentKindRegistry, userSecretKindRegistry, resolveWorkspaceModelDefault, providerApiKeyRepository, localModelEndpointRepository, providerSubscriptionTokenRepository, personalSubscriptionRepository, subscriptionActivationRepository, wrapModelProviderResolver, cloudflareModelsEnabled: cloudflareModelsEnabledOverride, caches, } = input;
38
+ // The direct-provider API-key pool + the per-scope model-provider resolver, shared by
39
+ // the inline executor, the inline modules (planner/reviewer/fragment selector), the
40
+ // API-key controller, and the LLM proxy key lease.
41
+ const apiKeys = buildNodeApiKeyService(env, db, workspaceRepository, idGenerator, clock, providerApiKeyRepository);
42
+ // The inbound public-API key store — drives the public `/api/v1` surface's authentication.
43
+ const publicApiKeys = buildNodePublicApiKeyService(env, db, idGenerator, clock);
44
+ // The per-user locally-run model endpoints store (Ollama / LM Studio / …), shared by
45
+ // the local-runner controller, the per-user model catalog, the inline model provider,
46
+ // and the LLM proxy.
47
+ const localModelEndpoints = buildNodeLocalModelEndpointService(env, db, clock, localModelEndpointRepository);
48
+ // The per-user generic secret store (a GitHub PAT today), shared by the user-secret
49
+ // controller and the run-initiator PAT resolver below.
50
+ const userSecrets = buildNodeUserSecretService(env, db, clock, userSecretKindRegistry, caches?.viewerRepos);
51
+ // Resolve the run initiator's stored GitHub PAT (when set) — preferred over the
52
+ // App/env token by the container push-token mint + the engine GitHub client.
53
+ const resolveUserGitHubToken = userSecrets
54
+ ? (userId) => userSecrets.resolve(userId, 'github_pat')
55
+ : undefined;
56
+ // The per-workspace OpenRouter dynamic-catalog store — shared by the catalog controller,
57
+ // the per-workspace model catalog's dynamic OpenRouter entries, and the spend overlay.
58
+ const openRouterCatalog = buildNodeOpenRouterCatalogService(env, db, clock, apiKeys, config.spend.currency);
59
+ // The subscription-token pool (Claude Code / Codex credentials), shared by the
60
+ // container executor (lease + usage feedback) and the vendor-credential controller.
61
+ // Built HERE (before the model-provider wrap below) so its lease closures can be handed
62
+ // to `wrapModelProviderResolver` — the local facade's inline-harness wrap serves an
63
+ // inline subscription ref through a warm container on a LEASED credential, so it needs the
64
+ // same lease seams the container executor uses (built once, shared by both).
65
+ const subscriptions = buildNodeSubscriptionService(env, db, workspaceRepository, idGenerator, clock, providerSubscriptionTokenRepository);
66
+ // The per-user individual-usage subscription store (Claude), shared by the
67
+ // container executor's personal lease, the personal-subscription controller, and the
68
+ // inline-harness wrap's per-run personal lease.
69
+ const personalSubscriptions = buildNodePersonalSubscriptionService(env, db, idGenerator, clock, personalSubscriptionRepository, subscriptionActivationRepository);
70
+ // The ONE external trace sink for this container (memoised per config): the core, the
71
+ // container executor AND the inline model-provider instrumentation all share this single
72
+ // instance, so the OTel SDK exporter's batch processors/timers exist exactly once (and its
73
+ // shutdown is wired below). Its `recordPrompts` matches the proxied path's gating.
74
+ const traceSink = buildTraceSink(config);
75
+ const baseModelProviderResolver = buildModelProviderResolver(env, db, apiKeys, localModelEndpoints, traceSink ? { traceSink, recordPrompts: config.observability.recordPrompts } : undefined);
76
+ const wrappedModelProviderResolver = wrapModelProviderResolver
77
+ ? wrapModelProviderResolver(baseModelProviderResolver, {
78
+ ...(personalSubscriptions
79
+ ? {
80
+ leasePersonalSubscriptionToken: (executionId, userId, vendor) => personalSubscriptions.leaseForRun(executionId, userId, vendor),
81
+ }
82
+ : {}),
83
+ ...(subscriptions
84
+ ? {
85
+ leaseSubscriptionToken: (workspaceId, vendor) => subscriptions.leaseToken(workspaceId, vendor),
86
+ }
87
+ : {}),
88
+ })
89
+ : baseModelProviderResolver;
90
+ // Cap concurrent inline calls to a subscription vendor, OUTERMOST so it sits outside the
91
+ // local facade's subscription-inline harness wrap above (and therefore sees the un-degraded
92
+ // subscription ref). One limiter per container = per process for a stock node, per tenant in
93
+ // mothership mode; a pass-through when nothing is capped. Symmetric with the Worker's wrap in
94
+ // `buildModelProviderResolver` (see "Keep the runtimes symmetric").
95
+ const modelProviderResolver = wrapResolverWithLimiter(wrappedModelProviderResolver, vendorConcurrencyLimiterFromEnv((key) => env[key]));
96
+ // Cloudflare Workers AI is opt-in on Node: enabled when the REST creds are present.
97
+ const cloudflareModelsEnabled = cloudflareModelsEnabledOverride ?? !!(env.CLOUDFLARE_ACCOUNT_ID && env.CLOUDFLARE_API_TOKEN);
98
+ const inline = new AiAgentExecutor({
99
+ modelProviderResolver,
100
+ agentRouting: config.agents.routing,
101
+ resolveBlockModel: config.agents.resolveBlockModel,
102
+ resolveWorkspaceModelDefault,
103
+ // In local mode this keeps an ambient-eligible subscription harness ref so the inline
104
+ // design/research kinds run on the developer's Claude Code / Codex CLI; undefined on
105
+ // stock Node (no inline harness), where such a ref degrades to the routing default.
106
+ ...(config.agents.inlineHarnessRef ? { runsInline: config.agents.inlineHarnessRef } : {}),
107
+ // Opt-in provider web search for the inline design/research kinds (no-op unless
108
+ // INLINE_WEB_SEARCH_ENABLED and an Anthropic/OpenAI model).
109
+ webSearch: inlineWebSearchOptionsFromEnv(env),
110
+ agentKindRegistry,
111
+ });
112
+ return {
113
+ apiKeys,
114
+ publicApiKeys,
115
+ localModelEndpoints,
116
+ userSecrets,
117
+ resolveUserGitHubToken,
118
+ openRouterCatalog,
119
+ subscriptions,
120
+ personalSubscriptions,
121
+ traceSink,
122
+ modelProviderResolver,
123
+ cloudflareModelsEnabled,
124
+ inline,
125
+ };
126
+ }
127
+ //# sourceMappingURL=container-model-deps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container-model-deps.js","sourceRoot":"","sources":["../src/container-model-deps.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import { type AgentKindRegistry } from '@cat-factory/agents';
2
+ import { type AgentExecutor, type ModelProviderResolver, type NotificationChannel } from '@cat-factory/kernel';
3
+ import type { CoreDependencies } from '@cat-factory/orchestration';
4
+ import { type AppConfig, type CompositeAgentExecutor, FanOutEventPublisher } from '@cat-factory/server';
5
+ import type { DrizzleDb } from './db/client.js';
6
+ import { type LocalEventSink } from './realtime.js';
7
+ import type { createDrizzleRepositories } from './repositories/drizzle.js';
8
+ type NodeRepositories = ReturnType<typeof createDrizzleRepositories>;
9
+ /** Inputs {@link buildNodeRealtimeDeps} needs from the composition root. */
10
+ export interface NodeRealtimeDepsInput {
11
+ env: NodeJS.ProcessEnv;
12
+ config: AppConfig;
13
+ repos: NodeRepositories;
14
+ sourced: <T>(name: string, build: (d: DrizzleDb) => T) => T;
15
+ realtimeSink?: LocalEventSink;
16
+ standardAgentExecutor: CompositeAgentExecutor;
17
+ modelProviderResolver: ModelProviderResolver;
18
+ resolveWorkspaceModelDefault: (workspaceId: string, agentKind: string, modelPresetId?: string) => Promise<string | undefined>;
19
+ agentKindRegistry: AgentKindRegistry;
20
+ }
21
+ /**
22
+ * The real-time event-publisher + notification-channel + optional consensus wrap of the Node
23
+ * composition root, lifted out of `buildNodeContainer` so that root stays within the file-size
24
+ * budget. Builds the Slack deps, the fan-out event publisher (when a realtime hub is wired),
25
+ * the (optionally consensus-wrapped) agent executor, and the composite notification channel.
26
+ */
27
+ export declare function buildNodeRealtimeDeps(input: NodeRealtimeDepsInput): {
28
+ slackDeps: Partial<CoreDependencies>;
29
+ executionEventPublisher: FanOutEventPublisher | undefined;
30
+ agentExecutor: AgentExecutor;
31
+ notificationChannel: NotificationChannel | undefined;
32
+ };
33
+ export {};
34
+ //# sourceMappingURL=container-realtime-deps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container-realtime-deps.d.ts","sourceRoot":"","sources":["../src/container-realtime-deps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAG5D,OAAO,EACL,KAAK,aAAa,EAElB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACzB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAClE,OAAO,EACL,KAAK,SAAS,EACd,KAAK,sBAAsB,EAC3B,oBAAoB,EAIrB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,EAAE,KAAK,cAAc,EAAsB,MAAM,eAAe,CAAA;AACvE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAA;AAO1E,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,yBAAyB,CAAC,CAAA;AAsEpE,4EAA4E;AAC5E,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAA;IACtB,MAAM,EAAE,SAAS,CAAA;IACjB,KAAK,EAAE,gBAAgB,CAAA;IACvB,OAAO,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,CAAC,KAAK,CAAC,CAAA;IAC3D,YAAY,CAAC,EAAE,cAAc,CAAA;IAC7B,qBAAqB,EAAE,sBAAsB,CAAA;IAC7C,qBAAqB,EAAE,qBAAqB,CAAA;IAC5C,4BAA4B,EAAE,CAC5B,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,aAAa,CAAC,EAAE,MAAM,KACnB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IAChC,iBAAiB,EAAE,iBAAiB,CAAA;CACrC;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,qBAAqB;;;;;EA2DjE"}