@agent-team-foundation/first-tree-hub 0.14.5 → 0.14.6

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 (101) hide show
  1. package/dist/bootstrap-BmeaRhRp.mjs +3 -0
  2. package/dist/{bootstrap-CQQGgIx1.mjs → bootstrap-CmkHQsnS.mjs} +24 -16
  3. package/dist/cli/index.mjs +6 -94
  4. package/dist/{dist-CrdnqZjv.mjs → feishu-BE7QRxnE.mjs} +170 -379
  5. package/dist/feishu-De9_bA91.mjs +3 -0
  6. package/dist/index.mjs +5 -12
  7. package/dist/saas-connect-CNY9Ve5V.mjs +13748 -0
  8. package/package.json +4 -12
  9. package/dist/chunk-BSw8zbkd.mjs +0 -37
  10. package/dist/client-BPRIfrOT-CoV_2o7e.mjs +0 -4230
  11. package/dist/client-CEdYVnoj-BGiGcJbH.mjs +0 -7
  12. package/dist/dist-LgF7LHpE.mjs +0 -430
  13. package/dist/drizzle/0000_shocking_darkhawk.sql +0 -92
  14. package/dist/drizzle/0001_v2_schema_updates.sql +0 -26
  15. package/dist/drizzle/0002_adapter_tables.sql +0 -64
  16. package/dist/drizzle/0003_feishu_adapter.sql +0 -21
  17. package/dist/drizzle/0004_adapter_refactor.sql +0 -13
  18. package/dist/drizzle/0005_delegate_mention.sql +0 -1
  19. package/dist/drizzle/0006_agent_tree_path.sql +0 -1
  20. package/dist/drizzle/0007_decouple_context_tree.sql +0 -2
  21. package/dist/drizzle/0008_uuid_identity.sql +0 -12
  22. package/dist/drizzle/0009_agent_runtime_m1.sql +0 -31
  23. package/dist/drizzle/0010_cloud_multi_tenancy.sql +0 -34
  24. package/dist/drizzle/0011_org_uuid_pk.sql +0 -22
  25. package/dist/drizzle/0012_session_level_state.sql +0 -19
  26. package/dist/drizzle/0013_hub_tasks.sql +0 -38
  27. package/dist/drizzle/0014_drop_task_fks.sql +0 -9
  28. package/dist/drizzle/0015_member_system.sql +0 -34
  29. package/dist/drizzle/0016_strange_havok.sql +0 -25
  30. package/dist/drizzle/0017_session_outputs_unique.sql +0 -1
  31. package/dist/drizzle/0018_agent_visibility.sql +0 -13
  32. package/dist/drizzle/0019_agent_configs.sql +0 -30
  33. package/dist/drizzle/0020_unified_user_token.sql +0 -154
  34. package/dist/drizzle/0021_drop_agents_profile.sql +0 -10
  35. package/dist/drizzle/0022_session_events.sql +0 -32
  36. package/dist/drizzle/0023_clients_org_scoping.sql +0 -40
  37. package/dist/drizzle/0024_display_name_not_null.sql +0 -31
  38. package/dist/drizzle/0025_inbox_silent_entries.sql +0 -53
  39. package/dist/drizzle/0026_saas_onboarding.sql +0 -153
  40. package/dist/drizzle/0027_runtime_provider.sql +0 -10
  41. package/dist/drizzle/0028_auth_identity_user_github_unique.sql +0 -12
  42. package/dist/drizzle/0029_direct_agent_only_mention_only.sql +0 -28
  43. package/dist/drizzle/0030_chat_first_workspace.sql +0 -129
  44. package/dist/drizzle/0031_drop_system_configs.sql +0 -11
  45. package/dist/drizzle/0032_organization_settings.sql +0 -36
  46. package/dist/drizzle/0033_onboarding_dismissed_at.sql +0 -13
  47. package/dist/drizzle/0034_pending_questions.sql +0 -34
  48. package/dist/drizzle/0035_drop_hub_tasks.sql +0 -7
  49. package/dist/drizzle/0036_github_entity_chat_mappings.sql +0 -47
  50. package/dist/drizzle/0037_github_app_installations.sql +0 -52
  51. package/dist/drizzle/0038_chat_membership_user_state.sql +0 -223
  52. package/dist/drizzle/0039_drop_chat_participants_subscriptions.sql +0 -26
  53. package/dist/drizzle/0040_chat_user_state_engagement.sql +0 -24
  54. package/dist/drizzle/0041_notifications_dedup_key.sql +0 -29
  55. package/dist/drizzle/0042_notifications_drop_legacy_types.sql +0 -36
  56. package/dist/drizzle/0043_onboarding_completed_at.sql +0 -32
  57. package/dist/drizzle/0044_agent_avatar_color.sql +0 -11
  58. package/dist/drizzle/0045_agent_avatar_image.sql +0 -17
  59. package/dist/drizzle/meta/0000_snapshot.json +0 -687
  60. package/dist/drizzle/meta/0001_snapshot.json +0 -687
  61. package/dist/drizzle/meta/0012_snapshot.json +0 -1451
  62. package/dist/drizzle/meta/0013_snapshot.json +0 -1771
  63. package/dist/drizzle/meta/0014_snapshot.json +0 -1717
  64. package/dist/drizzle/meta/0016_snapshot.json +0 -1917
  65. package/dist/drizzle/meta/0018_snapshot.json +0 -1938
  66. package/dist/drizzle/meta/_journal.json +0 -328
  67. package/dist/esm-iadMkGbV.mjs +0 -1516
  68. package/dist/execAsync-DUfRkc4a.mjs +0 -10
  69. package/dist/execAsync-YbEZSOYd.mjs +0 -10
  70. package/dist/feishu-DNoBroKK.mjs +0 -53
  71. package/dist/from-DQ7eNRwu.mjs +0 -3840
  72. package/dist/getMachineId-bsd-BmasEOJr.mjs +0 -27
  73. package/dist/getMachineId-bsd-Dh3h0DDE.mjs +0 -27
  74. package/dist/getMachineId-darwin-CuhM3hfZ.mjs +0 -24
  75. package/dist/getMachineId-darwin-D9wR0SLj.mjs +0 -24
  76. package/dist/getMachineId-linux-CYfb0oxZ.mjs +0 -20
  77. package/dist/getMachineId-linux-D8ZaSjAC.mjs +0 -20
  78. package/dist/getMachineId-unsupported-Cu3iisaD.mjs +0 -15
  79. package/dist/getMachineId-unsupported-DZqI4ZT5.mjs +0 -15
  80. package/dist/getMachineId-win-8ZJbtrdf.mjs +0 -26
  81. package/dist/getMachineId-win-DT-hqwVp.mjs +0 -26
  82. package/dist/invitation-C9m2gQx4-C_4f5VTs.mjs +0 -4
  83. package/dist/invitation-D_ENPHyj-5ETiae5r.mjs +0 -167
  84. package/dist/logger-core-BTmvdflj-DjW8FM4T.mjs +0 -146
  85. package/dist/multipart-parser-QRu3OKK4.mjs +0 -294
  86. package/dist/observability-BAScT_5S-BcW9HgkG.mjs +0 -96129
  87. package/dist/observability-eLA9iNK_.mjs +0 -5
  88. package/dist/saas-connect-CYp9TOB5.mjs +0 -21918
  89. package/dist/src-DFlbpJfU.mjs +0 -1176
  90. package/dist/src-DNBS5Yjj.mjs +0 -735
  91. package/dist/uuid-DbS_4vFh-iFghv4zA.mjs +0 -129
  92. package/dist/web/assets/index-9wK0udbH.js +0 -416
  93. package/dist/web/assets/index-C7x7O7dG.js +0 -11
  94. package/dist/web/assets/index-DE7Q3QWE.css +0 -1
  95. package/dist/web/favicon.svg +0 -9
  96. package/dist/web/fonts/inter-latin-ext.woff2 +0 -0
  97. package/dist/web/fonts/inter-latin.woff2 +0 -0
  98. package/dist/web/fonts/jetbrains-mono-latin-ext.woff2 +0 -0
  99. package/dist/web/fonts/jetbrains-mono-latin.woff2 +0 -0
  100. package/dist/web/index.html +0 -39
  101. /package/dist/{cli-fetch--tiwKm5S.mjs → cli-fetch-BGVItZxo.mjs} +0 -0
