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.
- package/README.md +42 -38
- package/dist/{api-client-ASJWIG3Z.js → api-client-4VT3FWOH.js} +1 -1
- package/dist/{chunk-JEHV35EU.js → chunk-H7AB42ES.js} +340 -30
- package/dist/cli.js +22157 -9229
- 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/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 +453 -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 +1 -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,866 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* n8n agent-step bridge smoke.
|
|
4
|
+
*
|
|
5
|
+
* Dry-run is the default. Set SMOKE_ENABLE_N8N_AGENT_STEP_BRIDGE=1 after the
|
|
6
|
+
* n8n plugin, native n8n MCP endpoint, and ThinkWork bridge endpoint are
|
|
7
|
+
* deployed for a tenant.
|
|
8
|
+
*
|
|
9
|
+
* The safest live path is to provide a disposable workflow trigger URL for a
|
|
10
|
+
* workflow that uses stock HTTP Request + Wait nodes to call ThinkWork:
|
|
11
|
+
* SMOKE_ENABLE_N8N_AGENT_STEP_BRIDGE=1
|
|
12
|
+
* SMOKE_N8N_MCP_URL=https://n8n.example.com/mcp-server/http
|
|
13
|
+
* SMOKE_N8N_MCP_SERVICE_TOKEN=<n8n MCP service credential>
|
|
14
|
+
* SMOKE_N8N_BRIDGE_TRIGGER_URL=<disposable n8n webhook URL>
|
|
15
|
+
* SMOKE_N8N_BRIDGE_CORRELATION_ID=<unique smoke correlation id>
|
|
16
|
+
* SMOKE_GRAPHQL_HTTP_URL=<ThinkWork GraphQL URL>
|
|
17
|
+
* SMOKE_TENANT_ID=<tenant id>
|
|
18
|
+
* API_AUTH_SECRET=<internal API secret> or GRAPHQL_API_KEY=<GraphQL API key>
|
|
19
|
+
*
|
|
20
|
+
* Optional workflow import:
|
|
21
|
+
* SMOKE_N8N_BRIDGE_WORKFLOW_FILE=plugins/n8n/smoke/example-workflow.json
|
|
22
|
+
* SMOKE_N8N_BRIDGE_CREATE_TOOL=create_workflow_from_code
|
|
23
|
+
* SMOKE_N8N_BRIDGE_CREATE_ARGS='{"code":"..."}'
|
|
24
|
+
*
|
|
25
|
+
* Optional execution inspection:
|
|
26
|
+
* SMOKE_N8N_BRIDGE_EXECUTION_ID=<n8n execution id>
|
|
27
|
+
* SMOKE_N8N_BRIDGE_GET_EXECUTION_TOOL=get_execution
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
import fs from "node:fs";
|
|
31
|
+
import path from "node:path";
|
|
32
|
+
import process from "node:process";
|
|
33
|
+
import { attachSmokeEvidence } from "../../../scripts/smoke/deployment-evidence.mjs";
|
|
34
|
+
|
|
35
|
+
const LIVE_ENABLED = process.env.SMOKE_ENABLE_N8N_AGENT_STEP_BRIDGE === "1";
|
|
36
|
+
const TIMEOUT_MS = Number(process.env.SMOKE_TIMEOUT_MS || 20_000);
|
|
37
|
+
const POLL_TIMEOUT_MS = Number(
|
|
38
|
+
process.env.SMOKE_N8N_BRIDGE_POLL_TIMEOUT_MS || 180_000,
|
|
39
|
+
);
|
|
40
|
+
const POLL_INTERVAL_MS = Number(
|
|
41
|
+
process.env.SMOKE_N8N_BRIDGE_POLL_INTERVAL_MS || 5_000,
|
|
42
|
+
);
|
|
43
|
+
const MCP_PROTOCOL_VERSION = "2025-03-26";
|
|
44
|
+
|
|
45
|
+
const env = {
|
|
46
|
+
...loadEnvFile(),
|
|
47
|
+
...process.env,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const n8nUrl = first(env.SMOKE_N8N_URL);
|
|
51
|
+
const mcpUrl = first(
|
|
52
|
+
env.SMOKE_N8N_MCP_URL,
|
|
53
|
+
n8nUrl ? new URL("/mcp-server/http", n8nUrl).toString() : undefined,
|
|
54
|
+
);
|
|
55
|
+
const mcpToken = first(
|
|
56
|
+
env.SMOKE_N8N_MCP_SERVICE_TOKEN,
|
|
57
|
+
env.N8N_MCP_SERVICE_CREDENTIAL,
|
|
58
|
+
);
|
|
59
|
+
const triggerUrl = first(env.SMOKE_N8N_BRIDGE_TRIGGER_URL);
|
|
60
|
+
const triggerMethod = first(env.SMOKE_N8N_BRIDGE_TRIGGER_METHOD, "POST");
|
|
61
|
+
const triggerHeaders = parseJsonEnv(
|
|
62
|
+
"SMOKE_N8N_BRIDGE_TRIGGER_HEADERS",
|
|
63
|
+
env.SMOKE_N8N_BRIDGE_TRIGGER_HEADERS,
|
|
64
|
+
{},
|
|
65
|
+
);
|
|
66
|
+
const smokeId = first(
|
|
67
|
+
env.SMOKE_N8N_BRIDGE_SMOKE_ID,
|
|
68
|
+
`n8n-bridge-smoke-${Date.now()}`,
|
|
69
|
+
);
|
|
70
|
+
const correlationId = first(env.SMOKE_N8N_BRIDGE_CORRELATION_ID, smokeId);
|
|
71
|
+
const workflowId = first(env.SMOKE_N8N_BRIDGE_WORKFLOW_ID);
|
|
72
|
+
const workflowName = first(
|
|
73
|
+
env.SMOKE_N8N_BRIDGE_WORKFLOW_NAME,
|
|
74
|
+
`ThinkWork bridge smoke ${smokeId}`,
|
|
75
|
+
);
|
|
76
|
+
const workflowFile = first(env.SMOKE_N8N_BRIDGE_WORKFLOW_FILE);
|
|
77
|
+
const createWorkflowTool = first(
|
|
78
|
+
env.SMOKE_N8N_BRIDGE_CREATE_TOOL,
|
|
79
|
+
"create_workflow_from_code",
|
|
80
|
+
);
|
|
81
|
+
const validateWorkflowTool = first(
|
|
82
|
+
env.SMOKE_N8N_BRIDGE_VALIDATE_TOOL,
|
|
83
|
+
"validate_workflow",
|
|
84
|
+
);
|
|
85
|
+
const executeWorkflowTool = first(
|
|
86
|
+
env.SMOKE_N8N_BRIDGE_EXECUTE_TOOL,
|
|
87
|
+
"execute_workflow",
|
|
88
|
+
);
|
|
89
|
+
const getExecutionTool = first(
|
|
90
|
+
env.SMOKE_N8N_BRIDGE_GET_EXECUTION_TOOL,
|
|
91
|
+
"get_execution",
|
|
92
|
+
);
|
|
93
|
+
const archiveWorkflowTool = first(
|
|
94
|
+
env.SMOKE_N8N_BRIDGE_ARCHIVE_TOOL,
|
|
95
|
+
"archive_workflow",
|
|
96
|
+
);
|
|
97
|
+
const executionId = first(env.SMOKE_N8N_BRIDGE_EXECUTION_ID);
|
|
98
|
+
const shouldArchiveWorkflow = env.SMOKE_N8N_BRIDGE_ARCHIVE_CREATED === "1";
|
|
99
|
+
const requireTelemetry = env.SMOKE_N8N_BRIDGE_REQUIRE_TELEMETRY !== "0";
|
|
100
|
+
const graphQlUrl = first(
|
|
101
|
+
env.SMOKE_GRAPHQL_HTTP_URL,
|
|
102
|
+
env.VITE_GRAPHQL_HTTP_URL,
|
|
103
|
+
env.GRAPHQL_HTTP_URL,
|
|
104
|
+
env.API_GRAPHQL_URL,
|
|
105
|
+
);
|
|
106
|
+
const tenantId = first(env.SMOKE_TENANT_ID, env.TENANT_ID);
|
|
107
|
+
const apiSecret = first(env.API_AUTH_SECRET, env.THINKWORK_API_SECRET);
|
|
108
|
+
const apiKey = first(
|
|
109
|
+
env.VITE_GRAPHQL_API_KEY,
|
|
110
|
+
env.APPSYNC_API_KEY,
|
|
111
|
+
env.GRAPHQL_API_KEY,
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
const checks = [];
|
|
115
|
+
|
|
116
|
+
if (!LIVE_ENABLED) {
|
|
117
|
+
console.log(
|
|
118
|
+
JSON.stringify(
|
|
119
|
+
await attachSmokeEvidence(
|
|
120
|
+
"n8n-agent-step-bridge",
|
|
121
|
+
{
|
|
122
|
+
ok: true,
|
|
123
|
+
skippedLive: true,
|
|
124
|
+
reason:
|
|
125
|
+
"set SMOKE_ENABLE_N8N_AGENT_STEP_BRIDGE=1 to run the deployed n8n agent-step bridge smoke",
|
|
126
|
+
dryRun: {
|
|
127
|
+
requiredWhenRunning: [
|
|
128
|
+
"n8n plugin installed and deployed through ThinkWork Settings -> Plugins",
|
|
129
|
+
"native n8n MCP endpoint reachable with the tenant service credential",
|
|
130
|
+
"a disposable n8n workflow trigger URL, or workflow import/execute MCP tool args",
|
|
131
|
+
"workflow uses stock HTTP Request plus Wait nodes and passes $execution.resumeUrl to ThinkWork",
|
|
132
|
+
"ThinkWork GraphQL telemetry access for the target tenant",
|
|
133
|
+
],
|
|
134
|
+
optionalWorkflowImportEnv: [
|
|
135
|
+
"SMOKE_N8N_BRIDGE_WORKFLOW_FILE",
|
|
136
|
+
"SMOKE_N8N_BRIDGE_CREATE_TOOL",
|
|
137
|
+
"SMOKE_N8N_BRIDGE_CREATE_ARGS",
|
|
138
|
+
"SMOKE_N8N_BRIDGE_VALIDATE_ARGS",
|
|
139
|
+
],
|
|
140
|
+
liveEnv: [
|
|
141
|
+
"SMOKE_N8N_MCP_URL or SMOKE_N8N_URL",
|
|
142
|
+
"SMOKE_N8N_MCP_SERVICE_TOKEN",
|
|
143
|
+
"SMOKE_N8N_BRIDGE_TRIGGER_URL or SMOKE_N8N_BRIDGE_EXECUTE_ARGS",
|
|
144
|
+
"SMOKE_N8N_BRIDGE_CORRELATION_ID",
|
|
145
|
+
"SMOKE_GRAPHQL_HTTP_URL or GRAPHQL_HTTP_URL",
|
|
146
|
+
"SMOKE_TENANT_ID",
|
|
147
|
+
"API_AUTH_SECRET/THINKWORK_API_SECRET or GraphQL API key",
|
|
148
|
+
],
|
|
149
|
+
verifies: [
|
|
150
|
+
"n8n MCP exposes workflow create/validate/execute/read helpers",
|
|
151
|
+
"disposable workflow is imported or an existing workflow is addressed",
|
|
152
|
+
"workflow start accepts a unique correlation id",
|
|
153
|
+
"ThinkWork records a bridge run with thread id and n8n workflow/execution evidence",
|
|
154
|
+
"ThinkWork reaches a terminal resumed status and n8n execution evidence is inspectable when configured",
|
|
155
|
+
],
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
env,
|
|
159
|
+
),
|
|
160
|
+
null,
|
|
161
|
+
2,
|
|
162
|
+
),
|
|
163
|
+
);
|
|
164
|
+
process.exit(0);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
const result = await runLiveSmoke();
|
|
169
|
+
const failed = checks.filter((check) => !check.ok);
|
|
170
|
+
const payload = {
|
|
171
|
+
ok: failed.length === 0,
|
|
172
|
+
checks,
|
|
173
|
+
...result,
|
|
174
|
+
};
|
|
175
|
+
console.log(
|
|
176
|
+
JSON.stringify(
|
|
177
|
+
await attachSmokeEvidence("n8n-agent-step-bridge", payload, env),
|
|
178
|
+
null,
|
|
179
|
+
2,
|
|
180
|
+
),
|
|
181
|
+
);
|
|
182
|
+
process.exit(failed.length === 0 ? 0 : 1);
|
|
183
|
+
} catch (error) {
|
|
184
|
+
console.error(
|
|
185
|
+
JSON.stringify(
|
|
186
|
+
{
|
|
187
|
+
ok: false,
|
|
188
|
+
error: error instanceof Error ? error.message : String(error),
|
|
189
|
+
checks,
|
|
190
|
+
},
|
|
191
|
+
null,
|
|
192
|
+
),
|
|
193
|
+
);
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async function runLiveSmoke() {
|
|
198
|
+
requireEnv("SMOKE_N8N_MCP_URL or SMOKE_N8N_URL", mcpUrl);
|
|
199
|
+
requireEnv("SMOKE_N8N_MCP_SERVICE_TOKEN", mcpToken);
|
|
200
|
+
|
|
201
|
+
const client = makeDirectMcpClient();
|
|
202
|
+
const tools = await client.listTools();
|
|
203
|
+
const toolNames = new Set(tools.map(toolName).filter(Boolean));
|
|
204
|
+
assertBridgeTools(toolNames);
|
|
205
|
+
|
|
206
|
+
let createdWorkflow = null;
|
|
207
|
+
if (!workflowId && workflowFile) {
|
|
208
|
+
createdWorkflow = await createWorkflow(client, toolNames);
|
|
209
|
+
} else if (workflowId) {
|
|
210
|
+
pass("workflow selected", { workflowId, workflowName });
|
|
211
|
+
} else {
|
|
212
|
+
skip(
|
|
213
|
+
"workflow import",
|
|
214
|
+
"SMOKE_N8N_BRIDGE_WORKFLOW_ID and SMOKE_N8N_BRIDGE_WORKFLOW_FILE are unset; assuming SMOKE_N8N_BRIDGE_TRIGGER_URL targets a disposable workflow",
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const targetWorkflowId = workflowId ?? extractWorkflowId(createdWorkflow);
|
|
219
|
+
if (targetWorkflowId && toolNames.has(validateWorkflowTool)) {
|
|
220
|
+
await validateWorkflow(client, targetWorkflowId);
|
|
221
|
+
} else {
|
|
222
|
+
skip(
|
|
223
|
+
"workflow validation",
|
|
224
|
+
"no workflow id resolved or validate_workflow tool unavailable",
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const start = await startWorkflow(client, toolNames, targetWorkflowId);
|
|
229
|
+
const telemetry = await waitForBridgeTelemetry({
|
|
230
|
+
targetWorkflowId,
|
|
231
|
+
triggerResult: start,
|
|
232
|
+
});
|
|
233
|
+
const execution = await inspectExecution(client, toolNames, {
|
|
234
|
+
telemetry,
|
|
235
|
+
triggerResult: start,
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
if (
|
|
239
|
+
createdWorkflow &&
|
|
240
|
+
shouldArchiveWorkflow &&
|
|
241
|
+
toolNames.has(archiveWorkflowTool)
|
|
242
|
+
) {
|
|
243
|
+
await archiveWorkflow(client, extractWorkflowId(createdWorkflow));
|
|
244
|
+
} else if (createdWorkflow) {
|
|
245
|
+
skip(
|
|
246
|
+
"archive imported workflow",
|
|
247
|
+
"SMOKE_N8N_BRIDGE_ARCHIVE_CREATED=1 not set or archive tool unavailable; leave workflow disabled/disposable",
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return {
|
|
252
|
+
smokeId,
|
|
253
|
+
correlationId,
|
|
254
|
+
workflowId: targetWorkflowId ?? workflowId ?? null,
|
|
255
|
+
workflowName,
|
|
256
|
+
trigger: previewObject(start),
|
|
257
|
+
bridgeRun: telemetry,
|
|
258
|
+
n8nExecution: execution,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function assertBridgeTools(toolNames) {
|
|
263
|
+
const available = [...toolNames].sort();
|
|
264
|
+
const hasCreate = toolNames.has(createWorkflowTool);
|
|
265
|
+
const hasExecute = toolNames.has(executeWorkflowTool);
|
|
266
|
+
const hasGetExecution = toolNames.has(getExecutionTool);
|
|
267
|
+
const hasValidate = toolNames.has(validateWorkflowTool);
|
|
268
|
+
const hasWorkflowNamedTool = available.some((name) => /workflow/i.test(name));
|
|
269
|
+
|
|
270
|
+
if (
|
|
271
|
+
!hasWorkflowNamedTool &&
|
|
272
|
+
!hasCreate &&
|
|
273
|
+
!hasExecute &&
|
|
274
|
+
!hasGetExecution &&
|
|
275
|
+
!hasValidate
|
|
276
|
+
) {
|
|
277
|
+
failCheck("n8n MCP exposes workflow tools", { available });
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
pass("n8n MCP exposes workflow tools", {
|
|
281
|
+
createWorkflowTool: hasCreate,
|
|
282
|
+
executeWorkflowTool: hasExecute,
|
|
283
|
+
getExecutionTool: hasGetExecution,
|
|
284
|
+
validateWorkflowTool: hasValidate,
|
|
285
|
+
available: available.slice(0, 80),
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
async function createWorkflow(client, toolNames) {
|
|
290
|
+
if (!toolNames.has(createWorkflowTool)) {
|
|
291
|
+
throw new Error(
|
|
292
|
+
`MCP tool ${createWorkflowTool} is unavailable; set SMOKE_N8N_BRIDGE_WORKFLOW_ID or SMOKE_N8N_BRIDGE_CREATE_TOOL`,
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
const args = parseJsonEnv(
|
|
296
|
+
"SMOKE_N8N_BRIDGE_CREATE_ARGS",
|
|
297
|
+
env.SMOKE_N8N_BRIDGE_CREATE_ARGS,
|
|
298
|
+
defaultCreateArgsFromFile(workflowFile),
|
|
299
|
+
);
|
|
300
|
+
const result = await client.call(createWorkflowTool, args);
|
|
301
|
+
pass("workflow imported", {
|
|
302
|
+
tool: createWorkflowTool,
|
|
303
|
+
workflowId: extractWorkflowId(result),
|
|
304
|
+
preview: preview(result),
|
|
305
|
+
});
|
|
306
|
+
return result;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function defaultCreateArgsFromFile(file) {
|
|
310
|
+
const raw = fs.readFileSync(path.resolve(file), "utf8");
|
|
311
|
+
return {
|
|
312
|
+
code: raw,
|
|
313
|
+
name: workflowName,
|
|
314
|
+
description:
|
|
315
|
+
"Disposable ThinkWork n8n agent-step bridge smoke workflow. Keep disabled unless actively testing.",
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
async function validateWorkflow(client, targetWorkflowId) {
|
|
320
|
+
const args = parseJsonEnv(
|
|
321
|
+
"SMOKE_N8N_BRIDGE_VALIDATE_ARGS",
|
|
322
|
+
env.SMOKE_N8N_BRIDGE_VALIDATE_ARGS,
|
|
323
|
+
{ id: targetWorkflowId },
|
|
324
|
+
);
|
|
325
|
+
const result = await client.call(validateWorkflowTool, args);
|
|
326
|
+
pass("workflow validation", {
|
|
327
|
+
tool: validateWorkflowTool,
|
|
328
|
+
workflowId: targetWorkflowId,
|
|
329
|
+
preview: preview(result),
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
async function startWorkflow(client, toolNames, targetWorkflowId) {
|
|
334
|
+
if (triggerUrl) {
|
|
335
|
+
const body = parseJsonEnv(
|
|
336
|
+
"SMOKE_N8N_BRIDGE_TRIGGER_BODY",
|
|
337
|
+
env.SMOKE_N8N_BRIDGE_TRIGGER_BODY,
|
|
338
|
+
{
|
|
339
|
+
smokeId,
|
|
340
|
+
correlationId,
|
|
341
|
+
requestedAt: new Date().toISOString(),
|
|
342
|
+
classificationInput: "Classify this as an n8n ThinkWork bridge smoke.",
|
|
343
|
+
},
|
|
344
|
+
);
|
|
345
|
+
const response = await fetchWithTimeout(triggerUrl, {
|
|
346
|
+
method: triggerMethod,
|
|
347
|
+
headers: {
|
|
348
|
+
accept: "application/json, text/plain, */*",
|
|
349
|
+
"content-type": "application/json",
|
|
350
|
+
...triggerHeaders,
|
|
351
|
+
},
|
|
352
|
+
body:
|
|
353
|
+
triggerMethod.toUpperCase() === "GET"
|
|
354
|
+
? undefined
|
|
355
|
+
: JSON.stringify(body),
|
|
356
|
+
});
|
|
357
|
+
const text = await response.text();
|
|
358
|
+
const result = {
|
|
359
|
+
mode: "webhook",
|
|
360
|
+
url: redactUrl(triggerUrl),
|
|
361
|
+
statusCode: response.status,
|
|
362
|
+
ok: response.ok,
|
|
363
|
+
bodyPreview: text.slice(0, 1_500),
|
|
364
|
+
};
|
|
365
|
+
if (!response.ok) {
|
|
366
|
+
failCheck("workflow trigger", result);
|
|
367
|
+
throw new Error(`n8n workflow trigger failed: HTTP ${response.status}`);
|
|
368
|
+
}
|
|
369
|
+
pass("workflow trigger", result);
|
|
370
|
+
return result;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (!toolNames.has(executeWorkflowTool)) {
|
|
374
|
+
throw new Error(
|
|
375
|
+
`Set SMOKE_N8N_BRIDGE_TRIGGER_URL or provide MCP tool ${executeWorkflowTool}`,
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
const args = parseJsonEnv(
|
|
379
|
+
"SMOKE_N8N_BRIDGE_EXECUTE_ARGS",
|
|
380
|
+
env.SMOKE_N8N_BRIDGE_EXECUTE_ARGS,
|
|
381
|
+
targetWorkflowId
|
|
382
|
+
? { id: targetWorkflowId, input: { smokeId, correlationId } }
|
|
383
|
+
: null,
|
|
384
|
+
);
|
|
385
|
+
if (!args) {
|
|
386
|
+
throw new Error(
|
|
387
|
+
"SMOKE_N8N_BRIDGE_EXECUTE_ARGS is required when no trigger URL or workflow id is available",
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
const result = await client.call(executeWorkflowTool, args);
|
|
391
|
+
pass("workflow execute", {
|
|
392
|
+
tool: executeWorkflowTool,
|
|
393
|
+
workflowId: targetWorkflowId,
|
|
394
|
+
preview: preview(result),
|
|
395
|
+
});
|
|
396
|
+
return result;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
async function waitForBridgeTelemetry({ targetWorkflowId, triggerResult }) {
|
|
400
|
+
if (!graphQlUrl || (!apiSecret && !apiKey) || !tenantId) {
|
|
401
|
+
const reason =
|
|
402
|
+
"GraphQL telemetry env missing; set SMOKE_GRAPHQL_HTTP_URL/GRAPHQL_HTTP_URL, SMOKE_TENANT_ID, and API auth";
|
|
403
|
+
if (requireTelemetry) throw new Error(reason);
|
|
404
|
+
return skip("ThinkWork bridge telemetry", reason);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
const deadline = Date.now() + POLL_TIMEOUT_MS;
|
|
408
|
+
let lastRuns = [];
|
|
409
|
+
while (Date.now() <= deadline) {
|
|
410
|
+
lastRuns = await readBridgeRuns();
|
|
411
|
+
const match = findBridgeRun(lastRuns, {
|
|
412
|
+
targetWorkflowId,
|
|
413
|
+
triggerResult,
|
|
414
|
+
});
|
|
415
|
+
if (match) {
|
|
416
|
+
pass("ThinkWork bridge run observed", summarizeBridgeRun(match));
|
|
417
|
+
if (isTerminalBridgeRun(match)) {
|
|
418
|
+
pass("ThinkWork bridge run terminal", summarizeBridgeRun(match));
|
|
419
|
+
if (!isSuccessfulBridgeRun(match)) {
|
|
420
|
+
failCheck("ThinkWork bridge run resumed successfully", {
|
|
421
|
+
reason: "bridge run reached an unsuccessful terminal state",
|
|
422
|
+
run: summarizeBridgeRun(match),
|
|
423
|
+
});
|
|
424
|
+
} else {
|
|
425
|
+
pass(
|
|
426
|
+
"ThinkWork bridge run resumed successfully",
|
|
427
|
+
summarizeBridgeRun(match),
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
return summarizeBridgeRun(match);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
await sleep(POLL_INTERVAL_MS);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
failCheck("ThinkWork bridge telemetry", {
|
|
437
|
+
reason: "timed out waiting for terminal bridge run",
|
|
438
|
+
correlationId,
|
|
439
|
+
workflowId: targetWorkflowId ?? null,
|
|
440
|
+
lastRuns: lastRuns.slice(0, 5).map(summarizeBridgeRun),
|
|
441
|
+
});
|
|
442
|
+
throw new Error(
|
|
443
|
+
`Timed out after ${POLL_TIMEOUT_MS}ms waiting for bridge run ${correlationId}`,
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
async function readBridgeRuns() {
|
|
448
|
+
const data = await gql(
|
|
449
|
+
`query N8nBridgeSmokeRuns($limit: Int) {
|
|
450
|
+
n8nAgentStepRuns(limit: $limit) {
|
|
451
|
+
id
|
|
452
|
+
pluginInstallId
|
|
453
|
+
managedApplicationId
|
|
454
|
+
spaceId
|
|
455
|
+
agentId
|
|
456
|
+
threadId
|
|
457
|
+
status
|
|
458
|
+
resumeStatus
|
|
459
|
+
workflowId
|
|
460
|
+
workflowName
|
|
461
|
+
executionId
|
|
462
|
+
stepId
|
|
463
|
+
correlationId
|
|
464
|
+
requestId
|
|
465
|
+
outputPreview
|
|
466
|
+
errorMessage
|
|
467
|
+
summary
|
|
468
|
+
links
|
|
469
|
+
resumeAttemptCount
|
|
470
|
+
lastResumeHttpStatus
|
|
471
|
+
lastResumeError
|
|
472
|
+
expiresAt
|
|
473
|
+
updatedAt
|
|
474
|
+
}
|
|
475
|
+
}`,
|
|
476
|
+
{ limit: Number(env.SMOKE_N8N_BRIDGE_TELEMETRY_LIMIT || 20) },
|
|
477
|
+
);
|
|
478
|
+
return data.n8nAgentStepRuns ?? [];
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
function findBridgeRun(runs, { targetWorkflowId, triggerResult }) {
|
|
482
|
+
const expectedExecutionId = first(
|
|
483
|
+
executionId,
|
|
484
|
+
extractExecutionId(triggerResult),
|
|
485
|
+
);
|
|
486
|
+
return runs.find((run) => {
|
|
487
|
+
if (run.correlationId !== correlationId) return false;
|
|
488
|
+
if (targetWorkflowId && run.workflowId !== String(targetWorkflowId)) {
|
|
489
|
+
return false;
|
|
490
|
+
}
|
|
491
|
+
if (
|
|
492
|
+
expectedExecutionId &&
|
|
493
|
+
run.executionId !== String(expectedExecutionId)
|
|
494
|
+
) {
|
|
495
|
+
return false;
|
|
496
|
+
}
|
|
497
|
+
return true;
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function summarizeBridgeRun(run) {
|
|
502
|
+
if (!run || run.skipped) return run;
|
|
503
|
+
return {
|
|
504
|
+
id: run.id,
|
|
505
|
+
status: run.status,
|
|
506
|
+
resumeStatus: run.resumeStatus,
|
|
507
|
+
workflowId: run.workflowId,
|
|
508
|
+
workflowName: run.workflowName,
|
|
509
|
+
executionId: run.executionId,
|
|
510
|
+
stepId: run.stepId,
|
|
511
|
+
correlationId: run.correlationId,
|
|
512
|
+
threadId: run.threadId,
|
|
513
|
+
summary: run.summary,
|
|
514
|
+
outputPreview: run.outputPreview,
|
|
515
|
+
errorMessage: run.errorMessage,
|
|
516
|
+
links: run.links,
|
|
517
|
+
resumeAttemptCount: run.resumeAttemptCount,
|
|
518
|
+
lastResumeHttpStatus: run.lastResumeHttpStatus,
|
|
519
|
+
lastResumeError: run.lastResumeError,
|
|
520
|
+
expiresAt: run.expiresAt,
|
|
521
|
+
updatedAt: run.updatedAt,
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
async function inspectExecution(
|
|
526
|
+
client,
|
|
527
|
+
toolNames,
|
|
528
|
+
{ telemetry, triggerResult },
|
|
529
|
+
) {
|
|
530
|
+
const resolvedExecutionId = first(
|
|
531
|
+
executionId,
|
|
532
|
+
telemetry?.executionId,
|
|
533
|
+
extractExecutionId(triggerResult),
|
|
534
|
+
);
|
|
535
|
+
if (!resolvedExecutionId || !toolNames.has(getExecutionTool)) {
|
|
536
|
+
return skip(
|
|
537
|
+
"n8n execution inspection",
|
|
538
|
+
"execution id is unavailable or get_execution tool is unavailable",
|
|
539
|
+
);
|
|
540
|
+
}
|
|
541
|
+
const args = parseJsonEnv(
|
|
542
|
+
"SMOKE_N8N_BRIDGE_GET_EXECUTION_ARGS",
|
|
543
|
+
env.SMOKE_N8N_BRIDGE_GET_EXECUTION_ARGS,
|
|
544
|
+
{ id: resolvedExecutionId },
|
|
545
|
+
);
|
|
546
|
+
const result = await client.call(getExecutionTool, args);
|
|
547
|
+
pass("n8n execution inspection", {
|
|
548
|
+
tool: getExecutionTool,
|
|
549
|
+
executionId: resolvedExecutionId,
|
|
550
|
+
preview: preview(result),
|
|
551
|
+
});
|
|
552
|
+
return previewObject(result);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
async function archiveWorkflow(client, targetWorkflowId) {
|
|
556
|
+
if (!targetWorkflowId) {
|
|
557
|
+
skip("archive imported workflow", "no workflow id resolved");
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
const args = parseJsonEnv(
|
|
561
|
+
"SMOKE_N8N_BRIDGE_ARCHIVE_ARGS",
|
|
562
|
+
env.SMOKE_N8N_BRIDGE_ARCHIVE_ARGS,
|
|
563
|
+
{ id: targetWorkflowId },
|
|
564
|
+
);
|
|
565
|
+
const result = await client.call(archiveWorkflowTool, args);
|
|
566
|
+
pass("archive imported workflow", {
|
|
567
|
+
tool: archiveWorkflowTool,
|
|
568
|
+
workflowId: targetWorkflowId,
|
|
569
|
+
preview: preview(result),
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
function makeDirectMcpClient() {
|
|
574
|
+
return {
|
|
575
|
+
async listTools() {
|
|
576
|
+
return mcpRequest("tools/list", {}, mcpUrl, {
|
|
577
|
+
authorization: `Bearer ${mcpToken}`,
|
|
578
|
+
}).then((result) => result.tools ?? []);
|
|
579
|
+
},
|
|
580
|
+
async call(tool, args) {
|
|
581
|
+
return mcpRequest("tools/call", { name: tool, arguments: args }, mcpUrl, {
|
|
582
|
+
authorization: `Bearer ${mcpToken}`,
|
|
583
|
+
}).then(parseMcpToolResult);
|
|
584
|
+
},
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
async function mcpRequest(method, params, url, headers) {
|
|
589
|
+
let id = 1;
|
|
590
|
+
let sessionId = null;
|
|
591
|
+
const initialize = await jsonRpc(url, headers, {
|
|
592
|
+
jsonrpc: "2.0",
|
|
593
|
+
id: id++,
|
|
594
|
+
method: "initialize",
|
|
595
|
+
params: {
|
|
596
|
+
protocolVersion: MCP_PROTOCOL_VERSION,
|
|
597
|
+
capabilities: {},
|
|
598
|
+
clientInfo: {
|
|
599
|
+
name: "thinkwork-n8n-agent-step-bridge-smoke",
|
|
600
|
+
version: "1.0.0",
|
|
601
|
+
},
|
|
602
|
+
},
|
|
603
|
+
});
|
|
604
|
+
sessionId = initialize.sessionId;
|
|
605
|
+
await jsonRpc(
|
|
606
|
+
url,
|
|
607
|
+
headers,
|
|
608
|
+
{
|
|
609
|
+
jsonrpc: "2.0",
|
|
610
|
+
method: "notifications/initialized",
|
|
611
|
+
params: {},
|
|
612
|
+
},
|
|
613
|
+
sessionId,
|
|
614
|
+
);
|
|
615
|
+
const response = await jsonRpc(
|
|
616
|
+
url,
|
|
617
|
+
headers,
|
|
618
|
+
{ jsonrpc: "2.0", id: id++, method, params },
|
|
619
|
+
sessionId,
|
|
620
|
+
);
|
|
621
|
+
if (response.body.error) {
|
|
622
|
+
throw new Error(
|
|
623
|
+
`${method} JSON-RPC error: ${JSON.stringify(response.body.error)}`,
|
|
624
|
+
);
|
|
625
|
+
}
|
|
626
|
+
return response.body.result ?? {};
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
async function jsonRpc(url, authHeaders, body, sessionId = null) {
|
|
630
|
+
const response = await fetchWithTimeout(url, {
|
|
631
|
+
method: "POST",
|
|
632
|
+
headers: {
|
|
633
|
+
accept: "application/json, text/event-stream",
|
|
634
|
+
"content-type": "application/json",
|
|
635
|
+
"MCP-Protocol-Version": MCP_PROTOCOL_VERSION,
|
|
636
|
+
...(sessionId ? { "mcp-session-id": sessionId } : {}),
|
|
637
|
+
...authHeaders,
|
|
638
|
+
},
|
|
639
|
+
body: JSON.stringify(body),
|
|
640
|
+
});
|
|
641
|
+
const text = await response.text();
|
|
642
|
+
if (!response.ok) {
|
|
643
|
+
throw new Error(`MCP HTTP ${response.status}: ${text.slice(0, 500)}`);
|
|
644
|
+
}
|
|
645
|
+
if (!("id" in body)) return { body: {}, sessionId };
|
|
646
|
+
return {
|
|
647
|
+
body: parseMcpResponse(text, response.headers.get("content-type")),
|
|
648
|
+
sessionId: response.headers.get("mcp-session-id") ?? sessionId,
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
function parseMcpResponse(text, contentType) {
|
|
653
|
+
if (contentType?.includes("text/event-stream")) {
|
|
654
|
+
const data = text
|
|
655
|
+
.split(/\r?\n/)
|
|
656
|
+
.filter((line) => line.startsWith("data:"))
|
|
657
|
+
.map((line) => line.slice(5).trim())
|
|
658
|
+
.join("\n");
|
|
659
|
+
return data ? JSON.parse(data) : {};
|
|
660
|
+
}
|
|
661
|
+
return text ? JSON.parse(text) : {};
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
function parseMcpToolResult(result) {
|
|
665
|
+
if (result.structuredContent) {
|
|
666
|
+
return unwrapToolPayload(result.structuredContent);
|
|
667
|
+
}
|
|
668
|
+
const text = result.content?.find?.((item) => item.type === "text")?.text;
|
|
669
|
+
if (!text) return result;
|
|
670
|
+
try {
|
|
671
|
+
return unwrapToolPayload(JSON.parse(text));
|
|
672
|
+
} catch {
|
|
673
|
+
return { text };
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
function unwrapToolPayload(value) {
|
|
678
|
+
if (
|
|
679
|
+
value &&
|
|
680
|
+
typeof value === "object" &&
|
|
681
|
+
!Array.isArray(value) &&
|
|
682
|
+
Object.prototype.hasOwnProperty.call(value, "result")
|
|
683
|
+
) {
|
|
684
|
+
return value.result;
|
|
685
|
+
}
|
|
686
|
+
return value;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
async function gql(query, variables) {
|
|
690
|
+
const headers = {
|
|
691
|
+
"content-type": "application/json",
|
|
692
|
+
"x-tenant-id": tenantId,
|
|
693
|
+
};
|
|
694
|
+
if (apiSecret) headers.authorization = `Bearer ${apiSecret}`;
|
|
695
|
+
if (apiKey) headers["x-api-key"] = apiKey;
|
|
696
|
+
|
|
697
|
+
const response = await fetchWithTimeout(graphQlUrl, {
|
|
698
|
+
method: "POST",
|
|
699
|
+
headers,
|
|
700
|
+
body: JSON.stringify({ query, variables }),
|
|
701
|
+
});
|
|
702
|
+
const text = await response.text();
|
|
703
|
+
if (!response.ok) {
|
|
704
|
+
throw new Error(`GraphQL HTTP ${response.status}: ${text.slice(0, 500)}`);
|
|
705
|
+
}
|
|
706
|
+
const body = JSON.parse(text);
|
|
707
|
+
if (body.errors?.length) {
|
|
708
|
+
throw new Error(`GraphQL errors: ${JSON.stringify(body.errors)}`);
|
|
709
|
+
}
|
|
710
|
+
return body.data;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
async function fetchWithTimeout(url, options = {}) {
|
|
714
|
+
const controller = new AbortController();
|
|
715
|
+
const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
716
|
+
try {
|
|
717
|
+
return await fetch(url, { ...options, signal: controller.signal });
|
|
718
|
+
} finally {
|
|
719
|
+
clearTimeout(timer);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
function isTerminalBridgeRun(run) {
|
|
724
|
+
return ["RESUMED", "RESUME_FAILED", "FAILED", "EXPIRED"].includes(
|
|
725
|
+
normalizeEnum(run.status),
|
|
726
|
+
);
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
function isSuccessfulBridgeRun(run) {
|
|
730
|
+
return (
|
|
731
|
+
normalizeEnum(run.status) === "RESUMED" &&
|
|
732
|
+
normalizeEnum(run.resumeStatus) === "RESUMED"
|
|
733
|
+
);
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
function extractWorkflowId(value) {
|
|
737
|
+
return firstStringByKey(value, ["workflowId", "workflow_id", "id"]);
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
function extractExecutionId(value) {
|
|
741
|
+
return firstStringByKey(value, ["executionId", "execution_id", "id"]);
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
function firstStringByKey(value, keys) {
|
|
745
|
+
if (!value || typeof value !== "object") return null;
|
|
746
|
+
const seen = new Set();
|
|
747
|
+
const queue = [value];
|
|
748
|
+
while (queue.length) {
|
|
749
|
+
const current = queue.shift();
|
|
750
|
+
if (!current || typeof current !== "object" || seen.has(current)) continue;
|
|
751
|
+
seen.add(current);
|
|
752
|
+
for (const key of keys) {
|
|
753
|
+
const candidate = current[key];
|
|
754
|
+
if (typeof candidate === "string" && candidate.trim()) {
|
|
755
|
+
return candidate.trim();
|
|
756
|
+
}
|
|
757
|
+
if (typeof candidate === "number") {
|
|
758
|
+
return String(candidate);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
for (const child of Object.values(current)) {
|
|
762
|
+
if (child && typeof child === "object") queue.push(child);
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
return null;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
function toolName(tool) {
|
|
769
|
+
return String(tool?.name ?? tool?.tool ?? "");
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
function pass(name, detail) {
|
|
773
|
+
checks.push({ name, ok: true, ...(detail ? { detail } : {}) });
|
|
774
|
+
console.log(`PASS - ${name}${detail ? `: ${JSON.stringify(detail)}` : ""}`);
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
function failCheck(name, detail) {
|
|
778
|
+
checks.push({ name, ok: false, ...(detail ? { detail } : {}) });
|
|
779
|
+
console.log(`FAIL - ${name}${detail ? `: ${JSON.stringify(detail)}` : ""}`);
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
function skip(name, reason) {
|
|
783
|
+
checks.push({ name, ok: true, skipped: true, reason });
|
|
784
|
+
console.log(`SKIP - ${name}: ${reason}`);
|
|
785
|
+
return { skipped: true, reason };
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
function parseJsonEnv(name, value, fallback) {
|
|
789
|
+
if (!value) return fallback;
|
|
790
|
+
try {
|
|
791
|
+
return JSON.parse(value);
|
|
792
|
+
} catch (error) {
|
|
793
|
+
throw new Error(
|
|
794
|
+
`${name} must be valid JSON: ${error instanceof Error ? error.message : String(error)}`,
|
|
795
|
+
);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
function requireEnv(label, value) {
|
|
800
|
+
if (!value) {
|
|
801
|
+
throw new Error(`Missing required live smoke env: ${label}`);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
function first(...values) {
|
|
806
|
+
return values.find(
|
|
807
|
+
(value) => value !== undefined && value !== null && value !== "",
|
|
808
|
+
);
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
function preview(value) {
|
|
812
|
+
return JSON.stringify(value ?? null).slice(0, 1_500);
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
function previewObject(value) {
|
|
816
|
+
if (value?.skipped) return value;
|
|
817
|
+
return { preview: preview(value) };
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
function normalizeEnum(value) {
|
|
821
|
+
return String(value ?? "").toUpperCase();
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
function redactUrl(value) {
|
|
825
|
+
try {
|
|
826
|
+
const url = new URL(value);
|
|
827
|
+
url.username = "";
|
|
828
|
+
url.password = "";
|
|
829
|
+
url.search = url.search ? "?<redacted>" : "";
|
|
830
|
+
return url.toString();
|
|
831
|
+
} catch {
|
|
832
|
+
return "<invalid-url>";
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
function sleep(ms) {
|
|
837
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
function loadEnvFile() {
|
|
841
|
+
const explicit = process.env.COMPUTER_ENV_FILE;
|
|
842
|
+
if (explicit === "none") return {};
|
|
843
|
+
const candidates = [explicit, "apps/web/.env", ".env"].filter(Boolean);
|
|
844
|
+
|
|
845
|
+
for (const candidate of candidates) {
|
|
846
|
+
const resolved = path.resolve(candidate);
|
|
847
|
+
if (!fs.existsSync(resolved)) continue;
|
|
848
|
+
return Object.fromEntries(
|
|
849
|
+
fs
|
|
850
|
+
.readFileSync(resolved, "utf8")
|
|
851
|
+
.split(/\r?\n/)
|
|
852
|
+
.map((line) => line.trim())
|
|
853
|
+
.filter((line) => line && !line.startsWith("#") && line.includes("="))
|
|
854
|
+
.map((line) => {
|
|
855
|
+
const index = line.indexOf("=");
|
|
856
|
+
const key = line.slice(0, index).trim();
|
|
857
|
+
const value = line
|
|
858
|
+
.slice(index + 1)
|
|
859
|
+
.trim()
|
|
860
|
+
.replace(/^['"]|['"]$/g, "");
|
|
861
|
+
return [key, value];
|
|
862
|
+
}),
|
|
863
|
+
);
|
|
864
|
+
}
|
|
865
|
+
return {};
|
|
866
|
+
}
|