thinkwork-cli 0.12.15 → 0.12.17

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 (152) hide show
  1. package/dist/{api-client-4VT3FWOH.js → api-client-JUBCQQDF.js} +1 -1
  2. package/dist/{chunk-H7AB42ES.js → chunk-STY44FQO.js} +13 -0
  3. package/dist/cli.js +1107 -10225
  4. package/dist/commands/enterprise/templates/deploy-repo/docs/runbook.md +3 -8
  5. package/dist/commands/enterprise/templates/deploy-repo/terraform/main.tf +1 -184
  6. package/dist/drizzle/0050_brain_v0_entity_subtype.sql +2 -2
  7. package/dist/drizzle/0051_brain_v0_tenant_entity_pages.sql +6 -6
  8. package/dist/drizzle/0052_brain_v0_external_refs.sql +2 -2
  9. package/dist/drizzle/0053_brain_v0_unresolved_mentions_subtype.sql +2 -2
  10. package/dist/drizzle/0145_knowledge_graph_thread_ingest.sql +14 -14
  11. package/dist/drizzle/0146_knowledge_graph_source_scope.sql +1 -1
  12. package/dist/drizzle/0157_knowledge_graph_observations_source.sql +2 -2
  13. package/dist/drizzle/0158_wiki_tenant_scope.sql +1 -1
  14. package/dist/drizzle/0165_plugin_premium_entitlements.sql +2 -2
  15. package/dist/drizzle/{0166_company_brain_substrate_contract.sql → 0166_brain_substrate_contract.sql} +9 -9
  16. package/dist/drizzle/{0167_company_brain_artifact_manifest_runtime.sql → 0167_brain_artifact_manifest_runtime.sql} +5 -5
  17. package/dist/drizzle/0168_eval_skill_gate.sql +1 -1
  18. package/dist/drizzle/0183_okf_artifact_manifests.sql +1 -1
  19. package/dist/drizzle/0197_rcm_context_columns.sql +28 -0
  20. package/dist/drizzle/0200_eval_results_execution_tier.sql +40 -0
  21. package/dist/drizzle/0201_brain_dream_runs.sql +72 -0
  22. package/dist/drizzle/0202_backfill_thread_participants_from_senders.sql +110 -0
  23. package/dist/drizzle/0203_threads_mode_override.sql +61 -0
  24. package/dist/drizzle/0204_thread_turns_triggering_message_id.sql +48 -0
  25. package/dist/drizzle/0205_routines_git_python.sql +185 -0
  26. package/dist/drizzle/0206_agent_loop_versions_routine_actions.sql +40 -0
  27. package/dist/drizzle/0207_tenant_credentials_github_repo_kind.sql +52 -0
  28. package/dist/drizzle/0208_knowledge_graph_neutral_identifiers.sql +253 -0
  29. package/dist/drizzle/0209_living_artifacts_schema.sql +109 -0
  30. package/dist/drizzle/0210_think137_automations_additive_schema.sql +113 -0
  31. package/dist/drizzle/0211_backfill_agent_loop_versions_target_spec.sql +120 -0
  32. package/dist/drizzle/0212_fold_webhooks_into_automations.sql +312 -0
  33. package/dist/drizzle/0213_agent_loop_versions_judge_evidence_nullable.sql +63 -0
  34. package/dist/drizzle/0214_think137_drop_judge_evidence_roi.sql +99 -0
  35. package/dist/drizzle/0215_agent_loop_versions_goal_worker_policy_nullable.sql +70 -0
  36. package/dist/drizzle/0216_drop_agent_loop_versions_goal_worker_policy.sql +81 -0
  37. package/dist/drizzle/0217_agents_capability_folder_dispatch.sql +12 -0
  38. package/dist/drizzle/0218_document_plates.sql +30 -0
  39. package/dist/drizzle/0219_document_section_waivers.sql +29 -0
  40. package/dist/drizzle/0220_artifacts_created_by_user.sql +21 -0
  41. package/dist/drizzle/0221_artifact_shares.sql +29 -0
  42. package/dist/drizzle/0221_workflow_interpreter_thin_slice.sql +71 -0
  43. package/dist/drizzle/0222_compliance_drainer_select_audit_events.sql +21 -0
  44. package/dist/drizzle/0223_document_conformance_reports.sql +38 -0
  45. package/dist/drizzle/0224_artifact_refresh_state.sql +11 -0
  46. package/dist/drizzle/0225_think216_agent_loop_convergence.sql +21 -0
  47. package/dist/drizzle/0226_drop_n8n_agent_step_runs.sql +6 -0
  48. package/dist/drizzle/0227_analyst_reader_role.sql +1055 -0
  49. package/dist/drizzle/0228_tenant_credentials_rds_iam_kind.sql +62 -0
  50. package/dist/drizzle/0229_analyst_reader_rds_iam_grant.sql +79 -0
  51. package/dist/drizzle/0230_analyst_rls.sql +1613 -0
  52. package/dist/drizzle/0231_cost_events_cache_write_enforcement_exempt.sql +11 -0
  53. package/dist/plugins/catalog/package.json +0 -1
  54. package/dist/plugins/catalog/src/__tests__/build-catalog.test.ts +0 -1
  55. package/dist/plugins/catalog/src/__tests__/catalog.test.ts +16 -8
  56. package/dist/plugins/catalog/src/__tests__/contracts.test.ts +56 -0
  57. package/dist/plugins/catalog/src/__tests__/plugin-package.test.ts +0 -2
  58. package/dist/plugins/catalog/src/__tests__/plugin-registry.test.ts +0 -5
  59. package/dist/plugins/catalog/src/contracts.ts +112 -0
  60. package/dist/plugins/catalog/src/registry/generated-first-party.ts +0 -6
  61. package/dist/plugins/n8n/README.md +4 -36
  62. package/dist/plugins/n8n/src/deployment/managed-app.ts +0 -17
  63. package/dist/plugins/n8n/src/manifest.ts +0 -5
  64. package/dist/plugins/n8n/terraform/n8n/main.tf +0 -26
  65. package/dist/plugins/n8n/terraform/n8n/outputs.tf +0 -5
  66. package/dist/plugins/n8n/terraform/n8n/variables.tf +0 -6
  67. package/dist/plugins/n8n/test/manifest.test.ts +0 -1
  68. package/dist/plugins/twenty/package.json +5 -0
  69. package/dist/plugins/twenty/scripts/lib/__tests__/load-records.test.ts +232 -0
  70. package/dist/plugins/twenty/scripts/lib/__tests__/mappers.test.ts +489 -0
  71. package/dist/plugins/twenty/scripts/lib/__tests__/members-ensure.test.ts +199 -0
  72. package/dist/plugins/twenty/scripts/lib/__tests__/provision-members-db.test.ts +43 -0
  73. package/dist/plugins/twenty/scripts/lib/__tests__/schema-ensure.test.ts +230 -0
  74. package/dist/plugins/twenty/scripts/lib/__tests__/twenty-client.test.ts +207 -0
  75. package/dist/plugins/twenty/scripts/lib/lastmile-reader.ts +282 -0
  76. package/dist/plugins/twenty/scripts/lib/load-attachments.ts +220 -0
  77. package/dist/plugins/twenty/scripts/lib/load-records.ts +680 -0
  78. package/dist/plugins/twenty/scripts/lib/mappers.ts +559 -0
  79. package/dist/plugins/twenty/scripts/lib/members-ensure.ts +381 -0
  80. package/dist/plugins/twenty/scripts/lib/provision-members-db.ts +191 -0
  81. package/dist/plugins/twenty/scripts/lib/schema-ensure.ts +425 -0
  82. package/dist/plugins/twenty/scripts/lib/twenty-client.ts +246 -0
  83. package/dist/plugins/twenty/scripts/migrate-lastmile.ts +610 -0
  84. package/dist/plugins/twenty/scripts/provision-twenty-members.ts +214 -0
  85. package/dist/plugins/twenty/src/manifest.ts +99 -0
  86. package/dist/plugins/twenty/terraform/twenty/README.md +1 -1
  87. package/dist/plugins/twenty/test/manifest.test.ts +12 -2
  88. package/dist/terraform/examples/greenfield/main.tf +90 -380
  89. package/dist/terraform/examples/greenfield/terraform.tfvars.example +0 -1
  90. package/dist/terraform/modules/app/agentcore-pi/README.md +1 -3
  91. package/dist/terraform/modules/app/agentcore-pi/main.tf +36 -32
  92. package/dist/terraform/modules/app/agentcore-pi/variables.tf +23 -15
  93. package/dist/terraform/modules/app/agentcore-runtime/main.tf +3 -3
  94. package/dist/terraform/modules/app/customer-domain/main.tf +16 -2
  95. package/dist/terraform/modules/app/deployment-control-plane/main.tf +5 -0
  96. package/dist/terraform/modules/app/deployment-control-plane/runner.py +85 -207
  97. package/dist/terraform/modules/app/deployment-control-plane/test_runner_bundle.py +56 -2
  98. package/dist/terraform/modules/app/hindsight-memory/main.tf +52 -4
  99. package/dist/terraform/modules/app/lambda-api/eval-fanout.tf +7 -0
  100. package/dist/terraform/modules/app/lambda-api/handlers.tf +493 -89
  101. package/dist/terraform/modules/app/lambda-api/iam-grouped.tf +215 -96
  102. package/dist/terraform/modules/app/lambda-api/main.tf +24 -5
  103. package/dist/terraform/modules/app/lambda-api/outputs.tf +19 -11
  104. package/dist/terraform/modules/app/lambda-api/variables.tf +94 -67
  105. package/dist/terraform/modules/app/ses-email/main.tf +14 -2
  106. package/dist/terraform/modules/app/workflow-interpreter-stepfunctions/main.tf +493 -0
  107. package/dist/terraform/modules/app/workflow-interpreter-stepfunctions/outputs.tf +34 -0
  108. package/dist/terraform/modules/app/workflow-interpreter-stepfunctions/variables.tf +32 -0
  109. package/dist/terraform/modules/data/aurora-postgres/main.tf +55 -0
  110. package/dist/terraform/modules/data/aurora-postgres/outputs.tf +15 -0
  111. package/dist/terraform/modules/data/s3-buckets/main.tf +26 -0
  112. package/dist/terraform/modules/thinkwork/README.md +0 -1
  113. package/dist/terraform/modules/thinkwork/main.tf +167 -446
  114. package/dist/terraform/modules/thinkwork/outputs.tf +2 -142
  115. package/dist/terraform/modules/thinkwork/variables.tf +55 -309
  116. package/dist/terraform/schema.graphql +4 -0
  117. package/dist/workspace-defaults/files/AGENTS.md +45 -31
  118. package/dist/workspace-defaults/files/CONTEXT.md +48 -4
  119. package/dist/workspace-defaults/files/GUARDRAILS.md +18 -0
  120. package/dist/workspace-defaults/files/MEMORY_GUIDE.md +32 -4
  121. package/dist/workspace-defaults/files/SPACE.md +34 -19
  122. package/dist/workspace-defaults/files/TOOLS.md +30 -0
  123. package/dist/workspace-defaults/files/skills/document-composer/SKILL.md +154 -0
  124. package/dist/workspace-defaults/files/skills/document-composer/references/authoring-rules.md +101 -0
  125. package/package.json +2 -1
  126. package/dist/plugins/company-brain/README.md +0 -37
  127. package/dist/plugins/company-brain/package.json +0 -33
  128. package/dist/plugins/company-brain/runtime/cognee/Dockerfile +0 -11
  129. package/dist/plugins/company-brain/smoke/cognee-managed-app-smoke.mjs +0 -458
  130. package/dist/plugins/company-brain/smoke/cognee-memory-cutover-smoke.mjs +0 -539
  131. package/dist/plugins/company-brain/smoke/company-brain-context-engine-smoke.mjs +0 -312
  132. package/dist/plugins/company-brain/smoke/company-brain-operations-smoke.mjs +0 -449
  133. package/dist/plugins/company-brain/smoke/company-brain-plugin-smoke.mjs +0 -655
  134. package/dist/plugins/company-brain/smoke/hindsight-memory-isolation-smoke.mjs +0 -474
  135. package/dist/plugins/company-brain/src/api/cognee-client.ts +0 -896
  136. package/dist/plugins/company-brain/src/api/cognee-cluster-identity.ts +0 -49
  137. package/dist/plugins/company-brain/src/api/cognee-memory-scope.ts +0 -84
  138. package/dist/plugins/company-brain/src/api/context-engine-provider.ts +0 -888
  139. package/dist/plugins/company-brain/src/api/migration.ts +0 -665
  140. package/dist/plugins/company-brain/src/deployment/cognee-managed-app.ts +0 -396
  141. package/dist/plugins/company-brain/src/index.ts +0 -62
  142. package/dist/plugins/company-brain/src/manifest.ts +0 -112
  143. package/dist/plugins/company-brain/terraform/cognee/README.md +0 -263
  144. package/dist/plugins/company-brain/terraform/cognee/main.tf +0 -766
  145. package/dist/plugins/company-brain/terraform/cognee/outputs.tf +0 -144
  146. package/dist/plugins/company-brain/terraform/cognee/variables.tf +0 -402
  147. package/dist/plugins/company-brain/test/api/cognee-client.test.ts +0 -562
  148. package/dist/plugins/company-brain/test/api/cognee-memory-scope.test.ts +0 -74
  149. package/dist/plugins/company-brain/test/api/context-engine-provider.test.ts +0 -447
  150. package/dist/plugins/company-brain/test/api/migration.test.ts +0 -465
  151. package/dist/plugins/company-brain/test/manifest.test.ts +0 -95
  152. 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
- }