thinkwork-cli 0.12.16 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/dist/cli.js +517 -10403
  2. package/dist/commands/enterprise/templates/deploy-repo/docs/runbook.md +3 -8
  3. package/dist/commands/enterprise/templates/deploy-repo/terraform/main.tf +1 -184
  4. package/dist/drizzle/0050_brain_v0_entity_subtype.sql +2 -2
  5. package/dist/drizzle/0051_brain_v0_tenant_entity_pages.sql +6 -6
  6. package/dist/drizzle/0052_brain_v0_external_refs.sql +2 -2
  7. package/dist/drizzle/0053_brain_v0_unresolved_mentions_subtype.sql +2 -2
  8. package/dist/drizzle/0145_knowledge_graph_thread_ingest.sql +14 -14
  9. package/dist/drizzle/0146_knowledge_graph_source_scope.sql +1 -1
  10. package/dist/drizzle/0157_knowledge_graph_observations_source.sql +2 -2
  11. package/dist/drizzle/0158_wiki_tenant_scope.sql +1 -1
  12. package/dist/drizzle/0165_plugin_premium_entitlements.sql +2 -2
  13. package/dist/drizzle/{0166_company_brain_substrate_contract.sql → 0166_brain_substrate_contract.sql} +9 -9
  14. package/dist/drizzle/{0167_company_brain_artifact_manifest_runtime.sql → 0167_brain_artifact_manifest_runtime.sql} +5 -5
  15. package/dist/drizzle/0168_eval_skill_gate.sql +1 -1
  16. package/dist/drizzle/0183_okf_artifact_manifests.sql +1 -1
  17. package/dist/drizzle/0200_eval_results_execution_tier.sql +40 -0
  18. package/dist/drizzle/0201_brain_dream_runs.sql +72 -0
  19. package/dist/drizzle/0202_backfill_thread_participants_from_senders.sql +110 -0
  20. package/dist/drizzle/0203_threads_mode_override.sql +61 -0
  21. package/dist/drizzle/0204_thread_turns_triggering_message_id.sql +48 -0
  22. package/dist/drizzle/0205_routines_git_python.sql +185 -0
  23. package/dist/drizzle/0206_agent_loop_versions_routine_actions.sql +40 -0
  24. package/dist/drizzle/0207_tenant_credentials_github_repo_kind.sql +52 -0
  25. package/dist/drizzle/0208_knowledge_graph_neutral_identifiers.sql +253 -0
  26. package/dist/drizzle/0209_living_artifacts_schema.sql +109 -0
  27. package/dist/drizzle/0210_think137_automations_additive_schema.sql +113 -0
  28. package/dist/drizzle/0211_backfill_agent_loop_versions_target_spec.sql +120 -0
  29. package/dist/drizzle/0212_fold_webhooks_into_automations.sql +312 -0
  30. package/dist/drizzle/0213_agent_loop_versions_judge_evidence_nullable.sql +63 -0
  31. package/dist/drizzle/0214_think137_drop_judge_evidence_roi.sql +99 -0
  32. package/dist/drizzle/0215_agent_loop_versions_goal_worker_policy_nullable.sql +70 -0
  33. package/dist/drizzle/0216_drop_agent_loop_versions_goal_worker_policy.sql +81 -0
  34. package/dist/drizzle/0217_agents_capability_folder_dispatch.sql +12 -0
  35. package/dist/drizzle/0218_document_plates.sql +30 -0
  36. package/dist/drizzle/0219_document_section_waivers.sql +29 -0
  37. package/dist/drizzle/0220_artifacts_created_by_user.sql +21 -0
  38. package/dist/drizzle/0221_artifact_shares.sql +29 -0
  39. package/dist/drizzle/0221_workflow_interpreter_thin_slice.sql +71 -0
  40. package/dist/drizzle/0222_compliance_drainer_select_audit_events.sql +21 -0
  41. package/dist/drizzle/0223_document_conformance_reports.sql +38 -0
  42. package/dist/drizzle/0224_artifact_refresh_state.sql +11 -0
  43. package/dist/drizzle/0225_think216_agent_loop_convergence.sql +21 -0
  44. package/dist/drizzle/0226_drop_n8n_agent_step_runs.sql +6 -0
  45. package/dist/drizzle/0227_analyst_reader_role.sql +1055 -0
  46. package/dist/drizzle/0228_tenant_credentials_rds_iam_kind.sql +62 -0
  47. package/dist/drizzle/0229_analyst_reader_rds_iam_grant.sql +79 -0
  48. package/dist/drizzle/0230_analyst_rls.sql +1613 -0
  49. package/dist/drizzle/0231_cost_events_cache_write_enforcement_exempt.sql +11 -0
  50. package/dist/plugins/catalog/package.json +0 -1
  51. package/dist/plugins/catalog/src/__tests__/build-catalog.test.ts +0 -1
  52. package/dist/plugins/catalog/src/__tests__/catalog.test.ts +16 -8
  53. package/dist/plugins/catalog/src/__tests__/contracts.test.ts +56 -0
  54. package/dist/plugins/catalog/src/__tests__/plugin-package.test.ts +0 -2
  55. package/dist/plugins/catalog/src/__tests__/plugin-registry.test.ts +0 -5
  56. package/dist/plugins/catalog/src/contracts.ts +112 -0
  57. package/dist/plugins/catalog/src/registry/generated-first-party.ts +0 -6
  58. package/dist/plugins/n8n/README.md +4 -36
  59. package/dist/plugins/n8n/src/deployment/managed-app.ts +0 -17
  60. package/dist/plugins/n8n/src/manifest.ts +0 -5
  61. package/dist/plugins/n8n/terraform/n8n/main.tf +0 -26
  62. package/dist/plugins/n8n/terraform/n8n/outputs.tf +0 -5
  63. package/dist/plugins/n8n/terraform/n8n/variables.tf +0 -6
  64. package/dist/plugins/n8n/test/manifest.test.ts +0 -1
  65. package/dist/plugins/twenty/package.json +5 -0
  66. package/dist/plugins/twenty/scripts/lib/__tests__/load-records.test.ts +232 -0
  67. package/dist/plugins/twenty/scripts/lib/__tests__/mappers.test.ts +489 -0
  68. package/dist/plugins/twenty/scripts/lib/__tests__/members-ensure.test.ts +199 -0
  69. package/dist/plugins/twenty/scripts/lib/__tests__/provision-members-db.test.ts +43 -0
  70. package/dist/plugins/twenty/scripts/lib/__tests__/schema-ensure.test.ts +230 -0
  71. package/dist/plugins/twenty/scripts/lib/__tests__/twenty-client.test.ts +207 -0
  72. package/dist/plugins/twenty/scripts/lib/lastmile-reader.ts +282 -0
  73. package/dist/plugins/twenty/scripts/lib/load-attachments.ts +220 -0
  74. package/dist/plugins/twenty/scripts/lib/load-records.ts +680 -0
  75. package/dist/plugins/twenty/scripts/lib/mappers.ts +559 -0
  76. package/dist/plugins/twenty/scripts/lib/members-ensure.ts +381 -0
  77. package/dist/plugins/twenty/scripts/lib/provision-members-db.ts +191 -0
  78. package/dist/plugins/twenty/scripts/lib/schema-ensure.ts +425 -0
  79. package/dist/plugins/twenty/scripts/lib/twenty-client.ts +246 -0
  80. package/dist/plugins/twenty/scripts/migrate-lastmile.ts +610 -0
  81. package/dist/plugins/twenty/scripts/provision-twenty-members.ts +214 -0
  82. package/dist/plugins/twenty/src/manifest.ts +99 -0
  83. package/dist/plugins/twenty/terraform/twenty/README.md +1 -1
  84. package/dist/plugins/twenty/test/manifest.test.ts +12 -2
  85. package/dist/terraform/examples/greenfield/main.tf +90 -380
  86. package/dist/terraform/examples/greenfield/terraform.tfvars.example +0 -1
  87. package/dist/terraform/modules/app/agentcore-pi/README.md +1 -3
  88. package/dist/terraform/modules/app/agentcore-pi/main.tf +29 -38
  89. package/dist/terraform/modules/app/agentcore-pi/variables.tf +23 -15
  90. package/dist/terraform/modules/app/agentcore-runtime/main.tf +3 -3
  91. package/dist/terraform/modules/app/customer-domain/main.tf +16 -2
  92. package/dist/terraform/modules/app/deployment-control-plane/main.tf +5 -0
  93. package/dist/terraform/modules/app/deployment-control-plane/runner.py +85 -207
  94. package/dist/terraform/modules/app/deployment-control-plane/test_runner_bundle.py +56 -2
  95. package/dist/terraform/modules/app/hindsight-memory/main.tf +52 -4
  96. package/dist/terraform/modules/app/lambda-api/eval-fanout.tf +7 -0
  97. package/dist/terraform/modules/app/lambda-api/handlers.tf +493 -89
  98. package/dist/terraform/modules/app/lambda-api/iam-grouped.tf +215 -96
  99. package/dist/terraform/modules/app/lambda-api/main.tf +24 -5
  100. package/dist/terraform/modules/app/lambda-api/outputs.tf +19 -11
  101. package/dist/terraform/modules/app/lambda-api/variables.tf +94 -67
  102. package/dist/terraform/modules/app/ses-email/main.tf +14 -2
  103. package/dist/terraform/modules/app/workflow-interpreter-stepfunctions/main.tf +493 -0
  104. package/dist/terraform/modules/app/workflow-interpreter-stepfunctions/outputs.tf +34 -0
  105. package/dist/terraform/modules/app/workflow-interpreter-stepfunctions/variables.tf +32 -0
  106. package/dist/terraform/modules/data/aurora-postgres/main.tf +55 -0
  107. package/dist/terraform/modules/data/aurora-postgres/outputs.tf +15 -0
  108. package/dist/terraform/modules/data/s3-buckets/main.tf +26 -0
  109. package/dist/terraform/modules/thinkwork/README.md +0 -1
  110. package/dist/terraform/modules/thinkwork/main.tf +167 -446
  111. package/dist/terraform/modules/thinkwork/outputs.tf +2 -142
  112. package/dist/terraform/modules/thinkwork/variables.tf +55 -309
  113. package/dist/terraform/schema.graphql +4 -0
  114. package/dist/workspace-defaults/files/AGENTS.md +45 -31
  115. package/dist/workspace-defaults/files/CONTEXT.md +48 -4
  116. package/dist/workspace-defaults/files/GUARDRAILS.md +18 -0
  117. package/dist/workspace-defaults/files/MEMORY_GUIDE.md +32 -4
  118. package/dist/workspace-defaults/files/SPACE.md +34 -19
  119. package/dist/workspace-defaults/files/TOOLS.md +30 -0
  120. package/dist/workspace-defaults/files/skills/document-composer/SKILL.md +154 -0
  121. package/dist/workspace-defaults/files/skills/document-composer/references/authoring-rules.md +101 -0
  122. package/package.json +1 -1
  123. package/dist/plugins/company-brain/README.md +0 -37
  124. package/dist/plugins/company-brain/package.json +0 -33
  125. package/dist/plugins/company-brain/runtime/cognee/Dockerfile +0 -11
  126. package/dist/plugins/company-brain/smoke/cognee-managed-app-smoke.mjs +0 -458
  127. package/dist/plugins/company-brain/smoke/cognee-memory-cutover-smoke.mjs +0 -539
  128. package/dist/plugins/company-brain/smoke/company-brain-context-engine-smoke.mjs +0 -312
  129. package/dist/plugins/company-brain/smoke/company-brain-operations-smoke.mjs +0 -449
  130. package/dist/plugins/company-brain/smoke/company-brain-plugin-smoke.mjs +0 -655
  131. package/dist/plugins/company-brain/smoke/hindsight-memory-isolation-smoke.mjs +0 -474
  132. package/dist/plugins/company-brain/src/api/cognee-client.ts +0 -896
  133. package/dist/plugins/company-brain/src/api/cognee-cluster-identity.ts +0 -49
  134. package/dist/plugins/company-brain/src/api/cognee-memory-scope.ts +0 -84
  135. package/dist/plugins/company-brain/src/api/context-engine-provider.ts +0 -888
  136. package/dist/plugins/company-brain/src/api/migration.ts +0 -665
  137. package/dist/plugins/company-brain/src/deployment/cognee-managed-app.ts +0 -396
  138. package/dist/plugins/company-brain/src/index.ts +0 -62
  139. package/dist/plugins/company-brain/src/manifest.ts +0 -112
  140. package/dist/plugins/company-brain/terraform/cognee/README.md +0 -263
  141. package/dist/plugins/company-brain/terraform/cognee/main.tf +0 -766
  142. package/dist/plugins/company-brain/terraform/cognee/outputs.tf +0 -144
  143. package/dist/plugins/company-brain/terraform/cognee/variables.tf +0 -402
  144. package/dist/plugins/company-brain/test/api/cognee-client.test.ts +0 -562
  145. package/dist/plugins/company-brain/test/api/cognee-memory-scope.test.ts +0 -74
  146. package/dist/plugins/company-brain/test/api/context-engine-provider.test.ts +0 -447
  147. package/dist/plugins/company-brain/test/api/migration.test.ts +0 -465
  148. package/dist/plugins/company-brain/test/manifest.test.ts +0 -95
  149. package/dist/plugins/company-brain/tsconfig.json +0 -8
