thinkwork-cli 0.12.16 → 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 (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,312 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Read-only Company Brain Context Engine smoke (THNK-20 / U5a).
4
- *
5
- * Dry-run is the default. Set SMOKE_ENABLE_COMPANY_BRAIN_CONTEXT=1 to run live
6
- * against a deployed stage. Live mode calls the existing MCP Context Engine
7
- * endpoint with service auth and does not mutate production state.
8
- *
9
- * Live env:
10
- * CONTEXT_ENGINE_MCP_URL or API_CONTEXT_ENGINE_MCP_URL
11
- * Optional fallback: VITE_GRAPHQL_HTTP_URL / GRAPHQL_HTTP_URL / API_GRAPHQL_URL
12
- * with /graphql replaced by /mcp/context-engine.
13
- * API_AUTH_SECRET or THINKWORK_API_SECRET
14
- * SMOKE_TENANT_ID=<tenant uuid>
15
- * SMOKE_USER_ID=<users.id in that tenant>
16
- *
17
- * Optional:
18
- * SMOKE_COMPANY_BRAIN_CONTEXT_QUERY="Acme renewal risk"
19
- * SMOKE_COMPANY_BRAIN_EXPECTED_TERM="procurement"
20
- * SMOKE_COMPANY_BRAIN_SOURCE_KIND=thread
21
- * SMOKE_COMPANY_BRAIN_SOURCE_TYPE=thread_message
22
- * SMOKE_COMPANY_BRAIN_DATASET_ID=<dataset/source scope>
23
- * SMOKE_COMPANY_BRAIN_NODESETS=customer-success,renewals
24
- */
25
-
26
- import fs from "node:fs";
27
- import path from "node:path";
28
- import process from "node:process";
29
- import { attachSmokeEvidence } from "../../../scripts/smoke/deployment-evidence.mjs";
30
-
31
- const LIVE_ENABLED = process.env.SMOKE_ENABLE_COMPANY_BRAIN_CONTEXT === "1";
32
- const TIMEOUT_MS = Number(process.env.SMOKE_TIMEOUT_MS || 20_000);
33
- const env = { ...loadEnvFile(), ...process.env };
34
-
35
- const graphqlUrl = first(
36
- env.VITE_GRAPHQL_HTTP_URL,
37
- env.GRAPHQL_HTTP_URL,
38
- env.API_GRAPHQL_URL,
39
- );
40
- const mcpUrl = first(
41
- env.CONTEXT_ENGINE_MCP_URL,
42
- env.API_CONTEXT_ENGINE_MCP_URL,
43
- deriveMcpUrl(graphqlUrl),
44
- );
45
- const apiSecret = first(env.API_AUTH_SECRET, env.THINKWORK_API_SECRET);
46
- const tenantId = first(env.SMOKE_TENANT_ID, env.TENANT_ID);
47
- const userId = first(env.SMOKE_USER_ID, env.SMOKE_ADMIN_USER_ID);
48
- const query = first(
49
- env.SMOKE_COMPANY_BRAIN_CONTEXT_QUERY,
50
- "Acme renewal risk and next best action",
51
- );
52
- const expectedTerm = first(env.SMOKE_COMPANY_BRAIN_EXPECTED_TERM);
53
-
54
- const checks = [];
55
-
56
- if (!LIVE_ENABLED) {
57
- console.log(
58
- JSON.stringify(
59
- await attachSmokeEvidence(
60
- "company-brain-context-engine",
61
- {
62
- ok: true,
63
- skippedLive: true,
64
- reason:
65
- "set SMOKE_ENABLE_COMPANY_BRAIN_CONTEXT=1 to run the deployed read-only Context Engine Brain smoke",
66
- dryRun: {
67
- requiredWhenRunning: [
68
- "CONTEXT_ENGINE_MCP_URL or GraphQL URL that can derive /mcp/context-engine",
69
- "API_AUTH_SECRET or THINKWORK_API_SECRET",
70
- "SMOKE_TENANT_ID",
71
- "SMOKE_USER_ID",
72
- ],
73
- optionalScope: [
74
- "SMOKE_COMPANY_BRAIN_CONTEXT_QUERY",
75
- "SMOKE_COMPANY_BRAIN_EXPECTED_TERM",
76
- "SMOKE_COMPANY_BRAIN_SOURCE_KIND",
77
- "SMOKE_COMPANY_BRAIN_SOURCE_TYPE",
78
- "SMOKE_COMPANY_BRAIN_DATASET_ID",
79
- "SMOKE_COMPANY_BRAIN_NODESETS",
80
- ],
81
- verifies: [
82
- "query_brain_context returns Company Brain hits through Context Engine",
83
- "Brain provider status exposes active read route, shadow migration, vault provenance, and provider-local retrieval posture",
84
- "Brain hits include untrusted source-data boundary metadata",
85
- "Brain answer is better than memory-only for the named workflow by hit count or expected-term match",
86
- "query_memory_context remains a separate Cognee-backed user/space memory path rather than an implicit Brain fallback",
87
- ],
88
- },
89
- },
90
- env,
91
- ),
92
- null,
93
- 2,
94
- ),
95
- );
96
- process.exit(0);
97
- }
98
-
99
- try {
100
- await runLiveSmoke();
101
- const failed = checks.filter((check) => !check.ok);
102
- console.log(
103
- JSON.stringify(
104
- await attachSmokeEvidence(
105
- "company-brain-context-engine",
106
- {
107
- ok: failed.length === 0,
108
- query,
109
- checks,
110
- },
111
- env,
112
- ),
113
- null,
114
- 2,
115
- ),
116
- );
117
- process.exit(failed.length === 0 ? 0 : 1);
118
- } catch (error) {
119
- console.error(
120
- JSON.stringify(
121
- await attachSmokeEvidence(
122
- "company-brain-context-engine",
123
- {
124
- ok: false,
125
- query,
126
- error: error instanceof Error ? error.message : String(error),
127
- checks,
128
- },
129
- env,
130
- ),
131
- null,
132
- 2,
133
- ),
134
- );
135
- process.exit(1);
136
- }
137
-
138
- async function runLiveSmoke() {
139
- requireEnv("CONTEXT_ENGINE_MCP_URL", mcpUrl);
140
- requireEnv("API_AUTH_SECRET or THINKWORK_API_SECRET", apiSecret);
141
- requireEnv("SMOKE_TENANT_ID", tenantId);
142
- requireEnv("SMOKE_USER_ID", userId);
143
-
144
- const brain = await callTool("query_brain_context", {
145
- query,
146
- mode: "answer",
147
- scope: "team",
148
- limit: 5,
149
- sourceKind: first(env.SMOKE_COMPANY_BRAIN_SOURCE_KIND),
150
- sourceType: first(env.SMOKE_COMPANY_BRAIN_SOURCE_TYPE),
151
- datasetId: first(env.SMOKE_COMPANY_BRAIN_DATASET_ID),
152
- nodeSetIds: csv(env.SMOKE_COMPANY_BRAIN_NODESETS),
153
- onlyContext: true,
154
- });
155
- const memory = await callTool("query_memory_context", {
156
- query,
157
- mode: "answer",
158
- scope: "personal",
159
- limit: 5,
160
- });
161
-
162
- const brainContent = brain.result?.structuredContent;
163
- const memoryContent = memory.result?.structuredContent;
164
- const brainHits = Array.isArray(brainContent?.hits) ? brainContent.hits : [];
165
- const memoryHits = Array.isArray(memoryContent?.hits)
166
- ? memoryContent.hits
167
- : [];
168
- const brainProviders = Array.isArray(brainContent?.providers)
169
- ? brainContent.providers
170
- : [];
171
- const brainProvider = brainProviders.find(
172
- (provider) => provider.providerId === "brain",
173
- );
174
- const brainText = JSON.stringify(brain.result ?? {});
175
-
176
- assert("Brain provider returns at least one hit", brainHits.length > 0, {
177
- brainHitCount: brainHits.length,
178
- });
179
- assert(
180
- "Brain provider exposes provider-local status",
181
- Boolean(brainProvider),
182
- { providers: brainProviders },
183
- );
184
- assert(
185
- "Brain provider exposes migration-aware read posture",
186
- Boolean(
187
- brainProvider?.metadata?.readPosture?.active?.role === "active" &&
188
- brainProvider.metadata.readPosture.vault?.role === "vault",
189
- ),
190
- { readPosture: brainProvider?.metadata?.readPosture ?? null },
191
- );
192
- assert(
193
- "Brain hits carry untrusted source-data boundaries",
194
- brainHits.every(
195
- (hit) =>
196
- hit?.metadata?.sourceDataPolicy ||
197
- hit?.provenance?.metadata?.instructionBoundary ===
198
- "untrusted_source_data",
199
- ),
200
- { sampleHit: brainHits[0] ?? null },
201
- );
202
-
203
- const betterByCount = brainHits.length > memoryHits.length;
204
- const betterByTerm = expectedTerm
205
- ? brainText.toLowerCase().includes(expectedTerm.toLowerCase())
206
- : false;
207
- assert(
208
- "Brain answer is materially better than memory-only for named workflow",
209
- betterByCount || betterByTerm,
210
- {
211
- brainHitCount: brainHits.length,
212
- memoryHitCount: memoryHits.length,
213
- expectedTerm: expectedTerm ?? null,
214
- betterByCount,
215
- betterByTerm,
216
- },
217
- );
218
- }
219
-
220
- async function callTool(name, args) {
221
- const body = {
222
- jsonrpc: "2.0",
223
- id: name,
224
- method: "tools/call",
225
- params: {
226
- name,
227
- arguments: Object.fromEntries(
228
- Object.entries(args).filter(
229
- ([, value]) =>
230
- value !== undefined &&
231
- value !== null &&
232
- (!Array.isArray(value) || value.length > 0),
233
- ),
234
- ),
235
- },
236
- };
237
- const response = await fetch(mcpUrl, {
238
- method: "POST",
239
- headers: {
240
- "Content-Type": "application/json",
241
- Authorization: `Bearer ${apiSecret}`,
242
- "x-tenant-id": tenantId,
243
- "x-user-id": userId,
244
- },
245
- body: JSON.stringify(body),
246
- signal: AbortSignal.timeout(TIMEOUT_MS),
247
- });
248
- const payload = await response.json().catch(() => ({}));
249
- if (!response.ok || payload.error) {
250
- throw new Error(
251
- `${name} failed: ${JSON.stringify(payload.error ?? payload)}`,
252
- );
253
- }
254
- return payload;
255
- }
256
-
257
- function assert(name, ok, details = {}) {
258
- checks.push({ name, ok, ...details });
259
- if (!ok) {
260
- throw new Error(`${name} failed`);
261
- }
262
- }
263
-
264
- function requireEnv(name, value) {
265
- if (!value) throw new Error(`${name} is required`);
266
- }
267
-
268
- function deriveMcpUrl(url) {
269
- if (!url) return null;
270
- try {
271
- const parsed = new URL(url);
272
- parsed.pathname = parsed.pathname.replace(/\/graphql\/?$/, "");
273
- parsed.pathname = `${parsed.pathname.replace(/\/$/, "")}/mcp/context-engine`;
274
- parsed.search = "";
275
- parsed.hash = "";
276
- return parsed.toString();
277
- } catch {
278
- return null;
279
- }
280
- }
281
-
282
- function csv(value) {
283
- return value
284
- ? value
285
- .split(",")
286
- .map((item) => item.trim())
287
- .filter(Boolean)
288
- : undefined;
289
- }
290
-
291
- function first(...values) {
292
- return values
293
- .find((value) => typeof value === "string" && value.trim())
294
- ?.trim();
295
- }
296
-
297
- function loadEnvFile() {
298
- const candidates = [
299
- path.resolve("apps/web/.env"),
300
- path.resolve("terraform/examples/greenfield/.env"),
301
- ];
302
- const output = {};
303
- for (const file of candidates) {
304
- if (!fs.existsSync(file)) continue;
305
- for (const line of fs.readFileSync(file, "utf8").split(/\r?\n/)) {
306
- const match = line.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*)\s*$/);
307
- if (!match) continue;
308
- output[match[1]] = match[2].replace(/^['"]|['"]$/g, "");
309
- }
310
- }
311
- return output;
312
- }