thinkwork-cli 0.12.11 → 0.12.15

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 (474) hide show
  1. package/README.md +42 -38
  2. package/dist/{api-client-ASJWIG3Z.js → api-client-4VT3FWOH.js} +1 -1
  3. package/dist/{chunk-JEHV35EU.js → chunk-H7AB42ES.js} +340 -30
  4. package/dist/cli.js +22157 -9229
  5. package/dist/commands/enterprise/templates/deploy-repo/.github/workflows/deploy.yml +17 -6
  6. package/dist/commands/enterprise/templates/deploy-repo/docs/runbook.md +81 -9
  7. package/dist/commands/enterprise/templates/deploy-repo/scripts/apply-release.mjs +183 -21
  8. package/dist/commands/enterprise/templates/deploy-repo/scripts/smoke.mjs +1 -2
  9. package/dist/commands/enterprise/templates/deploy-repo/terraform/main.tf +286 -0
  10. package/dist/drizzle/0000_petite_marvel_apes.sql +1188 -0
  11. package/dist/drizzle/0001_milky_surge.sql +103 -0
  12. package/dist/drizzle/0002_aberrant_mattie_franklin.sql +41 -0
  13. package/dist/drizzle/0003_exotic_ogun.sql +3 -0
  14. package/dist/drizzle/0004_glamorous_magneto.sql +2 -0
  15. package/dist/drizzle/0005_ancient_nocturne.sql +2 -0
  16. package/dist/drizzle/0006_new_colonel_america.sql +2 -0
  17. package/dist/drizzle/0007_unique_external_task_id.sql +31 -0
  18. package/dist/drizzle/0008_external_task_id_column.sql +43 -0
  19. package/dist/drizzle/0009_evaluations.sql +64 -0
  20. package/dist/drizzle/0010_eval_agent_template.sql +2 -0
  21. package/dist/drizzle/0011_eval_run_template.sql +2 -0
  22. package/dist/drizzle/0012_eval_seed_unique.sql +16 -0
  23. package/dist/drizzle/0013_motionless_white_queen.sql +140 -0
  24. package/dist/drizzle/0014_wiki_aggregation.sql +11 -0
  25. package/dist/drizzle/0015_pg_trgm_alias_title_indexes.sql +9 -0
  26. package/dist/drizzle/0016_wiki_schema_drops.sql +24 -0
  27. package/dist/drizzle/0017_wiki_places.sql +46 -0
  28. package/dist/drizzle/0018_agent_workspace_overlay.sql +26 -0
  29. package/dist/drizzle/0018_cool_firebird.sql +24 -0
  30. package/dist/drizzle/0018_skill_runs.sql +84 -0
  31. package/dist/drizzle/0019_condemned_dragon_man.sql +95 -0
  32. package/dist/drizzle/0019_webhook_skill_runs.sql +58 -0
  33. package/dist/drizzle/0020_crazy_the_anarchist.sql +9 -0
  34. package/dist/drizzle/0020_mutation_idempotency.sql +64 -0
  35. package/dist/drizzle/0021_crm_work_links.sql +76 -0
  36. package/dist/drizzle/0021_skill_runs_completion_hmac.sql +33 -0
  37. package/dist/drizzle/0022_add_billing_tables.sql +70 -0
  38. package/dist/drizzle/0022_seed_thinkwork_admin_permissions.sql +160 -0
  39. package/dist/drizzle/0022_stripe_billing_indexes.sql +48 -0
  40. package/dist/drizzle/0023_tenants_deactivation.sql +27 -0
  41. package/dist/drizzle/0024_tenant_mcp_admin_keys.sql +63 -0
  42. package/dist/drizzle/0025_v1_agent_architecture.sql +182 -0
  43. package/dist/drizzle/0026_thread_turns_add_kind.sql +28 -0
  44. package/dist/drizzle/0027_capability_catalog_and_manifests.sql +219 -0
  45. package/dist/drizzle/0028_aws_s3_extension.sql +26 -0
  46. package/dist/drizzle/0029_collapse_execution_types.sql +42 -0
  47. package/dist/drizzle/0030_retire_composition_primitives.sql +48 -0
  48. package/dist/drizzle/0031_thread_cleanup_drops.sql +131 -0
  49. package/dist/drizzle/0032_add_browser_automation_template_config.sql +24 -0
  50. package/dist/drizzle/0033_agent_operation_leases.sql +32 -0
  51. package/dist/drizzle/0034_agent_workspace_events.sql +116 -0
  52. package/dist/drizzle/0035_workspace_review_decisions.sql +19 -0
  53. package/dist/drizzle/0036_user_scoped_memory_wiki.sql +152 -0
  54. package/dist/drizzle/0037_user_profile_operating_model.sql +34 -0
  55. package/dist/drizzle/0042_agent_runtime_selector.sql +41 -0
  56. package/dist/drizzle/0043_wiki_search_tsv_tokenization.sql +48 -0
  57. package/dist/drizzle/0044_add_web_search_template_config.sql +7 -0
  58. package/dist/drizzle/0045_add_send_email_template_config.sql +7 -0
  59. package/dist/drizzle/0046_tenant_mcp_context_tools.sql +26 -0
  60. package/dist/drizzle/0047_add_context_engine_template_config.sql +7 -0
  61. package/dist/drizzle/0048_tenant_context_provider_settings.sql +22 -0
  62. package/dist/drizzle/0050_brain_v0_entity_subtype.sql +29 -0
  63. package/dist/drizzle/0051_brain_v0_tenant_entity_pages.sql +170 -0
  64. package/dist/drizzle/0052_brain_v0_external_refs.sql +41 -0
  65. package/dist/drizzle/0053_brain_v0_unresolved_mentions_subtype.sql +48 -0
  66. package/dist/drizzle/0054_wiki_compile_jobs_input.sql +28 -0
  67. package/dist/drizzle/0055_routines_stepfunctions_substrate.sql +202 -0
  68. package/dist/drizzle/0056_routine_step_events_dedup_idx.sql +25 -0
  69. package/dist/drizzle/0057_archive_legacy_python_routines.sql +36 -0
  70. package/dist/drizzle/0058_routines_visibility_and_owning_agent.sql +61 -0
  71. package/dist/drizzle/0061_routine_execution_asl_version_id.sql +29 -0
  72. package/dist/drizzle/0062_migrate_pi_to_flue.sql +110 -0
  73. package/dist/drizzle/0063_threads_session_data.sql +23 -0
  74. package/dist/drizzle/0064_tenant_credentials.sql +65 -0
  75. package/dist/drizzle/0067_thinkwork_computers_phase_one.sql +174 -0
  76. package/dist/drizzle/0068_drop_system_workflows_and_activation.sql +115 -0
  77. package/dist/drizzle/0069_compliance_schema.sql +364 -0
  78. package/dist/drizzle/0070_compliance_aurora_roles.sql +171 -0
  79. package/dist/drizzle/0072_threads_computer_ownership.sql +24 -0
  80. package/dist/drizzle/0073_compliance_tenant_anchor_state.sql +105 -0
  81. package/dist/drizzle/0074_compliance_event_hash_index.sql +49 -0
  82. package/dist/drizzle/0075_scheduled_jobs_computer_ownership.sql +27 -0
  83. package/dist/drizzle/0076_scheduled_jobs_marco_backfill.sql +69 -0
  84. package/dist/drizzle/0077_computers_primary_agent_id.sql +38 -0
  85. package/dist/drizzle/0078_tenant_customize_catalog.sql +46 -0
  86. package/dist/drizzle/0079_seed_tenant_customize_catalog.sql +53 -0
  87. package/dist/drizzle/0081_routines_catalog_slug.sql +42 -0
  88. package/dist/drizzle/0082_messages_parts_jsonb.sql +52 -0
  89. package/dist/drizzle/0083_computer_runbooks.sql +103 -0
  90. package/dist/drizzle/0084_artifacts_favorited_at.sql +32 -0
  91. package/dist/drizzle/0085_seed_thinkwork_computer_default_template.sql +46 -0
  92. package/dist/drizzle/0086_update_default_template_models.sql +19 -0
  93. package/dist/drizzle/0087_retire_oss_connectors.sql +77 -0
  94. package/dist/drizzle/0088_compliance_event_types_finance_pilot.sql +37 -0
  95. package/dist/drizzle/0089_remove_maniflow_eval_seeds.sql +81 -0
  96. package/dist/drizzle/0089_wiki_schema_extraction.sql +315 -0
  97. package/dist/drizzle/0090_brain_schema_extraction.sql +274 -0
  98. package/dist/drizzle/0091_drop_wiki_brain_compat_views.sql +118 -0
  99. package/dist/drizzle/0092_finish_oss_connector_retirement.sql +97 -0
  100. package/dist/drizzle/0093_eval_runs_scheduled_job_id.sql +23 -0
  101. package/dist/drizzle/0094_slack_workspace_app.sql +140 -0
  102. package/dist/drizzle/0095_eval_runs_computer_id.sql +22 -0
  103. package/dist/drizzle/0096_true_redteam_eval_seed_cleanup.sql +67 -0
  104. package/dist/drizzle/0097_shared_computers.sql +191 -0
  105. package/dist/drizzle/0098_business_ontology.sql +587 -0
  106. package/dist/drizzle/0099_thread_idle_learning.sql +145 -0
  107. package/dist/drizzle/0100_ontology_gated_brain_dynamic_subtypes.sql +7 -0
  108. package/dist/drizzle/0101_ontology_gated_unresolved_mentions_dynamic_subtypes.sql +7 -0
  109. package/dist/drizzle/0102_wiki_brain_owner_repair.sql +87 -0
  110. package/dist/drizzle/0103_brain_section_source_trigger_repair.sql +75 -0
  111. package/dist/drizzle/0104_expand_seed_ontology_for_user_memory.sql +166 -0
  112. package/dist/drizzle/0105_spaces_domain.sql +349 -0
  113. package/dist/drizzle/0106_expand_seed_ontology_for_triples.sql +173 -0
  114. package/dist/drizzle/0106_space_threads_participants.sql +197 -0
  115. package/dist/drizzle/0107_linked_task_mirror.sql +245 -0
  116. package/dist/drizzle/0108_message_mentions.sql +95 -0
  117. package/dist/drizzle/0109_space_owned_threads.sql +217 -0
  118. package/dist/drizzle/0110_thread_participant_read_state.sql +21 -0
  119. package/dist/drizzle/0111_agents_tenant_name_unique.sql +38 -0
  120. package/dist/drizzle/0112_recast_spaces_as_contextual_workrooms.sql +138 -0
  121. package/dist/drizzle/0113_agents_own_runtime_fields.sql +48 -0
  122. package/dist/drizzle/0114_migrate_templates_to_agents_and_spaces.sql +361 -0
  123. package/dist/drizzle/0115_remove_computer_eval_template_dependencies.sql +69 -0
  124. package/dist/drizzle/0116_backfill_thread_participants_access.sql +126 -0
  125. package/dist/drizzle/0117_space_access_mode.sql +40 -0
  126. package/dist/drizzle/0118_normalize_tenant_member_principal_type.sql +41 -0
  127. package/dist/drizzle/0119_space_knowledge_bases.sql +126 -0
  128. package/dist/drizzle/0120_space_automations.sql +58 -0
  129. package/dist/drizzle/0121_drop_computer_runbooks.sql +26 -0
  130. package/dist/drizzle/0122_space_email_triggers.sql +24 -0
  131. package/dist/drizzle/0123_single_platform_agent_and_overrides.sql +58 -0
  132. package/dist/drizzle/0124_thread_turns_finalized_at.sql +17 -0
  133. package/dist/drizzle/0125_drop_space_agent_assignments.sql +42 -0
  134. package/dist/drizzle/0126_migrate_flue_to_pi.sql +42 -0
  135. package/dist/drizzle/0127_runtime_type_observability.sql +28 -0
  136. package/dist/drizzle/0128_drop_eval_test_cases_agent_id.sql +37 -0
  137. package/dist/drizzle/0129_drop_code_factory_tables.sql +43 -0
  138. package/dist/drizzle/0129_eval_results_system_prompt.sql +30 -0
  139. package/dist/drizzle/0130_drop_teams_and_team_id_columns.sql +54 -0
  140. package/dist/drizzle/0131_drop_skill_catalog_and_tenant_skills.sql +33 -0
  141. package/dist/drizzle/0132_drop_computer_tables.sql +31 -0
  142. package/dist/drizzle/0133_drop_seed_view_tombstones.sql +79 -0
  143. package/dist/drizzle/0133_thread_turns_system_prompt.sql +22 -0
  144. package/dist/drizzle/0134_drop_dead_agent_runtime_tables.sql +53 -0
  145. package/dist/drizzle/0135_native_checklist_linked_tasks.sql +48 -0
  146. package/dist/drizzle/0136_goal_ledger.sql +55 -0
  147. package/dist/drizzle/0136_space_email_trigger_status.sql +66 -0
  148. package/dist/drizzle/0137_thread_participant_pins.sql +25 -0
  149. package/dist/drizzle/0138_users_cognito_sub.sql +30 -0
  150. package/dist/drizzle/0139_mobile_turn_client_id.sql +23 -0
  151. package/dist/drizzle/0140_workspace_folder_names.sql +36 -0
  152. package/dist/drizzle/0141_eval_runs_desktop_pi_provenance.sql +31 -0
  153. package/dist/drizzle/0142_pi_only_agent_runtime.sql +61 -0
  154. package/dist/drizzle/0143_add_web_extract_builtin_config.sql +28 -0
  155. package/dist/drizzle/0144_skill_catalog_index.sql +40 -0
  156. package/dist/drizzle/0145_knowledge_graph_thread_ingest.sql +512 -0
  157. package/dist/drizzle/0146_knowledge_graph_source_scope.sql +413 -0
  158. package/dist/drizzle/0147_knowledge_graph_scope_trigger_qualification.sql +211 -0
  159. package/dist/drizzle/0148_user_cost_attribution.sql +171 -0
  160. package/dist/drizzle/0149_managed_mcp_servers.sql +64 -0
  161. package/dist/drizzle/0149_user_model_approvals.sql +89 -0
  162. package/dist/drizzle/0150_bootstrap_first_admin_claim.sql +11 -0
  163. package/dist/drizzle/0151_managed_deployments.sql +91 -0
  164. package/dist/drizzle/0152_agent_profiles.sql +81 -0
  165. package/dist/drizzle/0153_message_mentions_agent_profile.sql +9 -0
  166. package/dist/drizzle/0154_customer_deployment_sessions.sql +61 -0
  167. package/dist/drizzle/0155_tenant_model_catalog.sql +152 -0
  168. package/dist/drizzle/0156_bootstrap_credential_leases.sql +52 -0
  169. package/dist/drizzle/0157_knowledge_graph_observations_source.sql +79 -0
  170. package/dist/drizzle/0158_pending_user_questions.sql +80 -0
  171. package/dist/drizzle/0158_wiki_tenant_scope.sql +38 -0
  172. package/dist/drizzle/0159_agent_profiles_space_local.sql +49 -0
  173. package/dist/drizzle/0159_application_plugins.sql +193 -0
  174. package/dist/drizzle/0159_eval_scoring_version.sql +46 -0
  175. package/dist/drizzle/0160_compliance_event_types_plugins.sql +37 -0
  176. package/dist/drizzle/0160_eval_datasets.sql +75 -0
  177. package/dist/drizzle/0160_eval_results_thread_turn.sql +35 -0
  178. package/dist/drizzle/0161_eval_run_pinning.sql +54 -0
  179. package/dist/drizzle/0161_tenant_mcp_servers_plugin_source.sql +62 -0
  180. package/dist/drizzle/0162_eval_result_override.sql +49 -0
  181. package/dist/drizzle/0163_eval_replay_tool_allowlist.sql +50 -0
  182. package/dist/drizzle/0164_eval_replay_tool_override_mode.sql +52 -0
  183. package/dist/drizzle/0165_plugin_premium_entitlements.sql +153 -0
  184. package/dist/drizzle/0166_company_brain_substrate_contract.sql +386 -0
  185. package/dist/drizzle/0167_company_brain_artifact_manifest_runtime.sql +85 -0
  186. package/dist/drizzle/0168_eval_skill_gate.sql +44 -0
  187. package/dist/drizzle/0169_release_update_jobs.sql +67 -0
  188. package/dist/drizzle/0170_email_channel_plugin.sql +291 -0
  189. package/dist/drizzle/0171_linked_task_external_providers.sql +30 -0
  190. package/dist/drizzle/0172_email_channel_sendgrid_provider.sql +8 -0
  191. package/dist/drizzle/0173_auth_provider_resources.sql +83 -0
  192. package/dist/drizzle/0174_workos_auth_bridges.sql +37 -0
  193. package/dist/drizzle/0175_workos_auth_sessions.sql +38 -0
  194. package/dist/drizzle/0176_n8n_agent_step_runs.sql +107 -0
  195. package/dist/drizzle/0177_workflow_control_plane.sql +281 -0
  196. package/dist/drizzle/0178_workflow_backfill_existing_routines.sql +525 -0
  197. package/dist/drizzle/0179_tenant_goal_budget_settings.sql +21 -0
  198. package/dist/drizzle/0180_skill_drafts.sql +89 -0
  199. package/dist/drizzle/0181_skill_draft_publish_status.sql +21 -0
  200. package/dist/drizzle/0182_agent_loops.sql +260 -0
  201. package/dist/drizzle/0183_okf_artifact_manifests.sql +52 -0
  202. package/dist/drizzle/0184_skill_catalog_trust_cache.sql +35 -0
  203. package/dist/drizzle/0185_agent_loop_space.sql +16 -0
  204. package/dist/drizzle/0186_tenant_mcp_runtime_metadata.sql +10 -0
  205. package/dist/drizzle/0187_native_work_items.sql +220 -0
  206. package/dist/drizzle/0188_company_etl_plugin_rename.sql +99 -0
  207. package/dist/drizzle/0189_trace_cost_substrate.sql +247 -0
  208. package/dist/drizzle/0190_billing_export_reconciliation.sql +101 -0
  209. package/dist/drizzle/0191_open_engine_work_item_queue.sql +66 -0
  210. package/dist/drizzle/0192_work_item_labels.sql +44 -0
  211. package/dist/drizzle/0193_work_item_documents.sql +31 -0
  212. package/dist/drizzle/0194_memory_retain_attempts.sql +103 -0
  213. package/dist/drizzle/0194_work_item_comments.sql +35 -0
  214. package/dist/drizzle/0195_plugin_app_overlays.sql +45 -0
  215. package/dist/drizzle/0196_pi_extensions.sql +118 -0
  216. package/dist/drizzle/0197_eval_profiles.sql +150 -0
  217. package/dist/drizzle/0198_eval_runs_unstable.sql +27 -0
  218. package/dist/drizzle/0199_eval_runs_cost_partial.sql +27 -0
  219. package/dist/drizzle/meta/_journal.json +160 -0
  220. package/dist/plugins/README.md +162 -0
  221. package/dist/plugins/catalog/package.json +40 -0
  222. package/dist/plugins/catalog/scripts/build-catalog.ts +120 -0
  223. package/dist/plugins/catalog/scripts/generate-plugin-registry.ts +144 -0
  224. package/dist/plugins/catalog/src/__tests__/build-catalog.test.ts +86 -0
  225. package/dist/plugins/catalog/src/__tests__/catalog.test.ts +308 -0
  226. package/dist/plugins/catalog/src/__tests__/contracts.test.ts +861 -0
  227. package/dist/plugins/catalog/src/__tests__/plugin-package.test.ts +124 -0
  228. package/dist/plugins/catalog/src/__tests__/plugin-registry.test.ts +120 -0
  229. package/dist/plugins/catalog/src/catalog.ts +434 -0
  230. package/dist/plugins/catalog/src/contracts.ts +1498 -0
  231. package/dist/plugins/catalog/src/index.ts +4 -0
  232. package/dist/plugins/catalog/src/plugin-package.ts +171 -0
  233. package/dist/plugins/catalog/src/registry/generated-first-party.ts +76 -0
  234. package/dist/plugins/catalog/src/registry/index.ts +1 -0
  235. package/dist/plugins/catalog/tsconfig.json +8 -0
  236. package/dist/plugins/company-brain/README.md +37 -0
  237. package/dist/plugins/company-brain/package.json +33 -0
  238. package/dist/plugins/company-brain/runtime/cognee/Dockerfile +11 -0
  239. package/dist/plugins/company-brain/smoke/cognee-managed-app-smoke.mjs +458 -0
  240. package/dist/plugins/company-brain/smoke/cognee-memory-cutover-smoke.mjs +539 -0
  241. package/dist/plugins/company-brain/smoke/company-brain-context-engine-smoke.mjs +312 -0
  242. package/dist/plugins/company-brain/smoke/company-brain-operations-smoke.mjs +449 -0
  243. package/dist/plugins/company-brain/smoke/company-brain-plugin-smoke.mjs +655 -0
  244. package/dist/plugins/company-brain/smoke/hindsight-memory-isolation-smoke.mjs +474 -0
  245. package/dist/plugins/company-brain/src/api/cognee-client.ts +896 -0
  246. package/dist/plugins/company-brain/src/api/cognee-cluster-identity.ts +49 -0
  247. package/dist/plugins/company-brain/src/api/cognee-memory-scope.ts +84 -0
  248. package/dist/plugins/company-brain/src/api/context-engine-provider.ts +888 -0
  249. package/dist/plugins/company-brain/src/api/migration.ts +665 -0
  250. package/dist/plugins/company-brain/src/deployment/cognee-managed-app.ts +396 -0
  251. package/dist/plugins/company-brain/src/index.ts +62 -0
  252. package/dist/plugins/company-brain/src/manifest.ts +112 -0
  253. package/dist/plugins/company-brain/terraform/cognee/README.md +263 -0
  254. package/dist/plugins/company-brain/terraform/cognee/main.tf +766 -0
  255. package/dist/plugins/company-brain/terraform/cognee/outputs.tf +144 -0
  256. package/dist/plugins/company-brain/terraform/cognee/variables.tf +402 -0
  257. package/dist/plugins/company-brain/test/api/cognee-client.test.ts +562 -0
  258. package/dist/plugins/company-brain/test/api/cognee-memory-scope.test.ts +74 -0
  259. package/dist/plugins/company-brain/test/api/context-engine-provider.test.ts +447 -0
  260. package/dist/plugins/company-brain/test/api/migration.test.ts +465 -0
  261. package/dist/plugins/company-brain/test/manifest.test.ts +95 -0
  262. package/dist/plugins/company-brain/tsconfig.json +8 -0
  263. package/dist/plugins/company-data/README.md +49 -0
  264. package/dist/plugins/company-data/package.json +21 -0
  265. package/dist/plugins/company-data/src/index.ts +30 -0
  266. package/dist/plugins/company-data/src/manifest.ts +26 -0
  267. package/dist/plugins/company-data/test/manifest.test.ts +116 -0
  268. package/dist/plugins/company-data/tsconfig.json +8 -0
  269. package/dist/plugins/company-etl/README.md +46 -0
  270. package/dist/plugins/company-etl/package.json +21 -0
  271. package/dist/plugins/company-etl/src/index.ts +29 -0
  272. package/dist/plugins/company-etl/src/manifest.ts +26 -0
  273. package/dist/plugins/company-etl/test/manifest.test.ts +108 -0
  274. package/dist/plugins/company-etl/tsconfig.json +8 -0
  275. package/dist/plugins/email-channel/README.md +41 -0
  276. package/dist/plugins/email-channel/package.json +22 -0
  277. package/dist/plugins/email-channel/src/index.ts +36 -0
  278. package/dist/plugins/email-channel/src/manifest.ts +44 -0
  279. package/dist/plugins/email-channel/src/provider-contract.ts +36 -0
  280. package/dist/plugins/email-channel/test/manifest.test.ts +119 -0
  281. package/dist/plugins/email-channel/tsconfig.json +8 -0
  282. package/dist/plugins/lastmile/README.md +50 -0
  283. package/dist/plugins/lastmile/package.json +23 -0
  284. package/dist/plugins/lastmile/smoke/lastmile-plugin-smoke.mjs +661 -0
  285. package/dist/plugins/lastmile/src/api/tasks-adapter.ts +572 -0
  286. package/dist/plugins/lastmile/src/discovery.fixture.ts +64 -0
  287. package/dist/plugins/lastmile/src/index.ts +46 -0
  288. package/dist/plugins/lastmile/src/manifest.ts +139 -0
  289. package/dist/plugins/lastmile/test/api/tasks-adapter.test.ts +266 -0
  290. package/dist/plugins/lastmile/test/discovery.test.ts +88 -0
  291. package/dist/plugins/lastmile/tsconfig.json +8 -0
  292. package/dist/plugins/n8n/README.md +201 -0
  293. package/dist/plugins/n8n/n8n-app/README.md +33 -0
  294. package/dist/plugins/n8n/n8n-app/package.json +23 -0
  295. package/dist/plugins/n8n/n8n-app/src/application-config.ts +45 -0
  296. package/dist/plugins/n8n/n8n-app/src/front-components/thinkwork-workflows.front-component.tsx +970 -0
  297. package/dist/plugins/n8n/n8n-app/src/lib/n8n-app-data.ts +190 -0
  298. package/dist/plugins/n8n/n8n-app/src/vite-env.d.ts +7 -0
  299. package/dist/plugins/n8n/n8n-app/tsconfig.json +15 -0
  300. package/dist/plugins/n8n/package.json +35 -0
  301. package/dist/plugins/n8n/runtime/Dockerfile +18 -0
  302. package/dist/plugins/n8n/runtime/n8n-task-runners.json +14 -0
  303. package/dist/plugins/n8n/runtime/n8n-task-runners.json.template +14 -0
  304. package/dist/plugins/n8n/runtime/package-lock.json +13 -0
  305. package/dist/plugins/n8n/runtime/package.json +7 -0
  306. package/dist/plugins/n8n/scripts/sync-thinkwork-app.mjs +268 -0
  307. package/dist/plugins/n8n/smoke/README.md +95 -0
  308. package/dist/plugins/n8n/smoke/n8n-agent-step-bridge-smoke.mjs +866 -0
  309. package/dist/plugins/n8n/smoke/n8n-integrated-app-smoke.mjs +262 -0
  310. package/dist/plugins/n8n/smoke/n8n-managed-app-smoke.mjs +409 -0
  311. package/dist/plugins/n8n/smoke/n8n-mcp-smoke.mjs +624 -0
  312. package/dist/plugins/n8n/src/deployment/image-build.ts +172 -0
  313. package/dist/plugins/n8n/src/deployment/managed-app.ts +429 -0
  314. package/dist/plugins/n8n/src/index.ts +79 -0
  315. package/dist/plugins/n8n/src/manifest.ts +403 -0
  316. package/dist/plugins/n8n/src/package-config.ts +186 -0
  317. package/dist/plugins/n8n/src/skills/n8n-workflow-operator/SKILL.md +76 -0
  318. package/dist/plugins/n8n/src/skills/n8n-workflow-operator/references/mcp-tooling.md +40 -0
  319. package/dist/plugins/n8n/src/skills/n8n-workflow-operator/references/validation-and-handoff.md +40 -0
  320. package/dist/plugins/n8n/src/skills/n8n-workflow-operator/references/workflow-authoring.md +45 -0
  321. package/dist/plugins/n8n/terraform/n8n/README.md +113 -0
  322. package/dist/plugins/n8n/terraform/n8n/main.tf +918 -0
  323. package/dist/plugins/n8n/terraform/n8n/outputs.tf +124 -0
  324. package/dist/plugins/n8n/terraform/n8n/scripts/sync-database.py +250 -0
  325. package/dist/plugins/n8n/terraform/n8n/scripts/test_sync_database.py +55 -0
  326. package/dist/plugins/n8n/terraform/n8n/variables.tf +354 -0
  327. package/dist/plugins/n8n/test/image-build.test.ts +118 -0
  328. package/dist/plugins/n8n/test/integrated-app-contract.test.ts +353 -0
  329. package/dist/plugins/n8n/test/manifest.test.ts +278 -0
  330. package/dist/plugins/n8n/test/package-config.test.ts +57 -0
  331. package/dist/plugins/n8n/tsconfig.json +8 -0
  332. package/dist/plugins/sendgrid/README.md +30 -0
  333. package/dist/plugins/sendgrid/package.json +22 -0
  334. package/dist/plugins/sendgrid/src/index.ts +36 -0
  335. package/dist/plugins/sendgrid/src/manifest.ts +37 -0
  336. package/dist/plugins/sendgrid/src/provider-contract.ts +14 -0
  337. package/dist/plugins/sendgrid/test/manifest.test.ts +80 -0
  338. package/dist/plugins/sendgrid/tsconfig.json +8 -0
  339. package/dist/plugins/twenty/README.md +78 -0
  340. package/dist/plugins/twenty/package.json +27 -0
  341. package/dist/plugins/twenty/scripts/__tests__/sync-thinkwork-app.test.mjs +67 -0
  342. package/dist/plugins/twenty/scripts/sync-thinkwork-app.mjs +185 -0
  343. package/dist/plugins/twenty/scripts/wire-thinkwork-workflow.mjs +658 -0
  344. package/dist/plugins/twenty/smoke/twenty-managed-app-smoke.mjs +359 -0
  345. package/dist/plugins/twenty/smoke/twenty-mcp-oauth-smoke.mjs +574 -0
  346. package/dist/plugins/twenty/src/api/cutover.ts +209 -0
  347. package/dist/plugins/twenty/src/deployment/managed-app.ts +253 -0
  348. package/dist/plugins/twenty/src/index.ts +55 -0
  349. package/dist/plugins/twenty/src/manifest.ts +259 -0
  350. package/dist/plugins/twenty/terraform/twenty/README.md +97 -0
  351. package/dist/plugins/twenty/terraform/twenty/main.tf +829 -0
  352. package/dist/plugins/twenty/terraform/twenty/outputs.tf +79 -0
  353. package/dist/plugins/twenty/terraform/twenty/variables.tf +268 -0
  354. package/dist/plugins/twenty/test/api/cutover.test.ts +183 -0
  355. package/dist/plugins/twenty/test/manifest.test.ts +463 -0
  356. package/dist/plugins/twenty/tsconfig.json +9 -0
  357. package/dist/plugins/twenty/twenty-app/.nvmrc +1 -0
  358. package/dist/plugins/twenty/twenty-app/README.md +148 -0
  359. package/dist/plugins/twenty/twenty-app/package.json +30 -0
  360. package/dist/plugins/twenty/twenty-app/src/application-config.ts +44 -0
  361. package/dist/plugins/twenty/twenty-app/src/constants/universal-identifiers.ts +18 -0
  362. package/dist/plugins/twenty/twenty-app/src/default-role.ts +24 -0
  363. package/dist/plugins/twenty/twenty-app/src/front-components/thinkwork-settings.front-component.tsx +299 -0
  364. package/dist/plugins/twenty/twenty-app/src/logic-functions/thinkwork-webhook.logic-function.ts +354 -0
  365. package/dist/plugins/twenty/twenty-app/tsconfig.json +14 -0
  366. package/dist/plugins/twenty/twenty-app/yarn.lock +4144 -0
  367. package/dist/plugins/workos-auth/package.json +22 -0
  368. package/dist/plugins/workos-auth/src/index.ts +30 -0
  369. package/dist/plugins/workos-auth/src/manifest.ts +40 -0
  370. package/dist/plugins/workos-auth/src/provider-contract.ts +39 -0
  371. package/dist/plugins/workos-auth/test/manifest.test.ts +94 -0
  372. package/dist/plugins/workos-auth/tsconfig.json +8 -0
  373. package/dist/scripts/bootstrap-workspace.sh +162 -0
  374. package/dist/scripts/post-deploy.sh +290 -0
  375. package/dist/terraform/examples/greenfield/main.tf +903 -75
  376. package/dist/terraform/examples/greenfield/terraform.tfvars.example +67 -8
  377. package/dist/terraform/modules/app/agentcore-code-interpreter/Dockerfile.sandbox-base +2 -2
  378. package/dist/terraform/modules/app/agentcore-code-interpreter/README.md +8 -9
  379. package/dist/terraform/modules/app/agentcore-code-interpreter/sandbox/sitecustomize.py +227 -0
  380. package/dist/terraform/modules/app/agentcore-code-interpreter/sandbox/test_sitecustomize.py +277 -0
  381. package/dist/terraform/modules/app/agentcore-memory/README.md +6 -6
  382. package/dist/terraform/modules/app/agentcore-memory/main.tf +1 -1
  383. package/dist/terraform/modules/app/agentcore-memory/scripts/create_or_find_memory.sh +40 -9
  384. package/dist/terraform/modules/app/agentcore-pi/README.md +61 -0
  385. package/dist/terraform/modules/app/agentcore-pi/main.tf +453 -0
  386. package/dist/terraform/modules/app/agentcore-pi/outputs.tf +38 -0
  387. package/dist/terraform/modules/app/agentcore-pi/variables.tf +145 -0
  388. package/dist/terraform/modules/app/agentcore-platform/main.tf +83 -0
  389. package/dist/terraform/modules/app/agentcore-runtime/main.tf +9 -11
  390. package/dist/terraform/modules/app/appsync-subscriptions/main.tf +5 -1
  391. package/dist/terraform/modules/app/customer-domain/main.tf +483 -0
  392. package/dist/terraform/modules/app/deployment-control-plane/README.md +47 -0
  393. package/dist/terraform/modules/app/deployment-control-plane/buildspec.yml +24 -0
  394. package/dist/terraform/modules/app/deployment-control-plane/main.tf +614 -0
  395. package/dist/terraform/modules/app/deployment-control-plane/outputs.tf +54 -0
  396. package/dist/terraform/modules/app/deployment-control-plane/runner.py +4720 -0
  397. package/dist/terraform/modules/app/deployment-control-plane/test_runner_bundle.py +3026 -0
  398. package/dist/terraform/modules/app/deployment-control-plane/variables.tf +96 -0
  399. package/dist/terraform/modules/app/hindsight-memory/README.md +25 -23
  400. package/dist/terraform/modules/app/hindsight-memory/main.tf +26 -2
  401. package/dist/terraform/modules/app/lambda-api/eval-fanout.tf +17 -50
  402. package/dist/terraform/modules/app/lambda-api/handlers.tf +1290 -679
  403. package/dist/terraform/modules/app/lambda-api/iam-grouped.tf +933 -0
  404. package/dist/terraform/modules/app/lambda-api/main.tf +14 -527
  405. package/dist/terraform/modules/app/lambda-api/mcp-oauth.tf +3 -19
  406. package/dist/terraform/modules/app/lambda-api/outputs.tf +50 -6
  407. package/dist/terraform/modules/app/lambda-api/runtime-config.tf +163 -0
  408. package/dist/terraform/modules/app/lambda-api/slack-app-secrets.tf +3 -1
  409. package/dist/terraform/modules/app/lambda-api/stripe-secrets.tf +3 -1
  410. package/dist/terraform/modules/app/lambda-api/variables.tf +240 -53
  411. package/dist/terraform/modules/app/lambda-api/workspace-events.tf +2 -25
  412. package/dist/terraform/modules/app/ses-email/main.tf +143 -30
  413. package/dist/terraform/modules/app/static-site/main.tf +4 -3
  414. package/dist/terraform/modules/app/www-dns/main.tf +45 -5
  415. package/dist/terraform/modules/app/www-dns/outputs.tf +10 -0
  416. package/dist/terraform/modules/app/www-dns/variables.tf +24 -0
  417. package/dist/terraform/modules/data/aurora-postgres/main.tf +15 -1
  418. package/dist/terraform/modules/data/compliance-exports-bucket/main.tf +1 -1
  419. package/dist/terraform/modules/data/compliance-exports-bucket/variables.tf +6 -0
  420. package/dist/terraform/modules/foundation/cognito/main.tf +167 -11
  421. package/dist/terraform/modules/foundation/cognito/outputs.tf +5 -0
  422. package/dist/terraform/modules/foundation/cognito/variables.tf +110 -0
  423. package/dist/terraform/modules/foundation/vpc/main.tf +45 -3
  424. package/dist/terraform/modules/foundation/vpc/outputs.tf +20 -0
  425. package/dist/terraform/modules/foundation/vpc/variables.tf +18 -0
  426. package/dist/terraform/modules/thinkwork/README.md +71 -0
  427. package/dist/terraform/modules/thinkwork/main.tf +1325 -174
  428. package/dist/terraform/modules/thinkwork/outputs.tf +457 -24
  429. package/dist/terraform/modules/thinkwork/variables.tf +1169 -93
  430. package/dist/terraform/schema.graphql +82 -9
  431. package/dist/workspace-defaults/files/AGENTS.md +344 -0
  432. package/dist/workspace-defaults/files/CONTEXT.md +8 -0
  433. package/dist/workspace-defaults/files/GUARDRAILS.md +51 -0
  434. package/dist/workspace-defaults/files/MEMORY_GUIDE.md +65 -0
  435. package/dist/workspace-defaults/files/ROUTER.md +24 -0
  436. package/dist/workspace-defaults/files/SPACE.md +62 -0
  437. package/dist/workspace-defaults/files/TOOLS.md +65 -0
  438. package/dist/workspace-defaults/files/USER.md +40 -0
  439. package/dist/workspace-defaults/files/mcp.json +3 -0
  440. package/dist/workspace-defaults/files/memory/contacts.md +13 -0
  441. package/dist/workspace-defaults/files/memory/lessons.md +13 -0
  442. package/dist/workspace-defaults/files/memory/preferences.md +12 -0
  443. package/dist/workspace-defaults/files/skills/.gitkeep +1 -0
  444. package/dist/workspace-defaults/files/skills/artifact-builder/SKILL.md +79 -0
  445. package/dist/workspace-defaults/files/skills/artifact-builder/references/crm-dashboard.md +166 -0
  446. package/dist/workspace-defaults/files/skills/automation-loop-designer/SKILL.md +120 -0
  447. package/dist/workspace-defaults/files/skills/skill-creator/LICENSE.txt +202 -0
  448. package/dist/workspace-defaults/files/skills/skill-creator/SKILL.md +485 -0
  449. package/dist/workspace-defaults/files/skills/skill-creator/UPSTREAM.json +124 -0
  450. package/dist/workspace-defaults/files/skills/skill-creator/agents/analyzer.md +274 -0
  451. package/dist/workspace-defaults/files/skills/skill-creator/agents/comparator.md +202 -0
  452. package/dist/workspace-defaults/files/skills/skill-creator/agents/grader.md +223 -0
  453. package/dist/workspace-defaults/files/skills/skill-creator/assets/eval_review.html +146 -0
  454. package/dist/workspace-defaults/files/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  455. package/dist/workspace-defaults/files/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  456. package/dist/workspace-defaults/files/skills/skill-creator/references/schemas.md +430 -0
  457. package/dist/workspace-defaults/files/skills/skill-creator/scripts/__init__.py +0 -0
  458. package/dist/workspace-defaults/files/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  459. package/dist/workspace-defaults/files/skills/skill-creator/scripts/generate_report.py +326 -0
  460. package/dist/workspace-defaults/files/skills/skill-creator/scripts/improve_description.py +247 -0
  461. package/dist/workspace-defaults/files/skills/skill-creator/scripts/package_skill.py +136 -0
  462. package/dist/workspace-defaults/files/skills/skill-creator/scripts/quick_validate.py +103 -0
  463. package/dist/workspace-defaults/files/skills/skill-creator/scripts/run_eval.py +310 -0
  464. package/dist/workspace-defaults/files/skills/skill-creator/scripts/run_loop.py +328 -0
  465. package/dist/workspace-defaults/files/skills/skill-creator/scripts/utils.py +47 -0
  466. package/package.json +1 -1
  467. package/dist/terraform/modules/app/agentcore-flue/README.md +0 -58
  468. package/dist/terraform/modules/app/agentcore-flue/main.tf +0 -323
  469. package/dist/terraform/modules/app/agentcore-flue/outputs.tf +0 -23
  470. package/dist/terraform/modules/app/agentcore-flue/variables.tf +0 -97
  471. package/dist/terraform/modules/app/computer-runtime/README.md +0 -15
  472. package/dist/terraform/modules/app/computer-runtime/main.tf +0 -406
  473. package/dist/terraform/modules/app/computer-runtime/outputs.tf +0 -75
  474. package/dist/terraform/modules/app/computer-runtime/variables.tf +0 -66