@@ -1,12 +0,0 @@
1
- -- Agent identity refactoring: id → uuid (PK) + name (human-readable, per-org unique)
2
- -- Run BEFORE the data migration script (scripts/migrate-uuid.ts).
3
-
4
- -- 1. Add name column
5
- ALTER TABLE "agents" ADD COLUMN "name" text;
6
-
7
- -- 2. Rename id → uuid (PG auto-updates FK constraints referencing this column)
8
- ALTER TABLE "agents" RENAME COLUMN "id" TO "uuid";
9
-
10
- -- 3. Add composite unique constraint (org + name)
11
- -- NULLs are distinct in PG unique constraints, so deleted agents (name=NULL) don't conflict
12
- ALTER TABLE "agents" ADD CONSTRAINT "uq_agents_org_name" UNIQUE("organization_id", "name");
@@ -1,31 +0,0 @@
1
- -- M1: Agent Runtime — Process Awareness
2
- -- New clients table + agent_presence runtime columns
3
-
4
- CREATE TABLE IF NOT EXISTS "clients" (
5
- "id" text PRIMARY KEY NOT NULL,
6
- "status" text DEFAULT 'disconnected' NOT NULL,
7
- "sdk_version" text,
8
- "hostname" text,
9
- "os" text,
10
- "instance_id" text,
11
- "connected_at" timestamp with time zone,
12
- "last_seen_at" timestamp with time zone DEFAULT now() NOT NULL,
13
- "metadata" jsonb
14
- );
15
-
16
- ALTER TABLE "agent_presence" ADD COLUMN "client_id" text;
17
- ALTER TABLE "agent_presence" ADD COLUMN "runtime_type" text;
18
- ALTER TABLE "agent_presence" ADD COLUMN "runtime_version" text;
19
- ALTER TABLE "agent_presence" ADD COLUMN "runtime_state" text;
20
- ALTER TABLE "agent_presence" ADD COLUMN "runtime_description" text;
21
- ALTER TABLE "agent_presence" ADD COLUMN "active_sessions" integer;
22
- ALTER TABLE "agent_presence" ADD COLUMN "total_sessions" integer;
23
- ALTER TABLE "agent_presence" ADD COLUMN "error_message" text;
24
- ALTER TABLE "agent_presence" ADD COLUMN "task_ref" text;
25
- ALTER TABLE "agent_presence" ADD COLUMN "runtime_updated_at" timestamp with time zone;
26
-
27
- DO $$ BEGIN
28
- ALTER TABLE "agent_presence" ADD CONSTRAINT "agent_presence_client_id_clients_id_fk" FOREIGN KEY ("client_id") REFERENCES "public"."clients"("id") ON DELETE set null ON UPDATE no action;
29
- EXCEPTION
30
- WHEN duplicate_object THEN null;
31
- END $$;
@@ -1,34 +0,0 @@
1
- -- Cloud Multi-Tenancy Phase 1: organizations table + agents/chats FK + new agent fields
2
-
3
- -- 1. Create organizations table
4
- CREATE TABLE IF NOT EXISTS "organizations" (
5
- "id" text PRIMARY KEY NOT NULL,
6
- "display_name" text NOT NULL,
7
- "max_agents" integer NOT NULL DEFAULT 0,
8
- "max_messages_per_minute" integer NOT NULL DEFAULT 0,
9
- "features" jsonb NOT NULL DEFAULT '{}'::jsonb,
10
- "created_at" timestamptz NOT NULL DEFAULT now(),
11
- "updated_at" timestamptz NOT NULL DEFAULT now()
12
- );
13
-
14
- -- 2. Insert default organization (idempotent — skip if exists)
15
- INSERT INTO "organizations" ("id", "display_name")
16
- VALUES ('default', 'Default Organization')
17
- ON CONFLICT ("id") DO NOTHING;
18
-
19
- -- 3. Add FK from agents.organization_id → organizations.id
20
- ALTER TABLE "agents"
21
- ADD CONSTRAINT "agents_organization_id_organizations_id_fk"
22
- FOREIGN KEY ("organization_id") REFERENCES "organizations"("id")
23
- ON DELETE NO ACTION ON UPDATE NO ACTION;
24
-
25
- -- 4. Add FK from chats.organization_id → organizations.id
26
- ALTER TABLE "chats"
27
- ADD CONSTRAINT "chats_organization_id_organizations_id_fk"
28
- FOREIGN KEY ("organization_id") REFERENCES "organizations"("id")
29
- ON DELETE NO ACTION ON UPDATE NO ACTION;
30
-
31
- -- 5. Add new columns to agents
32
- ALTER TABLE "agents" ADD COLUMN "source" text;
33
- ALTER TABLE "agents" ADD COLUMN "cloud_user_id" text;
34
- ALTER TABLE "agents" ADD COLUMN "public" boolean NOT NULL DEFAULT false;
@@ -1,22 +0,0 @@
1
- -- Organization UUID PK: add name column with unique constraint, drop old defaults
2
-
3
- -- Step 1: Add name column
4
- ALTER TABLE "organizations" ADD COLUMN "name" text;
5
- --> statement-breakpoint
6
-
7
- -- Step 2: Backfill name from id for existing rows
8
- UPDATE "organizations" SET "name" = "id" WHERE "name" IS NULL;
9
- --> statement-breakpoint
10
-
11
- -- Step 3: Make name NOT NULL
12
- ALTER TABLE "organizations" ALTER COLUMN "name" SET NOT NULL;
13
- --> statement-breakpoint
14
-
15
- -- Step 4: Add UNIQUE constraint on name
16
- ALTER TABLE "organizations" ADD CONSTRAINT "organizations_name_unique" UNIQUE("name");
17
- --> statement-breakpoint
18
-
19
- -- Step 5: Drop old default values on organization_id columns (was 'default' slug)
20
- ALTER TABLE "agents" ALTER COLUMN "organization_id" DROP DEFAULT;
21
- --> statement-breakpoint
22
- ALTER TABLE "chats" ALTER COLUMN "organization_id" DROP DEFAULT;
@@ -1,19 +0,0 @@
1
- -- Session-level state reporting: new session table + drop unused presence columns
2
-
3
- CREATE TABLE "agent_chat_sessions" (
4
- "agent_id" text NOT NULL,
5
- "chat_id" text NOT NULL,
6
- "state" text NOT NULL,
7
- "updated_at" timestamp with time zone DEFAULT now() NOT NULL,
8
- CONSTRAINT "agent_chat_sessions_agent_id_chat_id_pk" PRIMARY KEY("agent_id","chat_id")
9
- );
10
- --> statement-breakpoint
11
- ALTER TABLE "agent_chat_sessions" ADD CONSTRAINT "agent_chat_sessions_agent_id_agents_uuid_fk" FOREIGN KEY ("agent_id") REFERENCES "public"."agents"("uuid") ON DELETE cascade ON UPDATE no action;
12
- --> statement-breakpoint
13
- ALTER TABLE "agent_chat_sessions" ADD CONSTRAINT "agent_chat_sessions_chat_id_chats_id_fk" FOREIGN KEY ("chat_id") REFERENCES "public"."chats"("id") ON DELETE cascade ON UPDATE no action;
14
- --> statement-breakpoint
15
- ALTER TABLE "agent_presence" DROP COLUMN IF EXISTS "runtime_description";
16
- --> statement-breakpoint
17
- ALTER TABLE "agent_presence" DROP COLUMN IF EXISTS "error_message";
18
- --> statement-breakpoint
19
- ALTER TABLE "agent_presence" DROP COLUMN IF EXISTS "task_ref";
@@ -1,38 +0,0 @@
1
- -- Hub Task — lightweight work units (tasks + task_chats)
2
-
3
- CREATE TABLE "tasks" (
4
- "id" text PRIMARY KEY NOT NULL,
5
- "organization_id" text NOT NULL,
6
- "title" text NOT NULL,
7
- "body" text DEFAULT '' NOT NULL,
8
- "status" text NOT NULL,
9
- "assignee_agent_id" text,
10
- "created_by_type" text NOT NULL,
11
- "created_by_id" text NOT NULL,
12
- "origin_ref" text,
13
- "result" text,
14
- "metadata" jsonb DEFAULT '{}'::jsonb NOT NULL,
15
- "created_at" timestamp with time zone DEFAULT now() NOT NULL,
16
- "updated_at" timestamp with time zone DEFAULT now() NOT NULL,
17
- "cancelled_at" timestamp with time zone,
18
- "cancelled_by_type" text,
19
- "cancelled_by_id" text
20
- );
21
- --> statement-breakpoint
22
- CREATE TABLE "task_chats" (
23
- "task_id" text NOT NULL,
24
- "chat_id" text NOT NULL,
25
- "linked_by_agent_id" text,
26
- "linked_at" timestamp with time zone DEFAULT now() NOT NULL,
27
- CONSTRAINT "task_chats_task_id_chat_id_pk" PRIMARY KEY("task_id","chat_id")
28
- );
29
- --> statement-breakpoint
30
- ALTER TABLE "tasks" ADD CONSTRAINT "tasks_organization_id_organizations_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organizations"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
31
- ALTER TABLE "task_chats" ADD CONSTRAINT "task_chats_task_id_tasks_id_fk" FOREIGN KEY ("task_id") REFERENCES "public"."tasks"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
32
- ALTER TABLE "task_chats" ADD CONSTRAINT "task_chats_chat_id_chats_id_fk" FOREIGN KEY ("chat_id") REFERENCES "public"."chats"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
33
- ALTER TABLE "task_chats" ADD CONSTRAINT "task_chats_linked_by_agent_id_agents_uuid_fk" FOREIGN KEY ("linked_by_agent_id") REFERENCES "public"."agents"("uuid") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
34
- CREATE INDEX "idx_tasks_org_status" ON "tasks" USING btree ("organization_id","status");--> statement-breakpoint
35
- CREATE INDEX "idx_tasks_assignee_status" ON "tasks" USING btree ("assignee_agent_id","status");--> statement-breakpoint
36
- CREATE INDEX "idx_tasks_origin_ref" ON "tasks" USING btree ("origin_ref");--> statement-breakpoint
37
- CREATE INDEX "idx_tasks_org_created_at" ON "tasks" USING btree ("organization_id","created_at");--> statement-breakpoint
38
- CREATE INDEX "idx_task_chats_chat" ON "task_chats" USING btree ("chat_id");
@@ -1,9 +0,0 @@
1
- -- Drop all FK constraints from the Hub Task tables.
2
- -- Referential integrity for tasks/task_chats is enforced in the service layer;
3
- -- DB-level FKs transfer the cost (cascade surprises, migration friction, test
4
- -- setup complexity) onto the database without adding value here.
5
-
6
- ALTER TABLE "tasks" DROP CONSTRAINT IF EXISTS "tasks_organization_id_organizations_id_fk";--> statement-breakpoint
7
- ALTER TABLE "task_chats" DROP CONSTRAINT IF EXISTS "task_chats_task_id_tasks_id_fk";--> statement-breakpoint
8
- ALTER TABLE "task_chats" DROP CONSTRAINT IF EXISTS "task_chats_chat_id_chats_id_fk";--> statement-breakpoint
9
- ALTER TABLE "task_chats" DROP CONSTRAINT IF EXISTS "task_chats_linked_by_agent_id_agents_uuid_fk";
@@ -1,34 +0,0 @@
1
- -- Create users table (replaces admin_users)
2
- CREATE TABLE "users" (
3
- "id" text PRIMARY KEY NOT NULL,
4
- "username" text NOT NULL,
5
- "password_hash" text NOT NULL,
6
- "display_name" text NOT NULL,
7
- "avatar_url" text,
8
- "status" text DEFAULT 'active' NOT NULL,
9
- "created_at" timestamp with time zone DEFAULT now() NOT NULL,
10
- "updated_at" timestamp with time zone DEFAULT now() NOT NULL,
11
- CONSTRAINT "users_username_unique" UNIQUE("username")
12
- );
13
-
14
- -- Create members table
15
- CREATE TABLE "members" (
16
- "id" text PRIMARY KEY NOT NULL,
17
- "user_id" text NOT NULL REFERENCES "users"("id"),
18
- "organization_id" text NOT NULL REFERENCES "organizations"("id"),
19
- "agent_id" text NOT NULL REFERENCES "agents"("uuid"),
20
- "role" text NOT NULL,
21
- "created_at" timestamp with time zone DEFAULT now() NOT NULL,
22
- CONSTRAINT "members_agent_id_unique" UNIQUE("agent_id"),
23
- CONSTRAINT "uq_members_user_org" UNIQUE("user_id", "organization_id")
24
- );
25
-
26
- CREATE INDEX "idx_members_user" ON "members" ("user_id");
27
- CREATE INDEX "idx_members_org" ON "members" ("organization_id");
28
-
29
- -- Add manager_id to agents with FK to members (FK in SQL only — not in Drizzle schema to avoid circular import)
30
- ALTER TABLE "agents" ADD COLUMN "manager_id" text REFERENCES "members"("id") ON DELETE SET NULL;
31
- CREATE INDEX "idx_agents_manager" ON "agents" ("manager_id");
32
-
33
- -- Drop admin_users table
34
- DROP TABLE "admin_users";
@@ -1,25 +0,0 @@
1
- CREATE TABLE "notifications" (
2
- "id" text PRIMARY KEY NOT NULL,
3
- "organization_id" text NOT NULL,
4
- "type" text NOT NULL,
5
- "severity" text NOT NULL,
6
- "agent_id" text,
7
- "chat_id" text,
8
- "message" text NOT NULL,
9
- "read" boolean DEFAULT false NOT NULL,
10
- "created_at" timestamp with time zone DEFAULT now() NOT NULL
11
- );
12
- --> statement-breakpoint
13
- CREATE TABLE "session_outputs" (
14
- "id" text PRIMARY KEY NOT NULL,
15
- "agent_id" text NOT NULL,
16
- "chat_id" text NOT NULL,
17
- "content" text DEFAULT '' NOT NULL,
18
- "updated_at" timestamp with time zone DEFAULT now() NOT NULL
19
- );
20
- --> statement-breakpoint
21
- ALTER TABLE "messages" ADD COLUMN "source" text;--> statement-breakpoint
22
- CREATE INDEX "idx_notifications_org_created" ON "notifications" USING btree ("organization_id","created_at");--> statement-breakpoint
23
- CREATE INDEX "idx_notifications_agent" ON "notifications" USING btree ("agent_id");--> statement-breakpoint
24
- CREATE INDEX "idx_notifications_org_read" ON "notifications" USING btree ("organization_id","read");--> statement-breakpoint
25
- CREATE INDEX "idx_session_outputs_agent_chat" ON "session_outputs" USING btree ("agent_id","chat_id");
@@ -1 +0,0 @@
1
- ALTER TABLE "session_outputs" ADD CONSTRAINT "uq_session_outputs_agent_chat" UNIQUE("agent_id","chat_id");
@@ -1,13 +0,0 @@
1
- -- Replace boolean "public" column with text "visibility" column
2
- ALTER TABLE "agents" ADD COLUMN "visibility" text NOT NULL DEFAULT 'private';--> statement-breakpoint
3
-
4
- -- Set defaults by agent type
5
- UPDATE "agents" SET "visibility" = 'organization' WHERE "type" = 'human';--> statement-breakpoint
6
- UPDATE "agents" SET "visibility" = 'organization' WHERE "type" = 'autonomous_agent';--> statement-breakpoint
7
- UPDATE "agents" SET "visibility" = 'private' WHERE "type" = 'personal_assistant';--> statement-breakpoint
8
-
9
- -- Drop old public column
10
- ALTER TABLE "agents" DROP COLUMN "public";--> statement-breakpoint
11
-
12
- -- Add index for visibility queries
13
- CREATE INDEX "idx_agents_visibility_org" ON "agents" USING btree ("organization_id","visibility");
@@ -1,30 +0,0 @@
1
- -- M1 agent configuration: Hub-managed runtime config table.
2
- -- Creates `agent_configs` and back-fills one row per non-deleted agent so
3
- -- Step 6 can flip Claude Code handler over to read prompt from config without
4
- -- silently dropping the existing `agents.profile` text.
5
-
6
- CREATE TABLE IF NOT EXISTS "agent_configs" (
7
- "agent_id" text PRIMARY KEY NOT NULL,
8
- "version" integer NOT NULL DEFAULT 1,
9
- "payload" jsonb NOT NULL,
10
- "updated_by" text NOT NULL,
11
- "updated_at" timestamp with time zone NOT NULL DEFAULT now()
12
- );
13
-
14
- --> statement-breakpoint
15
- INSERT INTO "agent_configs" ("agent_id", "version", "payload", "updated_by", "updated_at")
16
- SELECT
17
- "uuid",
18
- 1,
19
- jsonb_build_object(
20
- 'prompt', jsonb_build_object('append', COALESCE("profile", '')),
21
- 'model', '',
22
- 'mcpServers', '[]'::jsonb,
23
- 'env', '[]'::jsonb,
24
- 'gitRepos', '[]'::jsonb
25
- ),
26
- 'system',
27
- now()
28
- FROM "agents"
29
- WHERE "status" != 'deleted'
30
- ON CONFLICT ("agent_id") DO NOTHING;
@@ -1,154 +0,0 @@
1
- -- Unified user token milestone — retire agent tokens, authenticate every
2
- -- caller as a user.
3
- --
4
- -- This migration collapses the two-track auth (member JWT + `aghub_*` agent
5
- -- token) into a single member-JWT credential. Three structural changes:
6
- -- 1. Drop `agent_tokens` (table + FK cascade).
7
- -- 2. Add `clients.user_id` (nullable) — owning user of the physical client.
8
- -- 3. Add `agents.client_id` (nullable FK) — pin an agent to the client that
9
- -- runs it. `client_id` is backfilled from `agent_presence`. Rows that
10
- -- cannot be backfilled stay NULL and bind on first WS connect (see
11
- -- `api/agent/ws-client.ts` first-bind path). Originally this migration
12
- -- raised an exception when any non-human agent was unbacked — that
13
- -- gated startup on a data state the operator usually can't fix until
14
- -- the server is up. Relaxed to NOTICE so the loop is broken; runtime
15
- -- enforcement (Rule R-RUN in `services/agent.ts` + `agent-selector.ts`)
16
- -- still rejects unclaimed agents on the request path.
17
- -- 4. Make `agents.manager_id` NOT NULL after backfilling the first admin
18
- -- member of each org onto the unmanaged rows.
19
- --
20
- -- There is no compatibility layer: operators stop SDK/CLI processes, run
21
- -- `db:migrate`, then re-login via `first-tree-hub connect`. See the proposal
22
- -- "unified-user-token.20260417" for the full upgrade runbook.
23
- --
24
- -- NOTE: Do NOT wrap this file in BEGIN;/COMMIT;. The Drizzle migrator already
25
- -- runs every pending migration inside a single outer transaction, so a nested
26
- -- BEGIN raises WARNING 25001 and the inner COMMIT prematurely closes the
27
- -- outer transaction — which prevents the migration hash from being recorded
28
- -- and causes the server to loop through the same failure on every restart.
29
-
30
- DROP TABLE IF EXISTS "agent_tokens";
31
- --> statement-breakpoint
32
-
33
- -- ---------------------------------------------------------------------------
34
- -- clients.user_id — nullable FK to users(id).
35
- -- Nullable so legacy rows (created before handshake auth) keep existing;
36
- -- the WS handshake claims them on first re-register under a JWT.
37
- -- ---------------------------------------------------------------------------
38
- ALTER TABLE "clients"
39
- ADD COLUMN IF NOT EXISTS "user_id" text REFERENCES "users"("id") ON DELETE SET NULL;
40
- --> statement-breakpoint
41
-
42
- CREATE INDEX IF NOT EXISTS "idx_clients_user" ON "clients" ("user_id");
43
- --> statement-breakpoint
44
-
45
- -- ---------------------------------------------------------------------------
46
- -- agents.client_id — pin an agent to the physical client that runs it.
47
- -- ---------------------------------------------------------------------------
48
- ALTER TABLE "agents"
49
- ADD COLUMN IF NOT EXISTS "client_id" text REFERENCES "clients"("id") ON DELETE RESTRICT;
50
- --> statement-breakpoint
51
-
52
- -- Copy last-bound client from agent_presence.
53
- UPDATE "agents" a
54
- SET "client_id" = ap."client_id"
55
- FROM "agent_presence" ap
56
- WHERE ap."agent_id" = a."uuid"
57
- AND ap."client_id" IS NOT NULL
58
- AND a."client_id" IS NULL;
59
- --> statement-breakpoint
60
-
61
- -- Surface (do not block) any non-deleted non-human agent still missing a
62
- -- client_id after the backfill. They will sit in an "unclaimed" state until
63
- -- a client connects via WS and the first-bind path in
64
- -- `api/agent/ws-client.ts` claims them. Runtime guards reject HTTP / WS
65
- -- requests for those agents in the meantime.
66
- DO $$
67
- DECLARE
68
- unpinned_count integer;
69
- BEGIN
70
- SELECT COUNT(*) INTO unpinned_count
71
- FROM "agents"
72
- WHERE "client_id" IS NULL
73
- AND "type" <> 'human'
74
- AND "status" <> 'deleted';
75
-
76
- IF unpinned_count > 0 THEN
77
- RAISE NOTICE
78
- 'unified-user-token migration: % non-human agents have no client_id after backfill; '
79
- 'they will be claimed on first WS bind (see ws-client.ts first-bind path)',
80
- unpinned_count;
81
- END IF;
82
- END $$;
83
- --> statement-breakpoint
84
-
85
- CREATE INDEX IF NOT EXISTS "idx_agents_client" ON "agents" ("client_id");
86
- --> statement-breakpoint
87
-
88
- -- ---------------------------------------------------------------------------
89
- -- agents.manager_id — backfill then enforce NOT NULL.
90
- -- Human agents own their members row, so self-assign via members.
91
- -- Non-human agents get the first admin member in their org.
92
- -- ---------------------------------------------------------------------------
93
-
94
- -- Human agents: self-assign to their own member row.
95
- UPDATE "agents" a
96
- SET "manager_id" = m."id"
97
- FROM "members" m
98
- WHERE m."agent_id" = a."uuid"
99
- AND a."manager_id" IS NULL
100
- AND a."type" = 'human';
101
- --> statement-breakpoint
102
-
103
- -- Non-human agents: first admin in org, ordered by created_at asc.
104
- UPDATE "agents" a
105
- SET "manager_id" = m."id"
106
- FROM (
107
- SELECT DISTINCT ON (m."organization_id")
108
- m."id" AS id,
109
- m."organization_id" AS organization_id
110
- FROM "members" m
111
- WHERE m."role" = 'admin'
112
- ORDER BY m."organization_id", m."created_at" ASC
113
- ) m
114
- WHERE a."organization_id" = m."organization_id"
115
- AND a."manager_id" IS NULL;
116
- --> statement-breakpoint
117
-
118
- -- Fail loudly if any agent still lacks a manager.
119
- DO $$
120
- DECLARE
121
- orphan_count integer;
122
- BEGIN
123
- SELECT COUNT(*) INTO orphan_count
124
- FROM "agents"
125
- WHERE "manager_id" IS NULL
126
- AND "status" <> 'deleted';
127
-
128
- IF orphan_count > 0 THEN
129
- RAISE EXCEPTION
130
- 'unified-user-token migration: % non-deleted agents have no manager_id after backfill; '
131
- 'create at least one admin member per org, or set agents.manager_id manually, then retry',
132
- orphan_count;
133
- END IF;
134
- END $$;
135
- --> statement-breakpoint
136
-
137
- ALTER TABLE "agents"
138
- ALTER COLUMN "manager_id" SET NOT NULL;
139
- --> statement-breakpoint
140
-
141
- -- Recreate the manager_id FK as DEFERRABLE INITIALLY DEFERRED so the
142
- -- bootstrap path for a new human agent + member row can run inside a
143
- -- single transaction. The two rows reference each other (agents.manager_id
144
- -- → members.id, members.agent_id → agents.uuid); without deferred FKs the
145
- -- first INSERT always fails the sibling constraint.
146
- ALTER TABLE "agents"
147
- DROP CONSTRAINT IF EXISTS "agents_manager_id_fkey";
148
- --> statement-breakpoint
149
-
150
- ALTER TABLE "agents"
151
- ADD CONSTRAINT "agents_manager_id_fkey"
152
- FOREIGN KEY ("manager_id") REFERENCES "members"("id")
153
- ON DELETE SET NULL
154
- DEFERRABLE INITIALLY DEFERRED;
@@ -1,10 +0,0 @@
1
- -- PRD D7: remove `agents.profile` column and all dependent code paths.
2
- -- The column was backfilled into `agent_configs.payload.prompt.append` by
3
- -- migration 0018. After this migration, agent behavior instructions live
4
- -- exclusively in `agent_configs`; the `profile` column is dead weight.
5
- --
6
- -- Callers that used to read/write `profile` have been updated in the same
7
- -- release; operators must deploy this migration together with the matching
8
- -- code change — no compatibility layer.
9
-
10
- ALTER TABLE "agents" DROP COLUMN IF EXISTS "profile";
@@ -1,32 +0,0 @@
1
- -- NC2 (workspace-redesign S10): drop `session_outputs`, add `session_events`.
2
- --
3
- -- The old table held one `content` row per (agent, chat) with string
4
- -- concatenation on upsert. The new table captures structured events
5
- -- (`tool_call` / `error`) with a monotonic per-chat `seq` and a jsonb
6
- -- payload. Integrity is enforced in the service layer (Zod discriminated
7
- -- union on insert), so no FK / CHECK here — matches the project rule for
8
- -- new tables.
9
- --
10
- -- Discarding `session_outputs` data is intentional (tech plan decision):
11
- -- no content-migration path, no compatibility shim.
12
-
13
- DROP TABLE IF EXISTS "session_outputs" CASCADE;
14
-
15
- --> statement-breakpoint
16
- CREATE TABLE IF NOT EXISTS "session_events" (
17
- "id" text PRIMARY KEY NOT NULL,
18
- "agent_id" text NOT NULL,
19
- "chat_id" text NOT NULL,
20
- "seq" integer NOT NULL,
21
- "kind" text NOT NULL,
22
- "payload" jsonb NOT NULL,
23
- "created_at" timestamp with time zone NOT NULL DEFAULT now()
24
- );
25
-
26
- --> statement-breakpoint
27
- CREATE UNIQUE INDEX IF NOT EXISTS "uq_session_events_chat_seq"
28
- ON "session_events" ("agent_id", "chat_id", "seq");
29
-
30
- --> statement-breakpoint
31
- CREATE INDEX IF NOT EXISTS "idx_session_events_chat_created"
32
- ON "session_events" ("agent_id", "chat_id", "created_at" DESC);
@@ -1,40 +0,0 @@
1
- -- Multi-tenancy hardening:
2
- -- 1. Drop dead column `agents.cloud_user_id` (unused since introduction in
3
- -- 0010; never written by any code path).
4
- -- 2. Bind every client to exactly one organization via `clients.organization_id`.
5
- --
6
- -- A client is bound to one org for its lifetime — Rule R-RUN and the
7
- -- `client:register` handshake reject cross-org reuse of a clientId. See
8
- -- docs/multi-tenancy-hardening-design.md.
9
- --
10
- -- Backfill strategy (guarded for safety across environments):
11
- -- * Current production: exactly one org → UPDATE fills every row.
12
- -- * Fresh installs / empty DB: clients table is empty → UPDATE is a no-op,
13
- -- SET NOT NULL succeeds on the empty table.
14
- -- * Any environment reaching this migration with multi-org data but
15
- -- unpopulated clients.organization_id: the guard skips the UPDATE, and
16
- -- SET NOT NULL fails loudly rather than misassigning rows to an
17
- -- arbitrary org. Operator must backfill manually, then re-run.
18
-
19
- ALTER TABLE "agents" DROP COLUMN "cloud_user_id";
20
-
21
- --> statement-breakpoint
22
- ALTER TABLE "clients" ADD COLUMN "organization_id" text;
23
-
24
- --> statement-breakpoint
25
- ALTER TABLE "clients"
26
- ADD CONSTRAINT "clients_organization_id_organizations_id_fk"
27
- FOREIGN KEY ("organization_id") REFERENCES "organizations"("id")
28
- ON DELETE no action ON UPDATE no action;
29
-
30
- --> statement-breakpoint
31
- UPDATE "clients"
32
- SET "organization_id" = (SELECT "id" FROM "organizations" LIMIT 1)
33
- WHERE "organization_id" IS NULL
34
- AND (SELECT count(*) FROM "organizations") = 1;
35
-
36
- --> statement-breakpoint
37
- ALTER TABLE "clients" ALTER COLUMN "organization_id" SET NOT NULL;
38
-
39
- --> statement-breakpoint
40
- CREATE INDEX IF NOT EXISTS "idx_clients_org" ON "clients" ("organization_id");
@@ -1,31 +0,0 @@
1
- -- Phase 2 of the agent-naming refactor (docs/agent-naming-design.md §4).
2
- --
3
- -- Before this migration, `display_name` was nullable and the web layer
4
- -- silently fell back to `name` for rendering. CLI, server logs, and IM
5
- -- bridges saw raw NULLs. This migration closes the gap in three steps:
6
- --
7
- -- 1. Backfill every NULL row with a non-empty label — the agent's `name`
8
- -- when available, else the tombstone literal "[deleted agent]".
9
- -- Important: the third branch must NOT be `uuid`, because UUIDs would
10
- -- surface as human-visible strings in the chat roster and IM bridge.
11
- -- Only `status = 'deleted'` rows can have both `name` and
12
- -- `display_name` NULL (see `deleteAgent` in services/agent.ts), which
13
- -- is why the literal refers to deletion.
14
- --
15
- -- 2. Add a temporary empty-string DEFAULT so any old server instance
16
- -- still running during a rolling deploy — i.e. code that doesn't yet
17
- -- default `display_name` in `createAgent` — can INSERT without
18
- -- violating the upcoming NOT NULL. The application code treats an
19
- -- empty string as "no display name" (the Zod read schema accepts it);
20
- -- a follow-up migration can drop the default once the code is fully
21
- -- rolled.
22
- --
23
- -- 3. Promote the column to NOT NULL. Combined with the service-level
24
- -- default this closes the hole for new rows too.
25
-
26
- UPDATE "agents"
27
- SET "display_name" = COALESCE("display_name", "name", '[deleted agent]')
28
- WHERE "display_name" IS NULL;
29
-
30
- ALTER TABLE "agents" ALTER COLUMN "display_name" SET DEFAULT '';
31
- ALTER TABLE "agents" ALTER COLUMN "display_name" SET NOT NULL;
@@ -1,53 +0,0 @@
1
- -- Silent inbox entries for missed group-chat context.
2
- --
3
- -- Adds `inbox_entries.notify`, defaulting to true so existing rows continue to
4
- -- behave as "active" deliverables. Group-chat fan-out now writes a row for
5
- -- every non-sender participant — for `mention_only` participants who aren't
6
- -- explicitly @mentioned in the triggering message we set `notify = false` so
7
- -- the row is silently parked. Subsequent active deliveries to the same chat
8
- -- pick up these silent rows and replay them as preceding context, then
9
- -- bulk-ack them so they don't get re-replayed.
10
- --
11
- -- See proposals/group-chat-ux-improvements §1 (silent inbox).
12
- --
13
- -- ──────────────── Indexes ────────────────
14
- --
15
- -- idx_inbox_pending_notify — partial index used by pollInbox's claim.
16
- -- The query is "WHERE inbox_id = ? AND status = 'pending' AND notify = true
17
- -- ORDER BY created_at LIMIT N FOR UPDATE SKIP LOCKED". Without `notify` in
18
- -- the index, a chat that accumulates silent rows (mention_only agent in a
19
- -- chatty group) forces the planner to scan past them before finding the
20
- -- next trigger. Partial index keeps it bounded.
21
- --
22
- -- idx_inbox_chat_silent — used by collectPrecedingContext to walk the
23
- -- silent rows in a single (inbox, chat) bucket between two triggers.
24
- --
25
- -- ──────────────── Operator note ────────────────
26
- --
27
- -- Drizzle migrator wraps every migration file in a single transaction (see the
28
- -- comment block in 0020_unified_user_token.sql), which means we can't use
29
- -- `CREATE INDEX CONCURRENTLY` here — PG rejects it inside a tx. On a small
30
- -- `inbox_entries` table the regular `CREATE INDEX` finishes in <1s and is
31
- -- fine. For a large production table, the runbook is:
32
- --
33
- -- 1. Stop applying new migrations briefly.
34
- -- 2. Manually run, OUTSIDE a transaction:
35
- -- CREATE INDEX CONCURRENTLY idx_inbox_pending_notify
36
- -- ON inbox_entries (inbox_id, created_at)
37
- -- WHERE status = 'pending' AND notify = true;
38
- -- CREATE INDEX CONCURRENTLY idx_inbox_chat_silent
39
- -- ON inbox_entries (inbox_id, chat_id, notify, status);
40
- -- 3. Re-run `pnpm db:migrate`. The `IF NOT EXISTS` clauses below detect
41
- -- the pre-created indexes and skip them.
42
-
43
- ALTER TABLE "inbox_entries"
44
- ADD COLUMN "notify" boolean DEFAULT true NOT NULL;
45
-
46
- --> statement-breakpoint
47
- CREATE INDEX IF NOT EXISTS "idx_inbox_pending_notify"
48
- ON "inbox_entries" ("inbox_id", "created_at")
49
- WHERE status = 'pending' AND notify = true;
50
-
51
- --> statement-breakpoint
52
- CREATE INDEX IF NOT EXISTS "idx_inbox_chat_silent"
53
- ON "inbox_entries" ("inbox_id", "chat_id", "notify", "status");