thinkwork-cli 0.13.0 → 0.13.2

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 (178) hide show
  1. package/dist/{api-client-JUBCQQDF.js → api-client-JYZXYQJR.js} +3 -1
  2. package/dist/bowser-6Z6JFAIR.js +2822 -0
  3. package/dist/chunk-DV3MRBR5.js +43 -0
  4. package/dist/chunk-DVPBI5HM.js +1728 -0
  5. package/dist/chunk-EI5ZX7CN.js +522 -0
  6. package/dist/chunk-EUJ7X6YD.js +126 -0
  7. package/dist/chunk-GG5WKBOX.js +436 -0
  8. package/dist/chunk-I64EZSU5.js +358 -0
  9. package/dist/chunk-ILZKG5WV.js +6151 -0
  10. package/dist/chunk-KMIJ5KGT.js +128 -0
  11. package/dist/chunk-OCPHU34C.js +996 -0
  12. package/dist/chunk-QOERT44A.js +3286 -0
  13. package/dist/chunk-XYM7PE2A.js +2264 -0
  14. package/dist/{chunk-STY44FQO.js → chunk-Z2F6RJFR.js} +12 -18
  15. package/dist/cli.js +72564 -18884
  16. package/dist/dist-es-CRV46D5B.js +315 -0
  17. package/dist/dist-es-DCY4IC3Y.js +2000 -0
  18. package/dist/dist-es-ENBUC3JP.js +14726 -0
  19. package/dist/dist-es-G54LBMRN.js +48 -0
  20. package/dist/dist-es-G7PTG75M.js +176 -0
  21. package/dist/dist-es-GKDBE7E6.js +88 -0
  22. package/dist/dist-es-HY3535OI.js +70 -0
  23. package/dist/dist-es-KL7Y5NB2.js +377 -0
  24. package/dist/dist-es-LDE437AM.js +170 -0
  25. package/dist/dist-es-P26FWFLT.js +485 -0
  26. package/dist/dist-es-Q57SZXZ7.js +70 -0
  27. package/dist/dist-es-R7FGL2IB.js +88 -0
  28. package/dist/dist-es-USORBXZ5.js +318 -0
  29. package/dist/dist-es-ZKC2QKD2.js +377 -0
  30. package/dist/drizzle/0076_scheduled_jobs_marco_backfill.sql +2 -1
  31. package/dist/drizzle/0079_seed_tenant_customize_catalog.sql +1 -0
  32. package/dist/drizzle/0090_brain_schema_extraction.sql +10 -0
  33. package/dist/drizzle/0132_drop_computer_tables.sql +3 -0
  34. package/dist/drizzle/0160_compliance_event_types_plugins.sql +2 -0
  35. package/dist/drizzle/0214_think137_drop_judge_evidence_roi.sql +1 -0
  36. package/dist/drizzle/0216_drop_agent_loop_versions_goal_worker_policy.sql +1 -0
  37. package/dist/drizzle/0227_analyst_reader_role.sql +106 -38
  38. package/dist/drizzle/0230_analyst_rls.sql +192 -66
  39. package/dist/drizzle/0232_memory_source_thin_ledger.sql +176 -0
  40. package/dist/drizzle/0232_message_source_event_id.sql +9 -0
  41. package/dist/drizzle/0233_msteams_install_and_links.sql +151 -0
  42. package/dist/drizzle/0233_workflow_memory_stage_tokens.sql +20 -0
  43. package/dist/drizzle/0234_memory_claim_lifecycle.sql +160 -0
  44. package/dist/drizzle/0235_workflow_token_execution_claim.sql +34 -0
  45. package/dist/drizzle/0236_memory_retraction_fencing.sql +50 -0
  46. package/dist/drizzle/0237_memory_claims_active_value_uidx.sql +172 -0
  47. package/dist/drizzle/0238_memory_erase_generation_fence.sql +97 -0
  48. package/dist/drizzle/0239_canonical_entity_identity.sql +257 -0
  49. package/dist/drizzle/0240_memory_personal_scope.sql +45 -0
  50. package/dist/drizzle/0241_knowledge_base_document_manifest.sql +67 -0
  51. package/dist/drizzle/0242_search_queries.sql +28 -0
  52. package/dist/drizzle/0243_section_sources_thread_refs.sql +12 -0
  53. package/dist/drizzle/0244_system_automations_and_memory_stage_overrides.sql +45 -0
  54. package/dist/drizzle/0245_wiki_page_render.sql +21 -0
  55. package/dist/drizzle/0246_automation_workflow_ownership.sql +30 -0
  56. package/dist/drizzle/0247_capability_runtime.sql +402 -0
  57. package/dist/drizzle/0248_capability_private_interpreter.sql +13 -0
  58. package/dist/drizzle/0249_capability_headless_execution_evidence.sql +40 -0
  59. package/dist/drizzle/0250_kg_schema_extraction.sql +576 -0
  60. package/dist/drizzle/0251_agents_json_render_ui.sql +25 -0
  61. package/dist/drizzle/0251_brain_stragglers.sql +263 -0
  62. package/dist/drizzle/0252_drop_kg_and_straggler_compat_views.sql +100 -0
  63. package/dist/drizzle/0253_drop_brain_substrate.sql +93 -0
  64. package/dist/drizzle/0254_capability_autonomous_admission.sql +29 -0
  65. package/dist/drizzle/0255_capability_autonomous_approval_mode.sql +16 -0
  66. package/dist/drizzle/0256_agent_profile_manifest_authority.sql +18 -0
  67. package/dist/drizzle/0257_agents_runtime_allow_harness.sql +24 -0
  68. package/dist/drizzle/0257_capability_approvals.sql +53 -0
  69. package/dist/drizzle/0258_pending_tool_approvals.sql +84 -0
  70. package/dist/drizzle/0259_tenant_capability_registry_trust.sql +19 -0
  71. package/dist/drizzle/0260_scheduled_jobs_run_as_user.sql +20 -0
  72. package/dist/drizzle/0261_managed_harness_multiplayer.sql +313 -0
  73. package/dist/drizzle/0261_native_auth_control_plane.sql +328 -0
  74. package/dist/drizzle/0262_auth_subscription_tickets.sql +59 -0
  75. package/dist/drizzle/0262_parallel_harness_threads.sql +9 -0
  76. package/dist/drizzle/0263_agentcore_runtime_identifier.sql +69 -0
  77. package/dist/drizzle/0263_drop_workos_auth_runtime.sql +236 -0
  78. package/dist/drizzle/0264_auth_enrollment_attempt_limits.sql +15 -0
  79. package/dist/drizzle/0264_harness_tool_execution_ledger.sql +113 -0
  80. package/dist/drizzle/0265_eval_runs_requester_identity.sql +28 -0
  81. package/dist/drizzle/0265_require_fully_valid_auth_publication.sql +27 -0
  82. package/dist/drizzle/0266_auth_identity_recovery_grants.sql +9 -0
  83. package/dist/drizzle/0266_eval_profiles_runtime_type.sql +12 -0
  84. package/dist/drizzle/0267_ontology_candidate_rejections.sql +53 -0
  85. package/dist/drizzle/0268_identity_crosswalk_routing.sql +182 -0
  86. package/dist/drizzle/0269_ontology_system_map.sql +31 -0
  87. package/dist/event-streams-7JNLJEEL.js +894 -0
  88. package/dist/event-streams-KDF5RWR6.js +1515 -0
  89. package/dist/loadSso-DJVB7BXE.js +576 -0
  90. package/dist/loadSso-JAMNA3WY.js +583 -0
  91. package/dist/plugins/catalog/package.json +1 -2
  92. package/dist/plugins/catalog/src/__tests__/build-catalog.test.ts +0 -1
  93. package/dist/plugins/catalog/src/__tests__/contracts.test.ts +0 -69
  94. package/dist/plugins/catalog/src/__tests__/plugin-package.test.ts +0 -2
  95. package/dist/plugins/catalog/src/__tests__/plugin-registry.test.ts +0 -5
  96. package/dist/plugins/catalog/src/contracts.ts +2 -179
  97. package/dist/plugins/catalog/src/registry/generated-first-party.ts +0 -6
  98. package/dist/signin-UGDWTGS4.js +821 -0
  99. package/dist/sso-oidc-Q4VXANXY.js +837 -0
  100. package/dist/sts-CWLSE3GH.js +1241 -0
  101. package/dist/sts-DNZLNVOV.js +1245 -0
  102. package/dist/terraform/examples/greenfield/main.tf +247 -50
  103. package/dist/terraform/examples/greenfield/terraform.tfvars.example +15 -1
  104. package/dist/terraform/modules/app/agentcore-admin/main.tf +341 -0
  105. package/dist/terraform/modules/app/agentcore-admin/outputs.tf +20 -0
  106. package/dist/terraform/modules/app/agentcore-code-interpreter/main.tf +61 -0
  107. package/dist/terraform/modules/app/agentcore-gateway/main.tf +305 -0
  108. package/dist/terraform/modules/app/agentcore-gateway/outputs.tf +44 -0
  109. package/dist/terraform/modules/app/agentcore-gateway/scripts/delete_gateway.sh +93 -0
  110. package/dist/terraform/modules/app/agentcore-gateway/scripts/read_gateway.sh +33 -0
  111. package/dist/terraform/modules/app/agentcore-gateway/scripts/reconcile_gateway.sh +543 -0
  112. package/dist/terraform/modules/app/agentcore-gateway/variables.tf +70 -0
  113. package/dist/terraform/modules/app/agentcore-harness/main.tf +330 -0
  114. package/dist/terraform/modules/app/agentcore-harness/outputs.tf +72 -0
  115. package/dist/terraform/modules/app/agentcore-harness/scripts/delete_harness.sh +5 -0
  116. package/dist/terraform/modules/app/agentcore-harness/scripts/harness-lifecycle.mjs +430 -0
  117. package/dist/terraform/modules/app/agentcore-harness/scripts/harness-readback.mjs +180 -0
  118. package/dist/terraform/modules/app/agentcore-harness/scripts/harness-tool-contract.mjs +193 -0
  119. package/dist/terraform/modules/app/agentcore-harness/scripts/prune_harness.sh +5 -0
  120. package/dist/terraform/modules/app/agentcore-harness/scripts/read_harness.sh +5 -0
  121. package/dist/terraform/modules/app/agentcore-harness/scripts/reconcile_harness.sh +5 -0
  122. package/dist/terraform/modules/app/agentcore-harness/variables.tf +96 -0
  123. package/dist/terraform/modules/app/agentcore-identity/main.tf +173 -0
  124. package/dist/terraform/modules/app/agentcore-identity/outputs.tf +51 -0
  125. package/dist/terraform/modules/app/agentcore-identity/scripts/bootstrap_twenty_oauth_client.sh +122 -0
  126. package/dist/terraform/modules/app/agentcore-identity/scripts/delete_identity.sh +25 -0
  127. package/dist/terraform/modules/app/agentcore-identity/scripts/delete_twenty_identity.sh +16 -0
  128. package/dist/terraform/modules/app/agentcore-identity/scripts/read_identity.sh +40 -0
  129. package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_identity.sh +73 -0
  130. package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_twenty_identity.sh +74 -0
  131. package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_twenty_provider.mjs +61 -0
  132. package/dist/terraform/modules/app/agentcore-identity/variables.tf +54 -0
  133. package/dist/terraform/modules/app/agentcore-pi/main.tf +7 -0
  134. package/dist/terraform/modules/app/appsync-subscriptions/main.tf +127 -21
  135. package/dist/terraform/modules/app/appsync-subscriptions/outputs.tf +0 -6
  136. package/dist/terraform/modules/app/appsync-subscriptions/variables.tf +5 -0
  137. package/dist/terraform/modules/app/capability-broker/main.tf +393 -0
  138. package/dist/terraform/modules/app/capability-broker/outputs.tf +54 -0
  139. package/dist/terraform/modules/app/capability-broker/variables.tf +98 -0
  140. package/dist/terraform/modules/app/deployment-control-plane/runner.py +1011 -31
  141. package/dist/terraform/modules/app/deployment-control-plane/test_runner_bundle.py +655 -2
  142. package/dist/terraform/modules/app/lambda-api/agentcore-harness-alarms.tf +88 -0
  143. package/dist/terraform/modules/app/lambda-api/agentcore-identity-alarms.tf +91 -0
  144. package/dist/terraform/modules/app/lambda-api/capability-search-alarms.tf +60 -0
  145. package/dist/terraform/modules/app/lambda-api/handlers.tf +606 -37
  146. package/dist/terraform/modules/app/lambda-api/iam-grouped.tf +192 -21
  147. package/dist/terraform/modules/app/lambda-api/main.tf +35 -0
  148. package/dist/terraform/modules/app/lambda-api/mcp-oauth.tf +181 -4
  149. package/dist/terraform/modules/app/lambda-api/memory-alarms.tf +92 -0
  150. package/dist/terraform/modules/app/lambda-api/msteams-app-secrets.tf +46 -0
  151. package/dist/terraform/modules/app/lambda-api/outputs.tf +35 -0
  152. package/dist/terraform/modules/app/lambda-api/runtime-config.tf +3 -21
  153. package/dist/terraform/modules/app/lambda-api/variables.tf +188 -3
  154. package/dist/terraform/modules/app/workflow-interpreter-stepfunctions/alarms.tf +47 -0
  155. package/dist/terraform/modules/app/workflow-interpreter-stepfunctions/main.tf +43 -2
  156. package/dist/terraform/modules/foundation/cognito/main.tf +319 -73
  157. package/dist/terraform/modules/foundation/cognito/outputs.tf +42 -0
  158. package/dist/terraform/modules/foundation/cognito/variables.tf +124 -2
  159. package/dist/terraform/modules/foundation/vpc/outputs.tf +5 -0
  160. package/dist/terraform/modules/thinkwork/main.tf +396 -26
  161. package/dist/terraform/modules/thinkwork/outputs.tf +188 -5
  162. package/dist/terraform/modules/thinkwork/variables.tf +154 -5
  163. package/dist/terraform/schema.graphql +69 -36
  164. package/dist/workspace-defaults/files/TOOLS.md +39 -0
  165. package/dist/workspace-defaults/files/USER.md +1 -0
  166. package/dist/workspace-defaults/files/agents/analyst/INSTRUCTIONS.md +18 -0
  167. package/dist/workspace-defaults/files/agents/coding/INSTRUCTIONS.md +11 -0
  168. package/dist/workspace-defaults/files/agents/research/INSTRUCTIONS.md +12 -0
  169. package/dist/workspace-defaults/files/agents/reviewer/INSTRUCTIONS.md +15 -0
  170. package/dist/workspace-defaults/files/skills/document-composer/SKILL.md +6 -2
  171. package/package.json +6 -3
  172. package/dist/plugins/workos-auth/package.json +0 -22
  173. package/dist/plugins/workos-auth/src/index.ts +0 -30
  174. package/dist/plugins/workos-auth/src/manifest.ts +0 -40
  175. package/dist/plugins/workos-auth/src/provider-contract.ts +0 -39
  176. package/dist/plugins/workos-auth/test/manifest.test.ts +0 -94
  177. package/dist/plugins/workos-auth/tsconfig.json +0 -8
  178. /package/dist/workspace-defaults/files/{AGENTS.md → INSTRUCTIONS.md} +0 -0
