thinkwork-cli 0.13.1 → 1.0.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 (262) hide show
  1. package/README.md +3 -14
  2. package/dist/{api-client-4DZ266J5.js → api-client-4P4JZOBX.js} +3 -1
  3. package/dist/bowser-6Z6JFAIR.js +2822 -0
  4. package/dist/{chunk-Y2WHJECR.js → chunk-4OMDWYZQ.js} +5 -44
  5. package/dist/chunk-AD2NIWB5.js +6516 -0
  6. package/dist/chunk-DV3MRBR5.js +43 -0
  7. package/dist/chunk-EI5ZX7CN.js +522 -0
  8. package/dist/chunk-EUJ7X6YD.js +126 -0
  9. package/dist/chunk-GG5WKBOX.js +436 -0
  10. package/dist/chunk-I64EZSU5.js +358 -0
  11. package/dist/chunk-KMIJ5KGT.js +128 -0
  12. package/dist/chunk-MWQ7RO76.js +137 -0
  13. package/dist/chunk-OCPHU34C.js +996 -0
  14. package/dist/chunk-OLUQ4U2Z.js +1728 -0
  15. package/dist/chunk-XYM7PE2A.js +2264 -0
  16. package/dist/chunk-YQCYD6NE.js +3299 -0
  17. package/dist/cli.js +49156 -31257
  18. package/dist/commands/enterprise/templates/deploy-repo/scripts/apply-release.mjs +0 -1
  19. package/dist/commands/enterprise/templates/deploy-repo/scripts/smoke.mjs +0 -1
  20. package/dist/commands/enterprise/templates/deploy-repo/terraform/main.tf +0 -14
  21. package/dist/dist-es-2OTNTL4N.js +315 -0
  22. package/dist/dist-es-2XVAH4BQ.js +14726 -0
  23. package/dist/dist-es-3DPDUJAH.js +2000 -0
  24. package/dist/dist-es-BNZTBBVC.js +176 -0
  25. package/dist/dist-es-CD2RBDAC.js +88 -0
  26. package/dist/dist-es-I4FW57PS.js +88 -0
  27. package/dist/dist-es-KL7Y5NB2.js +377 -0
  28. package/dist/dist-es-KVFWJNDY.js +318 -0
  29. package/dist/dist-es-PS73DWNL.js +70 -0
  30. package/dist/dist-es-S3NZQFGT.js +170 -0
  31. package/dist/dist-es-SGCA4P32.js +48 -0
  32. package/dist/dist-es-WBM6J4RA.js +70 -0
  33. package/dist/dist-es-ZGVADYIF.js +485 -0
  34. package/dist/dist-es-ZKC2QKD2.js +377 -0
  35. package/dist/drizzle/0076_scheduled_jobs_marco_backfill.sql +2 -1
  36. package/dist/drizzle/0079_seed_tenant_customize_catalog.sql +1 -0
  37. package/dist/drizzle/0090_brain_schema_extraction.sql +10 -0
  38. package/dist/drizzle/0132_drop_computer_tables.sql +3 -0
  39. package/dist/drizzle/0160_compliance_event_types_plugins.sql +2 -0
  40. package/dist/drizzle/0214_think137_drop_judge_evidence_roi.sql +1 -0
  41. package/dist/drizzle/0216_drop_agent_loop_versions_goal_worker_policy.sql +1 -0
  42. package/dist/drizzle/0227_analyst_reader_role.sql +17 -20
  43. package/dist/drizzle/0230_analyst_rls.sql +28 -36
  44. package/dist/drizzle/0250_kg_schema_extraction.sql +27 -0
  45. package/dist/drizzle/0251_brain_stragglers.sql +21 -0
  46. package/dist/drizzle/0253_drop_brain_substrate.sql +2 -0
  47. package/dist/drizzle/0257_agents_runtime_allow_harness.sql +24 -0
  48. package/dist/drizzle/0261_native_auth_control_plane.sql +332 -0
  49. package/dist/drizzle/0262_auth_subscription_tickets.sql +59 -0
  50. package/dist/drizzle/0263_agentcore_runtime_identifier.sql +69 -0
  51. package/dist/drizzle/0263_drop_workos_auth_runtime.sql +236 -0
  52. package/dist/drizzle/0264_auth_enrollment_attempt_limits.sql +15 -0
  53. package/dist/drizzle/0265_eval_runs_requester_identity.sql +28 -0
  54. package/dist/drizzle/0265_require_fully_valid_auth_publication.sql +27 -0
  55. package/dist/drizzle/0266_auth_identity_recovery_grants.sql +9 -0
  56. package/dist/drizzle/0266_eval_profiles_runtime_type.sql +12 -0
  57. package/dist/drizzle/0267_ontology_candidate_rejections.sql +53 -0
  58. package/dist/drizzle/0268_identity_crosswalk_routing.sql +182 -0
  59. package/dist/drizzle/0269_ontology_system_map.sql +31 -0
  60. package/dist/drizzle/0270_tool_execution_ledger.sql +115 -0
  61. package/dist/drizzle/0271_ontology_twin_declarations.sql +47 -0
  62. package/dist/drizzle/0272_identity_graph_projection_cursor.sql +23 -0
  63. package/dist/drizzle/0273_twin_materialization_suggestions.sql +29 -0
  64. package/dist/drizzle/0274_tenant_mcp_twin_keys.sql +59 -0
  65. package/dist/drizzle/0275_identity_bulk_rebuild_fence.sql +30 -0
  66. package/dist/drizzle/0276_tool_execution_ledger_allow_cascade_delete.sql +18 -0
  67. package/dist/drizzle/0277_knowledge_base_sources.sql +107 -0
  68. package/dist/drizzle/0278_kb_page_transcription.sql +55 -0
  69. package/dist/drizzle/0279_mcp_servers_off_plugin_provenance.sql +93 -0
  70. package/dist/drizzle/0280_work_item_external_refs_drop_plane_provider.sql +46 -0
  71. package/dist/drizzle/0281_tenant_mcp_twin_keys_expiry_suffix.sql +9 -0
  72. package/dist/drizzle/0282_tenant_mcp_twin_keys_grants.sql +24 -0
  73. package/dist/drizzle/0283_agents_agentcore_runtime_dispatch.sql +13 -0
  74. package/dist/drizzle/0284_user_brain_claims.sql +69 -0
  75. package/dist/drizzle/0285_tenant_mcp_twin_keys_trusted_subsystem.sql +30 -0
  76. package/dist/drizzle/0286_brain_analytics_key.sql +26 -0
  77. package/dist/drizzle/0287_brain_subject.sql +25 -0
  78. package/dist/drizzle/0288_multi_lane_identities.sql +25 -0
  79. package/dist/event-streams-7JNLJEEL.js +894 -0
  80. package/dist/event-streams-KDF5RWR6.js +1515 -0
  81. package/dist/loadSso-ETCXTR4I.js +576 -0
  82. package/dist/loadSso-UBD7KUHE.js +583 -0
  83. package/dist/plugins/README.md +2 -2
  84. package/dist/plugins/catalog/package.json +1 -5
  85. package/dist/plugins/catalog/src/__tests__/build-catalog.test.ts +6 -4
  86. package/dist/plugins/catalog/src/__tests__/catalog.test.ts +21 -21
  87. package/dist/plugins/catalog/src/__tests__/contracts.test.ts +102 -94
  88. package/dist/plugins/catalog/src/__tests__/plugin-package.test.ts +7 -8
  89. package/dist/plugins/catalog/src/__tests__/plugin-registry.test.ts +0 -20
  90. package/dist/plugins/catalog/src/contracts.ts +17 -179
  91. package/dist/plugins/catalog/src/registry/generated-first-party.ts +0 -24
  92. package/dist/plugins/n8n/test/integrated-app-contract.test.ts +1 -1
  93. package/dist/plugins/twenty/package.json +2 -1
  94. package/dist/plugins/twenty/scripts/LAMBDA_DEPLOY.md +114 -0
  95. package/dist/plugins/twenty/scripts/build-lambda.sh +29 -0
  96. package/dist/plugins/twenty/scripts/configure-product-views.ts +195 -0
  97. package/dist/plugins/twenty/scripts/lambda-handler.ts +49 -0
  98. package/dist/plugins/twenty/scripts/lib/__tests__/load-attachments.test.ts +38 -0
  99. package/dist/plugins/twenty/scripts/lib/__tests__/load-records.test.ts +145 -2
  100. package/dist/plugins/twenty/scripts/lib/__tests__/mappers.test.ts +397 -151
  101. package/dist/plugins/twenty/scripts/lib/__tests__/members-ensure.test.ts +28 -129
  102. package/dist/plugins/twenty/scripts/lib/__tests__/provision-members-db.test.ts +10 -0
  103. package/dist/plugins/twenty/scripts/lib/__tests__/schema-ensure.test.ts +13 -8
  104. package/dist/plugins/twenty/scripts/lib/lastmile-reader.ts +222 -2
  105. package/dist/plugins/twenty/scripts/lib/load-attachments.ts +29 -0
  106. package/dist/plugins/twenty/scripts/lib/load-records.ts +160 -43
  107. package/dist/plugins/twenty/scripts/lib/mappers.ts +368 -152
  108. package/dist/plugins/twenty/scripts/lib/members-ensure.ts +43 -268
  109. package/dist/plugins/twenty/scripts/lib/provision-members-db.ts +57 -0
  110. package/dist/plugins/twenty/scripts/lib/schema-ensure.ts +136 -31
  111. package/dist/plugins/twenty/scripts/migrate-lastmile.ts +254 -152
  112. package/dist/plugins/twenty/scripts/provision-twenty-members.ts +44 -1
  113. package/dist/plugins/twenty/scripts/purge-lastmile-import.ts +178 -0
  114. package/dist/plugins/twenty/scripts/restructure-products.ts +312 -0
  115. package/dist/plugins/twenty/scripts/retag-stage-values.ts +362 -0
  116. package/dist/plugins/twenty/test/manifest.test.ts +2 -4
  117. package/dist/scripts/post-deploy.sh +79 -1
  118. package/dist/signin-5QZNRSOO.js +821 -0
  119. package/dist/sso-oidc-XK673P54.js +837 -0
  120. package/dist/sts-OXI2UALF.js +1113 -0
  121. package/dist/sts-SQW4NBK3.js +1117 -0
  122. package/dist/terraform/examples/greenfield/main.tf +391 -176
  123. package/dist/terraform/examples/greenfield/terraform.tfvars.example +26 -8
  124. package/dist/terraform/modules/app/agentcore-admin/main.tf +47 -0
  125. package/dist/terraform/modules/app/agentcore-code-interpreter/README.md +39 -47
  126. package/dist/terraform/modules/app/agentcore-code-interpreter/main.tf +13 -66
  127. package/dist/terraform/modules/app/agentcore-identity/main.tf +253 -0
  128. package/dist/terraform/modules/app/agentcore-identity/outputs.tf +51 -0
  129. package/dist/terraform/modules/app/agentcore-identity/scripts/bootstrap_twenty_oauth_client.sh +239 -0
  130. package/dist/terraform/modules/app/agentcore-identity/scripts/delete_identity.sh +22 -0
  131. package/dist/terraform/modules/app/agentcore-identity/scripts/delete_twenty_identity.sh +16 -0
  132. package/dist/terraform/modules/app/agentcore-identity/scripts/delete_workload_identity.sh +19 -0
  133. package/dist/terraform/modules/app/agentcore-identity/scripts/ensure_workload_identity.sh +29 -0
  134. package/dist/terraform/modules/app/agentcore-identity/scripts/read_identity.sh +55 -0
  135. package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_identity.sh +73 -0
  136. package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_twenty_identity.sh +45 -0
  137. package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_twenty_provider.mjs +123 -0
  138. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/after.tf +15 -0
  139. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/before.tf +7 -0
  140. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/identity-after.tf +8 -0
  141. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/identity-before.tf +9 -0
  142. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/thinkwork-after.tf +3 -0
  143. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/thinkwork-before.tf +3 -0
  144. package/dist/terraform/modules/app/agentcore-identity/variables.tf +60 -0
  145. package/dist/terraform/modules/app/agentcore-memory/README.md +46 -9
  146. package/dist/terraform/modules/app/agentcore-memory/main.tf +27 -10
  147. package/dist/terraform/modules/app/agentcore-memory/scripts/create_or_find_memory.sh +156 -24
  148. package/dist/terraform/modules/app/agentcore-pi/README.md +1 -3
  149. package/dist/terraform/modules/app/agentcore-pi/main.tf +42 -52
  150. package/dist/terraform/modules/app/agentcore-pi/outputs.tf +3 -3
  151. package/dist/terraform/modules/app/agentcore-pi/scripts/reconcile_pi_runtime.mjs +175 -0
  152. package/dist/terraform/modules/app/agentcore-pi/variables.tf +35 -28
  153. package/dist/terraform/modules/app/agentcore-platform/main.tf +68 -0
  154. package/dist/terraform/modules/app/agentcore-runtime/main.tf +4 -20
  155. package/dist/terraform/modules/app/appsync-subscriptions/main.tf +127 -21
  156. package/dist/terraform/modules/app/appsync-subscriptions/outputs.tf +0 -6
  157. package/dist/terraform/modules/app/appsync-subscriptions/variables.tf +5 -0
  158. package/dist/terraform/modules/app/capability-broker/main.tf +2 -2
  159. package/dist/terraform/modules/app/capability-broker/variables.tf +11 -0
  160. package/dist/terraform/modules/app/deployment-control-plane/README.md +264 -0
  161. package/dist/terraform/modules/app/deployment-control-plane/buildspec.yml +4 -1
  162. package/dist/terraform/modules/app/deployment-control-plane/main.tf +94 -0
  163. package/dist/terraform/modules/app/deployment-control-plane/outputs.tf +5 -0
  164. package/dist/terraform/modules/app/deployment-control-plane/runner.py +3689 -233
  165. package/dist/terraform/modules/app/deployment-control-plane/test_runner_bundle.py +2579 -140
  166. package/dist/terraform/modules/app/deployment-control-plane/variables.tf +33 -0
  167. package/dist/terraform/modules/app/lambda-api/auth-state.tf +72 -0
  168. package/dist/terraform/modules/app/lambda-api/chat-latency-observability.tf +466 -0
  169. package/dist/terraform/modules/app/lambda-api/dispatch-dlq.tf +55 -0
  170. package/dist/terraform/modules/app/lambda-api/handlers.tf +531 -619
  171. package/dist/terraform/modules/app/lambda-api/iam-grouped.tf +350 -241
  172. package/dist/terraform/modules/app/lambda-api/main.tf +75 -13
  173. package/dist/terraform/modules/app/lambda-api/memory-alarms.tf +3 -28
  174. package/dist/terraform/modules/app/lambda-api/oauth-secrets.tf +1 -2
  175. package/dist/terraform/modules/app/lambda-api/outputs.tf +17 -10
  176. package/dist/terraform/modules/app/lambda-api/runtime-config.tf +3 -21
  177. package/dist/terraform/modules/app/lambda-api/turn-assertion.tf +45 -0
  178. package/dist/terraform/modules/app/lambda-api/variables.tf +307 -121
  179. package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/README.md +1 -1
  180. package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/main.tf +18 -18
  181. package/dist/terraform/modules/app/sandbox-log-scrubber/README.md +11 -10
  182. package/dist/terraform/modules/app/sandbox-log-scrubber/main.tf +5 -5
  183. package/dist/terraform/modules/app/static-site/main.tf +1 -1
  184. package/dist/terraform/modules/app/www-dns/main.tf +9 -27
  185. package/dist/terraform/modules/app/www-dns/variables.tf +4 -10
  186. package/dist/terraform/modules/data/aurora-postgres/README.md +34 -0
  187. package/dist/terraform/modules/data/aurora-postgres/alarms.tf +82 -0
  188. package/dist/terraform/modules/data/aurora-postgres/main.tf +27 -57
  189. package/dist/terraform/modules/data/aurora-postgres/outputs.tf +0 -9
  190. package/dist/terraform/modules/data/aurora-postgres/variables.tf +41 -0
  191. package/dist/terraform/modules/data/s3-buckets/main.tf +5 -6
  192. package/dist/terraform/modules/foundation/cognito/main.tf +367 -72
  193. package/dist/terraform/modules/foundation/cognito/outputs.tf +47 -0
  194. package/dist/terraform/modules/foundation/cognito/variables.tf +131 -9
  195. package/dist/terraform/modules/thinkwork/README.md +5 -1
  196. package/dist/terraform/modules/thinkwork/main.tf +459 -234
  197. package/dist/terraform/modules/thinkwork/outputs.tf +44 -62
  198. package/dist/terraform/modules/thinkwork/variables.tf +353 -89
  199. package/dist/terraform/schema.graphql +69 -36
  200. package/dist/workspace-defaults/files/INSTRUCTIONS.md +9 -11
  201. package/dist/workspace-defaults/files/MEMORY_GUIDE.md +38 -35
  202. package/dist/workspace-defaults/files/ROUTER.md +1 -1
  203. package/dist/workspace-defaults/files/TOOLS.md +9 -39
  204. package/dist/workspace-defaults/files/USER.md +1 -0
  205. package/dist/workspace-defaults/files/agents/analyst/INSTRUCTIONS.md +6 -3
  206. package/dist/workspace-defaults/files/catalog-skills/brain-brief-builder/SKILL.md +165 -0
  207. package/dist/workspace-defaults/files/catalog-skills/n8n-workflow-operator/SKILL.md +75 -0
  208. package/dist/workspace-defaults/files/catalog-skills/n8n-workflow-operator/references/mcp-tooling.md +40 -0
  209. package/dist/workspace-defaults/files/catalog-skills/n8n-workflow-operator/references/validation-and-handoff.md +40 -0
  210. package/dist/workspace-defaults/files/catalog-skills/n8n-workflow-operator/references/workflow-authoring.md +46 -0
  211. package/dist/workspace-defaults/files/skills/artifact-builder/references/crm-dashboard.md +1 -1
  212. package/dist/workspace-defaults/files/skills/document-composer/SKILL.md +22 -3
  213. package/package.json +3 -2
  214. package/dist/drizzle/0261_thread_turns_origin_turn_index.sql +0 -11
  215. package/dist/plugins/company-data/README.md +0 -49
  216. package/dist/plugins/company-data/package.json +0 -21
  217. package/dist/plugins/company-data/src/index.ts +0 -30
  218. package/dist/plugins/company-data/src/manifest.ts +0 -26
  219. package/dist/plugins/company-data/test/manifest.test.ts +0 -116
  220. package/dist/plugins/company-data/tsconfig.json +0 -8
  221. package/dist/plugins/company-etl/README.md +0 -46
  222. package/dist/plugins/company-etl/package.json +0 -21
  223. package/dist/plugins/company-etl/src/index.ts +0 -29
  224. package/dist/plugins/company-etl/src/manifest.ts +0 -26
  225. package/dist/plugins/company-etl/test/manifest.test.ts +0 -108
  226. package/dist/plugins/company-etl/tsconfig.json +0 -8
  227. package/dist/plugins/lastmile/README.md +0 -50
  228. package/dist/plugins/lastmile/package.json +0 -23
  229. package/dist/plugins/lastmile/smoke/lastmile-plugin-smoke.mjs +0 -661
  230. package/dist/plugins/lastmile/src/api/tasks-adapter.ts +0 -572
  231. package/dist/plugins/lastmile/src/discovery.fixture.ts +0 -64
  232. package/dist/plugins/lastmile/src/index.ts +0 -46
  233. package/dist/plugins/lastmile/src/manifest.ts +0 -139
  234. package/dist/plugins/lastmile/test/api/tasks-adapter.test.ts +0 -266
  235. package/dist/plugins/lastmile/test/discovery.test.ts +0 -88
  236. package/dist/plugins/lastmile/tsconfig.json +0 -8
  237. package/dist/plugins/n8n/smoke/n8n-managed-app-smoke.mjs +0 -409
  238. package/dist/plugins/twenty/smoke/twenty-managed-app-smoke.mjs +0 -359
  239. package/dist/plugins/workos-auth/package.json +0 -22
  240. package/dist/plugins/workos-auth/src/index.ts +0 -30
  241. package/dist/plugins/workos-auth/src/manifest.ts +0 -40
  242. package/dist/plugins/workos-auth/src/provider-contract.ts +0 -39
  243. package/dist/plugins/workos-auth/test/manifest.test.ts +0 -94
  244. package/dist/plugins/workos-auth/tsconfig.json +0 -8
  245. package/dist/terraform/modules/app/agentcore-code-interpreter/Dockerfile.sandbox-base +0 -61
  246. package/dist/terraform/modules/app/agentcore-code-interpreter/sandbox/sitecustomize.py +0 -227
  247. package/dist/terraform/modules/app/agentcore-code-interpreter/sandbox/test_sitecustomize.py +0 -277
  248. package/dist/terraform/modules/app/agentcore-code-interpreter/scripts/build_and_push_sandbox_base.sh +0 -70
  249. package/dist/terraform/modules/app/agentcore-harness/main.tf +0 -101
  250. package/dist/terraform/modules/app/agentcore-harness/outputs.tf +0 -9
  251. package/dist/terraform/modules/app/agentcore-harness/variables.tf +0 -25
  252. package/dist/terraform/modules/app/hindsight-memory/README.md +0 -89
  253. package/dist/terraform/modules/app/hindsight-memory/main.tf +0 -411
  254. package/dist/terraform/modules/data/bedrock-knowledge-base/main.tf +0 -102
  255. /package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/outputs.tf +0 -0
  256. /package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/scripts/sync-database.py +0 -0
  257. /package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/scripts/test_sync_database.py +0 -0
  258. /package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/variables.tf +0 -0
  259. /package/dist/{plugins/twenty/terraform → terraform/modules/app}/twenty/README.md +0 -0
  260. /package/dist/{plugins/twenty/terraform → terraform/modules/app}/twenty/main.tf +0 -0
  261. /package/dist/{plugins/twenty/terraform → terraform/modules/app}/twenty/outputs.tf +0 -0
  262. /package/dist/{plugins/twenty/terraform → terraform/modules/app}/twenty/variables.tf +0 -0
