thinkwork-cli 0.12.12 → 0.12.16
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.
- package/README.md +42 -38
- package/dist/{api-client-ASJWIG3Z.js → api-client-JUBCQQDF.js} +1 -1
- package/dist/{chunk-JEHV35EU.js → chunk-STY44FQO.js} +353 -30
- package/dist/cli.js +23823 -10151
- package/dist/commands/enterprise/templates/deploy-repo/.github/workflows/deploy.yml +17 -6
- package/dist/commands/enterprise/templates/deploy-repo/docs/runbook.md +81 -9
- package/dist/commands/enterprise/templates/deploy-repo/scripts/apply-release.mjs +183 -21
- package/dist/commands/enterprise/templates/deploy-repo/scripts/smoke.mjs +1 -2
- package/dist/commands/enterprise/templates/deploy-repo/terraform/main.tf +286 -0
- package/dist/drizzle/0000_petite_marvel_apes.sql +1188 -0
- package/dist/drizzle/0001_milky_surge.sql +103 -0
- package/dist/drizzle/0002_aberrant_mattie_franklin.sql +41 -0
- package/dist/drizzle/0003_exotic_ogun.sql +3 -0
- package/dist/drizzle/0004_glamorous_magneto.sql +2 -0
- package/dist/drizzle/0005_ancient_nocturne.sql +2 -0
- package/dist/drizzle/0006_new_colonel_america.sql +2 -0
- package/dist/drizzle/0007_unique_external_task_id.sql +31 -0
- package/dist/drizzle/0008_external_task_id_column.sql +43 -0
- package/dist/drizzle/0009_evaluations.sql +64 -0
- package/dist/drizzle/0010_eval_agent_template.sql +2 -0
- package/dist/drizzle/0011_eval_run_template.sql +2 -0
- package/dist/drizzle/0012_eval_seed_unique.sql +16 -0
- package/dist/drizzle/0013_motionless_white_queen.sql +140 -0
- package/dist/drizzle/0014_wiki_aggregation.sql +11 -0
- package/dist/drizzle/0015_pg_trgm_alias_title_indexes.sql +9 -0
- package/dist/drizzle/0016_wiki_schema_drops.sql +24 -0
- package/dist/drizzle/0017_wiki_places.sql +46 -0
- package/dist/drizzle/0018_agent_workspace_overlay.sql +26 -0
- package/dist/drizzle/0018_cool_firebird.sql +24 -0
- package/dist/drizzle/0018_skill_runs.sql +84 -0
- package/dist/drizzle/0019_condemned_dragon_man.sql +95 -0
- package/dist/drizzle/0019_webhook_skill_runs.sql +58 -0
- package/dist/drizzle/0020_crazy_the_anarchist.sql +9 -0
- package/dist/drizzle/0020_mutation_idempotency.sql +64 -0
- package/dist/drizzle/0021_crm_work_links.sql +76 -0
- package/dist/drizzle/0021_skill_runs_completion_hmac.sql +33 -0
- package/dist/drizzle/0022_add_billing_tables.sql +70 -0
- package/dist/drizzle/0022_seed_thinkwork_admin_permissions.sql +160 -0
- package/dist/drizzle/0022_stripe_billing_indexes.sql +48 -0
- package/dist/drizzle/0023_tenants_deactivation.sql +27 -0
- package/dist/drizzle/0024_tenant_mcp_admin_keys.sql +63 -0
- package/dist/drizzle/0025_v1_agent_architecture.sql +182 -0
- package/dist/drizzle/0026_thread_turns_add_kind.sql +28 -0
- package/dist/drizzle/0027_capability_catalog_and_manifests.sql +219 -0
- package/dist/drizzle/0028_aws_s3_extension.sql +26 -0
- package/dist/drizzle/0029_collapse_execution_types.sql +42 -0
- package/dist/drizzle/0030_retire_composition_primitives.sql +48 -0
- package/dist/drizzle/0031_thread_cleanup_drops.sql +131 -0
- package/dist/drizzle/0032_add_browser_automation_template_config.sql +24 -0
- package/dist/drizzle/0033_agent_operation_leases.sql +32 -0
- package/dist/drizzle/0034_agent_workspace_events.sql +116 -0
- package/dist/drizzle/0035_workspace_review_decisions.sql +19 -0
- package/dist/drizzle/0036_user_scoped_memory_wiki.sql +152 -0
- package/dist/drizzle/0037_user_profile_operating_model.sql +34 -0
- package/dist/drizzle/0042_agent_runtime_selector.sql +41 -0
- package/dist/drizzle/0043_wiki_search_tsv_tokenization.sql +48 -0
- package/dist/drizzle/0044_add_web_search_template_config.sql +7 -0
- package/dist/drizzle/0045_add_send_email_template_config.sql +7 -0
- package/dist/drizzle/0046_tenant_mcp_context_tools.sql +26 -0
- package/dist/drizzle/0047_add_context_engine_template_config.sql +7 -0
- package/dist/drizzle/0048_tenant_context_provider_settings.sql +22 -0
- package/dist/drizzle/0050_brain_v0_entity_subtype.sql +29 -0
- package/dist/drizzle/0051_brain_v0_tenant_entity_pages.sql +170 -0
- package/dist/drizzle/0052_brain_v0_external_refs.sql +41 -0
- package/dist/drizzle/0053_brain_v0_unresolved_mentions_subtype.sql +48 -0
- package/dist/drizzle/0054_wiki_compile_jobs_input.sql +28 -0
- package/dist/drizzle/0055_routines_stepfunctions_substrate.sql +202 -0
- package/dist/drizzle/0056_routine_step_events_dedup_idx.sql +25 -0
- package/dist/drizzle/0057_archive_legacy_python_routines.sql +36 -0
- package/dist/drizzle/0058_routines_visibility_and_owning_agent.sql +61 -0
- package/dist/drizzle/0061_routine_execution_asl_version_id.sql +29 -0
- package/dist/drizzle/0062_migrate_pi_to_flue.sql +110 -0
- package/dist/drizzle/0063_threads_session_data.sql +23 -0
- package/dist/drizzle/0064_tenant_credentials.sql +65 -0
- package/dist/drizzle/0067_thinkwork_computers_phase_one.sql +174 -0
- package/dist/drizzle/0068_drop_system_workflows_and_activation.sql +115 -0
- package/dist/drizzle/0069_compliance_schema.sql +364 -0
- package/dist/drizzle/0070_compliance_aurora_roles.sql +171 -0
- package/dist/drizzle/0072_threads_computer_ownership.sql +24 -0
- package/dist/drizzle/0073_compliance_tenant_anchor_state.sql +105 -0
- package/dist/drizzle/0074_compliance_event_hash_index.sql +49 -0
- package/dist/drizzle/0075_scheduled_jobs_computer_ownership.sql +27 -0
- package/dist/drizzle/0076_scheduled_jobs_marco_backfill.sql +69 -0
- package/dist/drizzle/0077_computers_primary_agent_id.sql +38 -0
- package/dist/drizzle/0078_tenant_customize_catalog.sql +46 -0
- package/dist/drizzle/0079_seed_tenant_customize_catalog.sql +53 -0
- package/dist/drizzle/0081_routines_catalog_slug.sql +42 -0
- package/dist/drizzle/0082_messages_parts_jsonb.sql +52 -0
- package/dist/drizzle/0083_computer_runbooks.sql +103 -0
- package/dist/drizzle/0084_artifacts_favorited_at.sql +32 -0
- package/dist/drizzle/0085_seed_thinkwork_computer_default_template.sql +46 -0
- package/dist/drizzle/0086_update_default_template_models.sql +19 -0
- package/dist/drizzle/0087_retire_oss_connectors.sql +77 -0
- package/dist/drizzle/0088_compliance_event_types_finance_pilot.sql +37 -0
- package/dist/drizzle/0089_remove_maniflow_eval_seeds.sql +81 -0
- package/dist/drizzle/0089_wiki_schema_extraction.sql +315 -0
- package/dist/drizzle/0090_brain_schema_extraction.sql +274 -0
- package/dist/drizzle/0091_drop_wiki_brain_compat_views.sql +118 -0
- package/dist/drizzle/0092_finish_oss_connector_retirement.sql +97 -0
- package/dist/drizzle/0093_eval_runs_scheduled_job_id.sql +23 -0
- package/dist/drizzle/0094_slack_workspace_app.sql +140 -0
- package/dist/drizzle/0095_eval_runs_computer_id.sql +22 -0
- package/dist/drizzle/0096_true_redteam_eval_seed_cleanup.sql +67 -0
- package/dist/drizzle/0097_shared_computers.sql +191 -0
- package/dist/drizzle/0098_business_ontology.sql +587 -0
- package/dist/drizzle/0099_thread_idle_learning.sql +145 -0
- package/dist/drizzle/0100_ontology_gated_brain_dynamic_subtypes.sql +7 -0
- package/dist/drizzle/0101_ontology_gated_unresolved_mentions_dynamic_subtypes.sql +7 -0
- package/dist/drizzle/0102_wiki_brain_owner_repair.sql +87 -0
- package/dist/drizzle/0103_brain_section_source_trigger_repair.sql +75 -0
- package/dist/drizzle/0104_expand_seed_ontology_for_user_memory.sql +166 -0
- package/dist/drizzle/0105_spaces_domain.sql +349 -0
- package/dist/drizzle/0106_expand_seed_ontology_for_triples.sql +173 -0
- package/dist/drizzle/0106_space_threads_participants.sql +197 -0
- package/dist/drizzle/0107_linked_task_mirror.sql +245 -0
- package/dist/drizzle/0108_message_mentions.sql +95 -0
- package/dist/drizzle/0109_space_owned_threads.sql +217 -0
- package/dist/drizzle/0110_thread_participant_read_state.sql +21 -0
- package/dist/drizzle/0111_agents_tenant_name_unique.sql +38 -0
- package/dist/drizzle/0112_recast_spaces_as_contextual_workrooms.sql +138 -0
- package/dist/drizzle/0113_agents_own_runtime_fields.sql +48 -0
- package/dist/drizzle/0114_migrate_templates_to_agents_and_spaces.sql +361 -0
- package/dist/drizzle/0115_remove_computer_eval_template_dependencies.sql +69 -0
- package/dist/drizzle/0116_backfill_thread_participants_access.sql +126 -0
- package/dist/drizzle/0117_space_access_mode.sql +40 -0
- package/dist/drizzle/0118_normalize_tenant_member_principal_type.sql +41 -0
- package/dist/drizzle/0119_space_knowledge_bases.sql +126 -0
- package/dist/drizzle/0120_space_automations.sql +58 -0
- package/dist/drizzle/0121_drop_computer_runbooks.sql +26 -0
- package/dist/drizzle/0122_space_email_triggers.sql +24 -0
- package/dist/drizzle/0123_single_platform_agent_and_overrides.sql +58 -0
- package/dist/drizzle/0124_thread_turns_finalized_at.sql +17 -0
- package/dist/drizzle/0125_drop_space_agent_assignments.sql +42 -0
- package/dist/drizzle/0126_migrate_flue_to_pi.sql +42 -0
- package/dist/drizzle/0127_runtime_type_observability.sql +28 -0
- package/dist/drizzle/0128_drop_eval_test_cases_agent_id.sql +37 -0
- package/dist/drizzle/0129_drop_code_factory_tables.sql +43 -0
- package/dist/drizzle/0129_eval_results_system_prompt.sql +30 -0
- package/dist/drizzle/0130_drop_teams_and_team_id_columns.sql +54 -0
- package/dist/drizzle/0131_drop_skill_catalog_and_tenant_skills.sql +33 -0
- package/dist/drizzle/0132_drop_computer_tables.sql +31 -0
- package/dist/drizzle/0133_drop_seed_view_tombstones.sql +79 -0
- package/dist/drizzle/0133_thread_turns_system_prompt.sql +22 -0
- package/dist/drizzle/0134_drop_dead_agent_runtime_tables.sql +53 -0
- package/dist/drizzle/0135_native_checklist_linked_tasks.sql +48 -0
- package/dist/drizzle/0136_goal_ledger.sql +55 -0
- package/dist/drizzle/0136_space_email_trigger_status.sql +66 -0
- package/dist/drizzle/0137_thread_participant_pins.sql +25 -0
- package/dist/drizzle/0138_users_cognito_sub.sql +30 -0
- package/dist/drizzle/0139_mobile_turn_client_id.sql +23 -0
- package/dist/drizzle/0140_workspace_folder_names.sql +36 -0
- package/dist/drizzle/0141_eval_runs_desktop_pi_provenance.sql +31 -0
- package/dist/drizzle/0142_pi_only_agent_runtime.sql +61 -0
- package/dist/drizzle/0143_add_web_extract_builtin_config.sql +28 -0
- package/dist/drizzle/0144_skill_catalog_index.sql +40 -0
- package/dist/drizzle/0145_knowledge_graph_thread_ingest.sql +512 -0
- package/dist/drizzle/0146_knowledge_graph_source_scope.sql +413 -0
- package/dist/drizzle/0147_knowledge_graph_scope_trigger_qualification.sql +211 -0
- package/dist/drizzle/0148_user_cost_attribution.sql +171 -0
- package/dist/drizzle/0149_managed_mcp_servers.sql +64 -0
- package/dist/drizzle/0149_user_model_approvals.sql +89 -0
- package/dist/drizzle/0150_bootstrap_first_admin_claim.sql +11 -0
- package/dist/drizzle/0151_managed_deployments.sql +91 -0
- package/dist/drizzle/0152_agent_profiles.sql +81 -0
- package/dist/drizzle/0153_message_mentions_agent_profile.sql +9 -0
- package/dist/drizzle/0154_customer_deployment_sessions.sql +61 -0
- package/dist/drizzle/0155_tenant_model_catalog.sql +152 -0
- package/dist/drizzle/0156_bootstrap_credential_leases.sql +52 -0
- package/dist/drizzle/0157_knowledge_graph_observations_source.sql +79 -0
- package/dist/drizzle/0158_pending_user_questions.sql +80 -0
- package/dist/drizzle/0158_wiki_tenant_scope.sql +38 -0
- package/dist/drizzle/0159_agent_profiles_space_local.sql +49 -0
- package/dist/drizzle/0159_application_plugins.sql +193 -0
- package/dist/drizzle/0159_eval_scoring_version.sql +46 -0
- package/dist/drizzle/0160_compliance_event_types_plugins.sql +37 -0
- package/dist/drizzle/0160_eval_datasets.sql +75 -0
- package/dist/drizzle/0160_eval_results_thread_turn.sql +35 -0
- package/dist/drizzle/0161_eval_run_pinning.sql +54 -0
- package/dist/drizzle/0161_tenant_mcp_servers_plugin_source.sql +62 -0
- package/dist/drizzle/0162_eval_result_override.sql +49 -0
- package/dist/drizzle/0163_eval_replay_tool_allowlist.sql +50 -0
- package/dist/drizzle/0164_eval_replay_tool_override_mode.sql +52 -0
- package/dist/drizzle/0165_plugin_premium_entitlements.sql +153 -0
- package/dist/drizzle/0166_company_brain_substrate_contract.sql +386 -0
- package/dist/drizzle/0167_company_brain_artifact_manifest_runtime.sql +85 -0
- package/dist/drizzle/0168_eval_skill_gate.sql +44 -0
- package/dist/drizzle/0169_release_update_jobs.sql +67 -0
- package/dist/drizzle/0170_email_channel_plugin.sql +291 -0
- package/dist/drizzle/0171_linked_task_external_providers.sql +30 -0
- package/dist/drizzle/0172_email_channel_sendgrid_provider.sql +8 -0
- package/dist/drizzle/0173_auth_provider_resources.sql +83 -0
- package/dist/drizzle/0174_workos_auth_bridges.sql +37 -0
- package/dist/drizzle/0175_workos_auth_sessions.sql +38 -0
- package/dist/drizzle/0176_n8n_agent_step_runs.sql +107 -0
- package/dist/drizzle/0177_workflow_control_plane.sql +281 -0
- package/dist/drizzle/0178_workflow_backfill_existing_routines.sql +525 -0
- package/dist/drizzle/0179_tenant_goal_budget_settings.sql +21 -0
- package/dist/drizzle/0180_skill_drafts.sql +89 -0
- package/dist/drizzle/0181_skill_draft_publish_status.sql +21 -0
- package/dist/drizzle/0182_agent_loops.sql +260 -0
- package/dist/drizzle/0183_okf_artifact_manifests.sql +52 -0
- package/dist/drizzle/0184_skill_catalog_trust_cache.sql +35 -0
- package/dist/drizzle/0185_agent_loop_space.sql +16 -0
- package/dist/drizzle/0186_tenant_mcp_runtime_metadata.sql +10 -0
- package/dist/drizzle/0187_native_work_items.sql +220 -0
- package/dist/drizzle/0188_company_etl_plugin_rename.sql +99 -0
- package/dist/drizzle/0189_trace_cost_substrate.sql +247 -0
- package/dist/drizzle/0190_billing_export_reconciliation.sql +101 -0
- package/dist/drizzle/0191_open_engine_work_item_queue.sql +66 -0
- package/dist/drizzle/0192_work_item_labels.sql +44 -0
- package/dist/drizzle/0193_work_item_documents.sql +31 -0
- package/dist/drizzle/0194_memory_retain_attempts.sql +103 -0
- package/dist/drizzle/0194_work_item_comments.sql +35 -0
- package/dist/drizzle/0195_plugin_app_overlays.sql +45 -0
- package/dist/drizzle/0196_pi_extensions.sql +118 -0
- package/dist/drizzle/0197_eval_profiles.sql +150 -0
- package/dist/drizzle/0197_rcm_context_columns.sql +28 -0
- package/dist/drizzle/0198_eval_runs_unstable.sql +27 -0
- package/dist/drizzle/0199_eval_runs_cost_partial.sql +27 -0
- package/dist/drizzle/meta/_journal.json +160 -0
- package/dist/plugins/README.md +162 -0
- package/dist/plugins/catalog/package.json +40 -0
- package/dist/plugins/catalog/scripts/build-catalog.ts +120 -0
- package/dist/plugins/catalog/scripts/generate-plugin-registry.ts +144 -0
- package/dist/plugins/catalog/src/__tests__/build-catalog.test.ts +86 -0
- package/dist/plugins/catalog/src/__tests__/catalog.test.ts +308 -0
- package/dist/plugins/catalog/src/__tests__/contracts.test.ts +861 -0
- package/dist/plugins/catalog/src/__tests__/plugin-package.test.ts +124 -0
- package/dist/plugins/catalog/src/__tests__/plugin-registry.test.ts +120 -0
- package/dist/plugins/catalog/src/catalog.ts +434 -0
- package/dist/plugins/catalog/src/contracts.ts +1498 -0
- package/dist/plugins/catalog/src/index.ts +4 -0
- package/dist/plugins/catalog/src/plugin-package.ts +171 -0
- package/dist/plugins/catalog/src/registry/generated-first-party.ts +76 -0
- package/dist/plugins/catalog/src/registry/index.ts +1 -0
- package/dist/plugins/catalog/tsconfig.json +8 -0
- package/dist/plugins/company-brain/README.md +37 -0
- package/dist/plugins/company-brain/package.json +33 -0
- package/dist/plugins/company-brain/runtime/cognee/Dockerfile +11 -0
- package/dist/plugins/company-brain/smoke/cognee-managed-app-smoke.mjs +458 -0
- package/dist/plugins/company-brain/smoke/cognee-memory-cutover-smoke.mjs +539 -0
- package/dist/plugins/company-brain/smoke/company-brain-context-engine-smoke.mjs +312 -0
- package/dist/plugins/company-brain/smoke/company-brain-operations-smoke.mjs +449 -0
- package/dist/plugins/company-brain/smoke/company-brain-plugin-smoke.mjs +655 -0
- package/dist/plugins/company-brain/smoke/hindsight-memory-isolation-smoke.mjs +474 -0
- package/dist/plugins/company-brain/src/api/cognee-client.ts +896 -0
- package/dist/plugins/company-brain/src/api/cognee-cluster-identity.ts +49 -0
- package/dist/plugins/company-brain/src/api/cognee-memory-scope.ts +84 -0
- package/dist/plugins/company-brain/src/api/context-engine-provider.ts +888 -0
- package/dist/plugins/company-brain/src/api/migration.ts +665 -0
- package/dist/plugins/company-brain/src/deployment/cognee-managed-app.ts +396 -0
- package/dist/plugins/company-brain/src/index.ts +62 -0
- package/dist/plugins/company-brain/src/manifest.ts +112 -0
- package/dist/plugins/company-brain/terraform/cognee/README.md +263 -0
- package/dist/plugins/company-brain/terraform/cognee/main.tf +766 -0
- package/dist/plugins/company-brain/terraform/cognee/outputs.tf +144 -0
- package/dist/plugins/company-brain/terraform/cognee/variables.tf +402 -0
- package/dist/plugins/company-brain/test/api/cognee-client.test.ts +562 -0
- package/dist/plugins/company-brain/test/api/cognee-memory-scope.test.ts +74 -0
- package/dist/plugins/company-brain/test/api/context-engine-provider.test.ts +447 -0
- package/dist/plugins/company-brain/test/api/migration.test.ts +465 -0
- package/dist/plugins/company-brain/test/manifest.test.ts +95 -0
- package/dist/plugins/company-brain/tsconfig.json +8 -0
- package/dist/plugins/company-data/README.md +49 -0
- package/dist/plugins/company-data/package.json +21 -0
- package/dist/plugins/company-data/src/index.ts +30 -0
- package/dist/plugins/company-data/src/manifest.ts +26 -0
- package/dist/plugins/company-data/test/manifest.test.ts +116 -0
- package/dist/plugins/company-data/tsconfig.json +8 -0
- package/dist/plugins/company-etl/README.md +46 -0
- package/dist/plugins/company-etl/package.json +21 -0
- package/dist/plugins/company-etl/src/index.ts +29 -0
- package/dist/plugins/company-etl/src/manifest.ts +26 -0
- package/dist/plugins/company-etl/test/manifest.test.ts +108 -0
- package/dist/plugins/company-etl/tsconfig.json +8 -0
- package/dist/plugins/email-channel/README.md +41 -0
- package/dist/plugins/email-channel/package.json +22 -0
- package/dist/plugins/email-channel/src/index.ts +36 -0
- package/dist/plugins/email-channel/src/manifest.ts +44 -0
- package/dist/plugins/email-channel/src/provider-contract.ts +36 -0
- package/dist/plugins/email-channel/test/manifest.test.ts +119 -0
- package/dist/plugins/email-channel/tsconfig.json +8 -0
- package/dist/plugins/lastmile/README.md +50 -0
- package/dist/plugins/lastmile/package.json +23 -0
- package/dist/plugins/lastmile/smoke/lastmile-plugin-smoke.mjs +661 -0
- package/dist/plugins/lastmile/src/api/tasks-adapter.ts +572 -0
- package/dist/plugins/lastmile/src/discovery.fixture.ts +64 -0
- package/dist/plugins/lastmile/src/index.ts +46 -0
- package/dist/plugins/lastmile/src/manifest.ts +139 -0
- package/dist/plugins/lastmile/test/api/tasks-adapter.test.ts +266 -0
- package/dist/plugins/lastmile/test/discovery.test.ts +88 -0
- package/dist/plugins/lastmile/tsconfig.json +8 -0
- package/dist/plugins/n8n/README.md +201 -0
- package/dist/plugins/n8n/n8n-app/README.md +33 -0
- package/dist/plugins/n8n/n8n-app/package.json +23 -0
- package/dist/plugins/n8n/n8n-app/src/application-config.ts +45 -0
- package/dist/plugins/n8n/n8n-app/src/front-components/thinkwork-workflows.front-component.tsx +970 -0
- package/dist/plugins/n8n/n8n-app/src/lib/n8n-app-data.ts +190 -0
- package/dist/plugins/n8n/n8n-app/src/vite-env.d.ts +7 -0
- package/dist/plugins/n8n/n8n-app/tsconfig.json +15 -0
- package/dist/plugins/n8n/package.json +35 -0
- package/dist/plugins/n8n/runtime/Dockerfile +18 -0
- package/dist/plugins/n8n/runtime/n8n-task-runners.json +14 -0
- package/dist/plugins/n8n/runtime/n8n-task-runners.json.template +14 -0
- package/dist/plugins/n8n/runtime/package-lock.json +13 -0
- package/dist/plugins/n8n/runtime/package.json +7 -0
- package/dist/plugins/n8n/scripts/sync-thinkwork-app.mjs +268 -0
- package/dist/plugins/n8n/smoke/README.md +95 -0
- package/dist/plugins/n8n/smoke/n8n-agent-step-bridge-smoke.mjs +866 -0
- package/dist/plugins/n8n/smoke/n8n-integrated-app-smoke.mjs +262 -0
- package/dist/plugins/n8n/smoke/n8n-managed-app-smoke.mjs +409 -0
- package/dist/plugins/n8n/smoke/n8n-mcp-smoke.mjs +624 -0
- package/dist/plugins/n8n/src/deployment/image-build.ts +172 -0
- package/dist/plugins/n8n/src/deployment/managed-app.ts +429 -0
- package/dist/plugins/n8n/src/index.ts +79 -0
- package/dist/plugins/n8n/src/manifest.ts +403 -0
- package/dist/plugins/n8n/src/package-config.ts +186 -0
- package/dist/plugins/n8n/src/skills/n8n-workflow-operator/SKILL.md +76 -0
- package/dist/plugins/n8n/src/skills/n8n-workflow-operator/references/mcp-tooling.md +40 -0
- package/dist/plugins/n8n/src/skills/n8n-workflow-operator/references/validation-and-handoff.md +40 -0
- package/dist/plugins/n8n/src/skills/n8n-workflow-operator/references/workflow-authoring.md +45 -0
- package/dist/plugins/n8n/terraform/n8n/README.md +113 -0
- package/dist/plugins/n8n/terraform/n8n/main.tf +918 -0
- package/dist/plugins/n8n/terraform/n8n/outputs.tf +124 -0
- package/dist/plugins/n8n/terraform/n8n/scripts/sync-database.py +250 -0
- package/dist/plugins/n8n/terraform/n8n/scripts/test_sync_database.py +55 -0
- package/dist/plugins/n8n/terraform/n8n/variables.tf +354 -0
- package/dist/plugins/n8n/test/image-build.test.ts +118 -0
- package/dist/plugins/n8n/test/integrated-app-contract.test.ts +353 -0
- package/dist/plugins/n8n/test/manifest.test.ts +278 -0
- package/dist/plugins/n8n/test/package-config.test.ts +57 -0
- package/dist/plugins/n8n/tsconfig.json +8 -0
- package/dist/plugins/sendgrid/README.md +30 -0
- package/dist/plugins/sendgrid/package.json +22 -0
- package/dist/plugins/sendgrid/src/index.ts +36 -0
- package/dist/plugins/sendgrid/src/manifest.ts +37 -0
- package/dist/plugins/sendgrid/src/provider-contract.ts +14 -0
- package/dist/plugins/sendgrid/test/manifest.test.ts +80 -0
- package/dist/plugins/sendgrid/tsconfig.json +8 -0
- package/dist/plugins/twenty/README.md +78 -0
- package/dist/plugins/twenty/package.json +27 -0
- package/dist/plugins/twenty/scripts/__tests__/sync-thinkwork-app.test.mjs +67 -0
- package/dist/plugins/twenty/scripts/sync-thinkwork-app.mjs +185 -0
- package/dist/plugins/twenty/scripts/wire-thinkwork-workflow.mjs +658 -0
- package/dist/plugins/twenty/smoke/twenty-managed-app-smoke.mjs +359 -0
- package/dist/plugins/twenty/smoke/twenty-mcp-oauth-smoke.mjs +574 -0
- package/dist/plugins/twenty/src/api/cutover.ts +209 -0
- package/dist/plugins/twenty/src/deployment/managed-app.ts +253 -0
- package/dist/plugins/twenty/src/index.ts +55 -0
- package/dist/plugins/twenty/src/manifest.ts +259 -0
- package/dist/plugins/twenty/terraform/twenty/README.md +97 -0
- package/dist/plugins/twenty/terraform/twenty/main.tf +829 -0
- package/dist/plugins/twenty/terraform/twenty/outputs.tf +79 -0
- package/dist/plugins/twenty/terraform/twenty/variables.tf +268 -0
- package/dist/plugins/twenty/test/api/cutover.test.ts +183 -0
- package/dist/plugins/twenty/test/manifest.test.ts +463 -0
- package/dist/plugins/twenty/tsconfig.json +9 -0
- package/dist/plugins/twenty/twenty-app/.nvmrc +1 -0
- package/dist/plugins/twenty/twenty-app/README.md +148 -0
- package/dist/plugins/twenty/twenty-app/package.json +30 -0
- package/dist/plugins/twenty/twenty-app/src/application-config.ts +44 -0
- package/dist/plugins/twenty/twenty-app/src/constants/universal-identifiers.ts +18 -0
- package/dist/plugins/twenty/twenty-app/src/default-role.ts +24 -0
- package/dist/plugins/twenty/twenty-app/src/front-components/thinkwork-settings.front-component.tsx +299 -0
- package/dist/plugins/twenty/twenty-app/src/logic-functions/thinkwork-webhook.logic-function.ts +354 -0
- package/dist/plugins/twenty/twenty-app/tsconfig.json +14 -0
- package/dist/plugins/twenty/twenty-app/yarn.lock +4144 -0
- package/dist/plugins/workos-auth/package.json +22 -0
- package/dist/plugins/workos-auth/src/index.ts +30 -0
- package/dist/plugins/workos-auth/src/manifest.ts +40 -0
- package/dist/plugins/workos-auth/src/provider-contract.ts +39 -0
- package/dist/plugins/workos-auth/test/manifest.test.ts +94 -0
- package/dist/plugins/workos-auth/tsconfig.json +8 -0
- package/dist/scripts/bootstrap-workspace.sh +162 -0
- package/dist/scripts/post-deploy.sh +290 -0
- package/dist/terraform/examples/greenfield/main.tf +903 -75
- package/dist/terraform/examples/greenfield/terraform.tfvars.example +67 -8
- package/dist/terraform/modules/app/agentcore-code-interpreter/Dockerfile.sandbox-base +2 -2
- package/dist/terraform/modules/app/agentcore-code-interpreter/README.md +8 -9
- package/dist/terraform/modules/app/agentcore-code-interpreter/sandbox/sitecustomize.py +227 -0
- package/dist/terraform/modules/app/agentcore-code-interpreter/sandbox/test_sitecustomize.py +277 -0
- package/dist/terraform/modules/app/agentcore-memory/README.md +6 -6
- package/dist/terraform/modules/app/agentcore-memory/main.tf +1 -1
- package/dist/terraform/modules/app/agentcore-memory/scripts/create_or_find_memory.sh +40 -9
- package/dist/terraform/modules/app/agentcore-pi/README.md +61 -0
- package/dist/terraform/modules/app/agentcore-pi/main.tf +466 -0
- package/dist/terraform/modules/app/agentcore-pi/outputs.tf +38 -0
- package/dist/terraform/modules/app/agentcore-pi/variables.tf +145 -0
- package/dist/terraform/modules/app/agentcore-platform/main.tf +83 -0
- package/dist/terraform/modules/app/agentcore-runtime/main.tf +9 -11
- package/dist/terraform/modules/app/appsync-subscriptions/main.tf +5 -1
- package/dist/terraform/modules/app/customer-domain/main.tf +483 -0
- package/dist/terraform/modules/app/deployment-control-plane/README.md +47 -0
- package/dist/terraform/modules/app/deployment-control-plane/buildspec.yml +24 -0
- package/dist/terraform/modules/app/deployment-control-plane/main.tf +614 -0
- package/dist/terraform/modules/app/deployment-control-plane/outputs.tf +54 -0
- package/dist/terraform/modules/app/deployment-control-plane/runner.py +4720 -0
- package/dist/terraform/modules/app/deployment-control-plane/test_runner_bundle.py +3026 -0
- package/dist/terraform/modules/app/deployment-control-plane/variables.tf +96 -0
- package/dist/terraform/modules/app/hindsight-memory/README.md +25 -23
- package/dist/terraform/modules/app/hindsight-memory/main.tf +26 -2
- package/dist/terraform/modules/app/lambda-api/eval-fanout.tf +17 -50
- package/dist/terraform/modules/app/lambda-api/handlers.tf +1290 -679
- package/dist/terraform/modules/app/lambda-api/iam-grouped.tf +933 -0
- package/dist/terraform/modules/app/lambda-api/main.tf +14 -527
- package/dist/terraform/modules/app/lambda-api/mcp-oauth.tf +3 -19
- package/dist/terraform/modules/app/lambda-api/outputs.tf +50 -6
- package/dist/terraform/modules/app/lambda-api/runtime-config.tf +163 -0
- package/dist/terraform/modules/app/lambda-api/slack-app-secrets.tf +3 -1
- package/dist/terraform/modules/app/lambda-api/stripe-secrets.tf +3 -1
- package/dist/terraform/modules/app/lambda-api/variables.tf +240 -53
- package/dist/terraform/modules/app/lambda-api/workspace-events.tf +2 -25
- package/dist/terraform/modules/app/ses-email/main.tf +143 -30
- package/dist/terraform/modules/app/static-site/main.tf +4 -3
- package/dist/terraform/modules/app/www-dns/main.tf +45 -5
- package/dist/terraform/modules/app/www-dns/outputs.tf +10 -0
- package/dist/terraform/modules/app/www-dns/variables.tf +24 -0
- package/dist/terraform/modules/data/aurora-postgres/main.tf +15 -1
- package/dist/terraform/modules/data/compliance-exports-bucket/main.tf +1 -1
- package/dist/terraform/modules/data/compliance-exports-bucket/variables.tf +6 -0
- package/dist/terraform/modules/foundation/cognito/main.tf +167 -11
- package/dist/terraform/modules/foundation/cognito/outputs.tf +5 -0
- package/dist/terraform/modules/foundation/cognito/variables.tf +110 -0
- package/dist/terraform/modules/foundation/vpc/main.tf +45 -3
- package/dist/terraform/modules/foundation/vpc/outputs.tf +20 -0
- package/dist/terraform/modules/foundation/vpc/variables.tf +18 -0
- package/dist/terraform/modules/thinkwork/README.md +71 -0
- package/dist/terraform/modules/thinkwork/main.tf +1325 -174
- package/dist/terraform/modules/thinkwork/outputs.tf +457 -24
- package/dist/terraform/modules/thinkwork/variables.tf +1169 -93
- package/dist/terraform/schema.graphql +82 -9
- package/dist/workspace-defaults/files/AGENTS.md +344 -0
- package/dist/workspace-defaults/files/CONTEXT.md +8 -0
- package/dist/workspace-defaults/files/GUARDRAILS.md +51 -0
- package/dist/workspace-defaults/files/MEMORY_GUIDE.md +65 -0
- package/dist/workspace-defaults/files/ROUTER.md +24 -0
- package/dist/workspace-defaults/files/SPACE.md +62 -0
- package/dist/workspace-defaults/files/TOOLS.md +65 -0
- package/dist/workspace-defaults/files/USER.md +40 -0
- package/dist/workspace-defaults/files/mcp.json +3 -0
- package/dist/workspace-defaults/files/memory/contacts.md +13 -0
- package/dist/workspace-defaults/files/memory/lessons.md +13 -0
- package/dist/workspace-defaults/files/memory/preferences.md +12 -0
- package/dist/workspace-defaults/files/skills/.gitkeep +1 -0
- package/dist/workspace-defaults/files/skills/artifact-builder/SKILL.md +79 -0
- package/dist/workspace-defaults/files/skills/artifact-builder/references/crm-dashboard.md +166 -0
- package/dist/workspace-defaults/files/skills/automation-loop-designer/SKILL.md +120 -0
- package/dist/workspace-defaults/files/skills/skill-creator/LICENSE.txt +202 -0
- package/dist/workspace-defaults/files/skills/skill-creator/SKILL.md +485 -0
- package/dist/workspace-defaults/files/skills/skill-creator/UPSTREAM.json +124 -0
- package/dist/workspace-defaults/files/skills/skill-creator/agents/analyzer.md +274 -0
- package/dist/workspace-defaults/files/skills/skill-creator/agents/comparator.md +202 -0
- package/dist/workspace-defaults/files/skills/skill-creator/agents/grader.md +223 -0
- package/dist/workspace-defaults/files/skills/skill-creator/assets/eval_review.html +146 -0
- package/dist/workspace-defaults/files/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/dist/workspace-defaults/files/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/dist/workspace-defaults/files/skills/skill-creator/references/schemas.md +430 -0
- package/dist/workspace-defaults/files/skills/skill-creator/scripts/__init__.py +0 -0
- package/dist/workspace-defaults/files/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/dist/workspace-defaults/files/skills/skill-creator/scripts/generate_report.py +326 -0
- package/dist/workspace-defaults/files/skills/skill-creator/scripts/improve_description.py +247 -0
- package/dist/workspace-defaults/files/skills/skill-creator/scripts/package_skill.py +136 -0
- package/dist/workspace-defaults/files/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/dist/workspace-defaults/files/skills/skill-creator/scripts/run_eval.py +310 -0
- package/dist/workspace-defaults/files/skills/skill-creator/scripts/run_loop.py +328 -0
- package/dist/workspace-defaults/files/skills/skill-creator/scripts/utils.py +47 -0
- package/package.json +2 -1
- package/dist/terraform/modules/app/agentcore-flue/README.md +0 -58
- package/dist/terraform/modules/app/agentcore-flue/main.tf +0 -323
- package/dist/terraform/modules/app/agentcore-flue/outputs.tf +0 -23
- package/dist/terraform/modules/app/agentcore-flue/variables.tf +0 -97
- package/dist/terraform/modules/app/computer-runtime/README.md +0 -15
- package/dist/terraform/modules/app/computer-runtime/main.tf +0 -406
- package/dist/terraform/modules/app/computer-runtime/outputs.tf +0 -75
- 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 @@
|
|
|
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
|
+
}
|