thinkwork-cli 0.12.11 → 0.12.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (474) hide show
  1. package/README.md +42 -38
  2. package/dist/{api-client-ASJWIG3Z.js → api-client-4VT3FWOH.js} +1 -1
  3. package/dist/{chunk-JEHV35EU.js → chunk-H7AB42ES.js} +340 -30
  4. package/dist/cli.js +22157 -9229
  5. package/dist/commands/enterprise/templates/deploy-repo/.github/workflows/deploy.yml +17 -6
  6. package/dist/commands/enterprise/templates/deploy-repo/docs/runbook.md +81 -9
  7. package/dist/commands/enterprise/templates/deploy-repo/scripts/apply-release.mjs +183 -21
  8. package/dist/commands/enterprise/templates/deploy-repo/scripts/smoke.mjs +1 -2
  9. package/dist/commands/enterprise/templates/deploy-repo/terraform/main.tf +286 -0
  10. package/dist/drizzle/0000_petite_marvel_apes.sql +1188 -0
  11. package/dist/drizzle/0001_milky_surge.sql +103 -0
  12. package/dist/drizzle/0002_aberrant_mattie_franklin.sql +41 -0
  13. package/dist/drizzle/0003_exotic_ogun.sql +3 -0
  14. package/dist/drizzle/0004_glamorous_magneto.sql +2 -0
  15. package/dist/drizzle/0005_ancient_nocturne.sql +2 -0
  16. package/dist/drizzle/0006_new_colonel_america.sql +2 -0
  17. package/dist/drizzle/0007_unique_external_task_id.sql +31 -0
  18. package/dist/drizzle/0008_external_task_id_column.sql +43 -0
  19. package/dist/drizzle/0009_evaluations.sql +64 -0
  20. package/dist/drizzle/0010_eval_agent_template.sql +2 -0
  21. package/dist/drizzle/0011_eval_run_template.sql +2 -0
  22. package/dist/drizzle/0012_eval_seed_unique.sql +16 -0
  23. package/dist/drizzle/0013_motionless_white_queen.sql +140 -0
  24. package/dist/drizzle/0014_wiki_aggregation.sql +11 -0
  25. package/dist/drizzle/0015_pg_trgm_alias_title_indexes.sql +9 -0
  26. package/dist/drizzle/0016_wiki_schema_drops.sql +24 -0
  27. package/dist/drizzle/0017_wiki_places.sql +46 -0
  28. package/dist/drizzle/0018_agent_workspace_overlay.sql +26 -0
  29. package/dist/drizzle/0018_cool_firebird.sql +24 -0
  30. package/dist/drizzle/0018_skill_runs.sql +84 -0
  31. package/dist/drizzle/0019_condemned_dragon_man.sql +95 -0
  32. package/dist/drizzle/0019_webhook_skill_runs.sql +58 -0
  33. package/dist/drizzle/0020_crazy_the_anarchist.sql +9 -0
  34. package/dist/drizzle/0020_mutation_idempotency.sql +64 -0
  35. package/dist/drizzle/0021_crm_work_links.sql +76 -0
  36. package/dist/drizzle/0021_skill_runs_completion_hmac.sql +33 -0
  37. package/dist/drizzle/0022_add_billing_tables.sql +70 -0
  38. package/dist/drizzle/0022_seed_thinkwork_admin_permissions.sql +160 -0
  39. package/dist/drizzle/0022_stripe_billing_indexes.sql +48 -0
  40. package/dist/drizzle/0023_tenants_deactivation.sql +27 -0
  41. package/dist/drizzle/0024_tenant_mcp_admin_keys.sql +63 -0
  42. package/dist/drizzle/0025_v1_agent_architecture.sql +182 -0
  43. package/dist/drizzle/0026_thread_turns_add_kind.sql +28 -0
  44. package/dist/drizzle/0027_capability_catalog_and_manifests.sql +219 -0
  45. package/dist/drizzle/0028_aws_s3_extension.sql +26 -0
  46. package/dist/drizzle/0029_collapse_execution_types.sql +42 -0
  47. package/dist/drizzle/0030_retire_composition_primitives.sql +48 -0
  48. package/dist/drizzle/0031_thread_cleanup_drops.sql +131 -0
  49. package/dist/drizzle/0032_add_browser_automation_template_config.sql +24 -0
  50. package/dist/drizzle/0033_agent_operation_leases.sql +32 -0
  51. package/dist/drizzle/0034_agent_workspace_events.sql +116 -0
  52. package/dist/drizzle/0035_workspace_review_decisions.sql +19 -0
  53. package/dist/drizzle/0036_user_scoped_memory_wiki.sql +152 -0
  54. package/dist/drizzle/0037_user_profile_operating_model.sql +34 -0
  55. package/dist/drizzle/0042_agent_runtime_selector.sql +41 -0
  56. package/dist/drizzle/0043_wiki_search_tsv_tokenization.sql +48 -0
  57. package/dist/drizzle/0044_add_web_search_template_config.sql +7 -0
  58. package/dist/drizzle/0045_add_send_email_template_config.sql +7 -0
  59. package/dist/drizzle/0046_tenant_mcp_context_tools.sql +26 -0
  60. package/dist/drizzle/0047_add_context_engine_template_config.sql +7 -0
  61. package/dist/drizzle/0048_tenant_context_provider_settings.sql +22 -0
  62. package/dist/drizzle/0050_brain_v0_entity_subtype.sql +29 -0
  63. package/dist/drizzle/0051_brain_v0_tenant_entity_pages.sql +170 -0
  64. package/dist/drizzle/0052_brain_v0_external_refs.sql +41 -0
  65. package/dist/drizzle/0053_brain_v0_unresolved_mentions_subtype.sql +48 -0
  66. package/dist/drizzle/0054_wiki_compile_jobs_input.sql +28 -0
  67. package/dist/drizzle/0055_routines_stepfunctions_substrate.sql +202 -0
  68. package/dist/drizzle/0056_routine_step_events_dedup_idx.sql +25 -0
  69. package/dist/drizzle/0057_archive_legacy_python_routines.sql +36 -0
  70. package/dist/drizzle/0058_routines_visibility_and_owning_agent.sql +61 -0
  71. package/dist/drizzle/0061_routine_execution_asl_version_id.sql +29 -0
  72. package/dist/drizzle/0062_migrate_pi_to_flue.sql +110 -0
  73. package/dist/drizzle/0063_threads_session_data.sql +23 -0
  74. package/dist/drizzle/0064_tenant_credentials.sql +65 -0
  75. package/dist/drizzle/0067_thinkwork_computers_phase_one.sql +174 -0
  76. package/dist/drizzle/0068_drop_system_workflows_and_activation.sql +115 -0
  77. package/dist/drizzle/0069_compliance_schema.sql +364 -0
  78. package/dist/drizzle/0070_compliance_aurora_roles.sql +171 -0
  79. package/dist/drizzle/0072_threads_computer_ownership.sql +24 -0
  80. package/dist/drizzle/0073_compliance_tenant_anchor_state.sql +105 -0
  81. package/dist/drizzle/0074_compliance_event_hash_index.sql +49 -0
  82. package/dist/drizzle/0075_scheduled_jobs_computer_ownership.sql +27 -0
  83. package/dist/drizzle/0076_scheduled_jobs_marco_backfill.sql +69 -0
  84. package/dist/drizzle/0077_computers_primary_agent_id.sql +38 -0
  85. package/dist/drizzle/0078_tenant_customize_catalog.sql +46 -0
  86. package/dist/drizzle/0079_seed_tenant_customize_catalog.sql +53 -0
  87. package/dist/drizzle/0081_routines_catalog_slug.sql +42 -0
  88. package/dist/drizzle/0082_messages_parts_jsonb.sql +52 -0
  89. package/dist/drizzle/0083_computer_runbooks.sql +103 -0
  90. package/dist/drizzle/0084_artifacts_favorited_at.sql +32 -0
  91. package/dist/drizzle/0085_seed_thinkwork_computer_default_template.sql +46 -0
  92. package/dist/drizzle/0086_update_default_template_models.sql +19 -0
  93. package/dist/drizzle/0087_retire_oss_connectors.sql +77 -0
  94. package/dist/drizzle/0088_compliance_event_types_finance_pilot.sql +37 -0
  95. package/dist/drizzle/0089_remove_maniflow_eval_seeds.sql +81 -0
  96. package/dist/drizzle/0089_wiki_schema_extraction.sql +315 -0
  97. package/dist/drizzle/0090_brain_schema_extraction.sql +274 -0
  98. package/dist/drizzle/0091_drop_wiki_brain_compat_views.sql +118 -0
  99. package/dist/drizzle/0092_finish_oss_connector_retirement.sql +97 -0
  100. package/dist/drizzle/0093_eval_runs_scheduled_job_id.sql +23 -0
  101. package/dist/drizzle/0094_slack_workspace_app.sql +140 -0
  102. package/dist/drizzle/0095_eval_runs_computer_id.sql +22 -0
  103. package/dist/drizzle/0096_true_redteam_eval_seed_cleanup.sql +67 -0
  104. package/dist/drizzle/0097_shared_computers.sql +191 -0
  105. package/dist/drizzle/0098_business_ontology.sql +587 -0
  106. package/dist/drizzle/0099_thread_idle_learning.sql +145 -0
  107. package/dist/drizzle/0100_ontology_gated_brain_dynamic_subtypes.sql +7 -0
  108. package/dist/drizzle/0101_ontology_gated_unresolved_mentions_dynamic_subtypes.sql +7 -0
  109. package/dist/drizzle/0102_wiki_brain_owner_repair.sql +87 -0
  110. package/dist/drizzle/0103_brain_section_source_trigger_repair.sql +75 -0
  111. package/dist/drizzle/0104_expand_seed_ontology_for_user_memory.sql +166 -0
  112. package/dist/drizzle/0105_spaces_domain.sql +349 -0
  113. package/dist/drizzle/0106_expand_seed_ontology_for_triples.sql +173 -0
  114. package/dist/drizzle/0106_space_threads_participants.sql +197 -0
  115. package/dist/drizzle/0107_linked_task_mirror.sql +245 -0
  116. package/dist/drizzle/0108_message_mentions.sql +95 -0
  117. package/dist/drizzle/0109_space_owned_threads.sql +217 -0
  118. package/dist/drizzle/0110_thread_participant_read_state.sql +21 -0
  119. package/dist/drizzle/0111_agents_tenant_name_unique.sql +38 -0
  120. package/dist/drizzle/0112_recast_spaces_as_contextual_workrooms.sql +138 -0
  121. package/dist/drizzle/0113_agents_own_runtime_fields.sql +48 -0
  122. package/dist/drizzle/0114_migrate_templates_to_agents_and_spaces.sql +361 -0
  123. package/dist/drizzle/0115_remove_computer_eval_template_dependencies.sql +69 -0
  124. package/dist/drizzle/0116_backfill_thread_participants_access.sql +126 -0
  125. package/dist/drizzle/0117_space_access_mode.sql +40 -0
  126. package/dist/drizzle/0118_normalize_tenant_member_principal_type.sql +41 -0
  127. package/dist/drizzle/0119_space_knowledge_bases.sql +126 -0
  128. package/dist/drizzle/0120_space_automations.sql +58 -0
  129. package/dist/drizzle/0121_drop_computer_runbooks.sql +26 -0
  130. package/dist/drizzle/0122_space_email_triggers.sql +24 -0
  131. package/dist/drizzle/0123_single_platform_agent_and_overrides.sql +58 -0
  132. package/dist/drizzle/0124_thread_turns_finalized_at.sql +17 -0
  133. package/dist/drizzle/0125_drop_space_agent_assignments.sql +42 -0
  134. package/dist/drizzle/0126_migrate_flue_to_pi.sql +42 -0
  135. package/dist/drizzle/0127_runtime_type_observability.sql +28 -0
  136. package/dist/drizzle/0128_drop_eval_test_cases_agent_id.sql +37 -0
  137. package/dist/drizzle/0129_drop_code_factory_tables.sql +43 -0
  138. package/dist/drizzle/0129_eval_results_system_prompt.sql +30 -0
  139. package/dist/drizzle/0130_drop_teams_and_team_id_columns.sql +54 -0
  140. package/dist/drizzle/0131_drop_skill_catalog_and_tenant_skills.sql +33 -0
  141. package/dist/drizzle/0132_drop_computer_tables.sql +31 -0
  142. package/dist/drizzle/0133_drop_seed_view_tombstones.sql +79 -0
  143. package/dist/drizzle/0133_thread_turns_system_prompt.sql +22 -0
  144. package/dist/drizzle/0134_drop_dead_agent_runtime_tables.sql +53 -0
  145. package/dist/drizzle/0135_native_checklist_linked_tasks.sql +48 -0
  146. package/dist/drizzle/0136_goal_ledger.sql +55 -0
  147. package/dist/drizzle/0136_space_email_trigger_status.sql +66 -0
  148. package/dist/drizzle/0137_thread_participant_pins.sql +25 -0
  149. package/dist/drizzle/0138_users_cognito_sub.sql +30 -0
  150. package/dist/drizzle/0139_mobile_turn_client_id.sql +23 -0
  151. package/dist/drizzle/0140_workspace_folder_names.sql +36 -0
  152. package/dist/drizzle/0141_eval_runs_desktop_pi_provenance.sql +31 -0
  153. package/dist/drizzle/0142_pi_only_agent_runtime.sql +61 -0
  154. package/dist/drizzle/0143_add_web_extract_builtin_config.sql +28 -0
  155. package/dist/drizzle/0144_skill_catalog_index.sql +40 -0
  156. package/dist/drizzle/0145_knowledge_graph_thread_ingest.sql +512 -0
  157. package/dist/drizzle/0146_knowledge_graph_source_scope.sql +413 -0
  158. package/dist/drizzle/0147_knowledge_graph_scope_trigger_qualification.sql +211 -0
  159. package/dist/drizzle/0148_user_cost_attribution.sql +171 -0
  160. package/dist/drizzle/0149_managed_mcp_servers.sql +64 -0
  161. package/dist/drizzle/0149_user_model_approvals.sql +89 -0
  162. package/dist/drizzle/0150_bootstrap_first_admin_claim.sql +11 -0
  163. package/dist/drizzle/0151_managed_deployments.sql +91 -0
  164. package/dist/drizzle/0152_agent_profiles.sql +81 -0
  165. package/dist/drizzle/0153_message_mentions_agent_profile.sql +9 -0
  166. package/dist/drizzle/0154_customer_deployment_sessions.sql +61 -0
  167. package/dist/drizzle/0155_tenant_model_catalog.sql +152 -0
  168. package/dist/drizzle/0156_bootstrap_credential_leases.sql +52 -0
  169. package/dist/drizzle/0157_knowledge_graph_observations_source.sql +79 -0
  170. package/dist/drizzle/0158_pending_user_questions.sql +80 -0
  171. package/dist/drizzle/0158_wiki_tenant_scope.sql +38 -0
  172. package/dist/drizzle/0159_agent_profiles_space_local.sql +49 -0
  173. package/dist/drizzle/0159_application_plugins.sql +193 -0
  174. package/dist/drizzle/0159_eval_scoring_version.sql +46 -0
  175. package/dist/drizzle/0160_compliance_event_types_plugins.sql +37 -0
  176. package/dist/drizzle/0160_eval_datasets.sql +75 -0
  177. package/dist/drizzle/0160_eval_results_thread_turn.sql +35 -0
  178. package/dist/drizzle/0161_eval_run_pinning.sql +54 -0
  179. package/dist/drizzle/0161_tenant_mcp_servers_plugin_source.sql +62 -0
  180. package/dist/drizzle/0162_eval_result_override.sql +49 -0
  181. package/dist/drizzle/0163_eval_replay_tool_allowlist.sql +50 -0
  182. package/dist/drizzle/0164_eval_replay_tool_override_mode.sql +52 -0
  183. package/dist/drizzle/0165_plugin_premium_entitlements.sql +153 -0
  184. package/dist/drizzle/0166_company_brain_substrate_contract.sql +386 -0
  185. package/dist/drizzle/0167_company_brain_artifact_manifest_runtime.sql +85 -0
  186. package/dist/drizzle/0168_eval_skill_gate.sql +44 -0
  187. package/dist/drizzle/0169_release_update_jobs.sql +67 -0
  188. package/dist/drizzle/0170_email_channel_plugin.sql +291 -0
  189. package/dist/drizzle/0171_linked_task_external_providers.sql +30 -0
  190. package/dist/drizzle/0172_email_channel_sendgrid_provider.sql +8 -0
  191. package/dist/drizzle/0173_auth_provider_resources.sql +83 -0
  192. package/dist/drizzle/0174_workos_auth_bridges.sql +37 -0
  193. package/dist/drizzle/0175_workos_auth_sessions.sql +38 -0
  194. package/dist/drizzle/0176_n8n_agent_step_runs.sql +107 -0
  195. package/dist/drizzle/0177_workflow_control_plane.sql +281 -0
  196. package/dist/drizzle/0178_workflow_backfill_existing_routines.sql +525 -0
  197. package/dist/drizzle/0179_tenant_goal_budget_settings.sql +21 -0
  198. package/dist/drizzle/0180_skill_drafts.sql +89 -0
  199. package/dist/drizzle/0181_skill_draft_publish_status.sql +21 -0
  200. package/dist/drizzle/0182_agent_loops.sql +260 -0
  201. package/dist/drizzle/0183_okf_artifact_manifests.sql +52 -0
  202. package/dist/drizzle/0184_skill_catalog_trust_cache.sql +35 -0
  203. package/dist/drizzle/0185_agent_loop_space.sql +16 -0
  204. package/dist/drizzle/0186_tenant_mcp_runtime_metadata.sql +10 -0
  205. package/dist/drizzle/0187_native_work_items.sql +220 -0
  206. package/dist/drizzle/0188_company_etl_plugin_rename.sql +99 -0
  207. package/dist/drizzle/0189_trace_cost_substrate.sql +247 -0
  208. package/dist/drizzle/0190_billing_export_reconciliation.sql +101 -0
  209. package/dist/drizzle/0191_open_engine_work_item_queue.sql +66 -0
  210. package/dist/drizzle/0192_work_item_labels.sql +44 -0
  211. package/dist/drizzle/0193_work_item_documents.sql +31 -0
  212. package/dist/drizzle/0194_memory_retain_attempts.sql +103 -0
  213. package/dist/drizzle/0194_work_item_comments.sql +35 -0
  214. package/dist/drizzle/0195_plugin_app_overlays.sql +45 -0
  215. package/dist/drizzle/0196_pi_extensions.sql +118 -0
  216. package/dist/drizzle/0197_eval_profiles.sql +150 -0
  217. package/dist/drizzle/0198_eval_runs_unstable.sql +27 -0
  218. package/dist/drizzle/0199_eval_runs_cost_partial.sql +27 -0
  219. package/dist/drizzle/meta/_journal.json +160 -0
  220. package/dist/plugins/README.md +162 -0
  221. package/dist/plugins/catalog/package.json +40 -0
  222. package/dist/plugins/catalog/scripts/build-catalog.ts +120 -0
  223. package/dist/plugins/catalog/scripts/generate-plugin-registry.ts +144 -0
  224. package/dist/plugins/catalog/src/__tests__/build-catalog.test.ts +86 -0
  225. package/dist/plugins/catalog/src/__tests__/catalog.test.ts +308 -0
  226. package/dist/plugins/catalog/src/__tests__/contracts.test.ts +861 -0
  227. package/dist/plugins/catalog/src/__tests__/plugin-package.test.ts +124 -0
  228. package/dist/plugins/catalog/src/__tests__/plugin-registry.test.ts +120 -0
  229. package/dist/plugins/catalog/src/catalog.ts +434 -0
  230. package/dist/plugins/catalog/src/contracts.ts +1498 -0
  231. package/dist/plugins/catalog/src/index.ts +4 -0
  232. package/dist/plugins/catalog/src/plugin-package.ts +171 -0
  233. package/dist/plugins/catalog/src/registry/generated-first-party.ts +76 -0
  234. package/dist/plugins/catalog/src/registry/index.ts +1 -0
  235. package/dist/plugins/catalog/tsconfig.json +8 -0
  236. package/dist/plugins/company-brain/README.md +37 -0
  237. package/dist/plugins/company-brain/package.json +33 -0
  238. package/dist/plugins/company-brain/runtime/cognee/Dockerfile +11 -0
  239. package/dist/plugins/company-brain/smoke/cognee-managed-app-smoke.mjs +458 -0
  240. package/dist/plugins/company-brain/smoke/cognee-memory-cutover-smoke.mjs +539 -0
  241. package/dist/plugins/company-brain/smoke/company-brain-context-engine-smoke.mjs +312 -0
  242. package/dist/plugins/company-brain/smoke/company-brain-operations-smoke.mjs +449 -0
  243. package/dist/plugins/company-brain/smoke/company-brain-plugin-smoke.mjs +655 -0
  244. package/dist/plugins/company-brain/smoke/hindsight-memory-isolation-smoke.mjs +474 -0
  245. package/dist/plugins/company-brain/src/api/cognee-client.ts +896 -0
  246. package/dist/plugins/company-brain/src/api/cognee-cluster-identity.ts +49 -0
  247. package/dist/plugins/company-brain/src/api/cognee-memory-scope.ts +84 -0
  248. package/dist/plugins/company-brain/src/api/context-engine-provider.ts +888 -0
  249. package/dist/plugins/company-brain/src/api/migration.ts +665 -0
  250. package/dist/plugins/company-brain/src/deployment/cognee-managed-app.ts +396 -0
  251. package/dist/plugins/company-brain/src/index.ts +62 -0
  252. package/dist/plugins/company-brain/src/manifest.ts +112 -0
  253. package/dist/plugins/company-brain/terraform/cognee/README.md +263 -0
  254. package/dist/plugins/company-brain/terraform/cognee/main.tf +766 -0
  255. package/dist/plugins/company-brain/terraform/cognee/outputs.tf +144 -0
  256. package/dist/plugins/company-brain/terraform/cognee/variables.tf +402 -0
  257. package/dist/plugins/company-brain/test/api/cognee-client.test.ts +562 -0
  258. package/dist/plugins/company-brain/test/api/cognee-memory-scope.test.ts +74 -0
  259. package/dist/plugins/company-brain/test/api/context-engine-provider.test.ts +447 -0
  260. package/dist/plugins/company-brain/test/api/migration.test.ts +465 -0
  261. package/dist/plugins/company-brain/test/manifest.test.ts +95 -0
  262. package/dist/plugins/company-brain/tsconfig.json +8 -0
  263. package/dist/plugins/company-data/README.md +49 -0
  264. package/dist/plugins/company-data/package.json +21 -0
  265. package/dist/plugins/company-data/src/index.ts +30 -0
  266. package/dist/plugins/company-data/src/manifest.ts +26 -0
  267. package/dist/plugins/company-data/test/manifest.test.ts +116 -0
  268. package/dist/plugins/company-data/tsconfig.json +8 -0
  269. package/dist/plugins/company-etl/README.md +46 -0
  270. package/dist/plugins/company-etl/package.json +21 -0
  271. package/dist/plugins/company-etl/src/index.ts +29 -0
  272. package/dist/plugins/company-etl/src/manifest.ts +26 -0
  273. package/dist/plugins/company-etl/test/manifest.test.ts +108 -0
  274. package/dist/plugins/company-etl/tsconfig.json +8 -0
  275. package/dist/plugins/email-channel/README.md +41 -0
  276. package/dist/plugins/email-channel/package.json +22 -0
  277. package/dist/plugins/email-channel/src/index.ts +36 -0
  278. package/dist/plugins/email-channel/src/manifest.ts +44 -0
  279. package/dist/plugins/email-channel/src/provider-contract.ts +36 -0
  280. package/dist/plugins/email-channel/test/manifest.test.ts +119 -0
  281. package/dist/plugins/email-channel/tsconfig.json +8 -0
  282. package/dist/plugins/lastmile/README.md +50 -0
  283. package/dist/plugins/lastmile/package.json +23 -0
  284. package/dist/plugins/lastmile/smoke/lastmile-plugin-smoke.mjs +661 -0
  285. package/dist/plugins/lastmile/src/api/tasks-adapter.ts +572 -0
  286. package/dist/plugins/lastmile/src/discovery.fixture.ts +64 -0
  287. package/dist/plugins/lastmile/src/index.ts +46 -0
  288. package/dist/plugins/lastmile/src/manifest.ts +139 -0
  289. package/dist/plugins/lastmile/test/api/tasks-adapter.test.ts +266 -0
  290. package/dist/plugins/lastmile/test/discovery.test.ts +88 -0
  291. package/dist/plugins/lastmile/tsconfig.json +8 -0
  292. package/dist/plugins/n8n/README.md +201 -0
  293. package/dist/plugins/n8n/n8n-app/README.md +33 -0
  294. package/dist/plugins/n8n/n8n-app/package.json +23 -0
  295. package/dist/plugins/n8n/n8n-app/src/application-config.ts +45 -0
  296. package/dist/plugins/n8n/n8n-app/src/front-components/thinkwork-workflows.front-component.tsx +970 -0
  297. package/dist/plugins/n8n/n8n-app/src/lib/n8n-app-data.ts +190 -0
  298. package/dist/plugins/n8n/n8n-app/src/vite-env.d.ts +7 -0
  299. package/dist/plugins/n8n/n8n-app/tsconfig.json +15 -0
  300. package/dist/plugins/n8n/package.json +35 -0
  301. package/dist/plugins/n8n/runtime/Dockerfile +18 -0
  302. package/dist/plugins/n8n/runtime/n8n-task-runners.json +14 -0
  303. package/dist/plugins/n8n/runtime/n8n-task-runners.json.template +14 -0
  304. package/dist/plugins/n8n/runtime/package-lock.json +13 -0
  305. package/dist/plugins/n8n/runtime/package.json +7 -0
  306. package/dist/plugins/n8n/scripts/sync-thinkwork-app.mjs +268 -0
  307. package/dist/plugins/n8n/smoke/README.md +95 -0
  308. package/dist/plugins/n8n/smoke/n8n-agent-step-bridge-smoke.mjs +866 -0
  309. package/dist/plugins/n8n/smoke/n8n-integrated-app-smoke.mjs +262 -0
  310. package/dist/plugins/n8n/smoke/n8n-managed-app-smoke.mjs +409 -0
  311. package/dist/plugins/n8n/smoke/n8n-mcp-smoke.mjs +624 -0
  312. package/dist/plugins/n8n/src/deployment/image-build.ts +172 -0
  313. package/dist/plugins/n8n/src/deployment/managed-app.ts +429 -0
  314. package/dist/plugins/n8n/src/index.ts +79 -0
  315. package/dist/plugins/n8n/src/manifest.ts +403 -0
  316. package/dist/plugins/n8n/src/package-config.ts +186 -0
  317. package/dist/plugins/n8n/src/skills/n8n-workflow-operator/SKILL.md +76 -0
  318. package/dist/plugins/n8n/src/skills/n8n-workflow-operator/references/mcp-tooling.md +40 -0
  319. package/dist/plugins/n8n/src/skills/n8n-workflow-operator/references/validation-and-handoff.md +40 -0
  320. package/dist/plugins/n8n/src/skills/n8n-workflow-operator/references/workflow-authoring.md +45 -0
  321. package/dist/plugins/n8n/terraform/n8n/README.md +113 -0
  322. package/dist/plugins/n8n/terraform/n8n/main.tf +918 -0
  323. package/dist/plugins/n8n/terraform/n8n/outputs.tf +124 -0
  324. package/dist/plugins/n8n/terraform/n8n/scripts/sync-database.py +250 -0
  325. package/dist/plugins/n8n/terraform/n8n/scripts/test_sync_database.py +55 -0
  326. package/dist/plugins/n8n/terraform/n8n/variables.tf +354 -0
  327. package/dist/plugins/n8n/test/image-build.test.ts +118 -0
  328. package/dist/plugins/n8n/test/integrated-app-contract.test.ts +353 -0
  329. package/dist/plugins/n8n/test/manifest.test.ts +278 -0
  330. package/dist/plugins/n8n/test/package-config.test.ts +57 -0
  331. package/dist/plugins/n8n/tsconfig.json +8 -0
  332. package/dist/plugins/sendgrid/README.md +30 -0
  333. package/dist/plugins/sendgrid/package.json +22 -0
  334. package/dist/plugins/sendgrid/src/index.ts +36 -0
  335. package/dist/plugins/sendgrid/src/manifest.ts +37 -0
  336. package/dist/plugins/sendgrid/src/provider-contract.ts +14 -0
  337. package/dist/plugins/sendgrid/test/manifest.test.ts +80 -0
  338. package/dist/plugins/sendgrid/tsconfig.json +8 -0
  339. package/dist/plugins/twenty/README.md +78 -0
  340. package/dist/plugins/twenty/package.json +27 -0
  341. package/dist/plugins/twenty/scripts/__tests__/sync-thinkwork-app.test.mjs +67 -0
  342. package/dist/plugins/twenty/scripts/sync-thinkwork-app.mjs +185 -0
  343. package/dist/plugins/twenty/scripts/wire-thinkwork-workflow.mjs +658 -0
  344. package/dist/plugins/twenty/smoke/twenty-managed-app-smoke.mjs +359 -0
  345. package/dist/plugins/twenty/smoke/twenty-mcp-oauth-smoke.mjs +574 -0
  346. package/dist/plugins/twenty/src/api/cutover.ts +209 -0
  347. package/dist/plugins/twenty/src/deployment/managed-app.ts +253 -0
  348. package/dist/plugins/twenty/src/index.ts +55 -0
  349. package/dist/plugins/twenty/src/manifest.ts +259 -0
  350. package/dist/plugins/twenty/terraform/twenty/README.md +97 -0
  351. package/dist/plugins/twenty/terraform/twenty/main.tf +829 -0
  352. package/dist/plugins/twenty/terraform/twenty/outputs.tf +79 -0
  353. package/dist/plugins/twenty/terraform/twenty/variables.tf +268 -0
  354. package/dist/plugins/twenty/test/api/cutover.test.ts +183 -0
  355. package/dist/plugins/twenty/test/manifest.test.ts +463 -0
  356. package/dist/plugins/twenty/tsconfig.json +9 -0
  357. package/dist/plugins/twenty/twenty-app/.nvmrc +1 -0
  358. package/dist/plugins/twenty/twenty-app/README.md +148 -0
  359. package/dist/plugins/twenty/twenty-app/package.json +30 -0
  360. package/dist/plugins/twenty/twenty-app/src/application-config.ts +44 -0
  361. package/dist/plugins/twenty/twenty-app/src/constants/universal-identifiers.ts +18 -0
  362. package/dist/plugins/twenty/twenty-app/src/default-role.ts +24 -0
  363. package/dist/plugins/twenty/twenty-app/src/front-components/thinkwork-settings.front-component.tsx +299 -0
  364. package/dist/plugins/twenty/twenty-app/src/logic-functions/thinkwork-webhook.logic-function.ts +354 -0
  365. package/dist/plugins/twenty/twenty-app/tsconfig.json +14 -0
  366. package/dist/plugins/twenty/twenty-app/yarn.lock +4144 -0
  367. package/dist/plugins/workos-auth/package.json +22 -0
  368. package/dist/plugins/workos-auth/src/index.ts +30 -0
  369. package/dist/plugins/workos-auth/src/manifest.ts +40 -0
  370. package/dist/plugins/workos-auth/src/provider-contract.ts +39 -0
  371. package/dist/plugins/workos-auth/test/manifest.test.ts +94 -0
  372. package/dist/plugins/workos-auth/tsconfig.json +8 -0
  373. package/dist/scripts/bootstrap-workspace.sh +162 -0
  374. package/dist/scripts/post-deploy.sh +290 -0
  375. package/dist/terraform/examples/greenfield/main.tf +903 -75
  376. package/dist/terraform/examples/greenfield/terraform.tfvars.example +67 -8
  377. package/dist/terraform/modules/app/agentcore-code-interpreter/Dockerfile.sandbox-base +2 -2
  378. package/dist/terraform/modules/app/agentcore-code-interpreter/README.md +8 -9
  379. package/dist/terraform/modules/app/agentcore-code-interpreter/sandbox/sitecustomize.py +227 -0
  380. package/dist/terraform/modules/app/agentcore-code-interpreter/sandbox/test_sitecustomize.py +277 -0
  381. package/dist/terraform/modules/app/agentcore-memory/README.md +6 -6
  382. package/dist/terraform/modules/app/agentcore-memory/main.tf +1 -1
  383. package/dist/terraform/modules/app/agentcore-memory/scripts/create_or_find_memory.sh +40 -9
  384. package/dist/terraform/modules/app/agentcore-pi/README.md +61 -0
  385. package/dist/terraform/modules/app/agentcore-pi/main.tf +453 -0
  386. package/dist/terraform/modules/app/agentcore-pi/outputs.tf +38 -0
  387. package/dist/terraform/modules/app/agentcore-pi/variables.tf +145 -0
  388. package/dist/terraform/modules/app/agentcore-platform/main.tf +83 -0
  389. package/dist/terraform/modules/app/agentcore-runtime/main.tf +9 -11
  390. package/dist/terraform/modules/app/appsync-subscriptions/main.tf +5 -1
  391. package/dist/terraform/modules/app/customer-domain/main.tf +483 -0
  392. package/dist/terraform/modules/app/deployment-control-plane/README.md +47 -0
  393. package/dist/terraform/modules/app/deployment-control-plane/buildspec.yml +24 -0
  394. package/dist/terraform/modules/app/deployment-control-plane/main.tf +614 -0
  395. package/dist/terraform/modules/app/deployment-control-plane/outputs.tf +54 -0
  396. package/dist/terraform/modules/app/deployment-control-plane/runner.py +4720 -0
  397. package/dist/terraform/modules/app/deployment-control-plane/test_runner_bundle.py +3026 -0
  398. package/dist/terraform/modules/app/deployment-control-plane/variables.tf +96 -0
  399. package/dist/terraform/modules/app/hindsight-memory/README.md +25 -23
  400. package/dist/terraform/modules/app/hindsight-memory/main.tf +26 -2
  401. package/dist/terraform/modules/app/lambda-api/eval-fanout.tf +17 -50
  402. package/dist/terraform/modules/app/lambda-api/handlers.tf +1290 -679
  403. package/dist/terraform/modules/app/lambda-api/iam-grouped.tf +933 -0
  404. package/dist/terraform/modules/app/lambda-api/main.tf +14 -527
  405. package/dist/terraform/modules/app/lambda-api/mcp-oauth.tf +3 -19
  406. package/dist/terraform/modules/app/lambda-api/outputs.tf +50 -6
  407. package/dist/terraform/modules/app/lambda-api/runtime-config.tf +163 -0
  408. package/dist/terraform/modules/app/lambda-api/slack-app-secrets.tf +3 -1
  409. package/dist/terraform/modules/app/lambda-api/stripe-secrets.tf +3 -1
  410. package/dist/terraform/modules/app/lambda-api/variables.tf +240 -53
  411. package/dist/terraform/modules/app/lambda-api/workspace-events.tf +2 -25
  412. package/dist/terraform/modules/app/ses-email/main.tf +143 -30
  413. package/dist/terraform/modules/app/static-site/main.tf +4 -3
  414. package/dist/terraform/modules/app/www-dns/main.tf +45 -5
  415. package/dist/terraform/modules/app/www-dns/outputs.tf +10 -0
  416. package/dist/terraform/modules/app/www-dns/variables.tf +24 -0
  417. package/dist/terraform/modules/data/aurora-postgres/main.tf +15 -1
  418. package/dist/terraform/modules/data/compliance-exports-bucket/main.tf +1 -1
  419. package/dist/terraform/modules/data/compliance-exports-bucket/variables.tf +6 -0
  420. package/dist/terraform/modules/foundation/cognito/main.tf +167 -11
  421. package/dist/terraform/modules/foundation/cognito/outputs.tf +5 -0
  422. package/dist/terraform/modules/foundation/cognito/variables.tf +110 -0
  423. package/dist/terraform/modules/foundation/vpc/main.tf +45 -3
  424. package/dist/terraform/modules/foundation/vpc/outputs.tf +20 -0
  425. package/dist/terraform/modules/foundation/vpc/variables.tf +18 -0
  426. package/dist/terraform/modules/thinkwork/README.md +71 -0
  427. package/dist/terraform/modules/thinkwork/main.tf +1325 -174
  428. package/dist/terraform/modules/thinkwork/outputs.tf +457 -24
  429. package/dist/terraform/modules/thinkwork/variables.tf +1169 -93
  430. package/dist/terraform/schema.graphql +82 -9
  431. package/dist/workspace-defaults/files/AGENTS.md +344 -0
  432. package/dist/workspace-defaults/files/CONTEXT.md +8 -0
  433. package/dist/workspace-defaults/files/GUARDRAILS.md +51 -0
  434. package/dist/workspace-defaults/files/MEMORY_GUIDE.md +65 -0
  435. package/dist/workspace-defaults/files/ROUTER.md +24 -0
  436. package/dist/workspace-defaults/files/SPACE.md +62 -0
  437. package/dist/workspace-defaults/files/TOOLS.md +65 -0
  438. package/dist/workspace-defaults/files/USER.md +40 -0
  439. package/dist/workspace-defaults/files/mcp.json +3 -0
  440. package/dist/workspace-defaults/files/memory/contacts.md +13 -0
  441. package/dist/workspace-defaults/files/memory/lessons.md +13 -0
  442. package/dist/workspace-defaults/files/memory/preferences.md +12 -0
  443. package/dist/workspace-defaults/files/skills/.gitkeep +1 -0
  444. package/dist/workspace-defaults/files/skills/artifact-builder/SKILL.md +79 -0
  445. package/dist/workspace-defaults/files/skills/artifact-builder/references/crm-dashboard.md +166 -0
  446. package/dist/workspace-defaults/files/skills/automation-loop-designer/SKILL.md +120 -0
  447. package/dist/workspace-defaults/files/skills/skill-creator/LICENSE.txt +202 -0
  448. package/dist/workspace-defaults/files/skills/skill-creator/SKILL.md +485 -0
  449. package/dist/workspace-defaults/files/skills/skill-creator/UPSTREAM.json +124 -0
  450. package/dist/workspace-defaults/files/skills/skill-creator/agents/analyzer.md +274 -0
  451. package/dist/workspace-defaults/files/skills/skill-creator/agents/comparator.md +202 -0
  452. package/dist/workspace-defaults/files/skills/skill-creator/agents/grader.md +223 -0
  453. package/dist/workspace-defaults/files/skills/skill-creator/assets/eval_review.html +146 -0
  454. package/dist/workspace-defaults/files/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  455. package/dist/workspace-defaults/files/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  456. package/dist/workspace-defaults/files/skills/skill-creator/references/schemas.md +430 -0
  457. package/dist/workspace-defaults/files/skills/skill-creator/scripts/__init__.py +0 -0
  458. package/dist/workspace-defaults/files/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  459. package/dist/workspace-defaults/files/skills/skill-creator/scripts/generate_report.py +326 -0
  460. package/dist/workspace-defaults/files/skills/skill-creator/scripts/improve_description.py +247 -0
  461. package/dist/workspace-defaults/files/skills/skill-creator/scripts/package_skill.py +136 -0
  462. package/dist/workspace-defaults/files/skills/skill-creator/scripts/quick_validate.py +103 -0
  463. package/dist/workspace-defaults/files/skills/skill-creator/scripts/run_eval.py +310 -0
  464. package/dist/workspace-defaults/files/skills/skill-creator/scripts/run_loop.py +328 -0
  465. package/dist/workspace-defaults/files/skills/skill-creator/scripts/utils.py +47 -0
  466. package/package.json +1 -1
  467. package/dist/terraform/modules/app/agentcore-flue/README.md +0 -58
  468. package/dist/terraform/modules/app/agentcore-flue/main.tf +0 -323
  469. package/dist/terraform/modules/app/agentcore-flue/outputs.tf +0 -23
  470. package/dist/terraform/modules/app/agentcore-flue/variables.tf +0 -97
  471. package/dist/terraform/modules/app/computer-runtime/README.md +0 -15
  472. package/dist/terraform/modules/app/computer-runtime/main.tf +0 -406
  473. package/dist/terraform/modules/app/computer-runtime/outputs.tf +0 -75
  474. package/dist/terraform/modules/app/computer-runtime/variables.tf +0 -66
