thinkwork-cli 0.12.16 → 0.13.0

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 (149) hide show
  1. package/dist/cli.js +517 -10403
  2. package/dist/commands/enterprise/templates/deploy-repo/docs/runbook.md +3 -8
  3. package/dist/commands/enterprise/templates/deploy-repo/terraform/main.tf +1 -184
  4. package/dist/drizzle/0050_brain_v0_entity_subtype.sql +2 -2
  5. package/dist/drizzle/0051_brain_v0_tenant_entity_pages.sql +6 -6
  6. package/dist/drizzle/0052_brain_v0_external_refs.sql +2 -2
  7. package/dist/drizzle/0053_brain_v0_unresolved_mentions_subtype.sql +2 -2
  8. package/dist/drizzle/0145_knowledge_graph_thread_ingest.sql +14 -14
  9. package/dist/drizzle/0146_knowledge_graph_source_scope.sql +1 -1
  10. package/dist/drizzle/0157_knowledge_graph_observations_source.sql +2 -2
  11. package/dist/drizzle/0158_wiki_tenant_scope.sql +1 -1
  12. package/dist/drizzle/0165_plugin_premium_entitlements.sql +2 -2
  13. package/dist/drizzle/{0166_company_brain_substrate_contract.sql → 0166_brain_substrate_contract.sql} +9 -9
  14. package/dist/drizzle/{0167_company_brain_artifact_manifest_runtime.sql → 0167_brain_artifact_manifest_runtime.sql} +5 -5
  15. package/dist/drizzle/0168_eval_skill_gate.sql +1 -1
  16. package/dist/drizzle/0183_okf_artifact_manifests.sql +1 -1
  17. package/dist/drizzle/0200_eval_results_execution_tier.sql +40 -0
  18. package/dist/drizzle/0201_brain_dream_runs.sql +72 -0
  19. package/dist/drizzle/0202_backfill_thread_participants_from_senders.sql +110 -0
  20. package/dist/drizzle/0203_threads_mode_override.sql +61 -0
  21. package/dist/drizzle/0204_thread_turns_triggering_message_id.sql +48 -0
  22. package/dist/drizzle/0205_routines_git_python.sql +185 -0
  23. package/dist/drizzle/0206_agent_loop_versions_routine_actions.sql +40 -0
  24. package/dist/drizzle/0207_tenant_credentials_github_repo_kind.sql +52 -0
  25. package/dist/drizzle/0208_knowledge_graph_neutral_identifiers.sql +253 -0
  26. package/dist/drizzle/0209_living_artifacts_schema.sql +109 -0
  27. package/dist/drizzle/0210_think137_automations_additive_schema.sql +113 -0
  28. package/dist/drizzle/0211_backfill_agent_loop_versions_target_spec.sql +120 -0
  29. package/dist/drizzle/0212_fold_webhooks_into_automations.sql +312 -0
  30. package/dist/drizzle/0213_agent_loop_versions_judge_evidence_nullable.sql +63 -0
  31. package/dist/drizzle/0214_think137_drop_judge_evidence_roi.sql +99 -0
  32. package/dist/drizzle/0215_agent_loop_versions_goal_worker_policy_nullable.sql +70 -0
  33. package/dist/drizzle/0216_drop_agent_loop_versions_goal_worker_policy.sql +81 -0
  34. package/dist/drizzle/0217_agents_capability_folder_dispatch.sql +12 -0
  35. package/dist/drizzle/0218_document_plates.sql +30 -0
  36. package/dist/drizzle/0219_document_section_waivers.sql +29 -0
  37. package/dist/drizzle/0220_artifacts_created_by_user.sql +21 -0
  38. package/dist/drizzle/0221_artifact_shares.sql +29 -0
  39. package/dist/drizzle/0221_workflow_interpreter_thin_slice.sql +71 -0
  40. package/dist/drizzle/0222_compliance_drainer_select_audit_events.sql +21 -0
  41. package/dist/drizzle/0223_document_conformance_reports.sql +38 -0
  42. package/dist/drizzle/0224_artifact_refresh_state.sql +11 -0
  43. package/dist/drizzle/0225_think216_agent_loop_convergence.sql +21 -0
  44. package/dist/drizzle/0226_drop_n8n_agent_step_runs.sql +6 -0
  45. package/dist/drizzle/0227_analyst_reader_role.sql +1055 -0
  46. package/dist/drizzle/0228_tenant_credentials_rds_iam_kind.sql +62 -0
  47. package/dist/drizzle/0229_analyst_reader_rds_iam_grant.sql +79 -0
  48. package/dist/drizzle/0230_analyst_rls.sql +1613 -0
  49. package/dist/drizzle/0231_cost_events_cache_write_enforcement_exempt.sql +11 -0
  50. package/dist/plugins/catalog/package.json +0 -1
  51. package/dist/plugins/catalog/src/__tests__/build-catalog.test.ts +0 -1
  52. package/dist/plugins/catalog/src/__tests__/catalog.test.ts +16 -8
  53. package/dist/plugins/catalog/src/__tests__/contracts.test.ts +56 -0
  54. package/dist/plugins/catalog/src/__tests__/plugin-package.test.ts +0 -2
  55. package/dist/plugins/catalog/src/__tests__/plugin-registry.test.ts +0 -5
  56. package/dist/plugins/catalog/src/contracts.ts +112 -0
  57. package/dist/plugins/catalog/src/registry/generated-first-party.ts +0 -6
  58. package/dist/plugins/n8n/README.md +4 -36
  59. package/dist/plugins/n8n/src/deployment/managed-app.ts +0 -17
  60. package/dist/plugins/n8n/src/manifest.ts +0 -5
  61. package/dist/plugins/n8n/terraform/n8n/main.tf +0 -26
  62. package/dist/plugins/n8n/terraform/n8n/outputs.tf +0 -5
  63. package/dist/plugins/n8n/terraform/n8n/variables.tf +0 -6
  64. package/dist/plugins/n8n/test/manifest.test.ts +0 -1
  65. package/dist/plugins/twenty/package.json +5 -0
  66. package/dist/plugins/twenty/scripts/lib/__tests__/load-records.test.ts +232 -0
  67. package/dist/plugins/twenty/scripts/lib/__tests__/mappers.test.ts +489 -0
  68. package/dist/plugins/twenty/scripts/lib/__tests__/members-ensure.test.ts +199 -0
  69. package/dist/plugins/twenty/scripts/lib/__tests__/provision-members-db.test.ts +43 -0
  70. package/dist/plugins/twenty/scripts/lib/__tests__/schema-ensure.test.ts +230 -0
  71. package/dist/plugins/twenty/scripts/lib/__tests__/twenty-client.test.ts +207 -0
  72. package/dist/plugins/twenty/scripts/lib/lastmile-reader.ts +282 -0
  73. package/dist/plugins/twenty/scripts/lib/load-attachments.ts +220 -0
  74. package/dist/plugins/twenty/scripts/lib/load-records.ts +680 -0
  75. package/dist/plugins/twenty/scripts/lib/mappers.ts +559 -0
  76. package/dist/plugins/twenty/scripts/lib/members-ensure.ts +381 -0
  77. package/dist/plugins/twenty/scripts/lib/provision-members-db.ts +191 -0
  78. package/dist/plugins/twenty/scripts/lib/schema-ensure.ts +425 -0
  79. package/dist/plugins/twenty/scripts/lib/twenty-client.ts +246 -0
  80. package/dist/plugins/twenty/scripts/migrate-lastmile.ts +610 -0
  81. package/dist/plugins/twenty/scripts/provision-twenty-members.ts +214 -0
  82. package/dist/plugins/twenty/src/manifest.ts +99 -0
  83. package/dist/plugins/twenty/terraform/twenty/README.md +1 -1
  84. package/dist/plugins/twenty/test/manifest.test.ts +12 -2
  85. package/dist/terraform/examples/greenfield/main.tf +90 -380
  86. package/dist/terraform/examples/greenfield/terraform.tfvars.example +0 -1
  87. package/dist/terraform/modules/app/agentcore-pi/README.md +1 -3
  88. package/dist/terraform/modules/app/agentcore-pi/main.tf +29 -38
  89. package/dist/terraform/modules/app/agentcore-pi/variables.tf +23 -15
  90. package/dist/terraform/modules/app/agentcore-runtime/main.tf +3 -3
  91. package/dist/terraform/modules/app/customer-domain/main.tf +16 -2
  92. package/dist/terraform/modules/app/deployment-control-plane/main.tf +5 -0
  93. package/dist/terraform/modules/app/deployment-control-plane/runner.py +85 -207
  94. package/dist/terraform/modules/app/deployment-control-plane/test_runner_bundle.py +56 -2
  95. package/dist/terraform/modules/app/hindsight-memory/main.tf +52 -4
  96. package/dist/terraform/modules/app/lambda-api/eval-fanout.tf +7 -0
  97. package/dist/terraform/modules/app/lambda-api/handlers.tf +493 -89
  98. package/dist/terraform/modules/app/lambda-api/iam-grouped.tf +215 -96
  99. package/dist/terraform/modules/app/lambda-api/main.tf +24 -5
  100. package/dist/terraform/modules/app/lambda-api/outputs.tf +19 -11
  101. package/dist/terraform/modules/app/lambda-api/variables.tf +94 -67
  102. package/dist/terraform/modules/app/ses-email/main.tf +14 -2
  103. package/dist/terraform/modules/app/workflow-interpreter-stepfunctions/main.tf +493 -0
  104. package/dist/terraform/modules/app/workflow-interpreter-stepfunctions/outputs.tf +34 -0
  105. package/dist/terraform/modules/app/workflow-interpreter-stepfunctions/variables.tf +32 -0
  106. package/dist/terraform/modules/data/aurora-postgres/main.tf +55 -0
  107. package/dist/terraform/modules/data/aurora-postgres/outputs.tf +15 -0
  108. package/dist/terraform/modules/data/s3-buckets/main.tf +26 -0
  109. package/dist/terraform/modules/thinkwork/README.md +0 -1
  110. package/dist/terraform/modules/thinkwork/main.tf +167 -446
  111. package/dist/terraform/modules/thinkwork/outputs.tf +2 -142
  112. package/dist/terraform/modules/thinkwork/variables.tf +55 -309
  113. package/dist/terraform/schema.graphql +4 -0
  114. package/dist/workspace-defaults/files/AGENTS.md +45 -31
  115. package/dist/workspace-defaults/files/CONTEXT.md +48 -4
  116. package/dist/workspace-defaults/files/GUARDRAILS.md +18 -0
  117. package/dist/workspace-defaults/files/MEMORY_GUIDE.md +32 -4
  118. package/dist/workspace-defaults/files/SPACE.md +34 -19
  119. package/dist/workspace-defaults/files/TOOLS.md +30 -0
  120. package/dist/workspace-defaults/files/skills/document-composer/SKILL.md +154 -0
  121. package/dist/workspace-defaults/files/skills/document-composer/references/authoring-rules.md +101 -0
  122. package/package.json +1 -1
  123. package/dist/plugins/company-brain/README.md +0 -37
  124. package/dist/plugins/company-brain/package.json +0 -33
  125. package/dist/plugins/company-brain/runtime/cognee/Dockerfile +0 -11
  126. package/dist/plugins/company-brain/smoke/cognee-managed-app-smoke.mjs +0 -458
  127. package/dist/plugins/company-brain/smoke/cognee-memory-cutover-smoke.mjs +0 -539
  128. package/dist/plugins/company-brain/smoke/company-brain-context-engine-smoke.mjs +0 -312
  129. package/dist/plugins/company-brain/smoke/company-brain-operations-smoke.mjs +0 -449
  130. package/dist/plugins/company-brain/smoke/company-brain-plugin-smoke.mjs +0 -655
  131. package/dist/plugins/company-brain/smoke/hindsight-memory-isolation-smoke.mjs +0 -474
  132. package/dist/plugins/company-brain/src/api/cognee-client.ts +0 -896
  133. package/dist/plugins/company-brain/src/api/cognee-cluster-identity.ts +0 -49
  134. package/dist/plugins/company-brain/src/api/cognee-memory-scope.ts +0 -84
  135. package/dist/plugins/company-brain/src/api/context-engine-provider.ts +0 -888
  136. package/dist/plugins/company-brain/src/api/migration.ts +0 -665
  137. package/dist/plugins/company-brain/src/deployment/cognee-managed-app.ts +0 -396
  138. package/dist/plugins/company-brain/src/index.ts +0 -62
  139. package/dist/plugins/company-brain/src/manifest.ts +0 -112
  140. package/dist/plugins/company-brain/terraform/cognee/README.md +0 -263
  141. package/dist/plugins/company-brain/terraform/cognee/main.tf +0 -766
  142. package/dist/plugins/company-brain/terraform/cognee/outputs.tf +0 -144
  143. package/dist/plugins/company-brain/terraform/cognee/variables.tf +0 -402
  144. package/dist/plugins/company-brain/test/api/cognee-client.test.ts +0 -562
  145. package/dist/plugins/company-brain/test/api/cognee-memory-scope.test.ts +0 -74
  146. package/dist/plugins/company-brain/test/api/context-engine-provider.test.ts +0 -447
  147. package/dist/plugins/company-brain/test/api/migration.test.ts +0 -465
  148. package/dist/plugins/company-brain/test/manifest.test.ts +0 -95
  149. package/dist/plugins/company-brain/tsconfig.json +0 -8