@@ -0,0 +1,84 @@
1
+ -- THINK-302 U11: pending_tool_approvals — parked-turn HITL ledger.
2
+ --
3
+ -- A distinct pending kind from pending_user_questions (KTD-5): a gated tool
4
+ -- call parks the turn and this row is the recoverable ledger. Two partial
5
+ -- unique indexes drizzle-kit cannot express live here:
6
+ -- * one `pending` approval per thread (the one-slot invariant, R32) — so
7
+ -- an approval can COEXIST with a pending question (separate tables/slots),
8
+ -- and the intake endpoint returns 409 on a second concurrent park.
9
+ -- * resume-replay uniqueness (thread_turn_id, tool_call_id, manifest
10
+ -- fingerprint) — a stale approval cannot authorize a drifted definition
11
+ -- and a retried intake is idempotent.
12
+ --
13
+ -- Ships INERT: no writer touches this table until U11b; U12 consumes it.
14
+ --
15
+ -- Hand-rolled (partial indices, CHECK constraints); not in meta/_journal.json.
16
+ -- Apply manually:
17
+ -- psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f drizzle/0258_pending_tool_approvals.sql
18
+ -- creates: public.pending_tool_approvals
19
+ -- creates: public.pending_tool_approvals_one_pending_per_thread
20
+ -- creates: public.pending_tool_approvals_resume_identity
21
+ -- creates: public.idx_pending_tool_approvals_tenant
22
+ -- creates: public.idx_pending_tool_approvals_thread_status
23
+ -- creates: public.idx_pending_tool_approvals_message
24
+ -- creates: public.idx_pending_tool_approvals_purge
25
+
26
+ \set ON_ERROR_STOP on
27
+
28
+ SET lock_timeout = '5s';
29
+ SET statement_timeout = '15min';
30
+
31
+ SELECT pg_advisory_lock(hashtext('migration:0258_pending_tool_approvals'));
32
+
33
+ CREATE TABLE IF NOT EXISTS public.pending_tool_approvals (
34
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
35
+ tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
36
+ thread_id uuid NOT NULL REFERENCES public.threads(id) ON DELETE CASCADE,
37
+ thread_turn_id uuid NOT NULL REFERENCES public.thread_turns(id),
38
+ message_id uuid NOT NULL REFERENCES public.messages(id) ON DELETE CASCADE,
39
+ manifest_fingerprint text NOT NULL,
40
+ tool_call_id text NOT NULL,
41
+ class text NOT NULL,
42
+ slug text NOT NULL,
43
+ marker_sha text NOT NULL,
44
+ status text NOT NULL DEFAULT 'pending',
45
+ requesting_user_id uuid REFERENCES public.users(id) ON DELETE SET NULL,
46
+ encrypted_payload text,
47
+ display_summary jsonb NOT NULL,
48
+ approved_by uuid REFERENCES public.users(id) ON DELETE SET NULL,
49
+ answered_via text,
50
+ answered_at timestamptz,
51
+ payload_purged_at timestamptz,
52
+ created_at timestamptz NOT NULL DEFAULT now(),
53
+ CONSTRAINT pending_tool_approvals_status_allowed
54
+ CHECK (status IN ('pending','approved','denied','cancelled')),
55
+ CONSTRAINT pending_tool_approvals_answered_via_allowed
56
+ CHECK (answered_via IS NULL OR answered_via IN ('card','slack','governance','archive','reaper')),
57
+ CONSTRAINT pending_tool_approvals_terminal_consistency
58
+ CHECK ((status = 'pending') = (answered_at IS NULL))
59
+ );
60
+
61
+ -- One pending approval per thread (the one-slot invariant). Partial so
62
+ -- terminal rows never block a new park, and so it is INDEPENDENT of the
63
+ -- pending_user_questions slot (an approval + a question can both be pending).
64
+ CREATE UNIQUE INDEX IF NOT EXISTS pending_tool_approvals_one_pending_per_thread
65
+ ON public.pending_tool_approvals (thread_id)
66
+ WHERE status = 'pending';
67
+
68
+ -- Resume-replay identity: a park is unique per (turn, tool call, pinned
69
+ -- manifest) so a retried intake is idempotent and a stale approval cannot
70
+ -- authorize a drifted definition.
71
+ CREATE UNIQUE INDEX IF NOT EXISTS pending_tool_approvals_resume_identity
72
+ ON public.pending_tool_approvals (thread_turn_id, tool_call_id, manifest_fingerprint);
73
+
74
+ CREATE INDEX IF NOT EXISTS idx_pending_tool_approvals_tenant
75
+ ON public.pending_tool_approvals (tenant_id);
76
+ CREATE INDEX IF NOT EXISTS idx_pending_tool_approvals_thread_status
77
+ ON public.pending_tool_approvals (thread_id, status);
78
+ CREATE INDEX IF NOT EXISTS idx_pending_tool_approvals_message
79
+ ON public.pending_tool_approvals (message_id);
80
+ -- Reaper scan: terminal rows whose payload is not yet purged, by age.
81
+ CREATE INDEX IF NOT EXISTS idx_pending_tool_approvals_purge
82
+ ON public.pending_tool_approvals (status, payload_purged_at);
83
+
84
+ SELECT pg_advisory_unlock(hashtext('migration:0258_pending_tool_approvals'));
@@ -0,0 +1,19 @@
1
+ -- THINK-302 U3b: per-tenant capability registry-trust gate (KTD-8).
2
+ --
3
+ -- Off for every tenant at migration time; flipped on per tenant
4
+ -- (dev → TEI → McPherson) as the capability approval registry replaces
5
+ -- per-folder sidecar signatures. Read by the workspace renderer
6
+ -- (compose-tuple) to decide registry-trust vs legacy sidecar admission.
7
+ --
8
+ -- Additive, idempotent column add. Hand-rolled only so it carries a
9
+ -- drift-gate marker alongside the sibling hand-rolled capability migrations;
10
+ -- db:push would also add it from the ORM definition.
11
+ --
12
+ -- Apply manually:
13
+ -- psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f drizzle/0259_tenant_capability_registry_trust.sql
14
+ -- creates-column: public.tenants.capability_registry_trust
15
+
16
+ \set ON_ERROR_STOP on
17
+
18
+ ALTER TABLE public.tenants
19
+ ADD COLUMN IF NOT EXISTS capability_registry_trust boolean NOT NULL DEFAULT false;
@@ -0,0 +1,20 @@
1
+ -- THINK-302 U7 (R28/KTD-14): run-as identity for wakeup/scheduled turns.
2
+ --
3
+ -- The user a scheduled/wakeup turn runs AS, so it composes that user's +
4
+ -- the run-in-space's capability scopes. A job with no run_as_user_id
5
+ -- compiles root + sub-agent only — it NEVER inherits the creator's grants.
6
+ -- Set/cleared only through an authorized surface (KTD-14 save-time authz);
7
+ -- dispatch-time revalidation drops stale grants.
8
+ --
9
+ -- Additive, idempotent nullable-FK column add (ON DELETE SET NULL so a
10
+ -- deactivated user's jobs degrade to root-only rather than break).
11
+ -- Hand-rolled only to carry the drift-gate marker; db:push would also add it.
12
+ --
13
+ -- Apply manually:
14
+ -- psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f drizzle/0260_scheduled_jobs_run_as_user.sql
15
+ -- creates-column: public.scheduled_jobs.run_as_user_id
16
+
17
+ \set ON_ERROR_STOP on
18
+
19
+ ALTER TABLE public.scheduled_jobs
20
+ ADD COLUMN IF NOT EXISTS run_as_user_id uuid REFERENCES public.users(id) ON DELETE SET NULL;
@@ -0,0 +1,313 @@
1
+ -- creates: public.harness_managed_thread_enrollments
2
+ -- creates: public.thread_public_events
3
+ -- creates: public.harness_participant_sessions
4
+ -- creates: public.harness_participant_session_events
5
+ -- creates: public.harness_governed_tool_executions
6
+ -- creates: public.harness_disclosure_decisions
7
+ -- creates-function: public.capture_harness_message_public_event
8
+ -- creates-function: public.capture_harness_artifact_public_event
9
+ -- creates-trigger: public.messages.trg_capture_harness_message_public_event
10
+ -- creates-trigger: public.message_artifacts.trg_capture_harness_artifact_public_event
11
+ -- Managed multiplayer Harness proof ledger. Hand-rolled because this migration
12
+ -- also installs admission triggers over existing canonical message tables.
13
+
14
+ CREATE TABLE IF NOT EXISTS public.harness_managed_thread_enrollments (
15
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
16
+ tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
17
+ thread_id uuid NOT NULL REFERENCES public.threads(id) ON DELETE CASCADE,
18
+ logical_agent_id uuid NOT NULL REFERENCES public.agents(id),
19
+ trust_profile text NOT NULL,
20
+ harness_arn text NOT NULL,
21
+ qualifier text NOT NULL,
22
+ resolved_version text NOT NULL,
23
+ session_strategy text NOT NULL DEFAULT 'fresh'
24
+ CHECK (session_strategy = 'fresh'),
25
+ prior_runtime text NOT NULL,
26
+ status text NOT NULL DEFAULT 'active'
27
+ CHECK (status IN ('active', 'restoring', 'restored', 'failed')),
28
+ enrolled_by_user_id uuid NOT NULL REFERENCES public.users(id),
29
+ created_at timestamptz NOT NULL DEFAULT now(),
30
+ restored_at timestamptz,
31
+ UNIQUE (tenant_id, thread_id)
32
+ );
33
+
34
+ CREATE UNIQUE INDEX IF NOT EXISTS uq_harness_enrollment_active_profile
35
+ ON public.harness_managed_thread_enrollments (tenant_id, trust_profile)
36
+ WHERE status = 'active';
37
+
38
+ CREATE TABLE IF NOT EXISTS public.thread_public_events (
39
+ id bigserial PRIMARY KEY,
40
+ tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
41
+ thread_id uuid NOT NULL REFERENCES public.threads(id) ON DELETE CASCADE,
42
+ source_kind text NOT NULL CHECK (source_kind IN ('message', 'message_artifact')),
43
+ source_id uuid NOT NULL,
44
+ source_version text NOT NULL,
45
+ event_kind text NOT NULL CHECK (event_kind IN ('insert', 'invalidate')),
46
+ canonical_digest text NOT NULL,
47
+ created_at timestamptz NOT NULL DEFAULT now(),
48
+ UNIQUE (tenant_id, thread_id, source_kind, source_id, source_version)
49
+ );
50
+
51
+ CREATE INDEX IF NOT EXISTS idx_thread_public_events_prefix
52
+ ON public.thread_public_events (tenant_id, thread_id, id);
53
+
54
+ CREATE TABLE IF NOT EXISTS public.harness_participant_sessions (
55
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
56
+ tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
57
+ enrollment_id uuid NOT NULL REFERENCES public.harness_managed_thread_enrollments(id) ON DELETE CASCADE,
58
+ thread_id uuid NOT NULL REFERENCES public.threads(id) ON DELETE CASCADE,
59
+ participant_user_id uuid NOT NULL REFERENCES public.users(id),
60
+ turn_id uuid NOT NULL REFERENCES public.thread_turns(id) ON DELETE CASCADE,
61
+ runtime_session_id text NOT NULL UNIQUE,
62
+ generation integer NOT NULL DEFAULT 1 CHECK (generation = 1),
63
+ captured_high_water bigint NOT NULL,
64
+ applied_high_water bigint,
65
+ qualifier text NOT NULL,
66
+ resolved_version text NOT NULL,
67
+ base_fingerprint text NOT NULL,
68
+ participant_fingerprint text NOT NULL,
69
+ state text NOT NULL DEFAULT 'allocated'
70
+ CHECK (state IN ('allocated', 'running', 'finalizing', 'completed', 'abandoned')),
71
+ failure_reason text,
72
+ created_at timestamptz NOT NULL DEFAULT now(),
73
+ started_at timestamptz,
74
+ finished_at timestamptz,
75
+ UNIQUE (tenant_id, turn_id),
76
+ CHECK (
77
+ (state IN ('completed', 'abandoned') AND finished_at IS NOT NULL)
78
+ OR (state NOT IN ('completed', 'abandoned') AND finished_at IS NULL)
79
+ )
80
+ );
81
+
82
+ CREATE INDEX IF NOT EXISTS idx_harness_participant_sessions_thread
83
+ ON public.harness_participant_sessions
84
+ (tenant_id, thread_id, participant_user_id, created_at);
85
+
86
+ CREATE TABLE IF NOT EXISTS public.harness_participant_session_events (
87
+ id bigserial PRIMARY KEY,
88
+ tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
89
+ session_id uuid NOT NULL REFERENCES public.harness_participant_sessions(id) ON DELETE CASCADE,
90
+ turn_id uuid NOT NULL REFERENCES public.thread_turns(id) ON DELETE CASCADE,
91
+ event_type text NOT NULL,
92
+ from_state text,
93
+ to_state text NOT NULL
94
+ CHECK (to_state IN ('allocated', 'running', 'finalizing', 'completed', 'abandoned')),
95
+ reason_code text,
96
+ applied_high_water bigint,
97
+ evidence jsonb,
98
+ created_at timestamptz NOT NULL DEFAULT now()
99
+ );
100
+
101
+ CREATE INDEX IF NOT EXISTS idx_harness_session_events_session
102
+ ON public.harness_participant_session_events (session_id, id);
103
+
104
+ CREATE TABLE IF NOT EXISTS public.harness_governed_tool_executions (
105
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
106
+ tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
107
+ turn_id uuid NOT NULL REFERENCES public.thread_turns(id) ON DELETE CASCADE,
108
+ participant_user_id uuid NOT NULL REFERENCES public.users(id),
109
+ session_id uuid NOT NULL REFERENCES public.harness_participant_sessions(id) ON DELETE CASCADE,
110
+ idempotency_key text NOT NULL,
111
+ audience text NOT NULL,
112
+ operation text NOT NULL,
113
+ tool_use_id text NOT NULL,
114
+ input_digest text NOT NULL,
115
+ state text NOT NULL DEFAULT 'claimed'
116
+ CHECK (state IN ('claimed', 'completed', 'failed', 'ambiguous')),
117
+ policy_decision_id text,
118
+ credential_owner_alias text,
119
+ sanitized_result jsonb,
120
+ failure_reason text,
121
+ claimed_at timestamptz NOT NULL DEFAULT now(),
122
+ completed_at timestamptz,
123
+ UNIQUE (tenant_id, idempotency_key)
124
+ );
125
+
126
+ CREATE INDEX IF NOT EXISTS idx_harness_governed_tool_turn
127
+ ON public.harness_governed_tool_executions (turn_id);
128
+
129
+ CREATE TABLE IF NOT EXISTS public.harness_disclosure_decisions (
130
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
131
+ tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
132
+ participant_user_id uuid NOT NULL REFERENCES public.users(id),
133
+ thread_id uuid NOT NULL REFERENCES public.threads(id) ON DELETE CASCADE,
134
+ turn_id uuid NOT NULL REFERENCES public.thread_turns(id) ON DELETE CASCADE,
135
+ session_id uuid NOT NULL REFERENCES public.harness_participant_sessions(id) ON DELETE CASCADE,
136
+ operation text NOT NULL,
137
+ projection_digest text NOT NULL,
138
+ status text NOT NULL
139
+ CHECK (status IN ('published', 'withheld', 'confirmation_required')),
140
+ reason_code text NOT NULL,
141
+ expires_at timestamptz NOT NULL,
142
+ created_at timestamptz NOT NULL DEFAULT now()
143
+ );
144
+
145
+ CREATE INDEX IF NOT EXISTS idx_harness_disclosure_turn
146
+ ON public.harness_disclosure_decisions (turn_id);
147
+
148
+ CREATE OR REPLACE FUNCTION public.capture_harness_message_public_event()
149
+ RETURNS trigger
150
+ LANGUAGE plpgsql
151
+ AS $$
152
+ DECLARE
153
+ digest_value text;
154
+ version_value text;
155
+ event_value text;
156
+ admitted_before boolean;
157
+ admitted_now boolean;
158
+ BEGIN
159
+ IF TG_OP = 'DELETE' THEN
160
+ IF NOT EXISTS (
161
+ SELECT 1 FROM public.thread_public_events e
162
+ WHERE e.tenant_id = OLD.tenant_id
163
+ AND e.thread_id = OLD.thread_id
164
+ AND e.source_kind = 'message'
165
+ AND e.source_id = OLD.id
166
+ ) THEN
167
+ RETURN OLD;
168
+ END IF;
169
+ digest_value := encode(digest(concat_ws('|', OLD.role, coalesce(OLD.content, ''), coalesce(OLD.parts::text, ''), coalesce(OLD.metadata::text, '')), 'sha256'), 'hex');
170
+ version_value := 'delete:' || digest_value;
171
+ event_value := 'invalidate';
172
+ INSERT INTO public.thread_public_events (
173
+ tenant_id, thread_id, source_kind, source_id, source_version,
174
+ event_kind, canonical_digest
175
+ ) VALUES (
176
+ OLD.tenant_id, OLD.thread_id, 'message', OLD.id,
177
+ version_value, event_value, digest_value
178
+ ) ON CONFLICT DO NOTHING;
179
+ RETURN OLD;
180
+ END IF;
181
+
182
+ admitted_now := NEW.role IN ('user', 'assistant')
183
+ AND coalesce(NEW.metadata->>'visibility', 'public') = 'public'
184
+ AND coalesce(NEW.metadata->>'disclosure_status', 'published') NOT IN ('withheld', 'confirmation_required')
185
+ AND EXISTS (
186
+ SELECT 1 FROM public.harness_managed_thread_enrollments e
187
+ WHERE e.tenant_id = NEW.tenant_id
188
+ AND e.thread_id = NEW.thread_id
189
+ AND e.status = 'active'
190
+ );
191
+
192
+ IF TG_OP = 'UPDATE' THEN
193
+ admitted_before := EXISTS (
194
+ SELECT 1 FROM public.thread_public_events e
195
+ WHERE e.tenant_id = OLD.tenant_id
196
+ AND e.thread_id = OLD.thread_id
197
+ AND e.source_kind = 'message'
198
+ AND e.source_id = OLD.id
199
+ );
200
+ IF admitted_before THEN
201
+ digest_value := encode(digest(concat_ws('|', OLD.role, coalesce(OLD.content, ''), coalesce(OLD.parts::text, ''), coalesce(OLD.metadata::text, '')), 'sha256'), 'hex');
202
+ version_value := 'invalidate:update:' || encode(digest(concat_ws('|', NEW.role, coalesce(NEW.content, ''), coalesce(NEW.parts::text, ''), coalesce(NEW.metadata::text, '')), 'sha256'), 'hex');
203
+ INSERT INTO public.thread_public_events (
204
+ tenant_id, thread_id, source_kind, source_id, source_version,
205
+ event_kind, canonical_digest
206
+ ) VALUES (
207
+ OLD.tenant_id, OLD.thread_id, 'message', OLD.id,
208
+ version_value, 'invalidate', digest_value
209
+ ) ON CONFLICT DO NOTHING;
210
+ END IF;
211
+ END IF;
212
+
213
+ IF NOT admitted_now THEN
214
+ RETURN NEW;
215
+ END IF;
216
+
217
+ digest_value := encode(digest(concat_ws('|', NEW.role, coalesce(NEW.content, ''), coalesce(NEW.parts::text, '')), 'sha256'), 'hex');
218
+ version_value := lower(TG_OP) || ':' || digest_value || ':' || encode(digest(coalesce(NEW.metadata::text, ''), 'sha256'), 'hex');
219
+ INSERT INTO public.thread_public_events (
220
+ tenant_id, thread_id, source_kind, source_id, source_version,
221
+ event_kind, canonical_digest
222
+ ) VALUES (
223
+ NEW.tenant_id, NEW.thread_id, 'message', NEW.id,
224
+ version_value, 'insert', digest_value
225
+ ) ON CONFLICT DO NOTHING;
226
+ RETURN NEW;
227
+ END;
228
+ $$;
229
+
230
+ DROP TRIGGER IF EXISTS trg_capture_harness_message_public_event ON public.messages;
231
+ CREATE TRIGGER trg_capture_harness_message_public_event
232
+ AFTER INSERT OR UPDATE OR DELETE ON public.messages
233
+ FOR EACH ROW EXECUTE FUNCTION public.capture_harness_message_public_event();
234
+
235
+ CREATE OR REPLACE FUNCTION public.capture_harness_artifact_public_event()
236
+ RETURNS trigger
237
+ LANGUAGE plpgsql
238
+ AS $$
239
+ DECLARE
240
+ digest_value text;
241
+ version_value text;
242
+ admitted_before boolean;
243
+ admitted_now boolean;
244
+ BEGIN
245
+ IF TG_OP = 'DELETE' THEN
246
+ IF NOT EXISTS (
247
+ SELECT 1 FROM public.thread_public_events e
248
+ WHERE e.tenant_id = OLD.tenant_id
249
+ AND e.thread_id = OLD.thread_id
250
+ AND e.source_kind = 'message_artifact'
251
+ AND e.source_id = OLD.id
252
+ ) THEN
253
+ RETURN OLD;
254
+ END IF;
255
+ digest_value := encode(digest(concat_ws('|', OLD.artifact_type, coalesce(OLD.name, ''), coalesce(OLD.artifact_id::text, ''), coalesce(OLD.metadata::text, '')), 'sha256'), 'hex');
256
+ INSERT INTO public.thread_public_events (
257
+ tenant_id, thread_id, source_kind, source_id, source_version,
258
+ event_kind, canonical_digest
259
+ ) VALUES (
260
+ OLD.tenant_id, OLD.thread_id, 'message_artifact', OLD.id,
261
+ 'delete:' || digest_value, 'invalidate', digest_value
262
+ ) ON CONFLICT DO NOTHING;
263
+ RETURN OLD;
264
+ END IF;
265
+
266
+ admitted_now := EXISTS (
267
+ SELECT 1 FROM public.harness_managed_thread_enrollments e
268
+ WHERE e.tenant_id = NEW.tenant_id
269
+ AND e.thread_id = NEW.thread_id
270
+ AND e.status = 'active'
271
+ ) AND coalesce(NEW.metadata->>'access_state', 'public') = 'public';
272
+
273
+ IF TG_OP = 'UPDATE' THEN
274
+ admitted_before := EXISTS (
275
+ SELECT 1 FROM public.thread_public_events e
276
+ WHERE e.tenant_id = OLD.tenant_id
277
+ AND e.thread_id = OLD.thread_id
278
+ AND e.source_kind = 'message_artifact'
279
+ AND e.source_id = OLD.id
280
+ );
281
+ IF admitted_before THEN
282
+ digest_value := encode(digest(concat_ws('|', OLD.artifact_type, coalesce(OLD.name, ''), coalesce(OLD.artifact_id::text, ''), coalesce(OLD.metadata::text, '')), 'sha256'), 'hex');
283
+ version_value := 'invalidate:update:' || encode(digest(concat_ws('|', NEW.artifact_type, coalesce(NEW.name, ''), coalesce(NEW.artifact_id::text, ''), coalesce(NEW.metadata::text, '')), 'sha256'), 'hex');
284
+ INSERT INTO public.thread_public_events (
285
+ tenant_id, thread_id, source_kind, source_id, source_version,
286
+ event_kind, canonical_digest
287
+ ) VALUES (
288
+ OLD.tenant_id, OLD.thread_id, 'message_artifact', OLD.id,
289
+ version_value, 'invalidate', digest_value
290
+ ) ON CONFLICT DO NOTHING;
291
+ END IF;
292
+ END IF;
293
+
294
+ IF NOT admitted_now THEN
295
+ RETURN NEW;
296
+ END IF;
297
+
298
+ digest_value := encode(digest(concat_ws('|', NEW.artifact_type, coalesce(NEW.name, ''), coalesce(NEW.artifact_id::text, ''), coalesce(NEW.metadata::text, '')), 'sha256'), 'hex');
299
+ INSERT INTO public.thread_public_events (
300
+ tenant_id, thread_id, source_kind, source_id, source_version,
301
+ event_kind, canonical_digest
302
+ ) VALUES (
303
+ NEW.tenant_id, NEW.thread_id, 'message_artifact', NEW.id,
304
+ lower(TG_OP) || ':' || digest_value, 'insert', digest_value
305
+ ) ON CONFLICT DO NOTHING;
306
+ RETURN NEW;
307
+ END;
308
+ $$;
309
+
310
+ DROP TRIGGER IF EXISTS trg_capture_harness_artifact_public_event ON public.message_artifacts;
311
+ CREATE TRIGGER trg_capture_harness_artifact_public_event
312
+ AFTER INSERT OR UPDATE OR DELETE ON public.message_artifacts
313
+ FOR EACH ROW EXECUTE FUNCTION public.capture_harness_artifact_public_event();