@@ -13,12 +13,59 @@ account_id = "123456789012" # your AWS account ID
13
13
  database_engine = "rds-postgres"
14
14
 
15
15
  # Memory:
16
- # AgentCore managed memory is always on every agent gets automatic
17
- # per-turn retention with zero config. Uncomment the line below to
18
- # enable Hindsight as an optional add-on (adds an ECS+ALB service for
19
- # semantic + entity-graph + cross-encoder retrieval tools alongside the
20
- # built-in remember/recall/forget tools).
21
- # enable_hindsight = true
16
+ # Hindsight is the canonical user and Space memory provider for full
17
+ # ThinkWork installs and is enabled by default. Set enable_hindsight = false
18
+ # and memory_engine = "agentcore" only for explicit low-cost/development
19
+ # AgentCore-only deployments.
20
+ # enable_hindsight = false
21
+ # memory_engine = "agentcore"
22
+
23
+ # Managed applications:
24
+ # Twenty CRM is optional. First enable should set both booleans true after
25
+ # the deployment workflow has created the dedicated database URL secret and
26
+ # encryption-key secret. Later disable should leave twenty_provisioned=true
27
+ # and set twenty_runtime_enabled=false so CRM data/storage/cache are retained.
28
+ # Full cleanup should set both booleans false through the Managed
29
+ # Applications Destroy action so the deploy workflow can also drop the
30
+ # dedicated database and delete Twenty secrets after Terraform teardown.
31
+ #
32
+ # twenty_provisioned = false
33
+ # twenty_runtime_enabled = false
34
+ # twenty_image_uri = "twentycrm/twenty@sha256:..."
35
+ # twenty_db_username = "thinkwork_twenty"
36
+ # twenty_db_name = "thinkwork_twenty"
37
+ # twenty_db_url_secret_arn = "arn:aws:secretsmanager:us-east-1:123456789012:secret:thinkwork/dev/twenty/db-url-..."
38
+ # twenty_encryption_key_secret_arn = "arn:aws:secretsmanager:us-east-1:123456789012:secret:thinkwork/dev/twenty/encryption-key-..."
39
+ # twenty_public_url = "" # empty derives https://crm.<www_domain>
40
+ # twenty_certificate_arn = "" # empty creates a dedicated crm.<www_domain> certificate
41
+ # twenty_email_from_address = "" # empty derives noreply@ses_inbound_domain for SES SMTP
42
+ # twenty_email_from_name = "ThinkWork CRM"
43
+ #
44
+ # n8n is optional. First enable should set both booleans true after the
45
+ # managed-app workflow has prepared the dedicated thinkwork_n8n database URL
46
+ # secret, N8N_ENCRYPTION_KEY secret, shared operator credential, tenant
47
+ # service credential, wrapper image, and retained artifact bucket. Later
48
+ # disable should leave n8n_provisioned=true and set
49
+ # n8n_runtime_enabled=false so workflow data, credentials, cache, and
50
+ # artifacts are retained.
51
+ #
52
+ # n8n_provisioned = false
53
+ # n8n_runtime_enabled = false
54
+ # n8n_image_uri = "123456789012.dkr.ecr.us-east-1.amazonaws.com/thinkwork-n8n@sha256:..."
55
+ # n8n_database_admin_secret_arn = "arn:aws:secretsmanager:us-east-1:123456789012:secret:thinkwork/dev/database-admin-..."
56
+ # n8n_database_url_secret_arn = "arn:aws:secretsmanager:us-east-1:123456789012:secret:thinkwork/dev/n8n/database-url-..."
57
+ # n8n_database_username = "thinkwork_n8n"
58
+ # n8n_database_name = "thinkwork_n8n"
59
+ # n8n_encryption_key_secret_arn = "arn:aws:secretsmanager:us-east-1:123456789012:secret:thinkwork/dev/n8n/encryption-key-..."
60
+ # n8n_operator_secret_arn = "arn:aws:secretsmanager:us-east-1:123456789012:secret:thinkwork/dev/n8n/operator-..."
61
+ # n8n_service_credential_secret_arn = "arn:aws:secretsmanager:us-east-1:123456789012:secret:thinkwork/dev/n8n/service-credential-..."
62
+ # n8n_agent_step_bridge_credential_secret_arn = "arn:aws:secretsmanager:us-east-1:123456789012:secret:thinkwork/dev/n8n/agent-step-bridge-credential-..."
63
+ # n8n_storage_bucket_name = "thinkwork-dev-n8n"
64
+ # n8n_container_port = 5678
65
+ # n8n_cache_engine = "valkey"
66
+ # n8n_domain = "" # empty derives n8n.<www_domain>
67
+ # n8n_public_url = "" # empty derives https://n8n.<www_domain>
68
+ # n8n_certificate_arn = "" # empty creates a dedicated n8n.<www_domain> certificate
22
69
 