@@ -0,0 +1,253 @@
1
+ -- Purpose: rename retired substrate vocabulary that survives in the Knowledge
2
+ -- Graph pipeline to neutral graph/source terminology.
3
+ -- Plan: 2026-07-03-006 U7
4
+ -- Apply manually: psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f packages/database-pg/drizzle/0208_knowledge_graph_neutral_identifiers.sql
5
+ --
6
+ -- Hand-rolled (NOT registered in meta/_journal.json). Idempotent for both:
7
+ -- * existing databases that still have the retired column/value names, and
8
+ -- * fresh databases whose bootstrap SQL has already been scrubbed.
9
+ --
10
+ -- creates-column: public.knowledge_graph_ingest_runs.source_dataset_name
11
+ -- creates-column: public.knowledge_graph_ingest_runs.source_dataset_id
12
+ -- creates-column: public.knowledge_graph_entities.graph_node_id
13
+ -- creates-column: public.knowledge_graph_relationships.graph_edge_id
14
+ -- creates-column: brain.substrate_states.substrate_version
15
+ -- creates-column: brain.substrate_states.substrate_endpoint
16
+ -- creates: public.uq_kg_entities_run_graph_node
17
+ -- creates: public.uq_kg_relationships_run_graph_edge
18
+ -- creates-constraint: public.knowledge_graph_evidence.knowledge_graph_evidence_evidence_source_kind_allowed
19
+ -- creates-constraint: brain.substrate_states.brain_substrate_states_backend_allowed
20
+
21
+ \set ON_ERROR_STOP on
22
+
23
+ BEGIN;
24
+
25
+ SET LOCAL lock_timeout = '5s';
26
+
27
+ DO $$
28
+ DECLARE
29
+ retired_prefix text := 'co' || 'gnee';
30
+ old_dataset_name text := retired_prefix || '_dataset_name';
31
+ old_dataset_id text := retired_prefix || '_dataset_id';
32
+ old_node_id text := retired_prefix || '_node_id';
33
+ old_edge_id text := retired_prefix || '_edge_id';
34
+ BEGIN
35
+ IF to_regclass('public.knowledge_graph_ingest_runs') IS NOT NULL THEN
36
+ IF EXISTS (
37
+ SELECT 1
38
+ FROM information_schema.columns
39
+ WHERE table_schema = 'public'
40
+ AND table_name = 'knowledge_graph_ingest_runs'
41
+ AND column_name = old_dataset_name
42
+ ) AND NOT EXISTS (
43
+ SELECT 1
44
+ FROM information_schema.columns
45
+ WHERE table_schema = 'public'
46
+ AND table_name = 'knowledge_graph_ingest_runs'
47
+ AND column_name = 'source_dataset_name'
48
+ ) THEN
49
+ EXECUTE format(
50
+ 'ALTER TABLE public.knowledge_graph_ingest_runs RENAME COLUMN %I TO source_dataset_name',
51
+ old_dataset_name
52
+ );
53
+ END IF;
54
+
55
+ IF EXISTS (
56
+ SELECT 1
57
+ FROM information_schema.columns
58
+ WHERE table_schema = 'public'
59
+ AND table_name = 'knowledge_graph_ingest_runs'
60
+ AND column_name = old_dataset_id
61
+ ) AND NOT EXISTS (
62
+ SELECT 1
63
+ FROM information_schema.columns
64
+ WHERE table_schema = 'public'
65
+ AND table_name = 'knowledge_graph_ingest_runs'
66
+ AND column_name = 'source_dataset_id'
67
+ ) THEN
68
+ EXECUTE format(
69
+ 'ALTER TABLE public.knowledge_graph_ingest_runs RENAME COLUMN %I TO source_dataset_id',
70
+ old_dataset_id
71
+ );
72
+ END IF;
73
+ END IF;
74
+
75
+ IF to_regclass('public.knowledge_graph_entities') IS NOT NULL THEN
76
+ IF EXISTS (
77
+ SELECT 1
78
+ FROM information_schema.columns
79
+ WHERE table_schema = 'public'
80
+ AND table_name = 'knowledge_graph_entities'
81
+ AND column_name = old_node_id
82
+ ) AND NOT EXISTS (
83
+ SELECT 1
84
+ FROM information_schema.columns
85
+ WHERE table_schema = 'public'
86
+ AND table_name = 'knowledge_graph_entities'
87
+ AND column_name = 'graph_node_id'
88
+ ) THEN
89
+ EXECUTE format(
90
+ 'ALTER TABLE public.knowledge_graph_entities RENAME COLUMN %I TO graph_node_id',
91
+ old_node_id
92
+ );
93
+ END IF;
94
+ END IF;
95
+
96
+ IF to_regclass('public.knowledge_graph_relationships') IS NOT NULL THEN
97
+ IF EXISTS (
98
+ SELECT 1
99
+ FROM information_schema.columns
100
+ WHERE table_schema = 'public'
101
+ AND table_name = 'knowledge_graph_relationships'
102
+ AND column_name = old_edge_id
103
+ ) AND NOT EXISTS (
104
+ SELECT 1
105
+ FROM information_schema.columns
106
+ WHERE table_schema = 'public'
107
+ AND table_name = 'knowledge_graph_relationships'
108
+ AND column_name = 'graph_edge_id'
109
+ ) THEN
110
+ EXECUTE format(
111
+ 'ALTER TABLE public.knowledge_graph_relationships RENAME COLUMN %I TO graph_edge_id',
112
+ old_edge_id
113
+ );
114
+ END IF;
115
+ END IF;
116
+ END $$;
117
+
118
+ DO $$
119
+ DECLARE
120
+ retired_prefix text := 'co' || 'gnee';
121
+ old_entity_index text := 'uq_kg_entities_run_' || retired_prefix || '_node';
122
+ old_relationship_index text := 'uq_kg_relationships_run_' || retired_prefix || '_edge';
123
+ BEGIN
124
+ IF to_regclass('public.uq_kg_entities_run_graph_node') IS NULL
125
+ AND to_regclass('public.' || old_entity_index) IS NOT NULL THEN
126
+ EXECUTE format(
127
+ 'ALTER INDEX public.%I RENAME TO uq_kg_entities_run_graph_node',
128
+ old_entity_index
129
+ );
130
+ END IF;
131
+
132
+ IF to_regclass('public.uq_kg_relationships_run_graph_edge') IS NULL
133
+ AND to_regclass('public.' || old_relationship_index) IS NOT NULL THEN
134
+ EXECUTE format(
135
+ 'ALTER INDEX public.%I RENAME TO uq_kg_relationships_run_graph_edge',
136
+ old_relationship_index
137
+ );
138
+ END IF;
139
+ END $$;
140
+
141
+ DO $$
142
+ DECLARE
143
+ retired_payload text := ('co' || 'gnee') || '_payload';
144
+ BEGIN
145
+ IF to_regclass('public.knowledge_graph_evidence') IS NOT NULL THEN
146
+ ALTER TABLE public.knowledge_graph_evidence
147
+ DROP CONSTRAINT IF EXISTS knowledge_graph_evidence_evidence_source_kind_allowed;
148
+
149
+ UPDATE public.knowledge_graph_evidence
150
+ SET evidence_source_kind = 'graph_payload'
151
+ WHERE evidence_source_kind = retired_payload;
152
+
153
+ ALTER TABLE public.knowledge_graph_evidence
154
+ ADD CONSTRAINT knowledge_graph_evidence_evidence_source_kind_allowed
155
+ CHECK (evidence_source_kind IN (
156
+ 'thread_message',
157
+ 'wiki_page',
158
+ 'wiki_section',
159
+ 'brain_page',
160
+ 'brain_section',
161
+ 'hindsight_observation',
162
+ 'graph_payload',
163
+ 'normalizer'
164
+ ));
165
+ END IF;
166
+ END $$;
167
+
168
+ DO $$
169
+ DECLARE
170
+ retired_prefix text := 'co' || 'gnee';
171
+ old_version_column text := retired_prefix || '_version';
172
+ old_endpoint_column text := retired_prefix || '_endpoint';
173
+ old_backend_value text := 'legacy_' || retired_prefix;
174
+ BEGIN
175
+ IF to_regclass('brain.substrate_states') IS NOT NULL THEN
176
+ IF EXISTS (
177
+ SELECT 1
178
+ FROM information_schema.columns
179
+ WHERE table_schema = 'brain'
180
+ AND table_name = 'substrate_states'
181
+ AND column_name = old_version_column
182
+ ) AND NOT EXISTS (
183
+ SELECT 1
184
+ FROM information_schema.columns
185
+ WHERE table_schema = 'brain'
186
+ AND table_name = 'substrate_states'
187
+ AND column_name = 'substrate_version'
188
+ ) THEN
189
+ EXECUTE format(
190
+ 'ALTER TABLE brain.substrate_states RENAME COLUMN %I TO substrate_version',
191
+ old_version_column
192
+ );
193
+ END IF;
194
+
195
+ IF EXISTS (
196
+ SELECT 1
197
+ FROM information_schema.columns
198
+ WHERE table_schema = 'brain'
199
+ AND table_name = 'substrate_states'
200
+ AND column_name = old_endpoint_column
201
+ ) AND NOT EXISTS (
202
+ SELECT 1
203
+ FROM information_schema.columns
204
+ WHERE table_schema = 'brain'
205
+ AND table_name = 'substrate_states'
206
+ AND column_name = 'substrate_endpoint'
207
+ ) THEN
208
+ EXECUTE format(
209
+ 'ALTER TABLE brain.substrate_states RENAME COLUMN %I TO substrate_endpoint',
210
+ old_endpoint_column
211
+ );
212
+ END IF;
213
+
214
+ ALTER TABLE brain.substrate_states
215
+ DROP CONSTRAINT IF EXISTS brain_substrate_states_backend_allowed;
216
+
217
+ UPDATE brain.substrate_states
218
+ SET active_backend = 'legacy_graph'
219
+ WHERE active_backend = old_backend_value;
220
+
221
+ ALTER TABLE brain.substrate_states
222
+ ADD CONSTRAINT brain_substrate_states_backend_allowed
223
+ CHECK (active_backend IN ('none', 'default', 'production', 'legacy_graph'));
224
+ END IF;
225
+ END $$;
226
+
227
+ DO $$
228
+ DECLARE
229
+ retired_mechanism text := ('co' || 'gnee') || '_owl_ontology';
230
+ BEGIN
231
+ IF to_regclass('brain.artifact_manifests') IS NOT NULL THEN
232
+ UPDATE brain.artifact_manifests
233
+ SET ontology_mechanism = 'approved_ontology'
234
+ WHERE ontology_mechanism = retired_mechanism;
235
+ END IF;
236
+ END $$;
237
+
238
+ DO $$
239
+ DECLARE
240
+ retired_tag text := 'company-' || 'brain';
241
+ BEGIN
242
+ IF to_regclass('wiki.pages') IS NOT NULL THEN
243
+ UPDATE wiki.pages
244
+ SET tags = ARRAY(
245
+ SELECT DISTINCT CASE WHEN tag = retired_tag THEN 'brain' ELSE tag END
246
+ FROM unnest(tags) AS tag
247
+ ORDER BY 1
248
+ )
249
+ WHERE tags @> ARRAY[retired_tag]::text[];
250
+ END IF;
251
+ END $$;
252
+
253
+ COMMIT;
@@ -0,0 +1,109 @@
1
+ -- Living Artifacts core schema foundation (THINK-145 U1).
2
+ -- Plan: docs/plans/2026-07-04-001-feat-living-artifacts-core-plan.md (U1, KTD2/KTD3)
3
+ -- Apply manually: psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f packages/database-pg/drizzle/0209_living_artifacts_schema.sql
4
+ --
5
+ -- Hand-rolled (NOT registered in meta/_journal.json — this repo's drizzle
6
+ -- journal is frozen at 0021 and every migration since is authored by hand).
7
+ -- Additive only: existing artifact rows keep working (head_version defaults to
8
+ -- 0, space_id stays NULL). space_id FK is ON DELETE RESTRICT — never cascade
9
+ -- into spaces.* (owned by a separate workstream).
10
+ --
11
+ -- creates-column: public.artifacts.space_id
12
+ -- creates-column: public.artifacts.head_version
13
+ -- creates-column: public.artifacts.head_write_seq
14
+ -- creates: public.idx_artifacts_space_id
15
+ -- creates: public.artifact_versions
16
+ -- creates: public.idx_artifact_versions_tenant_id
17
+ -- creates: public.idx_artifact_versions_artifact_id
18
+ -- creates: public.uq_artifact_versions_artifact_version
19
+ -- creates: public.artifact_data_bindings
20
+ -- creates: public.idx_artifact_data_bindings_tenant_id
21
+ -- creates: public.idx_artifact_data_bindings_artifact_id
22
+ -- creates: public.uq_artifact_data_bindings_element
23
+ -- creates-constraint: public.artifact_data_bindings.artifact_data_bindings_auth_context_allowed
24
+ -- creates-constraint: public.artifact_data_bindings.artifact_data_bindings_quality_allowed
25
+
26
+ \set ON_ERROR_STOP on
27
+
28
+ BEGIN;
29
+
30
+ SET LOCAL lock_timeout = '5s';
31
+
32
+ -- ---------------------------------------------------------------------------
33
+ -- artifacts: space linkage + version-chain head pointer + concurrency counter
34
+ -- ---------------------------------------------------------------------------
35
+
36
+ ALTER TABLE artifacts
37
+ ADD COLUMN IF NOT EXISTS space_id uuid REFERENCES spaces(id) ON DELETE RESTRICT;
38
+
39
+ ALTER TABLE artifacts
40
+ ADD COLUMN IF NOT EXISTS head_version integer NOT NULL DEFAULT 0;
41
+
42
+ ALTER TABLE artifacts
43
+ ADD COLUMN IF NOT EXISTS head_write_seq integer NOT NULL DEFAULT 0;
44
+
45
+ CREATE INDEX IF NOT EXISTS idx_artifacts_space_id
46
+ ON artifacts (tenant_id, space_id);
47
+
48
+ -- ---------------------------------------------------------------------------
49
+ -- artifact_versions: content-addressed, write-once pinned revisions
50
+ -- ---------------------------------------------------------------------------
51
+
52
+ CREATE TABLE IF NOT EXISTS artifact_versions (
53
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
54
+ tenant_id uuid NOT NULL REFERENCES tenants(id),
55
+ artifact_id uuid NOT NULL REFERENCES artifacts(id) ON DELETE CASCADE,
56
+ version integer NOT NULL,
57
+ s3_key text NOT NULL,
58
+ content_hash text NOT NULL,
59
+ created_by uuid REFERENCES users(id) ON DELETE SET NULL,
60
+ created_at timestamptz NOT NULL DEFAULT now()
61
+ );
62
+
63
+ CREATE INDEX IF NOT EXISTS idx_artifact_versions_tenant_id
64
+ ON artifact_versions (tenant_id);
65
+
66
+ CREATE INDEX IF NOT EXISTS idx_artifact_versions_artifact_id
67
+ ON artifact_versions (artifact_id);
68
+
69
+ CREATE UNIQUE INDEX IF NOT EXISTS uq_artifact_versions_artifact_version
70
+ ON artifact_versions (artifact_id, version);
71
+
72
+ -- ---------------------------------------------------------------------------
73
+ -- artifact_data_bindings: the saved tool call behind each bound widget
74
+ -- ---------------------------------------------------------------------------
75
+
76
+ CREATE TABLE IF NOT EXISTS artifact_data_bindings (
77
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
78
+ tenant_id uuid NOT NULL REFERENCES tenants(id),
79
+ artifact_id uuid NOT NULL REFERENCES artifacts(id) ON DELETE CASCADE,
80
+ part_id text NOT NULL,
81
+ element_id text NOT NULL,
82
+ mcp_server_ref text NOT NULL,
83
+ server_name text NOT NULL,
84
+ tool_name text NOT NULL,
85
+ frozen_args jsonb NOT NULL DEFAULT '{}'::jsonb,
86
+ result_shape_hash text NOT NULL,
87
+ auth_context text NOT NULL,
88
+ owner_user_id uuid REFERENCES users(id) ON DELETE SET NULL,
89
+ quality text NOT NULL DEFAULT 'good',
90
+ last_fetched_at timestamptz,
91
+ last_good_at timestamptz,
92
+ created_at timestamptz NOT NULL DEFAULT now(),
93
+ updated_at timestamptz NOT NULL DEFAULT now(),
94
+ CONSTRAINT artifact_data_bindings_auth_context_allowed
95
+ CHECK (auth_context IN ('tenant_mcp', 'per_user_oauth')),
96
+ CONSTRAINT artifact_data_bindings_quality_allowed
97
+ CHECK (quality IN ('good', 'stale', 'bad', 'schema_stale'))
98
+ );
99
+
100
+ CREATE INDEX IF NOT EXISTS idx_artifact_data_bindings_tenant_id
101
+ ON artifact_data_bindings (tenant_id);
102
+
103
+ CREATE INDEX IF NOT EXISTS idx_artifact_data_bindings_artifact_id
104
+ ON artifact_data_bindings (artifact_id);
105
+
106
+ CREATE UNIQUE INDEX IF NOT EXISTS uq_artifact_data_bindings_element
107
+ ON artifact_data_bindings (artifact_id, part_id, element_id);
108
+
109
+ COMMIT;
@@ -0,0 +1,113 @@
1
+ -- Purpose: additive schema foundation for THINK-137 Automations
2
+ -- (plan 2026-07-03 U1). Lands every new column additively so later units
3
+ -- build on deployed schema. Additive DDL only — no drops of columns/tables,
4
+ -- no destructive data change. The one CHECK re-create (iteration status) is a
5
+ -- pure widening (7 → 9 accepted values); dropping-to-recreate a CHECK is not
6
+ -- a destructive data change.
7
+ --
8
+ -- Contents:
9
+ -- * agent_loop_versions.target_spec jsonb (nullable) — Automation target
10
+ -- resolution spec; populated by later units.
11
+ -- * agent_loops.run_as_user_id uuid (nullable) FK users(id) ON DELETE SET
12
+ -- NULL — matches the owner_user_id FK style on the same table.
13
+ -- * webhooks.agent_loop_id uuid (nullable) FK agent_loops(id) ON DELETE
14
+ -- CASCADE — a webhook bound to an Automation is torn down with it.
15
+ -- * agent_loop_iterations_status_check widened from the current 7-value set
16
+ -- to the 9-value set the run-ledger code (packages/agent-loops-core/
17
+ -- src/run-ledger.ts AgentLoopIterationStatus) treats as authoritative —
18
+ -- adds 'escalated' and 'skipped'. The sibling agent_loop_runs_status_check
19
+ -- already carries all 9, so this closes the iterations/runs skew.
20
+ --
21
+ -- NOT done here (deliberately):
22
+ -- * trigger-family CHECKs (agent_loops_trigger_family_check /
23
+ -- agent_loop_runs_trigger_family_check) already accept 'webhook' — no
24
+ -- widening required. Narrowing away dead families (api/app_event/n8n) is
25
+ -- U10's job, not this unit's.
26
+ -- * webhooks.target_type has no CHECK constraint (handler-enforced) — none
27
+ -- is added here.
28
+ --
29
+ -- Hand-rolled per convention (drizzle snapshot in meta/ is frozen;
30
+ -- precedent 0206/0207/0209). Idempotent: ADD COLUMN IF NOT EXISTS + guarded
31
+ -- CHECK drop/re-add. Safe to re-run.
32
+ --
33
+ -- Apply manually (verification pass before merge):
34
+ -- psql "$DATABASE_URL" -v ON_ERROR_STOP=1 --single-transaction \
35
+ -- -f packages/database-pg/drizzle/0210_think137_automations_additive_schema.sql
36
+ --
37
+ -- creates-column: public.agent_loop_versions.target_spec
38
+ -- creates-column: public.agent_loops.run_as_user_id
39
+ -- creates-column: public.webhooks.agent_loop_id
40
+ -- creates-constraint: public.agent_loop_iterations.agent_loop_iterations_status_check
41
+
42
+ \set ON_ERROR_STOP on
43
+
44
+ BEGIN;
45
+
46
+ SELECT pg_advisory_xact_lock(hashtext('think137_automations_additive_schema_0210'));
47
+
48
+ SET LOCAL lock_timeout = '5s';
49
+ SET LOCAL statement_timeout = '60s';
50
+
51
+ DO $$
52
+ BEGIN
53
+ IF to_regclass('public.agent_loop_versions') IS NULL THEN
54
+ RAISE EXCEPTION 'pre-flight: public.agent_loop_versions does not exist';
55
+ END IF;
56
+ IF to_regclass('public.agent_loops') IS NULL THEN
57
+ RAISE EXCEPTION 'pre-flight: public.agent_loops does not exist';
58
+ END IF;
59
+ IF to_regclass('public.agent_loop_iterations') IS NULL THEN
60
+ RAISE EXCEPTION 'pre-flight: public.agent_loop_iterations does not exist';
61
+ END IF;
62
+ IF to_regclass('public.webhooks') IS NULL THEN
63
+ RAISE EXCEPTION 'pre-flight: public.webhooks does not exist';
64
+ END IF;
65
+ IF to_regclass('public.users') IS NULL THEN
66
+ RAISE EXCEPTION 'pre-flight: public.users does not exist';
67
+ END IF;
68
+ END $$;
69
+
70
+ -- agent_loop_versions.target_spec — nullable jsonb, no FK.
71
+ ALTER TABLE public.agent_loop_versions
72
+ ADD COLUMN IF NOT EXISTS target_spec jsonb;
73
+
74
+ -- agent_loops.run_as_user_id — nullable uuid FK to users(id) ON DELETE SET
75
+ -- NULL (matches agent_loops.owner_user_id).
76
+ ALTER TABLE public.agent_loops
77
+ ADD COLUMN IF NOT EXISTS run_as_user_id uuid REFERENCES public.users(id) ON DELETE SET NULL;
78
+
79
+ -- webhooks.agent_loop_id — nullable uuid FK to agent_loops(id) ON DELETE
80
+ -- CASCADE.
81
+ ALTER TABLE public.webhooks
82
+ ADD COLUMN IF NOT EXISTS agent_loop_id uuid REFERENCES public.agent_loops(id) ON DELETE CASCADE;
83
+
84
+ -- Widen the iteration status CHECK: 7 → 9 accepted values (add 'escalated',
85
+ -- 'skipped'). Guarded drop/re-add so re-runs are no-ops once the widened
86
+ -- definition is in place.
87
+ DO $$
88
+ BEGIN
89
+ IF EXISTS (
90
+ SELECT 1
91
+ FROM pg_constraint
92
+ WHERE conname = 'agent_loop_iterations_status_check'
93
+ AND conrelid = 'public.agent_loop_iterations'::regclass
94
+ AND (pg_get_constraintdef(oid) NOT LIKE '%escalated%'
95
+ OR pg_get_constraintdef(oid) NOT LIKE '%skipped%')
96
+ ) THEN
97
+ ALTER TABLE public.agent_loop_iterations
98
+ DROP CONSTRAINT agent_loop_iterations_status_check;
99
+ END IF;
100
+
101
+ IF NOT EXISTS (
102
+ SELECT 1
103
+ FROM pg_constraint
104
+ WHERE conname = 'agent_loop_iterations_status_check'
105
+ AND conrelid = 'public.agent_loop_iterations'::regclass
106
+ ) THEN
107
+ ALTER TABLE public.agent_loop_iterations
108
+ ADD CONSTRAINT agent_loop_iterations_status_check
109
+ CHECK (status IN ('queued', 'running', 'waiting_for_human', 'completed', 'failed', 'budget_stopped', 'escalated', 'canceled', 'skipped'));
110
+ END IF;
111
+ END $$;
112
+
113
+ COMMIT;
@@ -0,0 +1,120 @@
1
+ -- Purpose: backfill agent_loop_versions.target_spec on every existing row
2
+ -- (THINK-137 Automations U3, plan 2026-07-03-006). target_spec becomes the
3
+ -- authoritative version spec; this migration derives it from the legacy
4
+ -- goal/worker/routineActions blobs using the SAME mapping as
5
+ -- targetSpecFromLegacy() in @thinkwork/agent-loops-core, expressed in SQL.
6
+ --
7
+ -- Mapping (identical to targetSpecFromLegacy):
8
+ -- * routine_actions_spec present, its `actions` a non-empty array, AND
9
+ -- agentTurn === false → kind 'routine'. The first action becomes
10
+ -- {routineId, input?, label?}; any remaining actions are preserved under
11
+ -- routine.additionalActions so the mapping is lossless and dispatch
12
+ -- reconstructs the exact original action list.
13
+ -- * everything else (agent-turn, or mixed agentTurn:true) → kind
14
+ -- 'agent_thread' from goal_spec.objective + goal_spec.completionCriteria +
15
+ -- worker_spec.id/type, threadMode 'new_per_run'. A mixed Automation's
16
+ -- bolt-on routine actions stay in routine_actions_spec (they are pre-steps
17
+ -- of the agent-thread target, not the target) and are read from there at
18
+ -- dispatch.
19
+ --
20
+ -- Data-only migration: the target_spec COLUMN already exists (added additively
21
+ -- in 0210). This file writes data, not schema. Following the 0202 data-backfill
22
+ -- precedent, it publishes a drift-marker VIEW whose presence proves the whole
23
+ -- transaction committed; the `-- creates:` marker below is what the drift
24
+ -- reporter (scripts/db-migrate-manual.sh) probes.
25
+ --
26
+ -- Idempotent: only rows WHERE target_spec IS NULL are updated; the marker view
27
+ -- is CREATE OR REPLACE. Safe to re-run. dev has ~7 version rows; customer
28
+ -- stages have 0.
29
+ --
30
+ -- Apply manually (verification pass before merge):
31
+ -- psql "$DATABASE_URL" -v ON_ERROR_STOP=1 --single-transaction \
32
+ -- -f packages/database-pg/drizzle/0211_backfill_agent_loop_versions_target_spec.sql
33
+ --
34
+ -- creates: public.view_agent_loop_versions_target_spec_backfilled
35
+
36
+ \set ON_ERROR_STOP on
37
+
38
+ BEGIN;
39
+
40
+ SELECT pg_advisory_xact_lock(hashtext('agent_loop_versions_target_spec_backfill_0211'));
41
+
42
+ SET LOCAL lock_timeout = '5s';
43
+ SET LOCAL statement_timeout = '60s';
44
+
45
+ DO $$
46
+ BEGIN
47
+ IF to_regclass('public.agent_loop_versions') IS NULL THEN
48
+ RAISE EXCEPTION 'pre-flight: public.agent_loop_versions does not exist';
49
+ END IF;
50
+ IF NOT EXISTS (
51
+ SELECT 1 FROM information_schema.columns
52
+ WHERE table_schema = 'public'
53
+ AND table_name = 'agent_loop_versions'
54
+ AND column_name = 'target_spec'
55
+ ) THEN
56
+ RAISE EXCEPTION 'pre-flight: public.agent_loop_versions.target_spec column missing (apply 0210 first)';
57
+ END IF;
58
+ END $$;
59
+
60
+ UPDATE public.agent_loop_versions v
61
+ SET target_spec = CASE
62
+ WHEN v.routine_actions_spec IS NOT NULL
63
+ AND jsonb_typeof(v.routine_actions_spec -> 'actions') = 'array'
64
+ AND jsonb_array_length(v.routine_actions_spec -> 'actions') >= 1
65
+ AND (v.routine_actions_spec -> 'agentTurn') = to_jsonb(false)
66
+ THEN jsonb_strip_nulls(jsonb_build_object(
67
+ 'kind', 'routine',
68
+ 'routine', jsonb_strip_nulls(jsonb_build_object(
69
+ 'routineId', v.routine_actions_spec -> 'actions' -> 0 ->> 'routineId',
70
+ 'input', v.routine_actions_spec -> 'actions' -> 0 -> 'input',
71
+ 'label', v.routine_actions_spec -> 'actions' -> 0 -> 'label',
72
+ 'additionalActions', CASE
73
+ WHEN jsonb_array_length(v.routine_actions_spec -> 'actions') > 1
74
+ THEN (
75
+ SELECT jsonb_agg(a.elem ORDER BY a.ord)
76
+ FROM jsonb_array_elements(v.routine_actions_spec -> 'actions')
77
+ WITH ORDINALITY AS a(elem, ord)
78
+ WHERE a.ord > 1
79
+ )
80
+ ELSE NULL
81
+ END
82
+ ))
83
+ ))
84
+ ELSE jsonb_strip_nulls(jsonb_build_object(
85
+ 'kind', 'agent_thread',
86
+ 'agentThread', jsonb_strip_nulls(jsonb_build_object(
87
+ 'instructions', COALESCE(v.goal_spec ->> 'objective', ''),
88
+ 'completionCriteria', CASE
89
+ WHEN jsonb_typeof(v.goal_spec -> 'completionCriteria') = 'array'
90
+ AND jsonb_array_length(v.goal_spec -> 'completionCriteria') >= 1
91
+ THEN v.goal_spec -> 'completionCriteria'
92
+ ELSE NULL
93
+ END,
94
+ 'workerId', v.worker_spec ->> 'id',
95
+ 'workerType', CASE
96
+ WHEN v.worker_spec ->> 'type' IN ('agent', 'agent_profile')
97
+ THEN v.worker_spec ->> 'type'
98
+ ELSE NULL
99
+ END,
100
+ 'threadMode', 'new_per_run'
101
+ ))
102
+ ))
103
+ END
104
+ WHERE v.target_spec IS NULL;
105
+
106
+ -- Drift marker + summary. Presence proves the backfill transaction committed.
107
+ CREATE OR REPLACE VIEW public.view_agent_loop_versions_target_spec_backfilled AS
108
+ SELECT
109
+ COUNT(*)::int AS total_versions,
110
+ COUNT(*) FILTER (WHERE target_spec IS NOT NULL)::int AS with_target_spec,
111
+ COUNT(*) FILTER (WHERE target_spec IS NULL)::int AS missing_target_spec,
112
+ COUNT(*) FILTER (WHERE target_spec ->> 'kind' = 'agent_thread')::int AS agent_thread_targets,
113
+ COUNT(*) FILTER (WHERE target_spec ->> 'kind' = 'routine')::int AS routine_targets,
114
+ now() AS checked_at
115
+ FROM public.agent_loop_versions;
116
+
117
+ COMMENT ON VIEW public.view_agent_loop_versions_target_spec_backfilled IS
118
+ 'Drift marker and summary for 0211_backfill_agent_loop_versions_target_spec.sql.';
119
+
120
+ COMMIT;