@@ -0,0 +1,175 @@
1
+ #!/usr/bin/env node
2
+ // Reconcile the Pi Bedrock AgentCore Runtime to a digest-pinned image
3
+ // (THINK-584 U5). Invoked by the deployment-control-plane runner with a JSON
4
+ // request on STDIN (never argv — the mirrored env contains secrets):
5
+ //
6
+ // {
7
+ // "region": "us-east-1",
8
+ // "runtimeName": "thinkwork_<stage>_pi",
9
+ // "runtimeId": "<optional known id>",
10
+ // "roleArn": "arn:aws:iam::...:role/thinkwork-<stage>-agentcore-pi-role",
11
+ // "imageUri": "<account>.dkr.ecr...amazonaws.com/...@sha256:<digest>",
12
+ // "environment": { ... mirrored Lambda env, control chars escaped ... },
13
+ // "waitSeconds": 900
14
+ // }
15
+ //
16
+ // Creates the runtime when absent, updates it when present, then waits for
17
+ // runtime READY + DEFAULT endpoint liveVersion == runtime version + the
18
+ // exact image URI. Prints a result JSON on stdout. Env VALUES are never
19
+ // printed — counts only (R19).
20
+
21
+ import {
22
+ BedrockAgentCoreControlClient,
23
+ CreateAgentRuntimeCommand,
24
+ GetAgentRuntimeCommand,
25
+ ListAgentRuntimesCommand,
26
+ ListAgentRuntimeEndpointsCommand,
27
+ UpdateAgentRuntimeCommand,
28
+ } from "@aws-sdk/client-bedrock-agentcore-control";
29
+
30
+ if (process.argv[2] === "--runtime-preflight") {
31
+ process.stdout.write(
32
+ JSON.stringify({
33
+ entrypoint: "reconcile_pi_runtime",
34
+ sdkImportReady:
35
+ typeof BedrockAgentCoreControlClient === "function" &&
36
+ typeof CreateAgentRuntimeCommand === "function" &&
37
+ typeof GetAgentRuntimeCommand === "function" &&
38
+ typeof ListAgentRuntimesCommand === "function" &&
39
+ typeof ListAgentRuntimeEndpointsCommand === "function" &&
40
+ typeof UpdateAgentRuntimeCommand === "function",
41
+ }),
42
+ );
43
+ process.exit(0);
44
+ }
45
+
46
+ const chunks = [];
47
+ for await (const chunk of process.stdin) chunks.push(chunk);
48
+ const input = JSON.parse(Buffer.concat(chunks).toString("utf8"));
49
+
50
+ const environment = input.environment ?? {};
51
+ const envCount = Object.keys(environment).length;
52
+ if (envCount === 0) {
53
+ // Atomic-or-abort: an empty mirrored env would strand the runtime.
54
+ process.stderr.write(
55
+ "reconcile_pi_runtime: refusing to proceed with an empty environment mirror\n",
56
+ );
57
+ process.exit(2);
58
+ }
59
+ if (!/@sha256:[0-9a-f]{64}$/.test(input.imageUri ?? "")) {
60
+ process.stderr.write(
61
+ "reconcile_pi_runtime: imageUri must be pinned to an immutable sha256 digest\n",
62
+ );
63
+ process.exit(2);
64
+ }
65
+
66
+ const client = new BedrockAgentCoreControlClient({ region: input.region });
67
+
68
+ let runtimeId = input.runtimeId || "";
69
+ if (!runtimeId) {
70
+ let nextToken;
71
+ do {
72
+ const page = await client.send(new ListAgentRuntimesCommand({ nextToken }));
73
+ const match = (page.agentRuntimes ?? []).find(
74
+ (runtime) => runtime.agentRuntimeName === input.runtimeName,
75
+ );
76
+ if (match) {
77
+ runtimeId = match.agentRuntimeId;
78
+ break;
79
+ }
80
+ nextToken = page.nextToken;
81
+ } while (nextToken);
82
+ }
83
+
84
+ const artifact = {
85
+ containerConfiguration: { containerUri: input.imageUri },
86
+ };
87
+ let created = false;
88
+ if (runtimeId) {
89
+ await client.send(
90
+ new UpdateAgentRuntimeCommand({
91
+ agentRuntimeId: runtimeId,
92
+ roleArn: input.roleArn,
93
+ agentRuntimeArtifact: artifact,
94
+ networkConfiguration: { networkMode: "PUBLIC" },
95
+ protocolConfiguration: { serverProtocol: "HTTP" },
96
+ environmentVariables: environment,
97
+ }),
98
+ );
99
+ } else {
100
+ const response = await client.send(
101
+ new CreateAgentRuntimeCommand({
102
+ agentRuntimeName: input.runtimeName,
103
+ roleArn: input.roleArn,
104
+ agentRuntimeArtifact: artifact,
105
+ networkConfiguration: { networkMode: "PUBLIC" },
106
+ protocolConfiguration: { serverProtocol: "HTTP" },
107
+ environmentVariables: environment,
108
+ }),
109
+ );
110
+ runtimeId = response.agentRuntimeId;
111
+ created = true;
112
+ }
113
+
114
+ const sleep = (milliseconds) =>
115
+ new Promise((resolve) => setTimeout(resolve, milliseconds));
116
+
117
+ const waitSeconds = Number(input.waitSeconds ?? 900);
118
+ const deadline = Date.now() + waitSeconds * 1000;
119
+ let detail;
120
+ let endpoint;
121
+ for (;;) {
122
+ detail = await client.send(
123
+ new GetAgentRuntimeCommand({ agentRuntimeId: runtimeId }),
124
+ );
125
+ const endpoints = await client.send(
126
+ new ListAgentRuntimeEndpointsCommand({ agentRuntimeId: runtimeId }),
127
+ );
128
+ endpoint = (endpoints.runtimeEndpoints ?? []).find(
129
+ (candidate) => candidate.name === "DEFAULT",
130
+ );
131
+ const mirroredCount = Object.keys(detail.environmentVariables ?? {}).length;
132
+ const image =
133
+ detail.agentRuntimeArtifact?.containerConfiguration?.containerUri ?? "";
134
+ const settled =
135
+ detail.status === "READY" &&
136
+ endpoint?.status === "READY" &&
137
+ (endpoint?.targetVersion == null ||
138
+ endpoint.targetVersion === detail.agentRuntimeVersion) &&
139
+ endpoint?.liveVersion === detail.agentRuntimeVersion &&
140
+ image === input.imageUri;
141
+ if (settled) {
142
+ if (mirroredCount === 0) {
143
+ // Post-update assertion half of atomic-or-abort: the runtime settled
144
+ // but reports an EMPTY env — the mirror did not stick. Fail loudly.
145
+ process.stderr.write(
146
+ "reconcile_pi_runtime: runtime settled with an EMPTY environment\n",
147
+ );
148
+ process.exit(2);
149
+ }
150
+ break;
151
+ }
152
+ if (Date.now() >= deadline) {
153
+ process.stderr.write(
154
+ `reconcile_pi_runtime: timed out waiting for ${runtimeId} ` +
155
+ `(runtime=${detail.status} endpoint=${endpoint?.status ?? "MISSING"} ` +
156
+ `live=${endpoint?.liveVersion ?? "null"} target=${endpoint?.targetVersion ?? "null"} ` +
157
+ `image=${image})\n`,
158
+ );
159
+ process.exit(1);
160
+ }
161
+ await sleep(15000);
162
+ }
163
+
164
+ process.stdout.write(
165
+ JSON.stringify({
166
+ runtimeId,
167
+ created,
168
+ version: detail.agentRuntimeVersion,
169
+ status: detail.status,
170
+ endpointStatus: endpoint?.status ?? "UNKNOWN",
171
+ liveVersion: endpoint?.liveVersion ?? null,
172
+ image: detail.agentRuntimeArtifact?.containerConfiguration?.containerUri,
173
+ envCount,
174
+ }),
175
+ );
@@ -43,18 +43,6 @@ variable "async_dlq_arn" {
43
43
  type = string
44
44
  }
