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,463 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { readFileSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { managedAppRegistry } from "@thinkwork/deployment-runner/apps/registry";
6
+
7
+ import {
8
+ PluginManifestError,
9
+ validatePluginManifest,
10
+ type InfrastructureComponent,
11
+ type McpServerComponent,
12
+ type PluginManifest,
13
+ type UiSurfaceComponent,
14
+ } from "@thinkwork/plugin-catalog/contracts";
15
+ import { defineFirstPartyPluginPackage } from "@thinkwork/plugin-catalog/plugin-package";
16
+
17
+ import { twentyPluginPackage } from "../src";
18
+ import { twentyManifest } from "../src/manifest";
19
+
20
+ const validatedTwentyManifest = validatePluginManifest(twentyManifest);
21
+ const testDir = dirname(fileURLToPath(import.meta.url));
22
+
23
+ function clone<T>(value: T): T {
24
+ return JSON.parse(JSON.stringify(value)) as T;
25
+ }
26
+
27
+ function manifest(mutate?: (manifest: PluginManifest) => void): PluginManifest {
28
+ const copy = validatePluginManifest(clone(twentyManifest));
29
+ mutate?.(copy);
30
+ return copy;
31
+ }
32
+
33
+ function mcpComponent(m: PluginManifest): McpServerComponent {
34
+ const component = m.versions[0].components.find(
35
+ (candidate) => candidate.type === "mcp-server",
36
+ );
37
+ if (component?.type !== "mcp-server") {
38
+ throw new Error("twenty manifest is missing its mcp-server component");
39
+ }
40
+ return component;
41
+ }
42
+
43
+ function latestVersion(m: PluginManifest) {
44
+ return [...m.versions].sort((a, b) =>
45
+ b.version.localeCompare(a.version, undefined, { numeric: true }),
46
+ )[0]!;
47
+ }
48
+
49
+ function latestMcpComponent(m: PluginManifest): McpServerComponent {
50
+ const component = latestVersion(m).components.find(
51
+ (candidate) => candidate.type === "mcp-server",
52
+ );
53
+ if (component?.type !== "mcp-server") {
54
+ throw new Error(
55
+ "latest twenty manifest is missing its mcp-server component",
56
+ );
57
+ }
58
+ return component;
59
+ }
60
+
61
+ function latestUiSurfaceComponent(m: PluginManifest): UiSurfaceComponent {
62
+ const component = latestVersion(m).components.find(
63
+ (candidate) => candidate.type === "ui-surface",
64
+ );
65
+ if (component?.type !== "ui-surface") {
66
+ throw new Error("latest twenty manifest is missing its ui-surface");
67
+ }
68
+ return component;
69
+ }
70
+
71
+ function infrastructureComponent(): InfrastructureComponent {
72
+ const component = latestVersion(validatedTwentyManifest).components.find(
73
+ (candidate) => candidate.type === "infrastructure",
74
+ );
75
+ if (component?.type !== "infrastructure") {
76
+ throw new Error("twenty manifest is missing its infrastructure component");
77
+ }
78
+ return component;
79
+ }
80
+
81
+ function adapterRequiredInputs(operation: "ENABLE" | "UPGRADE"): string[] {
82
+ const adapter = managedAppRegistry.find(
83
+ (candidate) => candidate.appKey === "twenty",
84
+ );
85
+ if (!adapter) {
86
+ throw new Error("Twenty managed-app adapter is not registered");
87
+ }
88
+ return adapter
89
+ .requiredInputs(operation)
90
+ .map((input) => input.key)
91
+ .sort();
92
+ }
93
+
94
+ function readTwentyApp(path: string): string {
95
+ return readFileSync(join(testDir, "..", "twenty-app", path), "utf8");
96
+ }
97
+
98
+ function readRepo(path: string): string {
99
+ return readFileSync(join(testDir, "..", "..", "..", path), "utf8");
100
+ }
101
+
102
+ describe("twenty plugin manifest", () => {
103
+ it("validates: one endpointFrom mcp-server + one infrastructure component", () => {
104
+ const validated = validatePluginManifest(twentyManifest);
105
+ expect(validated.pluginKey).toBe("twenty");
106
+ expect(validated.versions[0].version).toBe("0.1.0");
107
+ expect(validated.versions.map((version) => version.version)).toEqual([
108
+ "0.1.0",
109
+ "0.2.0",
110
+ "0.3.0",
111
+ ]);
112
+
113
+ const components = latestVersion(validated).components;
114
+ expect(components.map((component) => component.type).sort()).toEqual([
115
+ "infrastructure",
116
+ "mcp-server",
117
+ "ui-surface",
118
+ ]);
119
+
120
+ const mcp = latestMcpComponent(validated);
121
+ expect(mcp.endpointUrl).toBeUndefined();
122
+ expect(mcp.endpointFrom).toEqual({
123
+ managedApp: "twenty",
124
+ configKey: "publicUrl",
125
+ path: "/mcp",
126
+ });
127
+ expect(mcp.auth).toEqual({ mode: "oauth-per-instance" });
128
+ });
129
+
130
+ it("preserves older MCP contracts and keeps record-link hints in launchable versions", () => {
131
+ const validated = validatePluginManifest(twentyManifest);
132
+ const legacyMcp = mcpComponent(validated);
133
+ const recordLinkVersion = validated.versions.find(
134
+ (version) => version.version === "0.2.0",
135
+ );
136
+ const recordLinkMcp = recordLinkVersion?.components.find(
137
+ (component) => component.type === "mcp-server",
138
+ );
139
+ const latestMcp = latestMcpComponent(validated);
140
+
141
+ expect(validated.versions[0].version).toBe("0.1.0");
142
+ expect(legacyMcp.recordLinkHints).toBeUndefined();
143
+ expect(recordLinkMcp?.type).toBe("mcp-server");
144
+ expect(
145
+ recordLinkMcp?.type === "mcp-server"
146
+ ? recordLinkMcp.recordLinkHints
147
+ : undefined,
148
+ ).toEqual({
149
+ schemaVersion: 1,
150
+ source: "plugin-manifest",
151
+ routes: [
152
+ {
153
+ objectType: "opportunity",
154
+ routeTemplate: "/object/opportunity/{id}",
155
+ idFields: ["id", "opportunityId", "record.id", "opportunity.id"],
156
+ labelFields: [
157
+ "name",
158
+ "opportunityName",
159
+ "record.name",
160
+ "opportunity.name",
161
+ ],
162
+ },
163
+ ],
164
+ });
165
+ expect(latestVersion(validated).version).toBe("0.3.0");
166
+ expect(latestMcp.recordLinkHints).toEqual({
167
+ schemaVersion: 1,
168
+ source: "plugin-manifest",
169
+ routes: [
170
+ {
171
+ objectType: "opportunity",
172
+ routeTemplate: "/object/opportunity/{id}",
173
+ idFields: ["id", "opportunityId", "record.id", "opportunity.id"],
174
+ labelFields: [
175
+ "name",
176
+ "opportunityName",
177
+ "record.name",
178
+ "opportunity.name",
179
+ ],
180
+ },
181
+ ],
182
+ });
183
+ });
184
+
185
+ it("publishes a launchable Client Engagement app surface in the latest version", () => {
186
+ const surface = latestUiSurfaceComponent(validatedTwentyManifest);
187
+
188
+ expect(surface).toEqual({
189
+ type: "ui-surface",
190
+ key: "client-engagement",
191
+ displayName: "Client Engagement",
192
+ intendedMount: "apps.main",
193
+ launch: {
194
+ schemaVersion: 1,
195
+ type: "app",
196
+ appKey: "twenty-client-engagement",
197
+ routeSegment: "client-engagement",
198
+ mount: "main-shell",
199
+ runtime: "trusted-bundled-react",
200
+ description:
201
+ "Account and opportunity engagement workspace for Twenty CRM records.",
202
+ icon: "layout-dashboard",
203
+ entitlementProductKey: "twenty-client-engagement",
204
+ },
205
+ });
206
+ });
207
+
208
+ it("owns a native Twenty app package for the ThinkWork Webhook workflow action", () => {
209
+ const defined = defineFirstPartyPluginPackage(twentyPluginPackage);
210
+
211
+ expect(defined.ownedSources).toContainEqual({
212
+ kind: "runtime",
213
+ path: "plugins/twenty/twenty-app",
214
+ description:
215
+ "Native Twenty app package that exposes the ThinkWork Webhook workflow action.",
216
+ });
217
+
218
+ const appYarnLock = readTwentyApp("yarn.lock");
219
+ const appNvmrc = readTwentyApp(".nvmrc");
220
+ const appPackageJson = readTwentyApp("package.json");
221
+ const appReadme = readTwentyApp("README.md");
222
+ const applicationConfig = readTwentyApp("src/application-config.ts");
223
+ const settingsComponent = readTwentyApp(
224
+ "src/front-components/thinkwork-settings.front-component.tsx",
225
+ );
226
+ const workflowAction = readTwentyApp(
227
+ "src/logic-functions/thinkwork-webhook.logic-function.ts",
228
+ );
229
+
230
+ expect(appYarnLock).toContain("twenty-sdk@npm:2.9.0");
231
+ expect(appYarnLock).toContain("twenty-client-sdk@npm:2.9.0");
232
+ expect(appNvmrc.trim()).toBe("24");
233
+ expect(appPackageJson).toContain('"twenty": ">=2.9.0 <3.0.0"');
234
+ expect(appReadme).toContain(
235
+ "docs/runbooks/twenty-thinkwork-native-app-install.md",
236
+ );
237
+ expect(applicationConfig).toContain("defineApplication");
238
+ expect(applicationConfig).toContain("displayName: APP_DISPLAY_NAME");
239
+ expect(applicationConfig).toContain(
240
+ "settingsCustomTabFrontComponentUniversalIdentifier",
241
+ );
242
+ expect(applicationConfig).toContain(
243
+ "THINKWORK_SETTINGS_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER",
244
+ );
245
+ expect(applicationConfig).toContain("THINKWORK_WEBHOOK_URL");
246
+ expect(applicationConfig).toContain("isSecret: true");
247
+ expect(applicationConfig).toContain("THINKWORK_TRIGGER_STAGE");
248
+ expect(applicationConfig).toContain('value: "Customer"');
249
+ expect(applicationConfig).toContain("TWENTY_WORKSPACE_ID");
250
+ expect(applicationConfig).toContain("014f32a0-5868-402a-8152-225e54c4cf29");
251
+ expect(settingsComponent).toContain("defineFrontComponent");
252
+ expect(settingsComponent).toContain(
253
+ "THINKWORK_SETTINGS_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER",
254
+ );
255
+ expect(settingsComponent).toContain("updateOneApplicationVariable");
256
+ expect(settingsComponent).toContain("THINKWORK_WEBHOOK_URL");
257
+ expect(settingsComponent).toContain("THINKWORK_TRIGGER_STAGE");
258
+ expect(settingsComponent).toContain("TWENTY_WORKSPACE_ID");
259
+ expect(settingsComponent).toContain("Customer");
260
+ expect(workflowAction).toContain("defineLogicFunction");
261
+ expect(workflowAction).not.toContain("databaseEventTriggerSettings");
262
+ expect(workflowAction).toContain("workflowActionTriggerSettings");
263
+ expect(workflowAction).toContain('label: "ThinkWork Webhook"');
264
+ expect(workflowAction).toContain("process.env.THINKWORK_WEBHOOK_URL");
265
+ expect(workflowAction).toContain("process.env.THINKWORK_TRIGGER_STAGE");
266
+ expect(workflowAction).toContain("process.env.TWENTY_WORKSPACE_ID");
267
+ expect(workflowAction).toContain("/object/opportunity/");
268
+ expect(workflowAction).toContain("objects\\/opportunities");
269
+ expect(workflowAction).toContain('status: "skipped_stage"');
270
+ expect(workflowAction).toContain("triggerStage: configuredStage");
271
+ expect(workflowAction).toContain('source: "twenty-app"');
272
+ expect(workflowAction).not.toContain("opportunity.won");
273
+ });
274
+
275
+ it("documents native app release packaging and guarded sync paths", () => {
276
+ const releaseWorkflow = readRepo(".github/workflows/release.yml");
277
+ const deployWorkflow = readRepo(".github/workflows/deploy.yml");
278
+ const operationsWorkflow = readRepo(
279
+ ".github/workflows/twenty-thinkwork-app.yml",
280
+ );
281
+ const manifestBuilder = readRepo(
282
+ "scripts/release/build-release-manifest.ts",
283
+ );
284
+ const runner = readRepo(
285
+ "terraform/modules/app/deployment-control-plane/runner.py",
286
+ );
287
+ const syncScript = readRepo(
288
+ "plugins/twenty/scripts/sync-thinkwork-app.mjs",
289
+ );
290
+ const wireScript = readRepo(
291
+ "plugins/twenty/scripts/wire-thinkwork-workflow.mjs",
292
+ );
293
+
294
+ expect(releaseWorkflow).toContain("Stage Twenty ThinkWork app package");
295
+ expect(releaseWorkflow).toContain("twenty-thinkwork-app.tar.gz");
296
+ expect(releaseWorkflow).toContain("name=twenty-thinkwork-app,type=seed");
297
+ expect(manifestBuilder).toContain(
298
+ 'requiredArtifacts: ["twenty-thinkwork-app"]',
299
+ );
300
+ expect(runner).toContain("stage_managed_app_release_artifacts");
301
+ expect(runner).toContain("sync_twenty_thinkwork_app");
302
+ expect(runner).toContain("twentyAppSyncApiKey");
303
+ expect(runner).toContain("managedAppPostInstall");
304
+ expect(deployWorkflow).toContain("sync_twenty_thinkwork_app");
305
+ expect(deployWorkflow).toContain("TWENTY_DEPLOY_API_KEY");
306
+ expect(deployWorkflow).toContain("TWENTY_APP_SYNC_API_KEY");
307
+ expect(deployWorkflow).toContain("TWENTY_WORKSPACE_ID");
308
+ expect(deployWorkflow).toContain("sync-thinkwork-app.mjs");
309
+ expect(deployWorkflow).toContain("wire-thinkwork-workflow.mjs");
310
+ expect(operationsWorkflow).toContain("Twenty ThinkWork App Operations");
311
+ expect(operationsWorkflow).toContain("validate-package");
312
+ expect(operationsWorkflow).toContain("APPLY TWENTY THINKWORK APP");
313
+ expect(operationsWorkflow).toContain(
314
+ "YARN_ENABLE_IMMUTABLE_INSTALLS=false yarn install",
315
+ );
316
+ expect(operationsWorkflow).toContain("TWENTY_DEPLOY_API_KEY");
317
+ expect(operationsWorkflow).toContain("TWENTY_WORKSPACE_ID");
318
+ expect(operationsWorkflow).toContain("sync-thinkwork-app.mjs");
319
+ expect(operationsWorkflow).toContain("wire-thinkwork-workflow.mjs");
320
+ expect(operationsWorkflow).toContain("twenty_allow_active_update");
321
+ expect(operationsWorkflow).toContain("WIRE_ALLOW_ACTIVE_UPDATE");
322
+ expect(operationsWorkflow).not.toContain("terraform-apply");
323
+ expect(syncScript).toContain("app:publish");
324
+ expect(syncScript).toContain("--private");
325
+ expect(syncScript).toContain("app:install");
326
+ expect(syncScript).toContain("remote:status");
327
+ expect(syncScript).toContain("--dry-run");
328
+ expect(syncScript).not.toContain("HTTP_REQUEST");
329
+ expect(wireScript).toContain('type: "LOGIC_FUNCTION"');
330
+ expect(wireScript).toContain("UpdateWorkflowVersionStep");
331
+ expect(wireScript).toContain("findManyLogicFunctions");
332
+ expect(wireScript).toContain('path: "/metadata"');
333
+ expect(wireScript).toContain("findThinkWorkLogicFunction(metadataClient)");
334
+ expect(wireScript).toContain("findWorkflowVersionsForWorkflow");
335
+ expect(wireScript).toContain("--allow-active-update");
336
+ expect(wireScript).toContain("--workspace-id");
337
+ expect(wireScript).toContain("/object/${objectName}/");
338
+ expect(wireScript).toContain('objectName: "opportunity"');
339
+ expect(wireScript).not.toContain("/objects/opportunities/");
340
+ expect(wireScript).toContain("{{trigger.properties.after.id}}");
341
+ expect(wireScript).toContain("{{trigger.properties.after.name}}");
342
+ expect(wireScript).toContain("{{trigger.properties.after.companyId}}");
343
+ expect(wireScript).toContain("{{trigger.properties.after.updatedAt}}");
344
+ expect(wireScript).toContain(
345
+ "{{trigger.properties.after.amount.amountMicros}}",
346
+ );
347
+ expect(wireScript).not.toContain("{{trigger.object.");
348
+ expect(wireScript).not.toContain("AWS_LAMBDA");
349
+ });
350
+
351
+ it("enables Twenty local logic functions for the first-party workflow action", () => {
352
+ const terraformModule = readRepo("plugins/twenty/terraform/twenty/main.tf");
353
+ const terraformReadme = readRepo(
354
+ "plugins/twenty/terraform/twenty/README.md",
355
+ );
356
+
357
+ expect(terraformModule).toContain(
358
+ '{ name = "LOGIC_FUNCTION_TYPE", value = "LOCAL" }',
359
+ );
360
+ expect(terraformModule).toContain("server_environment = concat");
361
+ expect(terraformModule).toContain("worker_environment = concat");
362
+ expect(terraformReadme).toContain("LOGIC_FUNCTION_TYPE=LOCAL");
363
+ expect(terraformReadme).toContain("ThinkWork Webhook");
364
+ });
365
+
366
+ it("declares the infrastructure component against the twenty adapter key", () => {
367
+ const infra = infrastructureComponent();
368
+ expect(infra.managedAppKey).toBe("twenty");
369
+ expect(Object.keys(infra.terraformInputs).sort()).toEqual([
370
+ "certificateArn",
371
+ "dbUrlSecretArn",
372
+ "encryptionKeySecretArn",
373
+ "imageUri",
374
+ "publicUrl",
375
+ ]);
376
+ for (const spec of Object.values(infra.terraformInputs)) {
377
+ expect(spec.description.length).toBeGreaterThan(0);
378
+ expect(spec.type).toBe("string");
379
+ }
380
+ });
381
+
382
+ it("keeps infrastructure inputs aligned with the managed-app adapter", () => {
383
+ const inputs = Object.keys(
384
+ infrastructureComponent().terraformInputs,
385
+ ).sort();
386
+ expect(inputs).toEqual(adapterRequiredInputs("ENABLE"));
387
+ expect(inputs).toEqual(adapterRequiredInputs("UPGRADE"));
388
+ expect(inputs).toContain(
389
+ mcpComponent(validatedTwentyManifest).endpointFrom?.configKey,
390
+ );
391
+ });
392
+
393
+ it("rejects a component declaring both endpointUrl and endpointFrom", () => {
394
+ const bad = manifest();
395
+ mcpComponent(bad).endpointUrl = "https://crm.example.com/mcp";
396
+ expect(() => validatePluginManifest(bad)).toThrow(
397
+ /exactly one of endpointUrl \/ endpointFrom/,
398
+ );
399
+ });
400
+
401
+ it("rejects a component declaring neither endpointUrl nor endpointFrom", () => {
402
+ const bad = manifest();
403
+ delete mcpComponent(bad).endpointFrom;
404
+ expect(() => validatePluginManifest(bad)).toThrow(
405
+ /exactly one of endpointUrl \/ endpointFrom/,
406
+ );
407
+ });
408
+
409
+ it("rejects endpointFrom missing its configKey", () => {
410
+ const bad = manifest();
411
+ delete (mcpComponent(bad).endpointFrom as { configKey?: string }).configKey;
412
+ expect(() => validatePluginManifest(bad)).toThrow(
413
+ /endpointFrom\.configKey/,
414
+ );
415
+ });
416
+
417
+ it("rejects an endpointFrom path that is not absolute or carries a query", () => {
418
+ const noSlash = manifest();
419
+ mcpComponent(noSlash).endpointFrom!.path = "mcp";
420
+ expect(() => validatePluginManifest(noSlash)).toThrow(
421
+ /path must start with "\/"/,
422
+ );
423
+
424
+ const query = manifest();
425
+ mcpComponent(query).endpointFrom!.path = "/mcp?x=1";
426
+ expect(() => validatePluginManifest(query)).toThrow(PluginManifestError);
427
+ });
428
+
429
+ it("rejects oauth-per-instance auth on a static-endpoint server", () => {
430
+ const bad = manifest();
431
+ const mcp = mcpComponent(bad);
432
+ delete mcp.endpointFrom;
433
+ mcp.endpointUrl = "https://crm.example.com/mcp";
434
+ expect(() => validatePluginManifest(bad)).toThrow(
435
+ /"oauth-per-instance" requires endpointFrom/,
436
+ );
437
+ });
438
+
439
+ it("still requires non-empty scopes for STATIC oauth servers", () => {
440
+ // The per-instance exemption must not relax the static-server rule.
441
+ const bad = manifest();
442
+ const mcp = mcpComponent(bad);
443
+ delete mcp.endpointFrom;
444
+ mcp.endpointUrl = "https://crm.example.com/mcp";
445
+ mcp.auth = {
446
+ mode: "oauth",
447
+ authDomain: "https://auth.example.com",
448
+ resourceIndicator: "https://crm.example.com/mcp",
449
+ };
450
+ expect(() => validatePluginManifest(bad)).toThrow(
451
+ /non-empty requiredOauthScopes/,
452
+ );
453
+ });
454
+
455
+ it("allows empty requiredOauthScopes for a per-instance-only manifest", () => {
456
+ expect(
457
+ validatedTwentyManifest.versions.map(
458
+ (version) => version.requiredOauthScopes,
459
+ ),
460
+ ).toEqual([[], [], []]);
461
+ expect(() => validatePluginManifest(twentyManifest)).not.toThrow();
462
+ });
463
+ });
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": "."
6
+ },
7
+ "include": ["./**/*.ts"],
8
+ "exclude": ["twenty-app"]
9
+ }
@@ -0,0 +1 @@
1
+ 24
@@ -0,0 +1,148 @@
1
+ # ThinkWork Twenty App
2
+
3
+ Native Twenty app source for the THNK-33 workflow path:
4
+
5
+ ```text
6
+ Twenty workflow -> ThinkWork app -> ThinkWork Webhook
7
+ ```
8
+
9
+ The app exposes:
10
+
11
+ - one settings front component, `thinkwork-settings`, rendered by the native
12
+ Twenty app Settings tab;
13
+ - one logic function, `ThinkWork Webhook`, registered as a workflow action for
14
+ explicit workflow-builder use.
15
+
16
+ The settings component writes `THINKWORK_WEBHOOK_URL`,
17
+ `THINKWORK_TRIGGER_STAGE`, and `TWENTY_WORKSPACE_ID` as native Twenty
18
+ application variables. The workflow action reads those variables, compares the
19
+ incoming Twenty Opportunity stage with the configured app stage, and only posts
20
+ to the configured ThinkWork generic webhook URL when they match.
21
+
22
+ ## Configuration
23
+
24
+ After installing the app, open Twenty:
25
+
26
+ ```text
27
+ Settings -> Applications -> Installed -> ThinkWork -> Settings
28
+ ```
29
+
30
+ Set the app variables in the ThinkWork settings surface:
31
+
32
+ | Variable | Required | Default | Description |
33
+ | ------------------------- | -------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
34
+ | `THINKWORK_WEBHOOK_URL` | yes | none | Full ThinkWork generic webhook URL copied from ThinkWork Settings > Webhooks, for example `https://app.thinkwork.ai/webhooks/<token>`. |
35
+ | `THINKWORK_TRIGGER_STAGE` | yes | `Customer` | Twenty Opportunity stage label that should trigger the ThinkWork webhook. |
36
+ | `TWENTY_WORKSPACE_ID` | no | production workspace id | Twenty workspace id appended to canonical CRM record links. |
37
+
38
+ The webhook URL contains the ThinkWork webhook token, so the settings component
39
+ does not display the saved secret value after save; paste a new URL to rotate
40
+ it. The trigger stage defaults to `Customer` and is intentionally editable in
41
+ the app settings so the mapping stays in Twenty's ThinkWork app configuration.
42
+
43
+ ## Workflow Action
44
+
45
+ The logic function is available in the Twenty workflow builder as:
46
+
47
+ ```text
48
+ ThinkWork -> ThinkWork Webhook
49
+ ```
50
+
51
+ Recommended action input mapping:
52
+
53
+ | Input | Value |
54
+ | ----------------- | ------------------------------------------------------- |
55
+ | `event` | optional; defaults to `opportunity.stage.customer` |
56
+ | `opportunityId` | Current Opportunity record id |
57
+ | `opportunityName` | Current Opportunity name |
58
+ | `companyName` | Current Opportunity company/account name when available |
59
+ | `stage` | Current Opportunity stage |
60
+ | `opportunityUrl` | Current Opportunity URL when available |
61
+ | `workflowKey` | `customer_onboarding` |
62
+ | `workflowRunId` | Current workflow run id when available |
63
+ | `occurredAt` | Workflow run timestamp or current timestamp |
64
+ | `idempotencyKey` | Stable key such as `stage-customer:<opportunity-id>` |
65
+
66
+ The logic function sends those fields to ThinkWork with
67
+ `source: "twenty-app"` and `triggerStage: "<configured stage>"` when the
68
+ incoming stage matches `THINKWORK_TRIGGER_STAGE`. If the stage does not match,
69
+ the action returns `status: "skipped_stage"` and does not call ThinkWork.
70
+ The action normalizes legacy Opportunity links like
71
+ `/objects/opportunities/<id>` into Twenty's canonical
72
+ `/object/opportunity/<id>#<workspace-id>` route before sending the payload.
73
+
74
+ ThinkWork should record the resulting generic webhook delivery with
75
+ `source=twenty-app`, `stage=Customer`, and `triggerStage=Customer`, proving that
76
+ the path goes through the installed Twenty app settings.
77
+
78
+ ## Install / Deploy
79
+
80
+ Do not run these commands against production from an implementation PR. They
81
+ mutate the target Twenty instance.
82
+
83
+ ```bash
84
+ cd plugins/twenty/twenty-app
85
+ corepack enable
86
+ yarn install
87
+ yarn twenty remote:add --url https://crm.thinkwork.ai --api-key "$TWENTY_DEPLOY_API_KEY" --as thinkwork-crm
88
+ yarn twenty dev --once --dry-run
89
+ yarn twenty app:publish --private --remote thinkwork-crm
90
+ yarn twenty app:install --remote thinkwork-crm
91
+ ```
92
+
93
+ Or use the guarded operations workflow:
94
+
95
+ ```bash
96
+ node plugins/twenty/scripts/sync-thinkwork-app.mjs --apply
97
+ ```
98
+
99
+ For the full operator sequence, including deploy-key setup, dry-run, apply,
100
+ settings, workflow wiring, and verification evidence, see
101
+ `docs/runbooks/twenty-thinkwork-native-app-install.md`.
102
+
103
+ Dry-run mode uses Twenty's non-mutating dev sync preview. Apply mode follows
104
+ Twenty's private app lifecycle: deploy the app tarball with
105
+ `app:publish --private`, then install it into the target workspace with
106
+ `app:install`.
107
+
108
+ After install, the Twenty Applications screen should show a native installed
109
+ app named `ThinkWork`, the app Settings tab should render a
110
+ `ThinkWork Webhook` configuration form for the webhook URL and trigger stage,
111
+ and the workflow builder should offer a workflow action named
112
+ `ThinkWork Webhook`.
113
+
114
+ ## Workflow Wiring
115
+
116
+ The Opportunity workflow must call the app action rather than Twenty's built-in
117
+ HTTP request action:
118
+
119
+ ```text
120
+ Twenty Opportunity stage == Customer
121
+ -> ThinkWork -> ThinkWork Webhook
122
+ -> THINKWORK_WEBHOOK_URL from ThinkWork app settings
123
+ ```
124
+
125
+ Use the guarded wiring script in dry-run mode first:
126
+
127
+ ```bash
128
+ node plugins/twenty/scripts/wire-thinkwork-workflow.mjs \
129
+ --workflow-version-id <draft-workflow-version-id> \
130
+ --dry-run
131
+ ```
132
+
133
+ When the dry-run report identifies the intended workflow and step, an operator
134
+ can apply it to a draft workflow version:
135
+
136
+ ```bash
137
+ node plugins/twenty/scripts/wire-thinkwork-workflow.mjs \
138
+ --workflow-version-id <draft-workflow-version-id> \
139
+ --step-id <http-request-step-id> \
140
+ --workspace-id <twenty-workspace-id> \
141
+ --apply
142
+ ```
143
+
144
+ The Deploy workflow exposes the same guarded operation via
145
+ `wire_twenty_thinkwork_workflow`. The script refuses to mutate an active
146
+ workflow version unless an operator explicitly creates or targets a draft.
147
+ Set the repository variable `TWENTY_WORKSPACE_ID` so generated Opportunity
148
+ links use Twenty's canonical `/object/opportunity/<id>#<workspace-id>` route.
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@thinkwork/twenty-app",
3
+ "version": "0.1.4",
4
+ "private": true,
5
+ "license": "Apache-2.0",
6
+ "type": "module",
7
+ "engines": {
8
+ "node": "^24.5.0",
9
+ "twenty": ">=2.9.0 <3.0.0",
10
+ "npm": "please-use-yarn",
11
+ "yarn": ">=4.0.2"
12
+ },
13
+ "packageManager": "yarn@4.13.0",
14
+ "scripts": {
15
+ "twenty": "twenty",
16
+ "typecheck": "tsc --noEmit"
17
+ },
18
+ "dependencies": {
19
+ "react": "^19.2.0",
20
+ "react-dom": "^19.2.0"
21
+ },
22
+ "devDependencies": {
23
+ "@types/node": "^24.7.2",
24
+ "@types/react": "^19.2.0",
25
+ "@types/react-dom": "^19.2.0",
26
+ "twenty-client-sdk": "2.9.0",
27
+ "twenty-sdk": "2.9.0",
28
+ "typescript": "^5.9.3"
29
+ }
30
+ }