23
70
  # Database master password — use a strong password
24
71
  db_password = "CHANGE_ME_strong_password_here"
@@ -27,8 +74,9 @@ db_password = "CHANGE_ME_strong_password_here"
27
74
  # google_oauth_client_id = ""
28
75
  # google_oauth_client_secret = ""
29
76
 
30
- # Pre-signup Lambda (optional — leave empty if not using custom pre-signup logic)
31
- # pre_signup_lambda_zip = "./lambdas/pre-signup.zip"
77
+ # Cognito trigger Lambdas (optional — leave empty if not using custom auth logic)
78
+ # pre_signup_lambda_zip = "./lambdas/cognito-pre-signup.zip"
79
+ # cognito_custom_auth_lambda_zip = "./lambdas/cognito-custom-auth.zip"
32
80
 
33
81
  # Lambda artifacts:
34
82
  # - Source checkout deploys can set lambda_zips_dir after `pnpm build:lambdas`.
@@ -65,3 +113,14 @@ db_password = "CHANGE_ME_strong_password_here"
65
113
  # variable. NEVER put the token in this file.
66
114
  # www_domain = "thinkwork.ai"
67
115
  # cloudflare_zone_id = "your-cloudflare-zone-id"
116
+
117
+ # Tenant-scoped Space email addresses (optional).
118
+ # Keep the legacy agents.thinkwork.ai domain configured until retirement
119
+ # notices are no longer needed, then add tenant slugs before announcing
120
+ # <space>@<tenant>.thinkwork.ai addresses. Terraform creates one SES receiving
121
+ # identity and delegated Route53 subzone per tenant slug, then publishes NS
122
+ # delegation records in the Cloudflare parent zone above.
123
+ #
124
+ # ses_inbound_domain = "agents.thinkwork.ai"
125
+ # ses_parent_domain = "thinkwork.ai"
126
+ # tenant_slugs = ["dev"]
@@ -9,7 +9,7 @@
9
9
  # Tags are immutable; a bump ships as a reviewable PR.