45
45
 
46
- variable "hindsight_endpoint" {
47
- description = "Hindsight API endpoint. Empty string (default) disables Hindsight tools in the container; set to an endpoint URL to enable Hindsight as an add-on alongside the always-on managed memory."
48
- type = string
49
- default = ""
50
- }
51
-
52
- variable "hindsight_database_name" {
53
- description = "Dedicated Hindsight database name (THINK-220 cutover flag). Empty = the provider's direct SQL (high-confidence-fact recall, access-count writes) targets the `hindsight` schema of the primary database; set = that database's `public` schema."
54
- type = string
55
- default = ""
56
- }
57
-
58
46
  variable "agentcore_memory_id" {
59
47
  description = "AgentCore Memory resource ID. Populated automatically by the agentcore-memory module; injected into the container as AGENTCORE_MEMORY_ID for auto-retention."
60
48
  type = string
@@ -74,16 +62,6 @@ variable "api_auth_secret" {
74
62
  sensitive = true
75
63
  }
76
64
 
77
- variable "memory_engine" {
78
- description = "Active long-term memory engine ('hindsight' or 'agentcore'). Surfaced to the runtime as MEMORY_ENGINE for telemetry/debugging only; engine selection itself happens in the API's normalized memory layer when memory-retain is invoked."
79
- type = string
80
- default = "hindsight"
81
- validation {
82
- condition = contains(["hindsight", "agentcore"], var.memory_engine)
83
- error_message = "memory_engine must be 'hindsight' or 'agentcore'."
84
- }
85
- }
86
-
87
65
  variable "requester_idle_memory_learning_enabled" {
88
66
  description = "When true, requester memory learning runs through the API idle/dreaming pipeline instead of runtime retain-on-every-turn."
89
67
  type = bool
@@ -103,37 +81,37 @@ variable "db_secret_arn" {
103
81
  }
104
82
 
105
83
  variable "okf_efs_enabled" {
106
- description = "When true, mount the generated OKF wiki EFS view into Pi. Requires subnet/security-group inputs and an access point ARN."
84
+ description = "DEPRECATED (THINK-589): no-op, removal pending. The OKF wiki EFS feature is dead; this input is ignored — Pi is never VPC-attached and never mounts EFS. Declaration retained so existing passthroughs and tfvars keep working until PR 2 deletes it."
107
85
  type = bool
108
86
  default = false
109
87
  }
110
88
 
111
89
  variable "okf_efs_subnet_ids" {
112
- description = "Subnet IDs for the Pi Lambda VPC attachment used by the OKF wiki EFS mount."
90
+ description = "DEPRECATED (THINK-589): no-op, removal pending. The OKF wiki EFS feature is dead; this input is ignored — Pi is never VPC-attached and never mounts EFS. Declaration retained so existing passthroughs and tfvars keep working until PR 2 deletes it."
113
91
  type = list(string)
114
92
  default = []
115
93
  }
116
94
 
117
95
  variable "okf_efs_security_group_ids" {
118
- description = "Security group IDs for the Pi Lambda VPC attachment used by the OKF wiki EFS mount."
96
+ description = "DEPRECATED (THINK-589): no-op, removal pending. The OKF wiki EFS feature is dead; this input is ignored — Pi is never VPC-attached and never mounts EFS. Declaration retained so existing passthroughs and tfvars keep working until PR 2 deletes it."
119
97
  type = list(string)
120
98
  default = []
121
99
  }
122
100
 
123
101
  variable "okf_efs_file_system_arn" {
124
- description = "EFS file system ARN for read-only Pi OKF wiki access."
102
+ description = "DEPRECATED (THINK-589): no-op, removal pending. The OKF wiki EFS feature is dead; this input is ignored — Pi is never VPC-attached and never mounts EFS. Declaration retained so existing passthroughs and tfvars keep working until PR 2 deletes it."
125
103
  type = string
126
104
  default = ""
127
105
  }
128
106
 
129
107
  variable "okf_efs_read_access_point_arn" {
130
- description = "EFS access point ARN mounted read-only by Pi for OKF wiki traversal."
108
+ description = "DEPRECATED (THINK-589): no-op, removal pending. The OKF wiki EFS feature is dead; this input is ignored — Pi is never VPC-attached and never mounts EFS. Declaration retained so existing passthroughs and tfvars keep working until PR 2 deletes it."
131
109
  type = string
132
110
  default = ""
133
111
  }
134
112
 
135
113
  variable "okf_efs_mount_path" {
136
- description = "Local Lambda mount path for the OKF wiki EFS view. Must be under /mnt."
114
+ description = "DEPRECATED (THINK-589): no-op, removal pending. The OKF wiki EFS feature is dead; this input is ignored — Pi is never VPC-attached and never mounts EFS. Declaration retained so existing passthroughs and tfvars keep working until PR 2 deletes it."
137
115
  type = string
138
116
  default = "/mnt/thinkwork-okf"
139
117
  }
@@ -151,3 +129,32 @@ variable "capability_signing_public_key" {
151
129
  type = string
152
130
  default = ""
153
131
  }
132
+
133
+ # ---------------------------------------------------------------------------
134
+ # THINK-1082: Pi inside the VPC. Pi holds DB_CLUSTER_ARN + DB_SECRET_ARN (RDS
135
+ # Data API — no network path to the cluster itself) but ships alongside the
136
+ # api handlers, which reach Aurora over its public endpoint today. This lane
137
+ # lets the runtime sit in the same private subnets behind the same api-lambda
138
+ # security group so the stage's database port can close uniformly. NETWORK
139
+ # side only: the THINK-589 EFS mount stays gone (no file_system_config). The
140
+ # private subnets must be NAT-routed — Pi needs Bedrock / Anthropic / GitHub
141
+ # egress. Default off = byte-identical to today.
142
+ # ---------------------------------------------------------------------------
143
+
144
+ variable "in_vpc" {
145
+ description = "Attach the Pi runtime Lambda to the VPC (vpc_subnet_ids + vpc_security_group_ids). Requires both lists non-empty and NAT-routed subnets (Bedrock, Anthropic, GitHub egress). Network attachment only — never re-adds the retired EFS mount."
146
+ type = bool
147
+ default = false
148
+ }
149
+
150
+ variable "vpc_subnet_ids" {
151
+ description = "Private (NAT-routed) subnet IDs for the Pi runtime when in_vpc is true."
152
+ type = list(string)
153
+ default = []
154
+ }
155
+
156
+ variable "vpc_security_group_ids" {
157
+ description = "Security groups for the Pi runtime when in_vpc is true (the thinkwork module passes its api-lambda SG)."
158
+ type = list(string)
159
+ default = []
160
+ }
@@ -10,6 +10,12 @@ variable "stage" {
10
10
  type = string
11
11
  }
12
12
 
13
+ variable "release_mirror_principal_arns" {
14
+ description = "IAM principals allowed to mirror release runtime images into this stage's AgentCore ECR repository. AgentCore Runtime is arm64-only and the deployment runner resolves the runtime image from THIS account's ECR by the '<releaseVersion>-pi-arm64' tag, so the ThinkWork release pipeline must be able to push it (THINK-616). Set to [] to disable the cross-account grant and mirror by hand."
15
+ type = list(string)
16
+ default = []
17
+ }
18
+
13
19
  ################################################################################
14
20
  # ECR Repository
15
21
  ################################################################################
@@ -48,6 +54,68 @@ resource "aws_ecr_lifecycle_policy" "agentcore" {
48
54
  })
49
55
  }