@@ -1,888 +0,0 @@
1
- import { and, desc, eq, sql } from "drizzle-orm";
2
- import { getDb, type Database } from "@thinkwork/database-pg";
3
- import {
4
- brainArtifactManifests,
5
- brainSubstrateMigrations,
6
- brainSubstrateStates,
7
- } from "@thinkwork/database-pg/schema";
8
-
9
- export type ContextEngineMode = "results" | "answer";
10
- export type ContextEngineScope = "personal" | "team" | "auto";
11
- export type ContextEngineDepth = "quick" | "deep";
12
- export type ContextProviderFamily = "brain";
13
- export type ContextSourceFamily = "brain";
14
-
15
- export interface ContextEngineProviderRequest {
16
- query: string;
17
- mode: ContextEngineMode;
18
- scope: ContextEngineScope;
19
- depth: ContextEngineDepth;
20
- limit: number;
21
- providerOptions?: {
22
- brain?: {
23
- sourceKind?: string;
24
- sourceType?: string;
25
- datasetId?: string;
26
- nodeSetIds?: string[];
27
- topK?: number;
28
- onlyContext?: boolean;
29
- };
30
- };
31
- caller: {
32
- tenantId: string;
33
- userId?: string | null;
34
- agentId?: string | null;
35
- threadId?: string | null;
36
- spaceId?: string | null;
37
- templateId?: string | null;
38
- traceId?: string | null;
39
- };
40
- }
41
-
42
- export interface ContextHit {
43
- id: string;
44
- providerId: string;
45
- family: ContextProviderFamily;
46
- sourceFamily?: ContextSourceFamily;
47
- title: string;
48
- snippet: string;
49
- score?: number | null;
50
- rank?: number | null;
51
- scope: ContextEngineScope;
52
- provenance: {
53
- label?: string;
54
- uri?: string;
55
- sourceId?: string;
56
- metadata?: Record<string, unknown>;
57
- };
58
- metadata?: Record<string, unknown>;
59
- freshness?: {
60
- asOf: string;
61
- ttlSeconds: number;
62
- };
63
- }
64
-
65
- export interface ContextProviderStatus {
66
- providerId: string;
67
- family: ContextProviderFamily;
68
- sourceFamily?: ContextSourceFamily;
69
- displayName: string;
70
- state: "ok" | "skipped" | "error" | "timeout" | "stale";
71
- scope: ContextEngineScope;
72
- durationMs?: number;
73
- hitCount?: number;
74
- error?: string;
75
- reason?: string;
76
- defaultEnabled?: boolean;
77
- freshness?: {
78
- asOf: string;
79
- ttlSeconds: number;
80
- };
81
- metadata?: Record<string, unknown>;
82
- }
83
-
84
- export interface ContextProviderResult {
85
- hits: ContextHit[];
86
- status?: Partial<ContextProviderStatus>;
87
- }
88
-
89
- export interface ContextProviderDescriptor {
90
- id: string;
91
- family: ContextProviderFamily;
92
- sourceFamily?: ContextSourceFamily;
93
- displayName: string;
94
- enabled?: boolean;
95
- defaultEnabled: boolean;
96
- config?: Record<string, unknown>;
97
- supportedScopes?: ContextEngineScope[];
98
- timeoutMs?: number;
99
- query(request: ContextEngineProviderRequest): Promise<ContextProviderResult>;
100
- status?(
101
- request: ContextEngineProviderRequest,
102
- ): Promise<Partial<ContextProviderStatus> | null>;
103
- }
104
-
105
- const DEFAULT_BRAIN_LIMIT = 10;
106
- const MAX_BRAIN_LIMIT = 20;
107
- const REQUIRED_CAPABILITIES = ["retrieval", "provenance"] as const;
108
- const BRAIN_SEARCH_STOPWORDS = new Set([
109
- "a",
110
- "an",
111
- "and",
112
- "are",
113
- "at",
114
- "for",
115
- "from",
116
- "in",
117
- "is",
118
- "me",
119
- "my",
120
- "of",
121
- "on",
122
- "the",
123
- "to",
124
- "what",
125
- "whats",
126
- "what's",
127
- "with",
128
- ]);
129
-
130
- type CapabilityStatus = "enabled" | "disabled" | "degraded" | "unknown";
131
-
132
- interface BrainSubstrateState {
133
- id: string;
134
- tenant_id: string;
135
- storage_tier: string;
136
- active_backend: string;
137
- status: string;
138
- health_status: string;
139
- launch_capabilities: unknown;
140
- graph_provider: string | null;
141
- vector_provider: string | null;
142
- embedding_model: string | null;
143
- vector_dimension: number | null;
144
- cognee_version: string | null;
145
- latest_ingest_at: Date | string | null;
146
- latest_projection_at: Date | string | null;
147
- updated_at: Date | string;
148
- }
149
-
150
- interface BrainPageSearchRow {
151
- id: string;
152
- type: string;
153
- entity_subtype: string;
154
- slug: string;
155
- title: string;
156
- summary: string | null;
157
- body_md: string | null;
158
- last_compiled_at: Date | string | null;
159
- updated_at: Date | string;
160
- score: number | string | null;
161
- }
162
-
163
- interface BrainArtifactManifestSummary {
164
- id: string;
165
- manifest_kind: string;
166
- storage_tier: string;
167
- source_family: string | null;
168
- source_kind: string | null;
169
- source_type: string | null;
170
- source_id_hash: string | null;
171
- object_count: number;
172
- source_count: number;
173
- checksum_sha256: string | null;
174
- status: string;
175
- metadata: unknown;
176
- updated_at: Date | string;
177
- }
178
-
179
- interface BrainSubstrateMigrationSummary {
180
- id: string;
181
- phase: string;
182
- status: string;
183
- from_storage_tier: string;
184
- to_storage_tier: string;
185
- validation_summary: unknown;
186
- error_message: string | null;
187
- rollback_window_closes_at: Date | string | null;
188
- updated_at: Date | string;
189
- }
190
-
191
- interface BrainReadRoute {
192
- backend: "default" | "production";
193
- storageTier: "default" | "production";
194
- role: "active" | "shadow" | "fallback" | "vault";
195
- state: "serving" | "shadowing" | "available" | "unavailable";
196
- reason?: string;
197
- }
198
-
199
- interface BrainReadPosture {
200
- active: BrainReadRoute;
201
- shadow: BrainReadRoute | null;
202
- fallback: BrainReadRoute | null;
203
- vault: BrainReadRoute;
204
- migration: {
205
- id: string;
206
- phase: string;
207
- status: string;
208
- fromStorageTier: string;
209
- toStorageTier: string;
210
- validation: Record<string, unknown>;
211
- rollbackWindowClosesAt: string | null;
212
- } | null;
213
- }
214
-
215
- export interface CompanyBrainProviderOptions {
216
- db?: Database;
217
- defaultEnabled?: boolean;
218
- loadSubstrateState?: (
219
- tenantId: string,
220
- ) => Promise<BrainSubstrateState | null>;
221
- loadLatestMigration?: (args: {
222
- tenantId: string;
223
- substrateId: string;
224
- }) => Promise<BrainSubstrateMigrationSummary | null>;
225
- searchPages?: (args: {
226
- tenantId: string;
227
- query: string;
228
- limit: number;
229
- }) => Promise<BrainPageSearchRow[]>;
230
- loadArtifactManifests?: (args: {
231
- tenantId: string;
232
- limit: number;
233
- sourceKind?: string;
234
- sourceType?: string;
235
- }) => Promise<BrainArtifactManifestSummary[]>;
236
- }
237
-
238
- export function createCompanyBrainContextProvider(
239
- options: CompanyBrainProviderOptions = {},
240
- ): ContextProviderDescriptor {
241
- const db = options.db ?? getDb();
242
- const loadSubstrateState =
243
- options.loadSubstrateState ??
244
- ((tenantId: string) => loadSubstrateStateFromDb(db, tenantId));
245
- const searchPages =
246
- options.searchPages ?? ((args) => searchBrainPages(db, args));
247
- const loadArtifactManifests =
248
- options.loadArtifactManifests ??
249
- ((args) => loadArtifactManifestsFromDb(db, args));
250
- const loadLatestMigration =
251
- options.loadLatestMigration ??
252
- ((args) => loadLatestMigrationFromDb(db, args));
253
-
254
- return {
255
- id: "brain",
256
- family: "brain",
257
- sourceFamily: "brain",
258
- displayName: "Company Brain",
259
- defaultEnabled: options.defaultEnabled ?? true,
260
- supportedScopes: ["team", "auto"],
261
- async query(request): Promise<ContextProviderResult> {
262
- const substrate = await loadSubstrateState(request.caller.tenantId);
263
- const substrateStatus = evaluateSubstrate(substrate);
264
- if (!substrateStatus.canQuery) {
265
- return {
266
- hits: [],
267
- status: substrateStatus.status,
268
- };
269
- }
270
-
271
- const migration = await loadLatestMigration({
272
- tenantId: request.caller.tenantId,
273
- substrateId: substrate!.id,
274
- });
275
- const readPosture = brainReadPosture(substrate!, migration);
276
- const brainOptions = request.providerOptions?.brain ?? {};
277
- const manifests = await loadArtifactManifests({
278
- tenantId: request.caller.tenantId,
279
- limit: 10,
280
- sourceKind: brainOptions.sourceKind,
281
- sourceType: brainOptions.sourceType,
282
- });
283
- const rows = await searchPages({
284
- tenantId: request.caller.tenantId,
285
- query: request.query,
286
- limit: Math.min(
287
- brainOptions.topK ?? request.limit ?? DEFAULT_BRAIN_LIMIT,
288
- MAX_BRAIN_LIMIT,
289
- ),
290
- });
291
-
292
- return {
293
- hits: rows.map((row, index) =>
294
- brainPageToHit({
295
- row,
296
- request,
297
- substrate: substrate!,
298
- readPosture,
299
- manifests,
300
- index,
301
- }),
302
- ),
303
- status: {
304
- ...substrateStatus.status,
305
- state:
306
- substrateStatus.status.state === "ok" && rows.length === 0
307
- ? "stale"
308
- : substrateStatus.status.state,
309
- reason:
310
- rows.length === 0
311
- ? "active Company Brain substrate returned no matching graph context"
312
- : substrateStatus.status.reason,
313
- metadata: {
314
- ...substrateStatus.status.metadata,
315
- readPosture,
316
- retrievalOptions: {
317
- sourceKind: brainOptions.sourceKind ?? null,
318
- sourceType: brainOptions.sourceType ?? null,
319
- datasetId: brainOptions.datasetId ?? null,
320
- nodeSetIds: brainOptions.nodeSetIds ?? [],
321
- topK: brainOptions.topK ?? request.limit,
322
- depth: request.depth,
323
- onlyContext: brainOptions.onlyContext ?? true,
324
- },
325
- provenanceKinds: summarizeManifestKinds(manifests),
326
- vaultProvenance: vaultProvenance(manifests),
327
- },
328
- },
329
- };
330
- },
331
- };
332
- }
333
-
334
- async function loadSubstrateStateFromDb(
335
- db: Database,
336
- tenantId: string,
337
- ): Promise<BrainSubstrateState | null> {
338
- const [row] = await db
339
- .select()
340
- .from(brainSubstrateStates)
341
- .where(eq(brainSubstrateStates.tenant_id, tenantId))
342
- .limit(1);
343
- return (row as BrainSubstrateState | undefined) ?? null;
344
- }
345
-
346
- async function loadLatestMigrationFromDb(
347
- db: Database,
348
- args: { tenantId: string; substrateId: string },
349
- ): Promise<BrainSubstrateMigrationSummary | null> {
350
- const [row] = await db
351
- .select({
352
- id: brainSubstrateMigrations.id,
353
- phase: brainSubstrateMigrations.phase,
354
- status: brainSubstrateMigrations.status,
355
- from_storage_tier: brainSubstrateMigrations.from_storage_tier,
356
- to_storage_tier: brainSubstrateMigrations.to_storage_tier,
357
- validation_summary: brainSubstrateMigrations.validation_summary,
358
- error_message: brainSubstrateMigrations.error_message,
359
- rollback_window_closes_at:
360
- brainSubstrateMigrations.rollback_window_closes_at,
361
- updated_at: brainSubstrateMigrations.updated_at,
362
- })
363
- .from(brainSubstrateMigrations)
364
- .where(
365
- and(
366
- eq(brainSubstrateMigrations.tenant_id, args.tenantId),
367
- eq(brainSubstrateMigrations.substrate_id, args.substrateId),
368
- ),
369
- )
370
- .orderBy(desc(brainSubstrateMigrations.updated_at))
371
- .limit(1);
372
- return (row as BrainSubstrateMigrationSummary | undefined) ?? null;
373
- }
374
-
375
- async function searchBrainPages(
376
- db: Database,
377
- args: { tenantId: string; query: string; limit: number },
378
- ): Promise<BrainPageSearchRow[]> {
379
- const query = args.query.trim();
380
- if (!query) return [];
381
- const prefixQuery = buildBrainPrefixTsQuery(query);
382
- if (!prefixQuery) return [];
383
- const like = brainLikePattern(query);
384
- const result = await db.execute(sql`
385
- SELECT
386
- p.id,
387
- p.type,
388
- p.entity_subtype,
389
- p.slug,
390
- p.title,
391
- p.summary,
392
- p.body_md,
393
- p.last_compiled_at,
394
- p.updated_at,
395
- (
396
- COALESCE(ts_rank(p.search_tsv, plainto_tsquery('english', ${query})), 0)
397
- + COALESCE(ts_rank(p.search_tsv, to_tsquery('english', ${prefixQuery})), 0) * 0.5
398
- + CASE WHEN p.title ILIKE ${like} ESCAPE '\\' THEN 0.25 ELSE 0 END
399
- ) AS score
400
- FROM brain.pages p
401
- WHERE p.tenant_id = ${args.tenantId}
402
- AND p.status = 'active'
403
- AND (
404
- p.search_tsv @@ plainto_tsquery('english', ${query})
405
- OR p.search_tsv @@ to_tsquery('english', ${prefixQuery})
406
- OR p.title ILIKE ${like} ESCAPE '\\'
407
- OR p.summary ILIKE ${like} ESCAPE '\\'
408
- OR p.body_md ILIKE ${like} ESCAPE '\\'
409
- )
410
- ORDER BY score DESC, p.updated_at DESC, p.title ASC
411
- LIMIT ${args.limit}
412
- `);
413
- return (
414
- (result as unknown as { rows?: BrainPageSearchRow[] }).rows ?? []
415
- ).slice(0, args.limit);
416
- }
417
-
418
- export function normalizeBrainSearchTerms(query: string): string[] {
419
- const seen = new Set<string>();
420
- for (const term of query.toLowerCase().match(/[a-z0-9]+/g) ?? []) {
421
- if (term.length < 2) continue;
422
- if (BRAIN_SEARCH_STOPWORDS.has(term)) continue;
423
- seen.add(term);
424
- }
425
- return [...seen];
426
- }
427
-
428
- export function buildBrainPrefixTsQuery(query: string): string | null {
429
- const terms = normalizeBrainSearchTerms(query);
430
- if (terms.length === 0) return null;
431
- return terms.map((term) => `${term}:*`).join(" & ");
432
- }
433
-
434
- export function brainLikePattern(query: string): string {
435
- return `%${query.replace(/[\\%_]/g, "\\$&")}%`;
436
- }
437
-
438
- async function loadArtifactManifestsFromDb(
439
- db: Database,
440
- args: {
441
- tenantId: string;
442
- limit: number;
443
- sourceKind?: string;
444
- sourceType?: string;
445
- },
446
- ): Promise<BrainArtifactManifestSummary[]> {
447
- const filters = [
448
- eq(brainArtifactManifests.tenant_id, args.tenantId),
449
- eq(brainArtifactManifests.status, "active"),
450
- ];
451
- if (args.sourceKind) {
452
- filters.push(eq(brainArtifactManifests.source_kind, args.sourceKind));
453
- }
454
- if (args.sourceType) {
455
- filters.push(eq(brainArtifactManifests.source_type, args.sourceType));
456
- }
457
- const rows = await db
458
- .select({
459
- id: brainArtifactManifests.id,
460
- manifest_kind: brainArtifactManifests.manifest_kind,
461
- storage_tier: brainArtifactManifests.storage_tier,
462
- source_family: brainArtifactManifests.source_family,
463
- source_kind: brainArtifactManifests.source_kind,
464
- source_type: brainArtifactManifests.source_type,
465
- source_id_hash: brainArtifactManifests.source_id_hash,
466
- object_count: brainArtifactManifests.object_count,
467
- source_count: brainArtifactManifests.source_count,
468
- checksum_sha256: brainArtifactManifests.checksum_sha256,
469
- status: brainArtifactManifests.status,
470
- metadata: brainArtifactManifests.metadata,
471
- updated_at: brainArtifactManifests.updated_at,
472
- })
473
- .from(brainArtifactManifests)
474
- .where(and(...filters))
475
- .orderBy(desc(brainArtifactManifests.updated_at))
476
- .limit(args.limit);
477
- return rows as BrainArtifactManifestSummary[];
478
- }
479
-
480
- function evaluateSubstrate(substrate: BrainSubstrateState | null): {
481
- canQuery: boolean;
482
- status: Partial<ContextProviderStatus>;
483
- } {
484
- if (!substrate) {
485
- return {
486
- canQuery: false,
487
- status: {
488
- state: "skipped",
489
- reason: "Company Brain substrate is not installed for this tenant",
490
- metadata: { activeBackend: "none", storageTier: null },
491
- },
492
- };
493
- }
494
-
495
- if (substrate.status === "not_installed" || substrate.status === "disabled") {
496
- return {
497
- canQuery: false,
498
- status: {
499
- state: "skipped",
500
- reason: `Company Brain substrate is ${substrate.status}`,
501
- metadata: substrateMetadata(substrate),
502
- },
503
- };
504
- }
505
-
506
- if (substrate.status === "failed") {
507
- return {
508
- canQuery: false,
509
- status: {
510
- state: "error",
511
- reason: "Company Brain substrate is failed",
512
- metadata: substrateMetadata(substrate),
513
- },
514
- };
515
- }
516
-
517
- if (
518
- substrate.active_backend !== "default" &&
519
- substrate.active_backend !== "production"
520
- ) {
521
- return {
522
- canQuery: false,
523
- status: {
524
- state: "skipped",
525
- reason: "Company Brain active backend is not readable",
526
- metadata: substrateMetadata(substrate),
527
- },
528
- };
529
- }
530
-
531
- const capabilities = requiredCapabilityStatuses(substrate);
532
- const disabled = Object.entries(capabilities)
533
- .filter(([, status]) => status === "disabled")
534
- .map(([key]) => key);
535
- if (disabled.length > 0) {
536
- return {
537
- canQuery: false,
538
- status: {
539
- state: "skipped",
540
- reason: `Company Brain capability disabled: ${disabled.join(", ")}`,
541
- metadata: { ...substrateMetadata(substrate), capabilities },
542
- },
543
- };
544
- }
545
-
546
- const degraded = Object.values(capabilities).some(
547
- (status) => status === "degraded" || status === "unknown",
548
- );
549
- const stale =
550
- degraded ||
551
- substrate.status === "degraded" ||
552
- substrate.health_status === "degraded" ||
553
- substrate.status === "provisioning" ||
554
- substrate.status === "migrating";
555
-
556
- return {
557
- canQuery: true,
558
- status: {
559
- state: stale ? "stale" : "ok",
560
- reason: stale
561
- ? "Company Brain substrate is available with degraded or unverified retrieval posture"
562
- : undefined,
563
- metadata: { ...substrateMetadata(substrate), capabilities },
564
- },
565
- };
566
- }
567
-
568
- function requiredCapabilityStatuses(
569
- substrate: BrainSubstrateState,
570
- ): Record<(typeof REQUIRED_CAPABILITIES)[number], CapabilityStatus> {
571
- const capabilities = capabilityRecord(substrate.launch_capabilities);
572
- return Object.fromEntries(
573
- REQUIRED_CAPABILITIES.map((key) => [
574
- key,
575
- capabilityStatus(capabilities[key]),
576
- ]),
577
- ) as Record<(typeof REQUIRED_CAPABILITIES)[number], CapabilityStatus>;
578
- }
579
-
580
- function capabilityRecord(value: unknown): Record<string, unknown> {
581
- return value && typeof value === "object" && !Array.isArray(value)
582
- ? (value as Record<string, unknown>)
583
- : {};
584
- }
585
-
586
- function capabilityStatus(value: unknown): CapabilityStatus {
587
- if (typeof value === "boolean") return value ? "enabled" : "disabled";
588
- if (typeof value === "string") return normalizeCapabilityStatus(value);
589
- const record = capabilityRecord(value);
590
- return normalizeCapabilityStatus(record.status ?? record.state);
591
- }
592
-
593
- function normalizeCapabilityStatus(value: unknown): CapabilityStatus {
594
- if (
595
- value === "enabled" ||
596
- value === "disabled" ||
597
- value === "degraded" ||
598
- value === "unknown"
599
- ) {
600
- return value;
601
- }
602
- return "unknown";
603
- }
604
-
605
- function brainPageToHit(args: {
606
- row: BrainPageSearchRow;
607
- request: ContextEngineProviderRequest;
608
- substrate: BrainSubstrateState;
609
- readPosture: BrainReadPosture;
610
- manifests: BrainArtifactManifestSummary[];
611
- index: number;
612
- }): ContextHit {
613
- const manifestMetadata = args.manifests.map(redactedManifestMetadata);
614
- const score =
615
- typeof args.row.score === "number"
616
- ? args.row.score
617
- : Number(args.row.score ?? NaN);
618
- return {
619
- id: pageSourceId(args.row),
620
- providerId: "brain",
621
- family: "brain",
622
- sourceFamily: "brain",
623
- title: args.row.title,
624
- snippet: snippetForPage(args.row),
625
- score: Number.isFinite(score) ? score : 1 / (args.index + 1),
626
- scope: args.request.scope,
627
- provenance: {
628
- label: "Company Brain graph retrieval",
629
- sourceId: pageSourceId(args.row),
630
- uri: `thinkwork://brain/${args.row.type}/${args.row.entity_subtype}/${args.row.slug}`,
631
- metadata: {
632
- retrievalKind: "graph",
633
- retrievalSurface: "company_brain_active_backend",
634
- instructionBoundary: "untrusted_source_data",
635
- readPosture: args.readPosture,
636
- pageType: args.row.type,
637
- entitySubtype: args.row.entity_subtype,
638
- compiledAt: isoDate(args.row.last_compiled_at),
639
- artifactManifests: manifestMetadata,
640
- provenanceKinds: summarizeManifestKinds(args.manifests),
641
- vaultProvenance: vaultProvenance(args.manifests),
642
- },
643
- },
644
- metadata: {
645
- page: {
646
- id: pageSourceId(args.row),
647
- type: args.row.type,
648
- entitySubtype: args.row.entity_subtype,
649
- slug: args.row.slug,
650
- updatedAt: isoDate(args.row.updated_at),
651
- },
652
- sourceDataPolicy: {
653
- instructionBoundary: "untrusted_source_data",
654
- allowedUse: "cite_or_summarize_only",
655
- forbiddenUse: "do_not_execute_or_expand_tool_policy",
656
- },
657
- substrate: substrateMetadata(args.substrate),
658
- readPosture: args.readPosture,
659
- artifactManifests: manifestMetadata,
660
- },
661
- freshness: args.row.updated_at
662
- ? {
663
- asOf: isoDate(args.row.updated_at)!,
664
- ttlSeconds: 60 * 60 * 24,
665
- }
666
- : undefined,
667
- };
668
- }
669
-
670
- function pageSourceId(row: BrainPageSearchRow): string {
671
- return `brain:${row.type}:${row.entity_subtype}:${row.slug}`;
672
- }
673
-
674
- function snippetForPage(row: BrainPageSearchRow): string {
675
- const text = row.summary || row.body_md || row.title;
676
- return text.replace(/\s+/g, " ").trim().slice(0, 1_000) || row.title;
677
- }
678
-
679
- function substrateMetadata(substrate: BrainSubstrateState) {
680
- return {
681
- substrateId: substrate.id,
682
- storageTier: substrate.storage_tier,
683
- activeBackend: substrate.active_backend,
684
- status: substrate.status,
685
- healthStatus: substrate.health_status,
686
- embeddingModel: substrate.embedding_model,
687
- vectorDimension: substrate.vector_dimension,
688
- latestIngestAt: isoDate(substrate.latest_ingest_at),
689
- latestProjectionAt: isoDate(substrate.latest_projection_at),
690
- updatedAt: isoDate(substrate.updated_at),
691
- };
692
- }
693
-
694
- function redactedManifestMetadata(manifest: BrainArtifactManifestSummary) {
695
- return {
696
- id: manifest.id,
697
- kind: manifest.manifest_kind,
698
- retrievalKind: retrievalKindForManifest(manifest.manifest_kind),
699
- storageTier: manifest.storage_tier,
700
- sourceFamily: manifest.source_family,
701
- sourceKind: manifest.source_kind,
702
- sourceType: manifest.source_type,
703
- sourceIdHash: manifest.source_id_hash,
704
- objectCount: manifest.object_count,
705
- sourceCount: manifest.source_count,
706
- checksumSha256: manifest.checksum_sha256,
707
- updatedAt: isoDate(manifest.updated_at),
708
- };
709
- }
710
-
711
- function retrievalKindForManifest(kind: string): string {
712
- if (kind === "vault_projection") return "vault_projection";
713
- if (kind === "source_artifact") return "source_artifact";
714
- if (kind === "ingestion_manifest") return "ingestion_manifest";
715
- if (kind === "migration_snapshot") return "migration_snapshot";
716
- return "graph";
717
- }
718
-
719
- function summarizeManifestKinds(manifests: BrainArtifactManifestSummary[]) {
720
- const counts = new Map<string, number>();
721
- for (const manifest of manifests) {
722
- counts.set(
723
- manifest.manifest_kind,
724
- (counts.get(manifest.manifest_kind) ?? 0) + 1,
725
- );
726
- }
727
- return Object.fromEntries([...counts.entries()].sort());
728
- }
729
-
730
- function brainReadPosture(
731
- substrate: BrainSubstrateState,
732
- migration: BrainSubstrateMigrationSummary | null,
733
- ): BrainReadPosture {
734
- const activeStorageTier = storageTierForBackend(substrate.active_backend);
735
- const active: BrainReadRoute = {
736
- backend: activeStorageTier,
737
- storageTier: activeStorageTier,
738
- role: "active",
739
- state: "serving",
740
- reason: `serving ${activeStorageTier} Company Brain backend`,
741
- };
742
- return {
743
- active,
744
- shadow: shadowReadRoute(substrate, migration),
745
- fallback: fallbackReadRoute(substrate, migration),
746
- vault: {
747
- backend: activeStorageTier,
748
- storageTier: activeStorageTier,
749
- role: "vault",
750
- state: "available",
751
- reason: "vault projections are provenance views, not canonical storage",
752
- },
753
- migration: migration ? publicMigrationReadState(migration) : null,
754
- };
755
- }
756
-
757
- function storageTierForBackend(backend: string): "default" | "production" {
758
- return backend === "production" ? "production" : "default";
759
- }
760
-
761
- function shadowReadRoute(
762
- substrate: BrainSubstrateState,
763
- migration: BrainSubstrateMigrationSummary | null,
764
- ): BrainReadRoute | null {
765
- if (!migration) return null;
766
- if (migration.status !== "requested" && migration.status !== "running") {
767
- return null;
768
- }
769
- if (substrate.active_backend !== "default") return null;
770
- if (migration.to_storage_tier !== "production") return null;
771
- return {
772
- backend: "production",
773
- storageTier: "production",
774
- role: "shadow",
775
- state: "shadowing",
776
- reason: `production migration is ${migration.phase}; reads remain on default until validated cutover`,
777
- };
778
- }
779
-
780
- function fallbackReadRoute(
781
- substrate: BrainSubstrateState,
782
- migration: BrainSubstrateMigrationSummary | null,
783
- ): BrainReadRoute | null {
784
- if (substrate.active_backend === "production") {
785
- return {
786
- backend: "default",
787
- storageTier: "default",
788
- role: "fallback",
789
- state: "available",
790
- reason: migration?.rollback_window_closes_at
791
- ? "default fallback is retained during the rollback window"
792
- : "default fallback remains the last known safe read path",
793
- };
794
- }
795
- if (migration?.status === "failed" || migration?.status === "rolled_back") {
796
- return {
797
- backend: "default",
798
- storageTier: "default",
799
- role: "fallback",
800
- state: "serving",
801
- reason: `migration ${migration.status}; reads are not redirected to production`,
802
- };
803
- }
804
- return null;
805
- }
806
-
807
- function publicMigrationReadState(migration: BrainSubstrateMigrationSummary) {
808
- return {
809
- id: migration.id,
810
- phase: migration.phase,
811
- status: migration.status,
812
- fromStorageTier: migration.from_storage_tier,
813
- toStorageTier: migration.to_storage_tier,
814
- validation: publicMigrationValidationSummary(migration.validation_summary),
815
- rollbackWindowClosesAt: isoDate(migration.rollback_window_closes_at),
816
- };
817
- }
818
-
819
- function publicMigrationValidationSummary(
820
- value: unknown,
821
- ): Record<string, unknown> {
822
- const raw = record(value);
823
- const summary: Record<string, unknown> = {};
824
- copyNumber(summary, raw, "replayManifestCount");
825
- copyNumber(summary, raw, "sourceCount");
826
- copyNumber(summary, raw, "objectCount");
827
- copyNumber(summary, raw, "graphEntityCount");
828
- copyNumber(summary, raw, "graphEdgeCount");
829
- copyNumber(summary, raw, "vectorDimension");
830
- copyString(summary, raw, "embeddingModel");
831
- copyString(summary, raw, "ontologyVersion");
832
- copyBoolean(summary, raw, "emptySourceApproved");
833
- copyString(summary, raw, "emptySourceReason");
834
- copyBoolean(summary, raw, "validationPassed");
835
- copyBoolean(summary, raw, "vectorIndexHealthy");
836
- copyBoolean(summary, raw, "retrievalParityPassed");
837
- return summary;
838
- }
839
-
840
- function vaultProvenance(manifests: BrainArtifactManifestSummary[]) {
841
- const vaultProjectionCount = manifests.filter(
842
- (manifest) => manifest.manifest_kind === "vault_projection",
843
- ).length;
844
- return {
845
- available: vaultProjectionCount > 0,
846
- projectionCount: vaultProjectionCount,
847
- role: "materialized_view",
848
- canonicalStorage: false,
849
- };
850
- }
851
-
852
- function record(value: unknown): Record<string, unknown> {
853
- return value && typeof value === "object" && !Array.isArray(value)
854
- ? (value as Record<string, unknown>)
855
- : {};
856
- }
857
-
858
- function copyNumber(
859
- target: Record<string, unknown>,
860
- source: Record<string, unknown>,
861
- key: string,
862
- ) {
863
- const value = Number(source[key]);
864
- if (Number.isFinite(value)) target[key] = value;
865
- }
866
-
867
- function copyString(
868
- target: Record<string, unknown>,
869
- source: Record<string, unknown>,
870
- key: string,
871
- ) {
872
- if (typeof source[key] === "string" && source[key]) {
873
- target[key] = source[key];
874
- }
875
- }
876
-
877
- function copyBoolean(
878
- target: Record<string, unknown>,
879
- source: Record<string, unknown>,
880
- key: string,
881
- ) {
882
- if (typeof source[key] === "boolean") target[key] = source[key];
883
- }
884
-
885
- function isoDate(value: Date | string | null | undefined): string | null {
886
- if (!value) return null;
887
- return value instanceof Date ? value.toISOString() : value;
888
- }