10
10
  #
11
11
  # Build context is the repository root so the COPY line can reach the
12
- # Python source under packages/agentcore-strands/agent-container-sandbox/.
12
+ # module-owned Python source below.
13
13
  #
14
14
  # docker build -f terraform/modules/app/agentcore-code-interpreter/Dockerfile.sandbox-base .
15
15
 
@@ -47,7 +47,7 @@ RUN pip install --no-cache-dir \
47
47
  # (and before the framework traceback on cold start). See the module
48
48
  # docstring for the honestly-scoped invariant and named residual gaps.
49
49
  # ---------------------------------------------------------------------------
50
- COPY packages/agentcore-strands/agent-container-sandbox/sitecustomize.py \
50
+ COPY terraform/modules/app/agentcore-code-interpreter/sandbox/sitecustomize.py \
51
51
  /usr/local/lib/python3.12/site-packages/sitecustomize.py
52
52
 
53
53
  # ---------------------------------------------------------------------------
@@ -19,16 +19,15 @@ stops at the substrate everything else depends on.
19
19
 
20
20
  ## Files
21
21
 
22
- | File | Purpose |
23
- |---|---|
24
- | `main.tf` | ECR + outputs. No per-tenant resources. |
25
- | `Dockerfile.sandbox-base` | Python 3.12 + pinned libs + `sitecustomize.py`. Build context is the **repo root** so the COPY can reach `packages/agentcore-strands/agent-container-sandbox/sitecustomize.py`. |
26
- | `scripts/build_and_push_sandbox_base.sh` | CI builds + pushes. Not called from Terraform — image lifecycle is a reviewable-PR concern. |
22
+ | File | Purpose |
23
+ | ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
24
+ | `main.tf` | ECR + outputs. No per-tenant resources. |
25
+ | `Dockerfile.sandbox-base` | Python 3.12 + pinned libs + `sitecustomize.py`. Build context is the **repo root** so the COPY can reach the module-owned sandbox helper. |
26
+ | `scripts/build_and_push_sandbox_base.sh` | CI builds + pushes. Not called from Terraform — image lifecycle is a reviewable-PR concern. |
27
27
 
