@cat-factory/worker 0.99.1 → 0.99.3

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.
@@ -1,4 +1,4 @@
1
- import { CompositeNotificationChannel, DEFAULT_MODEL_PRESET_ID, composeTraceSinks, NoopWorkRunner, } from '@cat-factory/kernel';
1
+ import { CompositeNotificationChannel, composeTraceSinks, NoopWorkRunner, } from '@cat-factory/kernel';
2
2
  import { AiAgentExecutor, inlineWebSearchOptionsFromEnv, resolveAgentConfig, isProxyableProvider, vendorConcurrencyLimiterFromEnv, } from '@cat-factory/agents';
3
3
  import { cloudflareBindingRegistry } from '@cat-factory/provider-cloudflare';
4
4
  import { ConfluenceProvider, FigmaProvider, ZeplinProvider, GitHubDocsProvider, GitHubIssuesProvider, JiraProvider, LinearDocumentProvider, LinearTaskProvider, NotionProvider, EMAIL_CIPHER_INFO, PersonalSubscriptionService, ProviderSubscriptionService, RunnerPoolConnectionService, ProvisioningLogRecorder, LoggingRunnerTransport, SLACK_CIPHER_INFO, SlackNotificationChannel, TicketTrackerService, IssueWritebackService, githubIssuesLogic, OBSERVABILITY_CIPHER_INFO, RegistryReleaseHealthProvider, defaultObservabilityRegistry, RegistrySubscriptionQuotaProvider, defaultSubscriptionQuotaRegistry, WorkspaceIncidentEnrichmentProvider, INCIDENT_ENRICHMENT_CIPHER_INFO, AccountSettingsService, ACCOUNT_SETTINGS_CIPHER_INFO, TestSecretsService, TEST_SECRETS_CIPHER_INFO, createEmailSender, } from '@cat-factory/integrations';