50
56
 
57
+ ################################################################################
58
+ # Cross-account release-image mirror grant (THINK-616)
59
+ #
60
+ # The release workflow's `mirror-customer-images` job pushes
61
+ # `<releaseVersion>-pi-arm64` into this repository from the ThinkWork release
62
+ # account. A repository policy is the whole grant — no role, user, or key is
63
+ # provisioned here.
64
+ #
65
+ # `aws_ecr_repository_policy` REPLACES the repository policy document, so the
66
+ # Lambda image-retrieval statement that Lambda auto-attaches when a container
67
+ # function is created is restated here; dropping it would leave the Pi Lambda's
68
+ # image pull ungranted.
69
+ ################################################################################
70
+
71
+ data "aws_caller_identity" "current" {}
72
+
73
+ resource "aws_ecr_repository_policy" "agentcore" {
74
+ count = length(var.release_mirror_principal_arns) > 0 ? 1 : 0
75
+
76
+ repository = aws_ecr_repository.agentcore.name
77
+
78
+ policy = jsonencode({
79
+ Version = "2012-10-17"
80
+ Statement = [
81
+ {
82
+ Sid = "LambdaECRImageRetrievalPolicy"
83
+ Effect = "Allow"
84
+ Principal = {
85
+ Service = "lambda.amazonaws.com"
86
+ }
87
+ Action = [
88
+ "ecr:BatchGetImage",
89
+ "ecr:GetDownloadUrlForLayer",
90
+ ]
91
+ Condition = {
92
+ StringLike = {
93
+ "aws:sourceArn" = "arn:aws:lambda:*:${data.aws_caller_identity.current.account_id}:function:*"
94
+ }
95
+ }
96
+ },
97
+ {
98
+ Sid = "ThinkWorkReleaseImageMirror"
99
+ Effect = "Allow"
100
+ Principal = {
101
+ AWS = var.release_mirror_principal_arns
102
+ }
103
+ Action = [
104
+ "ecr:BatchCheckLayerAvailability",
105
+ "ecr:BatchGetImage",
106
+ "ecr:CompleteLayerUpload",
107
+ "ecr:DescribeImages",
108
+ "ecr:GetDownloadUrlForLayer",
109
+ "ecr:InitiateLayerUpload",
110
+ "ecr:ListImages",
111
+ "ecr:PutImage",
112
+ "ecr:UploadLayerPart",
113
+ ]
114
+ },
115
+ ]
116
+ })
117
+ }
118
+
51
119
  ################################################################################