28
28
  The Python source `sitecustomize.py` and its pytest suite `test_sitecustomize.py`
29
- live under `packages/agentcore-strands/agent-container-sandbox/` (colocated with
30
- the rest of the Strands agent-container Python, per handoff P2 #10). That's
31
- where `uv run pytest` finds them without extra config.
29
+ live under `terraform/modules/app/agentcore-code-interpreter/sandbox/`, next to
30
+ the sandbox base image they protect.
32
31
 
33
32
  ## What this module does **not** do
34
33
 
@@ -39,7 +38,7 @@ where `uv run pytest` finds them without extra config.
39
38
  ## Bumping the image
40
39
 
41
40
  1. Edit `Dockerfile.sandbox-base` (pin a new pandas / add a lib / etc.).
42
- 2. Edit `packages/agentcore-strands/agent-container-sandbox/sitecustomize.py` if the R13 invariant or its coverage gaps shift.
41
+ 2. Edit `terraform/modules/app/agentcore-code-interpreter/sandbox/sitecustomize.py` if the R13 invariant or its coverage gaps shift.
43
42
  3. PR. CI runs `pytest` on the scrubber plus a build-then-startup-assertion smoke test.
44
43
  4. After merge, `build_and_push_sandbox_base.sh` tags with the merge-commit SHA.
45
44
 
@@ -0,0 +1,227 @@
1
+ """sitecustomize — primary R13 token redactor for the AgentCore sandbox base image.
2
+
3
+ Python auto-imports any module named ``sitecustomize`` during interpreter
4
+ startup (before user code, before the preamble, before framework tracebacks on
5
+ cold start). This file installs a stdio write-wrapper keyed on a session-scoped
6
+ set of token values so no token leaks to stdout / stderr via Python-stdio
7
+ writes.
8
+
9
+ The invariant is honestly scoped per the brainstorm's R13 (as aligned in
10
+ docs/brainstorms/2026-04-22-agentcore-code-sandbox-requirements.md):
11
+
12
+ "no token value reaches a persisted log ... via Python-stdio-mediated writes"
13
+
14
+ Bytes that bypass Python stdio (``os.write(fd, ...)``, subprocesses inheriting
15
+ fds, C extensions, multiprocessing children) are the named residual class
16
+ covered by the Unit 12 CloudWatch subscription-filter backstop for known
17
+ OAuth prefixes, not by this module.
18
+
19
+ Public API, callable from the sandbox preamble:
20
+ register_token(value: str) -> None
21
+ register_tokens(values: Iterable[str]) -> None
22
+ clear_tokens() -> None
23
+ installed() -> bool
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ import base64
29
+ import binascii
30
+ import os
31
+ import sys
32
+ import urllib.parse
33
+ from collections.abc import Iterable
34
+ from typing import Any
35
+
36
+ # ---------------------------------------------------------------------------
37
+ # Module state
38
+ # ---------------------------------------------------------------------------
39
+
40
+ # Every unique byte-sequence we redact. Populated by ``register_token`` — each
41
+ # registered token expands into its cleartext, standard base64, URL-safe
42
+ # base64, URL-encoded, and hex forms (only the forms whose length is at least
43
+ # MIN_TOKEN_LEN, to avoid redacting short accidental matches like "AQ").
44
+ _redactions: set[bytes] = set()
45
+
46
+ # Redaction placeholder. Length unimportant — stream layout survives because
47
+ # writes stay synchronous.
48
+ _REDACTION = b"<redacted>"
49
+
50
+ # Forms shorter than this are rejected — redacting 3-character strings is the
51
+ # shape of a wildcard bug, not a security control.
52
+ MIN_TOKEN_LEN = 12
53
+
54
+ # Rolling-suffix buffer size. Set at ``register_token`` time to
55
+ # max(existing, 2 * len(new_token_form)). The wrapper keeps this many bytes
56
+ # from the previous write and prepends them to the current write before
57
+ # searching, so a token split across two ``write()`` calls is caught as long
58
+ # as neither split half exceeds the buffer. Adversarial fragmentation at
59
+ # arbitrary positions is a named residual (see R13).
60
+ _rolling_buffer_size: int = 0
61
+
62
+
63
+ def _expand(value: str) -> list[bytes]:
64
+ """Return the encoded forms of a token value we treat as equivalent.
65
+
66
+ Each form is added to the redaction set so ``print(base64.b64encode(token))``
67
+ and the cleartext ``print(token)`` are both scrubbed.
68
+ """
69
+ if not value:
70
+ return []
71
+ raw = value.encode("utf-8")
72
+ forms: list[bytes] = []
73
+
74
+ def maybe_add(candidate: bytes) -> None:
75
+ if len(candidate) >= MIN_TOKEN_LEN:
76
+ forms.append(candidate)
77
+
78
+ maybe_add(raw)
79
+ maybe_add(base64.b64encode(raw).rstrip(b"="))
80
+ maybe_add(base64.b64encode(raw))
81
+ maybe_add(base64.urlsafe_b64encode(raw).rstrip(b"="))
82
+ maybe_add(base64.urlsafe_b64encode(raw))
83
+ maybe_add(urllib.parse.quote(value, safe="").encode("ascii"))
84
+ maybe_add(binascii.hexlify(raw))
85
+ return forms
86
+
87
+
88
+ def register_token(value: str) -> None:
89
+ """Add a token (and its derived encodings) to the redaction set.
90
+
91
+ Safe to call multiple times with the same value. No-op for empty values.
92
+ """
93
+ global _rolling_buffer_size
94
+ for form in _expand(value):
95
+ _redactions.add(form)
96
+ required = 2 * len(form)
97
+ if required > _rolling_buffer_size:
98
+ _rolling_buffer_size = required
99
+
100
+
101
+ def register_tokens(values: Iterable[str]) -> None:
102
+ for v in values:
103
+ register_token(v)
104
+
105
+
106
+ def clear_tokens() -> None:
107
+ """Drop every registered token. Called at session teardown by the container."""
108
+ global _rolling_buffer_size
109
+ _redactions.clear()
110
+ _rolling_buffer_size = 0
111
+
112
+
113
+ # ---------------------------------------------------------------------------
114
+ # Stdio wrapper
115
+ # ---------------------------------------------------------------------------
116
+
117
+
118
+ def _redact(chunk: bytes, tail_buffer: bytearray) -> tuple[bytes, bytearray]:
119
+ """Return (scrubbed_output_chunk, new_tail_buffer).
120
+
121
+ The tail buffer holds the trailing N bytes of the previous write so we can
122
+ catch tokens split across write boundaries. The output we emit is the part
123
+ of ``tail_buffer + chunk`` that is safely past the trailing window; the
124
+ suffix stays in the new tail for the next call.
125
+ """
126
+ if not _redactions:
127
+ return chunk, tail_buffer
128
+
129
+ combined = bytes(tail_buffer) + chunk
130
+ for form in _redactions:
131
+ combined = combined.replace(form, _REDACTION)
132
+
133
+ if _rolling_buffer_size and len(combined) > _rolling_buffer_size:
134
+ emit = combined[:-_rolling_buffer_size]
135
+ new_tail = bytearray(combined[-_rolling_buffer_size:])
136
+ else:
137
+ emit = b""
138
+ new_tail = bytearray(combined)
139
+
140
+ return emit, new_tail
141
+
142
+
143
+ class _RedactingStream:
144
+ """Wraps sys.stdout / sys.stderr's underlying buffer with a redactor.
145
+
146
+ Intercepts both ``write(str)`` (TextIOBase) and ``.buffer.write(bytes)``
147
+ paths so ``print(...)``, ``sys.stdout.write(...)``, and
148
+ ``sys.stdout.buffer.write(...)`` all flow through the scrubber.
149
+ """
150
+
151
+ def __init__(self, wrapped: Any, name: str) -> None:
152
+ self._wrapped = wrapped
153
+ self._name = name
154
+ self._tail = bytearray()
155
+ # AgentCore writes to stdout/stderr line-buffered; we flush our tail
156
+ # on every newline-terminated write so output appears promptly.
157
+
158
+ def write(self, data: Any) -> int:
159
+ if isinstance(data, str):
160
+ payload = data.encode("utf-8", errors="replace")
161
+ wrote_str = True
162
+ elif isinstance(data, (bytes, bytearray, memoryview)):
163
+ payload = bytes(data)
164
+ wrote_str = False
165
+ else:
166
+ # Defer unknown types to the wrapped object — let it raise.
167
+ return self._wrapped.write(data)
168
+
169
+ emit, self._tail = _redact(payload, self._tail)
170
+ # A newline forces a tail flush so output doesn't lag arbitrarily when
171
+ # no new writes arrive. This is a UX concession, not a security one —
172
+ # redaction is complete whether we flush or not.
173
+ if b"\n" in payload:
174
+ emit = emit + bytes(self._tail)
175
+ self._tail = bytearray()
176
+
177
+ if not emit:
178
+ return len(data) if wrote_str else len(payload)
179
+
180
+ if wrote_str:
181
+ self._wrapped.write(emit.decode("utf-8", errors="replace"))
182
+ else:
183
+ # TextIOWrapper.write raises on bytes; prefer the underlying buffer.
184
+ buf = getattr(self._wrapped, "buffer", None)
185
+ if buf is not None:
186
+ buf.write(emit)
187
+ else:
188
+ self._wrapped.write(emit)
189
+ return len(data) if wrote_str else len(payload)
190
+
191
+ def flush(self) -> None:
192
+ if self._tail:
193
+ data = bytes(self._tail)
194
+ self._tail = bytearray()
195
+ buf = getattr(self._wrapped, "buffer", None)
196
+ if buf is not None:
197
+ buf.write(data)
198
+ else:
199
+ self._wrapped.write(data.decode("utf-8", errors="replace"))
200
+ self._wrapped.flush()
201
+
202
+ # Forward any other attribute access (fileno, isatty, encoding, etc.) so
203
+ # libraries that introspect the stream still see what they expect.
204
+ def __getattr__(self, item: str) -> Any:
205
+ return getattr(self._wrapped, item)
206
+
207
+
208
+ _installed = False
209
+
210
+
211
+ def installed() -> bool:
212
+ return _installed
213
+
214
+
215
+ def _install() -> None:
216
+ global _installed
217
+ if _installed:
218
+ return
219
+ sys.stdout = _RedactingStream(sys.stdout, "stdout")
220
+ sys.stderr = _RedactingStream(sys.stderr, "stderr")
221
+ _installed = True
222
+
223
+
224
+ # Install unconditionally on import. Disable only for a pytest diagnostic
225
+ # marker the test suite can opt out of (set THINKWORK_SANDBOX_SCRUBBER=off).
226
+ if os.environ.get("THINKWORK_SANDBOX_SCRUBBER", "on") != "off":
227
+ _install()
@@ -0,0 +1,277 @@
1
+ """Unit tests for the AgentCore sandbox base-image stdio token redactor.
2
+
3
+ Tests hit ``_RedactingStream`` directly with a test-owned stream instead of
4
+ mutating ``sys.stdout`` — that side-steps pytest's capture machinery, which
5
+ owns sys.stdout at test time and would otherwise see writes before the
6
+ wrapper does. Correctness of the sys.stdout replacement path is proven by
7
+ a separate end-to-end test that runs the module as a subprocess with its
8
+ auto-install path active.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import base64
14
+ import binascii
15
+ import importlib.util
16
+ import io
17
+ import os
18
+ import subprocess
19
+ import sys
20
+ import urllib.parse
21
+
22
+ import pytest
23
+
24
+ os.environ["THINKWORK_SANDBOX_SCRUBBER"] = "off"
25
+
26
+ _HERE = os.path.dirname(os.path.abspath(__file__))
27
+ _SPEC = importlib.util.spec_from_file_location(
28
+ "sandbox_base_sitecustomize",
29
+ os.path.join(_HERE, "sitecustomize.py"),
30
+ )
31
+ assert _SPEC is not None and _SPEC.loader is not None
32
+ sc = importlib.util.module_from_spec(_SPEC)
33
+ _SPEC.loader.exec_module(sc)
34
+
35
+
36
+ class _StringSink:
37
+ """Minimal sys.stdout-shaped target: the wrapper writes strings into us,
38
+ we collect them as UTF-8 bytes. Also exposes ``.buffer`` so bytes-path
39
+ writes have a path through the wrapper."""
40
+
41
+ def __init__(self) -> None:
42
+ self.str_bytes = bytearray()
43
+ self.buffer = io.BytesIO()
44
+ self.name = "test-sink"
45
+ self.encoding = "utf-8"
46
+ self.errors = "strict"
47
+
48
+ def write(self, s: str) -> int:
49
+ self.str_bytes.extend(s.encode("utf-8", errors="replace"))
50
+ return len(s)
51
+
52
+ def flush(self) -> None:
53
+ pass
54
+
55
+ def captured(self) -> str:
56
+ combined = bytes(self.str_bytes) + self.buffer.getvalue()
57
+ return combined.decode("utf-8", errors="replace")
58
+
59
+
60
+ @pytest.fixture
61
+ def wrapper() -> tuple:
62
+ """A fresh redactor wrapping a new sink, with an empty token set."""
63
+ sc.clear_tokens()
64
+ sink = _StringSink()
65
+ stream = sc._RedactingStream(sink, "test-stdout") # type: ignore[attr-defined]
66
+ yield stream, sink
67
+ stream.flush()
68
+ sc.clear_tokens()
69
+
70
+
71
+ def test_cleartext_is_redacted(wrapper):
72
+ stream, sink = wrapper
73
+ token = "ghp_abc123abc123abc123"
74
+ sc.register_token(token)
75
+ stream.write(f"the token was {token} and not noticeable\n")
76
+ stream.flush()
77
+ text = sink.captured()
78
+ assert token not in text
79
+ assert "<redacted>" in text
80
+ assert "the token was" in text
81
+
82
+
83
+ def test_base64_form_is_redacted(wrapper):
84
+ stream, sink = wrapper
85
+ token = "ghp_abc123abc123abc123"
86
+ sc.register_token(token)
87
+ encoded = base64.b64encode(token.encode()).decode()
88
+ stream.write(f"encoded={encoded}\n")
89
+ stream.flush()
90
+ text = sink.captured()
91
+ assert encoded not in text
92
+ assert "<redacted>" in text
93
+
94
+
95
+ def test_urlsafe_base64_form_is_redacted(wrapper):
96
+ stream, sink = wrapper
97
+ token = "some_opaque_secret_for_urlsafe"
98
+ sc.register_token(token)
99
+ encoded = base64.urlsafe_b64encode(token.encode()).decode()
100
+ stream.write(f"encoded={encoded}\n")
101
+ stream.flush()
102
+ text = sink.captured()
103
+ assert encoded not in text
104
+ assert "<redacted>" in text
105
+
106
+
107
+ def test_url_encoded_form_is_redacted(wrapper):
108
+ stream, sink = wrapper
109
+ token = "token with spaces & special=chars"
110
+ sc.register_token(token)
111
+ encoded = urllib.parse.quote(token, safe="")
112
+ stream.write(f"in_url={encoded}\n")
113
+ stream.flush()
114
+ text = sink.captured()
115
+ assert encoded not in text
116
+ assert "<redacted>" in text
117
+
118
+
119
+ def test_hex_form_is_redacted(wrapper):
120
+ stream, sink = wrapper
121
+ token = "0123456789abcdef01234567"
122
+ sc.register_token(token)
123
+ encoded = binascii.hexlify(token.encode()).decode()
124
+ stream.write(f"hex={encoded}\n")
125
+ stream.flush()
126
+ text = sink.captured()
127
+ assert encoded not in text
128
+ assert "<redacted>" in text
129
+
130
+
131
+ def test_register_after_first_write_still_redacts_subsequent(wrapper):
132
+ stream, sink = wrapper
133
+ stream.write("before registration\n")
134
+ token = "late_registered_token_value"
135
+ sc.register_token(token)
136
+ stream.write(f"after {token} registration\n")
137
+ stream.flush()
138
+ text = sink.captured()
139
+ assert "before registration" in text
140
+ assert token not in text
141
+ assert "<redacted>" in text
142
+
143
+
144
+ def test_split_write_across_boundary_is_caught(wrapper):
145
+ stream, sink = wrapper
146
+ token = "ghp_splitfragmenttokenvalue"
147
+ sc.register_token(token)
148
+ stream.write(token[:10])
149
+ stream.write(token[10:])
150
+ stream.write("\n")
151
+ stream.flush()
152
+ text = sink.captured()
153
+ assert token not in text
154
+ assert "<redacted>" in text
155
+
156
+
157
+ def test_short_token_below_min_len_is_ignored(wrapper):
158
+ """Redacting 3-char strings would produce wildcard false-positives."""
159
+ stream, sink = wrapper
160
+ sc.register_token("AQ")
161
+ stream.write("AQ should appear unchanged because AQ is too short to redact\n")
162
+ stream.flush()
163
+ text = sink.captured()
164
+ assert "AQ" in text
165
+ assert "<redacted>" not in text
166
+
167
+
168
+ def test_bytes_path_through_buffer(wrapper):
169
+ stream, sink = wrapper
170
+ token = "some_token_value_we_registered"
171
+ sc.register_token(token)
172
+ # Write bytes through the wrapper — it routes into sink.buffer.
173
+ stream.write(b"\x00\x01\x02binary with " + token.encode() + b" embedded\n")
174
+ stream.flush()
175
+ text = sink.captured()
176
+ assert token not in text
177
+ assert "<redacted>" in text
178
+ assert "binary with" in text
179
+
180
+
181
+ def test_clear_tokens_disables_redaction_for_later_writes(wrapper):
182
+ stream, sink = wrapper
183
+ token = "a_token_that_will_be_cleared_soon"
184
+ sc.register_token(token)
185
+ stream.write(f"before clear: {token}\n")
186
+ sc.clear_tokens()
187
+ stream.write(f"after clear: {token}\n")
188
+ stream.flush()
189
+ text = sink.captured()
190
+ assert text.count("<redacted>") == 1
191
+ assert text.count(token) == 1
192
+
193
+
194
+ def test_register_tokens_plural_is_equivalent(wrapper):
195
+ stream, sink = wrapper
196
+ sc.register_tokens(["first_registered_token_abc", "second_registered_token_def"])
197
+ stream.write("first_registered_token_abc / second_registered_token_def\n")
198
+ stream.flush()
199
+ text = sink.captured()
200
+ assert "first_registered_token_abc" not in text
201
+ assert "second_registered_token_def" not in text
202
+ assert text.count("<redacted>") >= 2
203
+
204
+
205
+ def test_empty_token_is_ignored(wrapper):
206
+ stream, sink = wrapper
207
+ sc.register_token("")
208
+ stream.write("nothing to redact here\n")
209
+ stream.flush()
210
+ text = sink.captured()
211
+ assert "nothing to redact here" in text
212
+ assert "<redacted>" not in text
213
+
214
+
215
+ def test_no_crash_on_raw_bytes_without_matching_token(wrapper):
216
+ stream, sink = wrapper
217
+ sc.register_token("something_registered_but_not_present")
218
+ stream.write(b"\x00\x01\x02binary bytes\n")
219
+ stream.flush()
220
+ text = sink.captured()
221
+ assert "binary bytes" in text
222
+
223
+
224
+ # --- End-to-end: the auto-install path ---------------------------------------
225
+ #
226
+ # Tests above exercise _RedactingStream directly, which is fine for the
227
+ # redaction logic itself but bypasses the sitecustomize auto-install step
228
+ # that replaces sys.stdout on interpreter startup. This subprocess test
229
+ # proves that step works — a fresh Python process, with PYTHONPATH pointed
230
+ # at the module directory and THINKWORK_SANDBOX_SCRUBBER unset, installs
231
+ # the wrapper on its own and redacts a registered token before stdout is
232
+ # flushed.
233
+
234
+
235
+ def test_auto_install_redacts_on_fresh_interpreter(tmp_path):
236
+ script = tmp_path / "run.py"
237
+ script.write_text(
238
+ """
239
+ import sys, sitecustomize
240
+ sitecustomize.register_token("ghp_autoInstallValueTokenX")
241
+ print("auto-install redacts ghp_autoInstallValueTokenX mid-line here")
242
+ """.strip()
243
+ )
244
+ env = os.environ.copy()
245
+ # Strip our opt-out so sitecustomize installs on import.
246
+ env.pop("THINKWORK_SANDBOX_SCRUBBER", None)
247
+ # Prepend the module dir so Python's startup hook finds our
248
+ # sitecustomize.py before any installed one.
249
+ env["PYTHONPATH"] = _HERE + os.pathsep + env.get("PYTHONPATH", "")
250
+ out = subprocess.run(
251
+ [sys.executable, str(script)],
252
+ env=env,
253
+ check=True,
254
+ capture_output=True,
255
+ text=True,
256
+ )
257
+ assert "ghp_autoInstallValueTokenX" not in out.stdout
258
+ assert "<redacted>" in out.stdout
259
+ assert "auto-install redacts" in out.stdout
260
+
261
+
262
+ def test_installed_reports_true_after_auto_install(tmp_path):
263
+ """Probe ``installed()`` from a fresh interpreter — confirms the startup
264
+ hook ran (and set the flag)."""
265
+ script = tmp_path / "run.py"
266
+ script.write_text("import sitecustomize; print(sitecustomize.installed())")
267
+ env = os.environ.copy()
268
+ env.pop("THINKWORK_SANDBOX_SCRUBBER", None)
269
+ env["PYTHONPATH"] = _HERE + os.pathsep + env.get("PYTHONPATH", "")
270
+ out = subprocess.run(
271
+ [sys.executable, str(script)],
272
+ env=env,
273
+ check=True,
274
+ capture_output=True,
275
+ text=True,
276
+ )
277
+ assert out.stdout.strip() == "True"
@@ -1,13 +1,13 @@
1
1
  # AgentCore Memory — App Module
2
2
 
3
3
  Provisions an AWS Bedrock AgentCore Memory resource with the four strategies
4
- the thinkwork Strands agent container uses for automatic retention:
4
+ the ThinkWork AgentCore runtime uses for automatic retention:
5
5
 
6
- | Strategy | Namespace template | Purpose |
7
- |-------------|------------------------------|------------------------------------------|
8
- | semantic | `assistant_{actorId}` | Cross-thread facts about the user |
9
- | preferences | `preferences_{actorId}` | User-stated preferences |
10
- | summaries | `session_{sessionId}` | Per-thread rolling summaries |
6
+ | Strategy | Namespace template | Purpose |
7
+ | ----------- | -------------------------------- | ------------------------------------ |
8
+ | semantic | `assistant_{actorId}` | Cross-thread facts about the user |
9
+ | preferences | `preferences_{actorId}` | User-stated preferences |
10
+ | summaries | `session_{sessionId}` | Per-thread rolling summaries |
11
11
  | episodes | `episodes_{actorId}/{sessionId}` | Episodic memory of past interactions |
12
12
 
13
13
  Automatic retention is wired in the agent container: every turn emits a
@@ -2,7 +2,7 @@
2
2
  # AgentCore Memory — App Module
3
3
  #
4
4
  # Provisions an AWS Bedrock AgentCore Memory resource with the four strategies
5
- # the Strands agent container expects (semantic, preferences, summaries,
5
+ # the ThinkWork AgentCore runtime expects (semantic, preferences, summaries,
6
6
  # episodes). The resource is always created — AgentCore managed memory is
7
7
  # on by default so every agent gets automatic per-turn retention into
8
8
  # semantic / preference / summary / episode strategies without any tool-