@@ -0,0 +1,574 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Smoke test the Twenty CRM managed MCP + per-user OAuth path.
4
+ *
5
+ * Dry-run is the default. Set SMOKE_ENABLE_TWENTY_MCP_OAUTH=1 after Twenty is
6
+ * running and the user has connected Twenty from Settings -> MCP Servers.
7
+ *
8
+ * Live mode is read-oriented unless SMOKE_TWENTY_MCP_CALL=1 is also set. The
9
+ * call step uses the ThinkWork MCP proxy with the caller's Cognito token, so it
10
+ * exercises the same per-user vault token selection and runtime injection path
11
+ * as the desktop agent experience.
12
+ *
13
+ * Optional live env:
14
+ * SMOKE_API_BASE_URL=https://api.example.com
15
+ * VITE_API_URL=https://api.example.com
16
+ * SMOKE_COGNITO_ID_TOKEN=<current user's Cognito id token>
17
+ * SMOKE_TENANT_ID=<tenant uuid>
18
+ * SMOKE_USER_ID=<ThinkWork users.id for the authenticated user>
19
+ * SMOKE_AGENT_ID=<agent id assigned to the Twenty MCP server>
20
+ * SMOKE_TWENTY_URL=https://crm.thinkwork.ai
21
+ * SMOKE_TWENTY_MCP_CALL=1
22
+ * SMOKE_TWENTY_USER_EMAIL=user@example.com
23
+ * SMOKE_TWENTY_WORKSPACE_MEMBER_ID=<Twenty workspace member uuid>
24
+ * SMOKE_TWENTY_OPPORTUNITIES_TOOL=execute_tool
25
+ * SMOKE_TWENTY_OPPORTUNITIES_ARGS='{"assignedTo":"me"}'
26
+ * SMOKE_TWENTY_EXPECTED_OPPORTUNITY_ID=<optional expected opportunity uuid>
27
+ * SMOKE_TWENTY_VERIFY_RECORD_URL=1
28
+ * SMOKE_TWENTY_WEB_COOKIE='twenty_session=...'
29
+ */
30
+
31
+ import fs from "node:fs";
32
+ import path from "node:path";
33
+ import process from "node:process";
34
+
35
+ const LIVE_ENABLED = process.env.SMOKE_ENABLE_TWENTY_MCP_OAUTH === "1";
36
+ const CALL_ENABLED = process.env.SMOKE_TWENTY_MCP_CALL === "1";
37
+ const TIMEOUT_MS = Number(process.env.SMOKE_TIMEOUT_MS || 15_000);
38
+
39
+ const env = {
40
+ ...loadEnvFile(),
41
+ ...process.env,
42
+ };
43
+
44
+ const apiBaseUrl = first(
45
+ env.SMOKE_API_BASE_URL,
46
+ env.VITE_API_URL,
47
+ env.API_BASE_URL,
48
+ );
49
+ const idToken = first(
50
+ env.SMOKE_COGNITO_ID_TOKEN,
51
+ env.COGNITO_ID_TOKEN,
52
+ env.THINKWORK_ID_TOKEN,
53
+ );
54
+ const tenantId = first(env.SMOKE_TENANT_ID, env.TENANT_ID);
55
+ const userId = first(env.SMOKE_USER_ID, env.USER_ID);
56
+ const agentId = first(env.SMOKE_AGENT_ID, env.AGENT_ID);
57
+ const twentyUrl = first(env.SMOKE_TWENTY_URL, "https://crm.thinkwork.ai");
58
+ const expectedServerName = env.SMOKE_TWENTY_MCP_SERVER_NAME || "twenty--crm";
59
+ const expectedServerTitle = env.SMOKE_TWENTY_MCP_TITLE || "Twenty CRM";
60
+ const opportunityToolOverride = first(env.SMOKE_TWENTY_OPPORTUNITIES_TOOL);
61
+ const twentyUserEmail = first(env.SMOKE_TWENTY_USER_EMAIL, env.USER_EMAIL);
62
+ const twentyWorkspaceMemberId = first(env.SMOKE_TWENTY_WORKSPACE_MEMBER_ID);
63
+ const opportunityArgs = parseJsonEnv(
64
+ "SMOKE_TWENTY_OPPORTUNITIES_ARGS",
65
+ env.SMOKE_TWENTY_OPPORTUNITIES_ARGS,
66
+ null,
67
+ );
68
+ const expectedOpportunityId = first(env.SMOKE_TWENTY_EXPECTED_OPPORTUNITY_ID);
69
+ const verifyRecordUrl = env.SMOKE_TWENTY_VERIFY_RECORD_URL === "1";
70
+ const twentyWebCookie = first(env.SMOKE_TWENTY_WEB_COOKIE);
71
+ const twentyWebAuthorization = first(env.SMOKE_TWENTY_WEB_AUTHORIZATION);
72
+
73
+ if (!LIVE_ENABLED) {
74
+ console.log(
75
+ JSON.stringify(
76
+ {
77
+ ok: true,
78
+ skippedLive: true,
79
+ reason:
80
+ "set SMOKE_ENABLE_TWENTY_MCP_OAUTH=1 to run the deployed Twenty MCP OAuth smoke",
81
+ dryRun: {
82
+ requiredWhenRunning: [
83
+ "SMOKE_API_BASE_URL or VITE_API_URL",
84
+ "SMOKE_COGNITO_ID_TOKEN",
85
+ "SMOKE_TENANT_ID",
86
+ "SMOKE_USER_ID",
87
+ "SMOKE_AGENT_ID",
88
+ "Twenty CRM running at SMOKE_TWENTY_URL or https://crm.thinkwork.ai",
89
+ ],
90
+ optionalAgentProof: [
91
+ "SMOKE_TWENTY_MCP_CALL=1",
92
+ "SMOKE_TWENTY_USER_EMAIL=<Twenty user email> or SMOKE_TWENTY_WORKSPACE_MEMBER_ID=<uuid>",
93
+ "SMOKE_TWENTY_OPPORTUNITIES_TOOL=<Twenty MCP opportunity-list tool or execute_tool>",
94
+ 'SMOKE_TWENTY_OPPORTUNITIES_ARGS=\'{"ownerId":{"eq":"<workspace-member-id>"},"limit":20,"offset":0,"select":["id","name","ownerId"]}\'',
95
+ "SMOKE_TWENTY_EXPECTED_OPPORTUNITY_ID=<optional expected Opportunity uuid>",
96
+ "SMOKE_TWENTY_VERIFY_RECORD_URL=1 plus SMOKE_TWENTY_WEB_COOKIE or SMOKE_TWENTY_WEB_AUTHORIZATION to HTTP-probe the generated record URL",
97
+ ],
98
+ verifies: [
99
+ "Twenty public MCP OAuth protected-resource metadata resolves",
100
+ "Settings -> MCP Servers server-side list contains managed Twenty CRM",
101
+ "Current user's Twenty auth status is active",
102
+ "ThinkWork MCP proxy tools/list exposes Twenty tools for the agent",
103
+ "Optional tools/call fetches assigned opportunities through ThinkWork runtime auth",
104
+ "Optional tools/call proof requires generated Opportunity recordLinks from the MCP proxy",
105
+ ],
106
+ },
107
+ },
108
+ null,
109
+ 2,
110
+ ),
111
+ );
112
+ process.exit(0);
113
+ }
114
+
115
+ try {
116
+ const result = await runLiveSmoke();
117
+ console.log(JSON.stringify({ ok: true, ...result }, null, 2));
118
+ } catch (error) {
119
+ fail(error instanceof Error ? error.message : String(error));
120
+ }
121
+
122
+ async function runLiveSmoke() {
123
+ requireEnv("SMOKE_API_BASE_URL or VITE_API_URL", apiBaseUrl);
124
+ requireEnv("SMOKE_COGNITO_ID_TOKEN", idToken);
125
+ requireEnv("SMOKE_TENANT_ID", tenantId);
126
+ requireEnv("SMOKE_USER_ID", userId);
127
+ requireEnv("SMOKE_AGENT_ID", agentId);
128
+
129
+ const metadata = await readOAuthMetadata(twentyUrl);
130
+ const userServers = await api("/api/skills/user-mcp-servers", {
131
+ method: "GET",
132
+ headers: {
133
+ "x-tenant-id": tenantId,
134
+ "x-principal-id": userId,
135
+ },
136
+ });
137
+ const twentyServer = findTwentyServer(userServers.servers ?? []);
138
+ if (!twentyServer) {
139
+ throw new Error(
140
+ `Managed Twenty MCP server was not visible in /api/skills/user-mcp-servers for user ${userId}.`,
141
+ );
142
+ }
143
+ if (twentyServer.authStatus !== "active") {
144
+ throw new Error(
145
+ `Twenty MCP authStatus must be active before agent proof; got ${twentyServer.authStatus ?? "missing"}.`,
146
+ );
147
+ }
148
+
149
+ const toolsList = await api("/api/mcp/tools/list", {
150
+ method: "POST",
151
+ body: { agentId },
152
+ });
153
+ const twentyTools = (toolsList.tools ?? []).filter(
154
+ (tool) => tool.server === expectedServerName,
155
+ );
156
+ if (twentyTools.length === 0) {
157
+ throw new Error(
158
+ `MCP proxy tools/list did not expose tools for server ${expectedServerName}.`,
159
+ );
160
+ }
161
+
162
+ const opportunityProof = CALL_ENABLED
163
+ ? await runOpportunityProof(twentyTools)
164
+ : {
165
+ skipped: true,
166
+ reason:
167
+ "set SMOKE_TWENTY_MCP_CALL=1 and SMOKE_TWENTY_OPPORTUNITIES_TOOL to run the assigned-opportunities tool call",
168
+ };
169
+
170
+ return {
171
+ metadata,
172
+ twentyServer: summarizeServer(twentyServer),
173
+ twentyTools: twentyTools.map((tool) => ({
174
+ name: tool.name,
175
+ tool: tool.tool,
176
+ description: tool.description ?? null,
177
+ })),
178
+ opportunityProof,
179
+ };
180
+ }
181
+
182
+ async function readOAuthMetadata(baseUrl) {
183
+ const resourceUrl = new URL(
184
+ "/.well-known/oauth-protected-resource/mcp",
185
+ baseUrl,
186
+ ).toString();
187
+ const resource = await fetchJson(resourceUrl);
188
+ const authorizationServer = resource.authorization_servers?.[0];
189
+ if (!authorizationServer) {
190
+ throw new Error(
191
+ `Twenty OAuth protected-resource metadata did not include authorization_servers: ${resourceUrl}`,
192
+ );
193
+ }
194
+ const authMetadata = await fetchJson(
195
+ new URL("/.well-known/oauth-authorization-server", authorizationServer),
196
+ ).catch(() =>
197
+ fetchJson(
198
+ new URL("/.well-known/openid-configuration", authorizationServer),
199
+ ),
200
+ );
201
+ if (!authMetadata.authorization_endpoint || !authMetadata.token_endpoint) {
202
+ throw new Error(
203
+ `Twenty OAuth authorization metadata is missing authorization_endpoint or token_endpoint.`,
204
+ );
205
+ }
206
+ return {
207
+ resourceUrl,
208
+ authorizationServer,
209
+ authorizationEndpoint: authMetadata.authorization_endpoint,
210
+ tokenEndpoint: authMetadata.token_endpoint,
211
+ };
212
+ }
213
+
214
+ async function runOpportunityProof(twentyTools) {
215
+ const executeTool = twentyTools.find((tool) => tool.tool === "execute_tool");
216
+ const selected = opportunityToolOverride
217
+ ? twentyTools.find(
218
+ (tool) =>
219
+ tool.tool === opportunityToolOverride ||
220
+ tool.name === opportunityToolOverride,
221
+ )
222
+ : (executeTool ??
223
+ twentyTools.find((tool) =>
224
+ /opportunit/i.test(
225
+ `${tool.name} ${tool.tool} ${tool.description ?? ""}`,
226
+ ),
227
+ ));
228
+
229
+ if (!selected) {
230
+ throw new Error(
231
+ opportunityToolOverride
232
+ ? `Configured opportunity tool ${opportunityToolOverride} was not found in Twenty tools/list.`
233
+ : "Could not infer an opportunity tool from Twenty tools/list; set SMOKE_TWENTY_OPPORTUNITIES_TOOL.",
234
+ );
235
+ }
236
+
237
+ const toolArguments =
238
+ selected.tool === "execute_tool"
239
+ ? await buildTwentyExecuteOpportunityArgs()
240
+ : (opportunityArgs ?? {});
241
+
242
+ const response = await api("/api/mcp/tools/call", {
243
+ method: "POST",
244
+ body: {
245
+ agentId,
246
+ server: expectedServerName,
247
+ tool: selected.tool,
248
+ arguments: toolArguments,
249
+ },
250
+ });
251
+ if (response.isError) {
252
+ throw new Error(
253
+ `Twenty opportunity tool returned isError=true: ${JSON.stringify(response.content)}`,
254
+ );
255
+ }
256
+ const recordLinks = validateOpportunityRecordLinks(response);
257
+ const urlOpenProof = await verifyRecordLinkUrl(recordLinks[0].url);
258
+ return {
259
+ skipped: false,
260
+ server: expectedServerName,
261
+ tool: selected.tool,
262
+ qualifiedName: selected.name,
263
+ argumentSummary: summarizeToolArguments(toolArguments),
264
+ contentSummary: summarizeContent(response.content),
265
+ recordLinkProof: {
266
+ count: recordLinks.length,
267
+ links: recordLinks,
268
+ urlOpenProof,
269
+ },
270
+ };
271
+ }
272
+
273
+ async function buildTwentyExecuteOpportunityArgs() {
274
+ if (opportunityArgs) {
275
+ return {
276
+ toolName: "find_many_opportunities",
277
+ arguments: opportunityArgs,
278
+ };
279
+ }
280
+
281
+ const workspaceMemberId =
282
+ twentyWorkspaceMemberId ?? (await discoverTwentyWorkspaceMemberId());
283
+ return {
284
+ toolName: "find_many_opportunities",
285
+ arguments: {
286
+ limit: 20,
287
+ offset: 0,
288
+ select: ["id", "name", "stage", "amount", "closeDate", "ownerId"],
289
+ ownerId: { eq: workspaceMemberId },
290
+ },
291
+ };
292
+ }
293
+
294
+ async function discoverTwentyWorkspaceMemberId() {
295
+ requireEnv(
296
+ "SMOKE_TWENTY_USER_EMAIL or SMOKE_TWENTY_WORKSPACE_MEMBER_ID",
297
+ twentyUserEmail,
298
+ );
299
+
300
+ const response = await api("/api/mcp/tools/call", {
301
+ method: "POST",
302
+ body: {
303
+ agentId,
304
+ server: expectedServerName,
305
+ tool: "execute_tool",
306
+ arguments: {
307
+ toolName: "find_many_workspace_members",
308
+ arguments: {
309
+ limit: 100,
310
+ offset: 0,
311
+ select: ["id", "userEmail", "name"],
312
+ },
313
+ },
314
+ },
315
+ });
316
+ if (response.isError) {
317
+ throw new Error(
318
+ `Twenty workspace member lookup returned isError=true: ${JSON.stringify(response.content)}`,
319
+ );
320
+ }
321
+ const payload = parseTwentyToolPayload(response);
322
+ const records = payload?.result?.records;
323
+ if (!Array.isArray(records)) {
324
+ throw new Error("Twenty workspace member lookup did not return records.");
325
+ }
326
+ const targetEmail = String(twentyUserEmail).toLowerCase();
327
+ const member = records.find(
328
+ (record) =>
329
+ typeof record?.userEmail === "string" &&
330
+ record.userEmail.toLowerCase() === targetEmail,
331
+ );
332
+ if (!member?.id) {
333
+ throw new Error(
334
+ `Could not find Twenty workspace member for ${twentyUserEmail}.`,
335
+ );
336
+ }
337
+ return member.id;
338
+ }
339
+
340
+ function parseTwentyToolPayload(response) {
341
+ const text = response.content?.find?.((item) => item.type === "text")?.text;
342
+ if (!text) return null;
343
+ return JSON.parse(text);
344
+ }
345
+
346
+ function validateOpportunityRecordLinks(response) {
347
+ const links = Array.isArray(response.recordLinks) ? response.recordLinks : [];
348
+ if (links.length === 0) {
349
+ throw new Error(
350
+ "Twenty opportunity proof did not return recordLinks. Health checks and tools/list are not sufficient proof; ensure the deployed API/runtime includes MCP record-link hints and the selected tool returns Opportunity records.",
351
+ );
352
+ }
353
+
354
+ const normalizedTwentyOrigin = originOf(twentyUrl);
355
+ const validLinks = links
356
+ .filter((link) => link?.objectType === "opportunity")
357
+ .map((link) => ({
358
+ objectType: link.objectType,
359
+ id: String(link.id ?? ""),
360
+ label: String(link.label ?? ""),
361
+ url: String(link.url ?? ""),
362
+ }))
363
+ .filter((link) => link.id && link.url);
364
+
365
+ if (validLinks.length === 0) {
366
+ throw new Error(
367
+ "Twenty opportunity proof returned recordLinks, but none were Opportunity links with an id and URL.",
368
+ );
369
+ }
370
+
371
+ if (
372
+ expectedOpportunityId &&
373
+ !validLinks.some((link) => link.id === expectedOpportunityId)
374
+ ) {
375
+ throw new Error(
376
+ `Twenty opportunity proof did not include expected Opportunity id ${expectedOpportunityId}.`,
377
+ );
378
+ }
379
+
380
+ const offOrigin = validLinks.find(
381
+ (link) => originOf(link.url) !== normalizedTwentyOrigin,
382
+ );
383
+ if (offOrigin) {
384
+ throw new Error(
385
+ `Generated record link does not use the expected Twenty origin ${normalizedTwentyOrigin}: ${redactUrl(offOrigin.url)}`,
386
+ );
387
+ }
388
+
389
+ return validLinks;
390
+ }
391
+
392
+ async function verifyRecordLinkUrl(url) {
393
+ if (!verifyRecordUrl) {
394
+ return {
395
+ skipped: true,
396
+ reason:
397
+ "set SMOKE_TWENTY_VERIFY_RECORD_URL=1 with SMOKE_TWENTY_WEB_COOKIE or SMOKE_TWENTY_WEB_AUTHORIZATION to HTTP-probe the generated URL; otherwise open the URL as the authorized user and record evidence.",
398
+ };
399
+ }
400
+
401
+ const headers = { accept: "text/html,application/xhtml+xml" };
402
+ if (twentyWebCookie) headers.cookie = twentyWebCookie;
403
+ if (twentyWebAuthorization) headers.authorization = twentyWebAuthorization;
404
+ if (!twentyWebCookie && !twentyWebAuthorization) {
405
+ throw new Error(
406
+ "SMOKE_TWENTY_VERIFY_RECORD_URL=1 requires SMOKE_TWENTY_WEB_COOKIE or SMOKE_TWENTY_WEB_AUTHORIZATION for the authorized Twenty user.",
407
+ );
408
+ }
409
+
410
+ const response = await fetchWithTimeout(url, { headers });
411
+ if (!response.ok) {
412
+ throw new Error(
413
+ `Generated Twenty record URL did not open for the authorized user: HTTP ${response.status} ${redactUrl(url)}`,
414
+ );
415
+ }
416
+ await response.text().catch(() => "");
417
+ return {
418
+ skipped: false,
419
+ status: response.status,
420
+ url: redactUrl(url),
421
+ };
422
+ }
423
+
424
+ function summarizeToolArguments(args) {
425
+ if (args?.toolName) {
426
+ return {
427
+ toolName: args.toolName,
428
+ argumentKeys: Object.keys(args.arguments ?? {}).sort(),
429
+ };
430
+ }
431
+ return { argumentKeys: Object.keys(args ?? {}).sort() };
432
+ }
433
+
434
+ function summarizeContent(content) {
435
+ const blocks = Array.isArray(content) ? content : [];
436
+ const textLength = blocks
437
+ .filter((item) => item?.type === "text" && typeof item.text === "string")
438
+ .reduce((total, item) => total + item.text.length, 0);
439
+ return {
440
+ blockCount: blocks.length,
441
+ textLength,
442
+ };
443
+ }
444
+
445
+ function originOf(value) {
446
+ return new URL(value).origin;
447
+ }
448
+
449
+ function redactUrl(value) {
450
+ const url = new URL(value);
451
+ return `${url.origin}${url.pathname ? "/..." : ""}`;
452
+ }
453
+
454
+ function findTwentyServer(servers) {
455
+ return servers.find(
456
+ (server) =>
457
+ server.managedApplicationKey === "twenty-crm" ||
458
+ server.slug === "twenty--crm" ||
459
+ server.slug === "twenty-crm" ||
460
+ server.name === expectedServerTitle,
461
+ );
462
+ }
463
+
464
+ function summarizeServer(server) {
465
+ return {
466
+ id: server.id,
467
+ name: server.name,
468
+ slug: server.slug,
469
+ url: server.url,
470
+ authType: server.authType,
471
+ authStatus: server.authStatus,
472
+ managementSource: server.managementSource,
473
+ managedApplicationKey: server.managedApplicationKey,
474
+ runtimeAssigned: server.runtimeAssigned,
475
+ runtimeEnabled: server.runtimeEnabled,
476
+ };
477
+ }
478
+
479
+ async function api(pathname, options) {
480
+ const url = new URL(pathname, apiBaseUrl).toString();
481
+ const headers = {
482
+ authorization: `Bearer ${idToken}`,
483
+ "content-type": "application/json",
484
+ ...(options.headers ?? {}),
485
+ };
486
+ const response = await fetchWithTimeout(url, {
487
+ method: options.method,
488
+ headers,
489
+ body: options.body ? JSON.stringify(options.body) : undefined,
490
+ });
491
+ const text = await response.text();
492
+ const body = text ? JSON.parse(text) : {};
493
+ if (!response.ok) {
494
+ throw new Error(`HTTP ${response.status} ${url}: ${text.slice(0, 500)}`);
495
+ }
496
+ return body;
497
+ }
498
+
499
+ async function fetchJson(url) {
500
+ const response = await fetchWithTimeout(url, {
501
+ headers: { accept: "application/json" },
502
+ });
503
+ const text = await response.text();
504
+ if (!response.ok) {
505
+ throw new Error(`HTTP ${response.status} ${url}: ${text.slice(0, 500)}`);
506
+ }
507
+ return text ? JSON.parse(text) : {};
508
+ }
509
+
510
+ async function fetchWithTimeout(url, options = {}) {
511
+ const controller = new AbortController();
512
+ const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
513
+ try {
514
+ return await fetch(url, { ...options, signal: controller.signal });
515
+ } finally {
516
+ clearTimeout(timer);
517
+ }
518
+ }
519
+
520
+ function parseJsonEnv(name, value, fallback) {
521
+ if (!value) return fallback;
522
+ try {
523
+ return JSON.parse(value);
524
+ } catch (error) {
525
+ throw new Error(
526
+ `${name} must be valid JSON: ${error instanceof Error ? error.message : String(error)}`,
527
+ );
528
+ }
529
+ }
530
+
531
+ function requireEnv(label, value) {
532
+ if (!value) {
533
+ throw new Error(`Missing required live smoke env: ${label}`);
534
+ }
535
+ }
536
+
537
+ function loadEnvFile() {
538
+ const explicit = process.env.COMPUTER_ENV_FILE;
539
+ if (explicit === "none") return {};
540
+ const candidates = [explicit, "apps/web/.env", ".env"].filter(Boolean);
541
+
542
+ for (const candidate of candidates) {
543
+ const resolved = path.resolve(candidate);
544
+ if (!fs.existsSync(resolved)) continue;
545
+ return Object.fromEntries(
546
+ fs
547
+ .readFileSync(resolved, "utf8")
548
+ .split(/\r?\n/)
549
+ .map((line) => line.trim())
550
+ .filter((line) => line && !line.startsWith("#") && line.includes("="))
551
+ .map((line) => {
552
+ const index = line.indexOf("=");
553
+ const key = line.slice(0, index).trim();
554
+ const value = line
555
+ .slice(index + 1)
556
+ .trim()
557
+ .replace(/^['"]|['"]$/g, "");
558
+ return [key, value];
559
+ }),
560
+ );
561
+ }
562
+ return {};
563
+ }
564
+
565
+ function first(...values) {
566
+ return values.find(
567
+ (value) => value !== undefined && value !== null && value !== "",
568
+ );
569
+ }
570
+
571
+ function fail(message) {
572
+ console.error(JSON.stringify({ ok: false, error: message }, null, 2));
573
+ process.exit(1);
574
+ }