52
120
  # Async-invoke DLQ
53
121
  ################################################################################
@@ -26,12 +26,6 @@ variable "bucket_name" {
26
26
  type = string
27
27
  }
28
28
 
29
- variable "hindsight_endpoint" {
30
- description = "Hindsight API endpoint. Empty string (default) disables Hindsight tools in the container; set to an endpoint URL to enable Hindsight as an add-on alongside the always-on managed memory."
31
- type = string
32
- default = ""
33
- }
34
-
35
29
  variable "agentcore_memory_id" {
36
30
  description = "AgentCore Memory resource ID. Populated automatically by the agentcore-memory module; injected into the container as AGENTCORE_MEMORY_ID for auto-retention."
37
31
  type = string
@@ -58,16 +52,6 @@ variable "nova_act_api_key" {
58
52
  sensitive = true
59
53
  }
60
54
 
61
- variable "memory_engine" {
62
- description = "Active long-term memory engine ('hindsight' or 'agentcore'). Surfaced to the runtime as MEMORY_ENGINE for telemetry/debugging only; engine selection itself happens in the API's normalized memory layer when memory-retain is invoked."
63
- type = string
64
- default = "hindsight"
65
- validation {
66
- condition = contains(["hindsight", "agentcore"], var.memory_engine)
67
- error_message = "memory_engine must be 'hindsight' or 'agentcore'."
68
- }
69
- }
70
-
71
55
  variable "requester_idle_memory_learning_enabled" {
72
56
  description = "When true, requester memory learning runs through the API idle/dreaming pipeline instead of runtime retain-on-every-turn."
73
57
  type = bool
@@ -302,9 +286,9 @@ resource "aws_iam_role_policy" "agentcore" {
302
286
  },
303
287
  {
304
288
  # Async-invoke the memory-retain Lambda after every chat turn so
305
- # the API's normalized memory layer can run the active engine's
306
- # retainTurn() path (Hindsight POST /memories or AgentCore
307
- # CreateEvent). InvocationType=Event from the Python client; this
289
+ # the API's normalized memory layer can run the AgentCore
290
+ # CreateEvent retainTurn() path. InvocationType=Event from the
291
+ # Python client; this
308
292
  # Lambda is the only target.
309
293
  Sid = "MemoryRetainInvoke"
310
294
  Effect = "Allow"
@@ -346,7 +330,7 @@ resource "aws_lambda_function" "agentcore" {
346
330
  AWS_LWA_PORT = "8080"
347
331
  AGENTCORE_MEMORY_ID = var.agentcore_memory_id
348
332
  AGENTCORE_FILES_BUCKET = var.bucket_name
349
- MEMORY_ENGINE = var.memory_engine
333
+ MEMORY_ENGINE = "agentcore"
350
334
  REQUESTER_IDLE_MEMORY_LEARNING_ENABLED = tostring(var.requester_idle_memory_learning_enabled)
351
335
  MEMORY_RETAIN_FN_NAME = local.memory_retain_fn_name
352
336
  # Needed by run_skill_dispatch.py to POST terminal state back to
@@ -18,21 +18,19 @@
18
18
 
19
19
  resource "aws_appsync_graphql_api" "subscriptions" {
20
20
  name = "thinkwork-${var.stage}-subscriptions"
21
- authentication_type = "API_KEY"
21
+ authentication_type = "AWS_LAMBDA"
22
22
  xray_enabled = false
23
23
 
24
24
  schema = var.subscription_schema
25
25
 
26
- additional_authentication_provider {
27
- authentication_type = "AWS_IAM"
26
+ lambda_authorizer_config {
27
+ authorizer_uri = "arn:aws:lambda:${var.region}:${var.account_id}:function:thinkwork-${var.stage}-api-appsync-subscription-authorizer"
28
+ authorizer_result_ttl_in_seconds = 0
29
+ identity_validation_expression = "^twsub1_[A-Za-z0-9_-]+$"
28
30
  }
29
31
 
30
32
  additional_authentication_provider {
31
- authentication_type = "AMAZON_COGNITO_USER_POOLS"
32
-
33
- user_pool_config {
34
- user_pool_id = var.user_pool_id
35
- }
33
+ authentication_type = "AWS_IAM"
36
34
  }
37
35
 
38
36
  tags = {
@@ -40,19 +38,6 @@ resource "aws_appsync_graphql_api" "subscriptions" {
40
38
  }
41
39
  }
42
40
 
43
- ################################################################################
44
- # API Key — 365 day expiry
45
- ################################################################################
46
-
47
- resource "aws_appsync_api_key" "main" {
48
- api_id = aws_appsync_graphql_api.subscriptions.id
49
- expires = timeadd(timestamp(), "8760h")
50
-
51
- lifecycle {
52
- ignore_changes = [expires]
53
- }
54
- }
55
-
56
41
  ################################################################################
57
42
  # NONE Data Source (passthrough for notification mutations)
58
43
  ################################################################################
@@ -84,6 +69,20 @@ locals {
84
69
  "notifyEvalRunUpdate",
85
70
  "notifyWorkspaceAccessRevoked",
86
71
  ]
72
+ subscription_scopes = {
73
+ onAgentStatusChanged = { argument = "tenantId", kind = "tenant" }
74
+ onNewMessage = { argument = "threadId", kind = "thread" }
75
+ onHeartbeatActivity = { argument = "tenantId", kind = "tenant" }
76
+ onThreadUpdated = { argument = "tenantId", kind = "tenant" }
77
+ onThreadActivity = { argument = "userId", kind = "user" }
78
+ onInboxItemStatusChanged = { argument = "tenantId", kind = "tenant" }
79
+ onThreadTurnUpdated = { argument = "tenantId", kind = "tenant" }
80
+ onThreadTurnStep = { argument = "threadId", kind = "thread" }
81
+ onOrgUpdated = { argument = "tenantId", kind = "tenant" }
82
+ onCostRecorded = { argument = "tenantId", kind = "tenant" }
83
+ onEvalRunUpdated = { argument = "tenantId", kind = "tenant" }
84
+ onWorkspaceAccessRevoked = { argument = "userId", kind = "user" }
85
+ }
87
86
  }
88
87
 
89
88
  resource "aws_appsync_resolver" "notifications" {
@@ -113,6 +112,113 @@ resource "aws_appsync_resolver" "notifications" {
113
112
  EOF
114
113
  }
115
114
 
115
+ ################################################################################
116
+ # Subscription registration filters + active-connection invalidation
117
+ ################################################################################
118
+
119
+ resource "aws_appsync_resolver" "subscription_admission" {
120
+ for_each = local.subscription_scopes
121
+
122
+ api_id = aws_appsync_graphql_api.subscriptions.id
123
+ type = "Subscription"
124
+ field = each.key
125
+ data_source = aws_appsync_datasource.none.name
126
+
127
+ runtime {
128
+ name = "APPSYNC_JS"
129
+ runtime_version = "1.0.0"
130
+ }
131
+
132
+ code = <<-JS
133
+ import { util, extensions } from '@aws-appsync/utils';
134
+
135
+ export function request() {
136
+ return { payload: null };
137
+ }
138
+
139
+ export function response(ctx) {
140
+ const identity = (ctx.identity && ctx.identity.resolverContext) || {};
141
+ const tenantId = identity.tenantId;
142
+ const userId = identity.stableUserId;
143
+ const resourceKind = identity.resourceKind;
144
+ const resourceId = identity.resourceId;
145
+ if (!tenantId || !userId || !resourceKind || !resourceId) {
146
+ util.unauthorized();
147
+ }
148
+
149
+ extensions.setSubscriptionFilter(util.transform.toSubscriptionFilter({
150
+ ${each.value.argument}: { eq: ctx.args.${each.value.argument} },
151
+ }));
152
+ extensions.setSubscriptionInvalidationFilter({
153
+ filterGroup: [
154
+ { filters: [
155
+ { fieldName: 'scope', operator: 'eq', value: 'tenant' },
156
+ { fieldName: 'tenantId', operator: 'eq', value: tenantId },
157
+ ]},
158
+ { filters: [
159
+ { fieldName: 'scope', operator: 'eq', value: 'user' },
160
+ { fieldName: 'tenantId', operator: 'eq', value: tenantId },
161
+ { fieldName: 'userId', operator: 'eq', value: userId },
162
+ ]},
163
+ { filters: [
164
+ { fieldName: 'scope', operator: 'eq', value: 'resource' },
165
+ { fieldName: 'tenantId', operator: 'eq', value: tenantId },
166
+ { fieldName: 'userId', operator: 'eq', value: userId },
167
+ { fieldName: 'resourceKind', operator: 'eq', value: resourceKind },
168
+ { fieldName: 'resourceId', operator: 'eq', value: resourceId },
169
+ ]},
170
+ ],
171
+ });
172
+ return null;
173
+ }
174
+ JS
175
+ }
176
+
177
+ resource "aws_appsync_resolver" "subscription_invalidation" {
178
+ api_id = aws_appsync_graphql_api.subscriptions.id
179
+ type = "Mutation"
180
+ field = "invalidateSubscription"
181
+ data_source = aws_appsync_datasource.none.name
182
+
183
+ runtime {
184
+ name = "APPSYNC_JS"
185
+ runtime_version = "1.0.0"
186
+ }
187
+
188
+ code = <<-JS
189
+ import { util, extensions } from '@aws-appsync/utils';
190
+
191
+ const fields = {
192
+ ON_AGENT_STATUS_CHANGED: 'onAgentStatusChanged',
193
+ ON_NEW_MESSAGE: 'onNewMessage',
194
+ ON_HEARTBEAT_ACTIVITY: 'onHeartbeatActivity',
195
+ ON_THREAD_UPDATED: 'onThreadUpdated',
196
+ ON_THREAD_ACTIVITY: 'onThreadActivity',
197
+ ON_INBOX_ITEM_STATUS_CHANGED: 'onInboxItemStatusChanged',
198
+ ON_THREAD_TURN_UPDATED: 'onThreadTurnUpdated',
199
+ ON_THREAD_TURN_STEP: 'onThreadTurnStep',
200
+ ON_ORG_UPDATED: 'onOrgUpdated',
201
+ ON_COST_RECORDED: 'onCostRecorded',
202
+ ON_EVAL_RUN_UPDATED: 'onEvalRunUpdated',
203
+ ON_WORKSPACE_ACCESS_REVOKED: 'onWorkspaceAccessRevoked',
204
+ };
205
+
206
+ export function request(ctx) {
207
+ return { payload: { ...ctx.args, subscriptionField: fields[ctx.args.subscriptionField] } };
208
+ }
209
+
210
+ export function response(ctx) {
211
+ const payload = ctx.result;
212
+ if (!payload.subscriptionField) util.error('Invalid subscription field');
213
+ extensions.invalidateSubscriptions({
214
+ subscriptionField: payload.subscriptionField,
215
+ payload,
216
+ });
217
+ return payload;
218
+ }
219
+ JS
220
+ }
221
+
116
222
  ################################################################################
117
223
  # Custom Domain (optional)
118
224
  ################################################################################
@@ -17,9 +17,3 @@ output "graphql_realtime_url" {
17
17
  description = "AppSync realtime WebSocket URL (used by frontend subscription clients)"
18
18
  value = aws_appsync_graphql_api.subscriptions.uris["REALTIME"]
19
19
  }
20
-
21
- output "graphql_api_key" {
22
- description = "AppSync API key"
23
- value = aws_appsync_api_key.main.key
24
- sensitive = true
25
- }
@@ -8,6 +8,11 @@ variable "region" {
8
8
  type = string
9
9
  }
10
10
 
11
+ variable "account_id" {
12
+ description = "AWS account ID hosting the AppSync authorizer Lambda"
13
+ type = string
14
+ }
15
+
11
16
  variable "user_pool_id" {
12
17
  description = "Cognito user pool ID for authentication"
13
18
  type = string
@@ -8,7 +8,7 @@
8
8
  #
9
9
  # THINK-144: this module owns a DEDICATED execute-api interface VPC endpoint
10
10
  # with private DNS DISABLED. It is never added to the app VPC's shared
11
- # okf_wiki_interface_endpoint_services list — that list's private DNS would
11
+ # vpc_interface_endpoint_services set — that list's private DNS would
12
12
  # capture every *.execute-api call in the VPC and 403 the stack's public HTTP
13
13
  # APIs. The session bootstrap targets this endpoint's own DNS name instead.
14
14
 
@@ -188,7 +188,7 @@ resource "aws_lambda_function" "broker" {
188
188
 
189
189
  vpc_config {
190
190
  subnet_ids = var.subnet_ids
191
- security_group_ids = [aws_security_group.broker_lambda[0].id]
191
+ security_group_ids = distinct(concat([aws_security_group.broker_lambda[0].id], var.additional_security_group_ids))
192
192
  }
193
193
 
194
194
  environment {
@@ -96,3 +96,14 @@ variable "log_retention_days" {
96
96
  type = number
97
97
  default = 30
98
98
  }
99
+
100
+ # THINK-1082: the broker is already VPC-attached (private subnets, its own
101
+ # egress-only SG) but reaches Aurora through the database SG's world-open
102
+ # 0.0.0.0/0 -> 5432 rule (the cluster's public hostname resolves to the
103
+ # private IP from inside the VPC). Extra SGs let the caller attach the
104
+ # api-lambda SG the database SG admits, so the public rule can close.
105
+ variable "additional_security_group_ids" {
106
+ description = "Extra security groups appended to the broker Lambda's vpc_config (e.g. the api-lambda SG granted tcp/5432 on the database SG). Default none = unchanged."
107
+ type = list(string)
108
+ default = []
109
+ }