@@ -10,11 +10,12 @@ import { ConfluenceProvider, FigmaProvider, ZeplinProvider, GitHubDocsProvider,
10
10
  // custom CA (Node/local) — exactly like a private-CA `kubernetes` connection — so on the Worker
11
11
  // the kind is offered but a connection to such a cluster fails TLS at run time, not silently.
12
12
  import { resolveWorkerRegistries } from './container-registries.js';
13
- import { AgentContextObservabilityService, SearchQueryObservabilityService, createCore, PACKAGE_REGISTRY_CIPHER_INFO, resolvePackageRegistriesForDispatch, LlmObservabilityService, makeHarnessCallRecorder, resolvePresetModelForKind, } from '@cat-factory/orchestration';
13
+ import { assembleWorkerContainer } from './container-assembly.js';
14
+ import { AgentContextObservabilityService, SearchQueryObservabilityService, PACKAGE_REGISTRY_CIPHER_INFO, resolvePackageRegistriesForDispatch, LlmObservabilityService, makeHarnessCallRecorder, resolvePresetModelForKind, } from '@cat-factory/orchestration';
14
15
  import { ISOLATE_SAFE_APP_CACHES_PROFILE, createAppCaches } from '@cat-factory/caching';
15
16
  import { createLangfuseSink } from '@cat-factory/observability-langfuse';
16
17
  import { createOtelSink } from '@cat-factory/observability-otel';
17
- import { buildResolveRepoTarget as buildSharedResolveRepoTarget, buildResolveRepoTargets as buildSharedResolveRepoTargets, ContainerEnvConfigRepairer, makeResolveDeployCloneTarget, makeResolveRunRepoContext, RunnerJobClient, makeResolveRepoFilesForCoords, makeResolveBinaryArtifactStore, ensureWorkBranchViaRest, FanOutEventPublisher, InAppNotificationChannel, PatPreferringAppRegistry, runWithInitiator, WebCryptoPasswordHasher, logger, buildInfrastructureCapabilities, testEnvHasZeroConfigDefault, createDefaultWebSearchUpstream, createWebSearchUpstream, createScopedModelProviderResolver, wrapResolverWithLimiter, ENV_HELP, configProblem, GitHubIdentityResolver, resolveUrlSafetyPolicy, resolveWorkspaceCapabilities, noRunnerBackendAvailableError, } from '@cat-factory/server';
18
+ import { buildResolveRepoTarget as buildSharedResolveRepoTarget, buildResolveRepoTargets as buildSharedResolveRepoTargets, ContainerEnvConfigRepairer, makeResolveDeployCloneTarget, makeResolveRunRepoContext, RunnerJobClient, makeResolveRepoFilesForCoords, makeResolveBinaryArtifactStore, ensureWorkBranchViaRest, FanOutEventPublisher, InAppNotificationChannel, PatPreferringAppRegistry, logger, buildInfrastructureCapabilities, createDefaultWebSearchUpstream, createWebSearchUpstream, createScopedModelProviderResolver, wrapResolverWithLimiter, ENV_HELP, configProblem, GitHubIdentityResolver, resolveUrlSafetyPolicy, noRunnerBackendAvailableError, } from '@cat-factory/server';
18
19
  import { loadConfig } from './config';
19
20
  import { loadLangfuseConfig } from './config/langfuse';
20
21
  import { loadObservabilityConfig } from './config/observability';
@@ -22,43 +23,28 @@ import { loadOtelConfig } from './config/otel';
22
23
  import { requireDb, requireTelemetryDb } from './env';
23
24
  import { baseUrlFor } from './ai/providerEndpoints';
24
25
  import { resolveExtraRegistries } from './ai/registries';
25
- import { DoRealtimeGateway } from './gateways/DoRealtimeGateway';
26
- import { CfGitHubWebhookIngest, WorkflowsBackfillScheduler } from './gateways/GitHubGateways';
27
- import { WorkersAiLlmUpstream } from './ai/WorkersAiLlmUpstream';
26
+ import { CfGitHubWebhookIngest } from './gateways/GitHubGateways';
28
27
  import { ContainerAgentExecutor, } from './ai/ContainerAgentExecutor';
29
28
  import { CloudflareContainerTransport } from './containers/CloudflareContainerTransport';
30
29
  import { ContainerInstanceRegistry } from './containers/ContainerInstanceRegistry';
31
30
  import { D1LiveContainerRepository } from './repositories/D1LiveContainerRepository';
32
31
  import { HttpRunnerPoolProvider } from './runners/HttpRunnerPoolProvider';
33
32
  import { D1RunnerPoolConnectionRepository } from './repositories/D1RunnerPoolConnectionRepository';
34
- import { D1SubscriptionActivationRepository } from './repositories/D1PersonalSubscriptionRepository';
35
33
  import { D1UserRepoAccessRepository } from './repositories/D1UserRepoAccessRepository';
36
- import { D1SealedSecretInventory } from './repositories/D1SealedSecretInventory';
37
34
  import { ContainerRepoBootstrapper } from './ai/ContainerRepoBootstrapper';
38
35
  import { CompositeAgentExecutor } from './ai/CompositeAgentExecutor';
39
36
  import { ContainerSessionService } from './containers/ContainerSessionService';
40
37
  import { DurableObjectEventPublisher } from './events/DurableObjectEventPublisher';
41
- import { DurableObjectMachineEventRelay } from './events/DurableObjectMachineEventRelay';
42
38
  import { WorkflowsWorkRunner } from './workflows/WorkflowsWorkRunner';
43
- import { WorkflowsBootstrapRunner } from './workflows/WorkflowsBootstrapRunner';
44
- import { WorkflowsEnvConfigRepairRunner } from './workflows/WorkflowsEnvConfigRepairRunner';
45
- import { WorkflowsEnvironmentTestRunner } from './workflows/WorkflowsEnvironmentTestRunner';
46
39
  import { D1BlockRepository } from './repositories/D1BlockRepository';
47
- import { D1ExecutionRepository } from './repositories/D1ExecutionRepository';
48
- import { D1PipelineRepository } from './repositories/D1PipelineRepository';
49
40
  import { D1ServiceRepository } from './repositories/D1ServiceRepository';
50
41
  import { D1WorkspaceMountRepository } from './repositories/D1WorkspaceMountRepository';
51
- import { D1TokenUsageRepository } from './repositories/D1TokenUsageRepository';
52
42
  import { D1LlmCallMetricRepository } from './repositories/D1LlmCallMetricRepository';
53
43
  import { D1AgentContextSnapshotRepository } from './repositories/D1AgentContextSnapshotRepository';
54
44
  import { D1AgentSearchQueryRepository } from './repositories/D1AgentSearchQueryRepository';
55
45
  import { D1ProvisioningLogRepository } from './repositories/D1ProvisioningLogRepository';
56
46
  import { D1WorkspaceRepository } from './repositories/D1WorkspaceRepository';
57
- import { D1WorkspaceMemberRepository } from './repositories/D1WorkspaceMemberRepository';
58
47
  import { D1SlackConnectionRepository, D1SlackMemberMappingRepository, D1SlackSettingsRepository, } from './repositories/D1SlackRepositories';
59
- import { D1AccountRepository } from './repositories/D1AccountRepository';
60
- import { D1MembershipRepository } from './repositories/D1MembershipRepository';
61
- import { D1UserRepository } from './repositories/D1UserRepository';
62
48
  import { D1AccountInvitationRepository } from './repositories/D1AccountInvitationRepository';
63
49
  import { D1PasswordResetTokenRepository } from './repositories/D1PasswordResetTokenRepository';
64
50
  import { D1EmailConnectionRepository } from './repositories/D1EmailConnectionRepository';
@@ -75,12 +61,7 @@ import { D1DocumentRepository } from './repositories/D1DocumentRepository';
75
61
  import { D1EnvironmentConnectionRepository } from './repositories/D1EnvironmentConnectionRepository';
76
62
  import { D1CustomManifestTypeRepository } from './repositories/D1CustomManifestTypeRepository';
77
63
  import { D1EnvironmentRegistryRepository } from './repositories/D1EnvironmentRegistryRepository';
78
- import { D1ReferenceArchitectureRepository } from './repositories/D1ReferenceArchitectureRepository';
79
64
  import { D1BootstrapJobRepository } from './repositories/D1BootstrapJobRepository';
80
- import { D1EnvConfigRepairJobRepository } from './repositories/D1EnvConfigRepairJobRepository';
81
- import { D1EnvironmentTestRunRepository } from './repositories/D1EnvironmentTestRunRepository';
82
- import { D1AgentRunRepository } from './repositories/D1AgentRunRepository';
83
- import { D1PlatformMetricsRepository } from './repositories/D1PlatformMetricsRepository';
84
65
  import { D1BinaryArtifactMetadataStore } from './repositories/D1BinaryArtifactMetadataStore';
85
66
  import { R2BinaryBlobBackend } from './storage/R2BinaryBlobBackend';
86
67
  import { D1RequirementReviewRepository } from './repositories/D1RequirementReviewRepository';
@@ -112,7 +93,7 @@ import { D1ServiceFragmentDefaultsRepository } from './repositories/D1ServiceFra
112
93
  // The built-in polling-gate suite (ci / conflicts / post-release-health + on-call). The facade
113
94
  // builds an app-owned `GateRegistry` pre-loaded with the suite via `gateRegistryWithBuiltins()`,
114
95
  // then wires each gate's provider below.
115
- import { applyGateProviders, wireCiStatusProvider, wireMergeabilityProvider, wireReleaseHealthProvider, wireIncidentEnrichment, wirePullRequestReviewProvider, wireDocQualityProvider, warnUnwiredGates, } from '@cat-factory/gates';
96
+ import { wireCiStatusProvider, wireMergeabilityProvider, wireReleaseHealthProvider, wireIncidentEnrichment, wirePullRequestReviewProvider, wireDocQualityProvider, } from '@cat-factory/gates';
116
97
  import { buildGitLabEngineClient, GitLabIdentityResolver, registerGitLab, StaticGitLabTokenSource, } from '@cat-factory/gitlab';
117
98
  import { GitHubDocQualityProvider, GitHubPullRequestReviewProvider } from '@cat-factory/server';
118
99
  import { GitHubCiStatusProvider } from './github/GitHubCiStatusProvider';
@@ -198,7 +179,7 @@ function buildResolveWorkspaceModelDefault(db) {
198
179
  const repo = new D1ModelPresetRepository({ db });
199
180
  return (workspaceId, agentKind, modelPresetId) => resolvePresetModelForKind(repo, workspaceId, agentKind, modelPresetId);
200
181
  }
201
- function selectAgentExecutor(deps) {
182
+ export function selectAgentExecutor(deps) {
202
183
  const { env, config, db, agentKindRegistry } = deps;
203
184
  const inline = new AiAgentExecutor({
204
185
  modelProviderResolver: buildModelProviderResolver(env, db),
@@ -237,7 +218,7 @@ function isTruthy(value) {
237
218
  * a multi-model process, persisting + pushing the transcript. Off ⇒ returns `standard`
238
219
  * unchanged (no traits, no wrapping), so behaviour is identical to before.
239
220
  */
240
- function maybeWrapConsensus(standard, env, config, db, eventPublisher, agentKindRegistry) {
221
+ export function maybeWrapConsensus(standard, env, config, db, eventPublisher, agentKindRegistry) {
241
222
  if (!isTruthy(env.CONSENSUS_ENABLED))
242
223
  return standard;
243
224
  registerConsensusTraits(agentKindRegistry);
@@ -333,7 +314,7 @@ function buildResolveTransport(deps) {
333
314
  * call routes correctly. Callers guard on `config.github.enabled`, which requires
334
315
  * GITHUB_APP_PRIVATE_KEY, so the default key is present.
335
316
  */
336
- function buildAppRegistry(env, config, db, clock) {
317
+ export function buildAppRegistry(env, config, db, clock) {
337
318
  const installationRepository = new D1GitHubInstallationRepository({ db });
338
319
  const makeAuth = (appId, privateKeyPem) => new GitHubAppAuth({
339
320
  appId,
@@ -372,7 +353,7 @@ function buildAppRegistry(env, config, db, clock) {
372
353
  * behaviour. The shared GitHub sync/webhook services still receive the (pass-through)
373
354
  * handle via `createGitHubModule`, so their invalidation code path stays symmetric.
374
355
  */
375
- function buildResolveRepoTarget(db) {
356
+ export function buildResolveRepoTarget(db) {
376
357
  return buildSharedResolveRepoTarget({
377
358
  installationRepository: new D1GitHubInstallationRepository({ db }),
378
359
  repoProjectionRepository: new D1RepoProjectionRepository({ db }),
@@ -437,7 +418,7 @@ function selectEngineVcsClient(env, config, db, clock, idGenerator) {
437
418
  }
438
419
  return undefined;
439
420
  }
440
- function selectMergeLifecycleDeps(env, config, db, clock, idGenerator, providerRegistry) {
421
+ export function selectMergeLifecycleDeps(env, config, db, clock, idGenerator, providerRegistry) {
441
422
  const deps = {
442
423
  notificationRepository: new D1NotificationRepository({ db }),
443
424
  riskPolicyRepository: new D1RiskPolicyRepository({ db }),
@@ -507,7 +488,7 @@ function selectMergeLifecycleDeps(env, config, db, clock, idGenerator, providerR
507
488
  * and (optionally) the PagerDuty / incident.io enrichment providers. Off → the gate is a
508
489
  * pass-through and the release-health module isn't built.
509
490
  */
510
- function selectReleaseHealthDeps(env, config, db, providerRegistry) {
491
+ export function selectReleaseHealthDeps(env, config, db, providerRegistry) {
511
492
  if (!config.releaseHealth.enabled || !config.releaseHealth.encryptionKey)
512
493
  return {};
513
494
  const observabilityConnectionRepository = new D1ObservabilityConnectionRepository({ db });
@@ -539,7 +520,7 @@ function selectReleaseHealthDeps(env, config, db, providerRegistry) {
539
520
  * to seal/unseal); a workspace with no entries is a no-op. The decrypted entries reach
540
521
  * agent containers via the executor's `resolvePackageRegistries` seam.
541
522
  */
542
- function selectPackageRegistryDeps(env, db) {
523
+ export function selectPackageRegistryDeps(env, db) {
543
524
  const encryptionKey = env.ENCRYPTION_KEY?.trim();
544
525
  if (!encryptionKey)
545
526
  return {};
@@ -598,7 +579,7 @@ function buildTestSecretsService(env, db, clock) {
598
579
  * workspace-backed provider is wired into the gate suite via `wireIncidentEnrichment`;
599
580
  * the connection repo + cipher stay on CoreDependencies to power the management API.
600
581
  */
601
- function selectIncidentEnrichmentDeps(env, db, providerRegistry) {
582
+ export function selectIncidentEnrichmentDeps(env, db, providerRegistry) {
602
583
  const encryptionKey = env.ENCRYPTION_KEY?.trim();
603
584
  if (!encryptionKey)
604
585
  return {};
@@ -722,7 +703,7 @@ function buildSlackChannel(config, db) {
722
703
  * the channel composed in by {@link selectMergeLifecycleDeps}. OAuth credentials
723
704
  * are optional — manual bot-token onboarding works without them.
724
705
  */
725
- function selectSlackDeps(config, db) {
706
+ export function selectSlackDeps(config, db) {
726
707
  const infra = buildSlackInfra(config, db);
727
708
  if (!infra)
728
709
  return {};
@@ -739,7 +720,7 @@ function selectSlackDeps(config, db) {
739
720
  * cipher are wired only when EMAIL is enabled (an encryption key is mandatory), so
740
721
  * an account can onboard a SendGrid/Resend key in the UI and have invites emailed.
741
722
  */
742
- function selectEmailInvitationDeps(config, db) {
723
+ export function selectEmailInvitationDeps(config, db) {
743
724
  const deps = {
744
725
  invitationRepository: new D1AccountInvitationRepository({ db }),
745
726
  // Password reset works without email (the link is logged in dev); the system
@@ -814,7 +795,7 @@ function buildOtelSink(otel) {
814
795
  function buildTraceSink(config) {
815
796
  return composeTraceSinks([buildLangfuseSink(config.langfuse), buildOtelSink(config.otel)]);
816
797
  }
817
- function selectTraceSink(config) {
798
+ export function selectTraceSink(config) {
818
799
  const sink = buildTraceSink(config);
819
800
  return sink ? { llmTraceSink: sink } : {};
820
801
  }
@@ -827,7 +808,7 @@ function selectTraceSink(config) {
827
808
  * integration's encryption key is set (so it can read the workspace's stored Jira
828
809
  * credentials). With neither, the `tracker` step passes through.
829
810
  */
830
- function selectRecurringDeps(env, config, db, clock, idGenerator) {
811
+ export function selectRecurringDeps(env, config, db, clock, idGenerator) {
831
812
  const trackerDeps = {
832
813
  trackerSettingsRepository: new D1TrackerSettingsRepository({ db }),
833
814
  // workerd exposes a global fetch; the Jira create call uses it.
@@ -1094,7 +1075,7 @@ function buildContainerExecutor(deps) {
1094
1075
  * - otherwise → no-op (e.g. tests, which override this anyway)
1095
1076
  * Tests override `workRunner` with a fake and drive the engine via advanceInstance.
1096
1077
  */
1097
- function selectWorkRunner(env) {
1078
+ export function selectWorkRunner(env) {
1098
1079
  if (env.EXECUTION_WORKFLOW) {
1099
1080
  return new WorkflowsWorkRunner({
1100
1081
  workflow: env.EXECUTION_WORKFLOW,
@@ -1123,7 +1104,7 @@ function selectEventPublisher(env, db) {
1123
1104
  * mirroring `selectWorkRunner`. Returns an empty object otherwise, so `createCore`
1124
1105
  * leaves the `github` module unassembled and the feature stays opt-in.
1125
1106
  */
1126
- function selectGitHubDeps(env, config, db, clock, idGenerator, repoFilesCache) {
1107
+ export function selectGitHubDeps(env, config, db, clock, idGenerator, repoFilesCache) {
1127
1108
  if (!config.github.enabled) {
1128
1109
  // GitLab-only deployment: the App-shaped connect / projection / provisioning wiring stays
1129
1110
  // off (GitLab ingests via the neutral `/vcs/:provider/webhooks` route), but the checkout-free
@@ -1197,7 +1178,7 @@ function selectGitHubDeps(env, config, db, clock, idGenerator, repoFilesCache) {
1197
1178
  * just needs a provider credential); the planner degrades to its deterministic parser
1198
1179
  * if no model is usable.
1199
1180
  */
1200
- function selectDocumentsDeps(env, config, db, clock, idGenerator) {
1181
+ export function selectDocumentsDeps(env, config, db, clock, idGenerator) {
1201
1182
  const providers = [];
1202
1183
  if (config.documents.sources.includes('confluence'))
1203
1184
  providers.push(new ConfluenceProvider());
@@ -1257,7 +1238,7 @@ function selectDocumentsDeps(env, config, db, clock, idGenerator) {
1257
1238
  * structure. Always on (config load fails loudly without the encryption key), so this
1258
1239
  * is wired on every deployment.
1259
1240
  */
1260
- function selectTasksDeps(env, config, db, clock, idGenerator) {
1241
+ export function selectTasksDeps(env, config, db, clock, idGenerator) {
1261
1242
  // Jira and Linear are always registered (their credentials are per-workspace, entered in the UI).
1262
1243
  const providers = [new JiraProvider(), new LinearTaskProvider()];
1263
1244
  // GitHub Issues reuse the workspace's installed GitHub App, so this provider is
@@ -1300,7 +1281,7 @@ function selectTasksDeps(env, config, db, clock, idGenerator) {
1300
1281
  * heading-based planner: that planner only engages when `documentPlannerModel` is
1301
1282
  * also set, which this does not touch.)
1302
1283
  */
1303
- function selectRequirementsDeps(env, config, db) {
1284
+ export function selectRequirementsDeps(env, config, db) {
1304
1285
  return {
1305
1286
  requirementReviewRepository: new D1RequirementReviewRepository({ db }),
1306
1287
  docInterviewRepository: new D1DocInterviewRepository({ db }),
@@ -1326,7 +1307,7 @@ function selectRequirementsDeps(env, config, db) {
1326
1307
  * id like a pipeline step). Mirrored by the Node facade's `createDrizzleSandboxDeps`
1327
1308
  * (a Postgres `sandbox` schema).
1328
1309
  */
1329
- function selectSandboxDeps(sandboxDb) {
1310
+ export function selectSandboxDeps(sandboxDb) {
1330
1311
  if (!sandboxDb)
1331
1312
  return {};
1332
1313
  return {
@@ -1346,7 +1327,7 @@ function selectSandboxDeps(sandboxDb) {
1346
1327
  * enable flag: whether a workspace provisions anything is decided by its registered
1347
1328
  * connection + whether its pipeline runs a `deployer`/`tester` step.
1348
1329
  */
1349
- function selectEnvironmentsDeps(env, config, db) {
1330
+ export function selectEnvironmentsDeps(env, config, db) {
1350
1331
  if (!config.environments.encryptionKey)
1351
1332
  return {};
1352
1333
  // The provider is resolved per-workspace from the env-backend registry by the stored
@@ -1385,7 +1366,7 @@ function selectEnvironmentsDeps(env, config, db) {
1385
1366
  * REST path is unaffected), exactly the unwired behaviour slice 9 shipped. Mirrors Node's pool
1386
1367
  * deploy wiring; the deploy container is the Worker's analogue of Node's self-hosted pool.
1387
1368
  */
1388
- function selectDeployDeps(env, config, db, clock) {
1369
+ export function selectDeployDeps(env, config, db, clock) {
1389
1370
  if (!config.environments.encryptionKey ||
1390
1371
  !env.DEPLOY_CONTAINER ||
1391
1372
  !config.github.enabled ||
@@ -1411,7 +1392,7 @@ function selectDeployDeps(env, config, db, clock) {
1411
1392
  * `Core.runners` (the connection-management API); the per-job transport selection
1412
1393
  * lives in `buildResolveTransport` above. Returns `{}` when disabled.
1413
1394
  */
1414
- function selectRunnersDeps(env, config, db) {
1395
+ export function selectRunnersDeps(env, config, db) {
1415
1396
  if (!config.runners.enabled)
1416
1397
  return {};
1417
1398
  const urlPolicy = resolveUrlSafetyPolicy(config.runners);
@@ -1437,7 +1418,7 @@ function selectRunnersDeps(env, config, db) {
1437
1418
  * undefined otherwise, leaving reference-architecture CRUD available while the run
1438
1419
  * path reports itself unavailable.
1439
1420
  */
1440
- function selectRepoBootstrapper(env, config, db, clock, idGenerator, resolveTransport) {
1421
+ export function selectRepoBootstrapper(env, config, db, clock, idGenerator, resolveTransport) {
1441
1422
  if (!resolveTransport ||
1442
1423
  !config.github.enabled ||
1443
1424
  !env.GITHUB_APP_PRIVATE_KEY ||
@@ -1483,7 +1464,7 @@ function selectRepoBootstrapper(env, config, db, clock, idGenerator, resolveTran
1483
1464
  * provider the engine validates with. NOT to be confused with the repo bootstrapper: this
1484
1465
  * is an ordinary clone→edit→push coding job (no history reset / force-push).
1485
1466
  */
1486
- function selectEnvConfigRepairer(deps) {
1467
+ export function selectEnvConfigRepairer(deps) {
1487
1468
  const { env, config, db, clock, resolveTransport, override, environmentBackendRegistry } = deps;
1488
1469
  const repairUrlPolicy = resolveUrlSafetyPolicy(config.environments);
1489
1470
  // Prefer the internal override (the conformance suite's fake repair provider) else scan
@@ -1533,7 +1514,7 @@ function selectEnvConfigRepairer(deps) {
1533
1514
  * tier's GitHub installation. Returns `{}` when disabled, so `createCore` leaves
1534
1515
  * the `fragmentLibrary` module unassembled and the engine uses manual fragmentIds.
1535
1516
  */
1536
- function selectFragmentLibraryDeps(env, config, db) {
1517
+ export function selectFragmentLibraryDeps(env, config, db) {
1537
1518
  if (!config.fragmentLibrary.enabled)
1538
1519
  return {};
1539
1520
  const installationRepository = new D1GitHubInstallationRepository({ db });
@@ -1566,7 +1547,7 @@ function selectFragmentLibraryDeps(env, config, db) {
1566
1547
  * flag as the fragment library (both are the repo-sourced prompt library). Returns
1567
1548
  * `{}` when disabled, so `createCore` leaves the skill module unassembled.
1568
1549
  */
1569
- function selectSkillLibraryDeps(_env, config, db) {
1550
+ export function selectSkillLibraryDeps(_env, config, db) {
1570
1551
  if (!config.fragmentLibrary.enabled)
1571
1552
  return {};
1572
1553
  const installationRepository = new D1GitHubInstallationRepository({ db });
@@ -1589,7 +1570,7 @@ function selectSkillLibraryDeps(_env, config, db) {
1589
1570
  * facade's `buildNodeVcsIdentityRegistry` per "keep the runtimes symmetric": a GitLab-only Worker
1590
1571
  * deployment must let a GitLab user sign in, not just gate/merge on GitLab under the hood.
1591
1572
  */
1592
- function buildWorkerVcsIdentityRegistry(config) {
1573
+ export function buildWorkerVcsIdentityRegistry(config) {
1593
1574
  const registry = {
1594
1575
  github: { resolver: new GitHubIdentityResolver({ apiBase: config.github.apiBase, logger }) },
1595
1576
  };
@@ -1785,340 +1766,46 @@ export function buildContainer(env, overrides = {}, opts = {}) {
1785
1766
  // once so the engine's skill-freshness fan-out (slice 4) enqueues through the SAME seam the
1786
1767
  // gateway exposes, rather than reaching for the queue binding a second time.
1787
1768
  const githubWebhookIngest = new CfGitHubWebhookIngest(env.GITHUB_SYNC_QUEUE);
1788
- const dependencies = {
1789
- // App-owned backend registries (kind → provider) the connection services resolve through.
1790
- environmentBackendRegistry,
1791
- runnerBackendRegistry,
1792
- // The code-defined custom provision-type catalog, merged with the workspace rows by
1793
- // `listCustomTypes` so a programmatically-registered type surfaces in the infra editor + the
1794
- // per-service provisioning picker.
1795
- customManifestTypeRegistry,
1796
- // Resolves the per-account binary-artifact store (screenshots) for the
1797
- // visual-confirmation gate; resolving to null ⇒ the gate passes through.
1798
- resolveBinaryArtifactStore,
1799
- workspaceRepository: new D1WorkspaceRepository({ db }),
1800
- workspaceMemberRepository: new D1WorkspaceMemberRepository({ db }),
1801
- accountRepository: new D1AccountRepository({ db }),
1802
- membershipRepository: new D1MembershipRepository({ db }),
1803
- userRepository: new D1UserRepository({ db }),
1804
- passwordHasher: new WebCryptoPasswordHasher(),
1805
- blockRepository: new D1BlockRepository({ db }),
1806
- pipelineRepository: new D1PipelineRepository({ db }),
1807
- executionRepository: new D1ExecutionRepository({ db, clock }),
1808
- // Clear a finished run's personal-credential activation promptly (TTL sweep is the backstop).
1809
- subscriptionActivationRepository: new D1SubscriptionActivationRepository({ db }),
1810
- serviceRepository: new D1ServiceRepository({ db }),
1811
- workspaceMountRepository: new D1WorkspaceMountRepository({ db }),
1812
- tokenUsageRepository: new D1TokenUsageRepository({ db }),
1813
- // Telemetry lives in the dedicated TELEMETRY_DB database.
1814
- llmCallMetricRepository: new D1LlmCallMetricRepository({ db: telemetryDb }),
1815
- // Deployment-level rollups over `agent_runs` (MAIN db, not telemetry) for the operator dashboard.
1816
- platformMetricsRepository: new D1PlatformMetricsRepository({ db }),
1817
- // Unified provisioning event log (separate D1 binding). Threads the recorder into
1818
- // the env services and exposes the read service for the logs controller; undefined
1819
- // when PROVISIONING_DB isn't bound.
1820
- ...(provisioningLogRepository ? { provisioningLogRepository } : {}),
1821
- recordLlmPrompts: config.observability.recordPrompts,
1822
- // Re-exposed on the core for the agent-context read endpoint; the same instance is
1823
- // injected into the container executor below for the write path.
1824
- agentContextObservability,
1825
- // Re-exposed on the core for the search-query read endpoint AND the search proxy's
1826
- // write path (it reads it off the request container).
1827
- searchQueryObservability,
1828
- idGenerator,
1829
- clock,
1830
- // When a caller injects its own agentExecutor (tests pass a FakeAgentExecutor)
1831
- // skip selection entirely — selectAgentExecutor throws when a sandbox is opted
1832
- // in but its prerequisites are missing, which is the desired loud failure in
1833
- // production but must not fire for tests that never reach the real executor.
1834
- agentExecutor: overrides.agentExecutor ??
1835
- maybeWrapConsensus(selectAgentExecutor({
1836
- env,
1837
- config,
1838
- db,
1839
- clock,
1840
- resolveTransport,
1841
- agentKindRegistry,
1842
- subscriptions,
1843
- personalSubscriptions,
1844
- agentContextObservability,
1845
- }), env, config, db, eventPublisher, agentKindRegistry),
1846
- agentKindRegistry,
1847
- // The app-owned gate + step-resolver registries; the engine's gate machine + completion hub
1848
- // read them, and the gate registry is re-exposed on Core for the boot-time validation.
1849
- gateRegistry,
1850
- stepResolverRegistry,
1851
- // The app-owned provider registry the gate providers were wired onto above; the engine's gate
1852
- // machine reads the SAME instance through its GateContext.
1853
- providerRegistry,
1854
- initiativePresetRegistry,
1855
- workRunner: selectWorkRunner(env),
1856
- executionEventPublisher: eventPublisher,
1857
- spendPricing: config.spend,
1858
- // Price metered dynamic OpenRouter models at their real per-model rate (not the
1859
- // bare-`openrouter` fallback) using this workspace's enabled catalog.
1860
- dynamicModelPricesFor: openRouterCatalog
1861
- ? (ws) => openRouterCatalog.capabilitiesFor(ws)
1862
- : undefined,
1863
- // Repo-bootstrap repositories are wired unconditionally (reference-architecture
1864
- // CRUD is always available); the run path additionally needs the bootstrapper.
1865
- referenceArchitectureRepository: new D1ReferenceArchitectureRepository({ db }),
1866
- bootstrapJobRepository: new D1BootstrapJobRepository({ db }),
1867
- repoBootstrapper: selectRepoBootstrapper(env, config, db, clock, idGenerator, resolveTransport),
1868
- // Durably drive each bootstrap run's poll loop when the Workflows binding is
1869
- // present (mirrors the execution driver); without it a run still dispatches.
1870
- bootstrapRunner: env.BOOTSTRAP_WORKFLOW
1871
- ? new WorkflowsBootstrapRunner(env.BOOTSTRAP_WORKFLOW)
1872
- : undefined,
1873
- // Env-config-repair runs share the unified `agent_runs` table (kind-scoped). The
1874
- // job repository is wired unconditionally; the repairer (the agent fallback) is wired
1875
- // post-overrides below over the FINAL provider, and the durable runner when its
1876
- // Workflows binding is present (else the cron sweep re-drives a run left running).
1877
- envConfigRepairJobRepository: new D1EnvConfigRepairJobRepository({ db }),
1878
- envConfigRepairRunner: env.ENV_CONFIG_REPAIR_WORKFLOW
1879
- ? new WorkflowsEnvConfigRepairRunner(env.ENV_CONFIG_REPAIR_WORKFLOW)
1880
- : undefined,
1881
- // The ephemeral-environment self-test: its own run store + the durable driver when the
1882
- // Workflows binding is present. The Workflow self-finalizes on poll-budget exhaustion,
1883
- // and the cron `sweepStuckEnvTests` (index.ts scheduled) is the backstop for a lost or
1884
- // terminal instance — the run store is not agent_runs, so the unified run sweep never
1885
- // covers it.
1886
- environmentTestRunRepository: new D1EnvironmentTestRunRepository({ db }),
1887
- environmentTestRunner: env.ENV_TEST_WORKFLOW
1888
- ? new WorkflowsEnvironmentTestRunner(env.ENV_TEST_WORKFLOW)
1889
- : undefined,
1890
- ...selectGitHubDeps(env, config, db, clock, idGenerator, caches.repoFiles),
1891
- ...selectMergeLifecycleDeps(env, config, db, clock, idGenerator, providerRegistry),
1892
- // A fresh workspace's model-preset library is seeded with Kimi K2.7 as the default
1893
- // (Cloudflare-runnable on the bare AI binding). A deployment overrides the out-of-the-box
1894
- // default by passing `defaultModelPresetId` through `createApp`'s / `buildContainer`'s
1895
- // `overrides` (a `Partial<CoreDependencies>` field). Read explicitly here — rather than
1896
- // relying on the trailing `...overrides` spread — so the seam stays legible and robust to a
1897
- // future reorder. Applied only at first seed, so a user's later manual default choice wins.
1898
- defaultModelPresetId: overrides.defaultModelPresetId ?? DEFAULT_MODEL_PRESET_ID,
1899
- ...selectReleaseHealthDeps(env, config, db, providerRegistry),
1900
- // Fold the service frame's SENSITIVE test-credential refs (key + description, never values)
1901
- // into the tester prompt; present only when ENCRYPTION_KEY is set.
1902
- ...(testSecretsService
1903
- ? {
1904
- resolveTestSecretRefs: (workspaceId, blockId) => testSecretsService.resolveRefsForBlock(workspaceId, blockId),
1905
- }
1906
- : {}),
1907
- ...selectIncidentEnrichmentDeps(env, db, providerRegistry),
1908
- ...selectPackageRegistryDeps(env, db),
1909
- ...(accountSettings ? { accountSettings } : {}),
1910
- ...selectSlackDeps(config, db),
1911
- ...selectEmailInvitationDeps(config, db),
1912
- ...selectTraceSink(config),
1913
- ...selectRecurringDeps(env, config, db, clock, idGenerator),
1914
- ...selectDocumentsDeps(env, config, db, clock, idGenerator),
1915
- ...selectTasksDeps(env, config, db, clock, idGenerator),
1916
- ...selectRequirementsDeps(env, config, db),
1917
- ...selectSandboxDeps(env.SANDBOX_DB),
1918
- ...selectEnvironmentsDeps(env, config, db),
1919
- ...selectDeployDeps(env, config, db, clock),
1920
- ...selectRunnersDeps(env, config, db),
1921
- ...selectFragmentLibraryDeps(env, config, db),
1922
- ...selectSkillLibraryDeps(env, config, db),
1923
- // Push-webhook skill-source freshness fan-out (slice 4): resync affected sources via the
1924
- // sync Queue. No queue bound (local/dev) ⇒ no proactive resync; the dispatch-time probe
1925
- // is the freshness backstop.
1926
- enqueueSkillResync: async ({ accountId, sourceId }) => {
1927
- await githubWebhookIngest.queueSkillResync(accountId, sourceId);
1928
- },
1929
- // The app-owned cache bag (built above so the repo-files + account-policy resolvers share
1930
- // it). Distributed invalidation is a genuine Node-only concern, not a facade-parity gap: the
1931
- // Worker's cross-instance state already lives in globally-addressed DOs / D1.
1932
- caches,
1933
- // The pipeline-start guard resolves what's configured for a workspace + initiator.
1934
- resolveProviderCapabilities: (workspaceId, initiatedBy) => resolveWorkspaceCapabilities({
1935
- apiKeys,
1936
- subscriptions,
1937
- personalSubscriptions,
1938
- cloudflareModelsEnabled,
1939
- baseUrlFor: (provider) => baseUrlFor(provider, env),
1940
- localModelEndpoints,
1941
- openRouterCatalog,
1942
- accountSettings,
1943
- workspaceAccountOf: (workspaceId) => new D1WorkspaceRepository({ db }).accountOf(workspaceId),
1944
- modelPolicySupported: config.infrastructure?.modelPolicy?.supported ?? false,
1945
- caches,
1946
- }, workspaceId, initiatedBy),
1947
- // Run the engine's gate-probe / merge GitHub reads under the run initiator's ambient
1948
- // context, so a per-user PAT (when set) is preferred over the App token.
1949
- runInitiatorScope: runWithInitiator,
1950
- ...overrides,
1951
- };
1952
- // Wire the live env-config repair agent over the FINAL environment provider (after the
1953
- // `...overrides` above), so a native adapter injected via overrides — not the default
1954
- // manifest provider — is the one the repair dispatcher uses. Unwired on a stock deployment
1955
- // (the generic provider has no `describeRepairAgent`), exactly like the service guard.
1956
- const envConfigRepairer = selectEnvConfigRepairer({
1769
+ return assembleWorkerContainer({
1957
1770
  env,
1958
1771
  config,
1959
1772
  db,
1773
+ telemetryDb,
1960
1774
  clock,
1961
- resolveTransport,
1962
- override: dependencies.environmentProvider,
1963
- environmentBackendRegistry,
1964
- });
1965
- // Don't clobber an override-provided repairer (e.g. the conformance suite's fake): an
1966
- // explicit `overrides.envConfigRepairer` wins, exactly like `repoBootstrapper`.
1967
- if (envConfigRepairer && !dependencies.envConfigRepairer) {
1968
- dependencies.envConfigRepairer = envConfigRepairer;
1969
- }
1970
- // Apply any test-injected gate providers LAST, so they override the config wiring done by the
1971
- // `select*Deps` spreads above (the conformance suite drives the externalized CI gate over a
1972
- // faked verdict). Production leaves `gateProviders` undefined, so this is a no-op outside tests.
1973
- applyGateProviders(providerRegistry, opts.gateProviders);
1974
- // Surface any gate left as a silent pass-through (no provider wired) so a misconfigured
1975
- // deployment is visible in the logs instead of quietly auto-merging without checking CI.
1976
- warnUnwiredGates(providerRegistry, logger);
1977
- // The unified `agent_runs` reader (kind-spanning) — surfaced on the container for
1978
- // `AgentRunController` AND folded into the mothership `repositories` registry below (it is the
1979
- // one repo not carried by `CoreDependencies`). One instance shared by both.
1980
- const agentRunRepository = new D1AgentRunRepository({ db });
1981
- return {
1982
- ...createCore(dependencies),
1983
- config,
1984
- // The deployment-wide trusted web-search upstream (built from this facade's own `WEB_SEARCH_*`
1985
- // env), read by `WebSearchProxyController` as the fallback when a run's account has no keys.
1986
- // Surfaced on the ServerContainer here (not part of `CoreDependencies`, so `createCore` doesn't
1987
- // carry it) — kept symmetric with the Node facade.
1988
- ...(defaultWebSearchUpstream ? { defaultWebSearchUpstream } : {}),
1989
- // Hosted source-control PAT login: a user signs in with their OWN GitHub/GitLab PAT (the
1990
- // shared `/auth/pat` flow resolves it to an account, held to the login/org/domain allowlist).
1991
- // GitHub always; GitLab when configured. Mirrors the Node facade so a GitLab-only Worker
1992
- // deployment lets a GitLab user sign in (previously the Worker wired none, leaving it
1993
- // OAuth-only / GitHub-only for sign-in even though the engine gated/merged on GitLab).
1994
- vcsIdentity: buildWorkerVcsIdentityRegistry(config),
1995
- // The app-owned VCS provider registry the neutral webhook route resolves a provider from.
1996
- vcsRegistry,
1997
- // The same checkout-free repo resolver the engine binds pre/post-ops with, surfaced so
1998
- // the shared service-spec read controller can read the `spec/` artifact off main.
1999
- resolveRunRepoContext: dependencies.resolveRunRepoContext,
2000
- // The block→service→repo resolver, surfaced so the task-search controller can scope a
2001
- // GitHub-issue search to the originating service's repo (and refuse it when unlinked).
2002
- resolveRepoTarget: buildResolveRepoTarget(db),
2003
- agentRunRepository,
2004
- // Execution-scoped repo, surfaced for the conformance suite's compareAndSwap parity check.
2005
- executionRepository: dependencies.executionRepository,
2006
- // Mothership-side GitHub token delegation (`POST /internal/github/installation-token`):
2007
- // when this deployment's GitHub App is configured, a machine-authed mothership-mode node
2008
- // can mint the short-lived installation tokens its agent containers/gates need — the App
2009
- // private key never leaves this Worker. The registry satisfies the seam structurally.
2010
- // Wired symmetrically on the Node facade.
2011
- ...(config.github.enabled
2012
- ? { githubTokenDelegation: buildAppRegistry(env, config, db, clock) }
2013
- : {}),
2014
- // Mothership-side real-time UPSTREAM delivery (`POST /internal/events/publish`): when this
2015
- // Worker is a mothership (its WORKSPACE_EVENTS hub is bound), a machine-authed mothership-mode
2016
- // node's relayed engine events are injected into the per-workspace WorkspaceEventsHub Durable
2017
- // Object, so hosted teammates on the shared board see the local node's activity live. Wired
2018
- // symmetrically on the Node facade (the in-process hub / propagator). Absent binding ⇒ the
2019
- // endpoint 503s.
2020
- ...(env.WORKSPACE_EVENTS
2021
- ? { machineEventRelay: new DurableObjectMachineEventRelay(env.WORKSPACE_EVENTS) }
2022
- : {}),
2023
- // The repository registry the mothership-mode machine API (`/internal/persistence`) reflects
2024
- // over, so a Cloudflare deployment can act as a mothership for mothership-mode local nodes.
2025
- // The controller gates which repo+method is callable (allow-list) and account-scopes each
2026
- // call; exposing the whole `dependencies` (which carries every repo under its canonical name)
2027
- // is safe. `agentRunRepository` is the one repo NOT part of `CoreDependencies` (the engine's
2028
- // Core never reads it — it's surfaced separately above for `AgentRunController`), so fold it
2029
- // in explicitly, else the board's retry/stop `getRef` call comes back `... is not wired`.
2030
- // Sourced identically on both facades so they attach the same registry surface.
2031
- repositories: {
2032
- ...dependencies,
2033
- agentRunRepository,
2034
- // The binary-artifact METADATA store (visual-confirmation gate screenshots/references) is
2035
- // not part of `CoreDependencies` (it's composed into `resolveBinaryArtifactStore`, not the
2036
- // engine's Core), so fold it into the reflected registry explicitly — else a mothership-mode
2037
- // node's artifact reads/writes come back `... is not wired`. The blob BYTES stay per-account
2038
- // local; only the metadata is proxied.
2039
- binaryArtifactMetadataStore: new D1BinaryArtifactMetadataStore({ db }),
2040
- // The sensitive per-service test-credential store is org/durable state the engine reads via
2041
- // the `resolveTestSecretRefs` FUNCTION (never the repo directly), so it isn't in
2042
- // `CoreDependencies` either — fold it in explicitly, else a mothership-mode node's tester
2043
- // run-path read + the inspector CRUD come back `... is not wired`. Only the SEALED blob is
2044
- // proxied (decrypted service-side under the LOCAL key), like the observability/runner-pool
2045
- // connections.
2046
- testSecretsRepository: new D1TestSecretsRepository({ db }),
2047
- // GitHub projection + installation reads the mothership serves over the persistence RPC even
2048
- // when its OWN github service is off. A mothership-mode local node reaches GitHub by token
2049
- // DELEGATION (no local App), which enables `container.github`, so its board snapshot
2050
- // (`github.service.listRepos` → `repoProjectionRepository.list`) and run-path repo resolution
2051
- // (`githubInstallationRepository.getByWorkspace` + `repoProjectionRepository.list`) read the
2052
- // projection over RPC. Both are plain org tables the mothership owns (`selectGitHubDeps`
2053
- // folds them into `dependencies` only when the App is configured), so reflect them regardless
2054
- // of `config.github.enabled`, else a mothership without its own App 500s that board load with
2055
- // `... is not wired`. Allow-listed in `REMOTE_PERSISTENCE_METHODS`; folded in explicitly like
2056
- // the stores above. Sourced identically on both facades.
2057
- repoProjectionRepository: new D1RepoProjectionRepository({ db }),
2058
- githubInstallationRepository: new D1GitHubInstallationRepository({ db }),
1775
+ idGenerator,
1776
+ caches,
1777
+ overrides,
1778
+ gateProviders: opts.gateProviders,
1779
+ cloudflareModelsEnabled,
1780
+ registries: {
1781
+ environmentBackendRegistry,
1782
+ runnerBackendRegistry,
1783
+ customManifestTypeRegistry,
1784
+ userSecretKindRegistry,
1785
+ agentKindRegistry,
1786
+ gateRegistry,
1787
+ stepResolverRegistry,
1788
+ initiativePresetRegistry,
1789
+ vcsRegistry,
1790
+ providerRegistry,
2059
1791
  },
2060
- // App-owned backend registries, surfaced so the workspace snapshot's backend-kind
2061
- // selectors (`environmentBackendKinds` / `runnerBackendKinds`) read the registered kinds.
2062
- environmentBackendRegistry,
2063
- runnerBackendRegistry,
2064
- // The consensus transcript store, for the read endpoint (the SPA window's initial
2065
- // load / reload). Always wired; live updates ride the `consensus` workspace event.
2066
- consensusSessionRepository: new D1ConsensusSessionRepository({ db }),
2067
- // Resolves the per-account binary-artifact store (screenshots) for the artifact
2068
- // controllers + the visual-confirmation gate (configured per-account in the UI).
2069
- resolveBinaryArtifactStore,
2070
- // The Worker's only test-env backend is the `environment-provider` (its UI-test container is
2071
- // torn down with the run — no long-lived in-container compose default), so a missing provider
2072
- // IS a real gap the "test environment not configured" banner should surface. Derived from the
2073
- // capability descriptor for symmetry with the Node facade (`testEnvHasZeroConfigDefault`).
2074
- ephemeralEnvironmentsRequireProvider: !testEnvHasZeroConfigDefault(config.infrastructure),
2075
- // The sensitive per-service test-credential store the shared test-secrets controller reads;
2076
- // present when the shared ENCRYPTION_KEY is configured.
2077
- ...(testSecretsService ? { testSecrets: testSecretsService } : {}),
2078
- // The vendor-credential (subscription token pool) service the shared controller
2079
- // reads; present when the shared ENCRYPTION_KEY is configured.
1792
+ provisioningLogRepository,
1793
+ resolveTransport,
2080
1794
  subscriptions,
2081
- // The per-user individual-usage subscription store (Claude); present when the
2082
- // shared ENCRYPTION_KEY is configured.
1795
+ testSecretsService,
2083
1796
  personalSubscriptions,
2084
- // The direct-provider API-key pool (account/workspace/user); present when the
2085
- // shared ENCRYPTION_KEY is configured.
2086
1797
  apiKeys,
2087
- // The inbound public-API key store; present when the shared ENCRYPTION_KEY is configured.
2088
1798
  publicApiKeys,
2089
- // Whether the opt-in Cloudflare Workers AI lib is enabled (the `AI` binding).
2090
- cloudflareModelsEnabled,
2091
- // The direct-provider base-URL resolver the catalog uses to gate selectability on a
2092
- // resolvable endpoint (e.g. LiteLLM stays unselectable until LITELLM_BASE_URL is set).
2093
- baseUrlFor: (provider) => baseUrlFor(provider, env),
2094
- // The per-user locally-run model endpoints store; present when ENCRYPTION_KEY is set.
2095
1799
  localModelEndpoints,
2096
- // The per-user generic secret store (GitHub PAT, …); present when ENCRYPTION_KEY is set.
2097
1800
  userSecrets,
2098
- // The per-user "repos my PAT can reach" projection (board redaction + picker expansion).
2099
- userRepoAccess: new D1UserRepoAccessRepository({ db }),
2100
- // The sealed-secret inventory the key-drift sweep + drop remediation use (ADR 0026 D6.2/D6.3);
2101
- // gated on ENCRYPTION_KEY (no key ⇒ nothing is sealed to scan).
2102
- ...(env.ENCRYPTION_KEY?.trim()
2103
- ? { sealedSecretInventory: new D1SealedSecretInventory({ db }) }
2104
- : {}),
2105
- // The per-workspace OpenRouter dynamic-catalog store; present when the API-key pool is.
2106
1801
  openRouterCatalog,
2107
- gateways: {
2108
- // Real-time event delivery via the per-workspace WorkspaceEventsHub DO (when
2109
- // the WORKSPACE_EVENTS namespace is bound; absent → the events route 501s).
2110
- realtime: new DoRealtimeGateway(env.WORKSPACE_EVENTS),
2111
- // GitHub backfill via Workflows; webhook/resync ingest via the sync Queue. Both
2112
- // fall back to inline handling when their binding is absent (local/dev/tests).
2113
- githubBackfill: new WorkflowsBackfillScheduler(env.GITHUB_BACKFILL_WORKFLOW),
2114
- githubWebhook: githubWebhookIngest,
2115
- // LLM proxy upstream: OpenAI-compatible providers from env keys + the in-process
2116
- // Workers AI binding path (the `workers-ai` provider).
2117
- llmUpstream: new WorkersAiLlmUpstream(env),
2118
- // Container web-search upstream is resolved per-account by the proxy controller
2119
- // (keys moved out of env into the per-account settings store), so no boot-time
2120
- // gateway upstream is wired here.
2121
- },
2122
- };
1802
+ eventPublisher,
1803
+ agentContextObservability,
1804
+ searchQueryObservability,
1805
+ accountSettings,
1806
+ defaultWebSearchUpstream,
1807
+ resolveBinaryArtifactStore,
1808
+ githubWebhookIngest,
1809
+ });
2123
1810
  }
2124
1811
  //# sourceMappingURL=container.js.map