@minion-stack/db 0.3.1 → 0.6.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 (135) hide show
  1. package/dist/crypto.d.ts +19 -0
  2. package/dist/crypto.d.ts.map +1 -0
  3. package/dist/crypto.js +65 -0
  4. package/dist/crypto.js.map +1 -0
  5. package/dist/crypto.test.d.ts +2 -0
  6. package/dist/crypto.test.d.ts.map +1 -0
  7. package/dist/crypto.test.js +23 -0
  8. package/dist/crypto.test.js.map +1 -0
  9. package/dist/pg/crypto.d.ts +1 -7
  10. package/dist/pg/crypto.d.ts.map +1 -1
  11. package/dist/pg/crypto.js +4 -41
  12. package/dist/pg/crypto.js.map +1 -1
  13. package/dist/pg/schema/agent-groups.d.ts +169 -0
  14. package/dist/pg/schema/agent-groups.d.ts.map +1 -0
  15. package/dist/pg/schema/agent-groups.js +21 -0
  16. package/dist/pg/schema/agent-groups.js.map +1 -0
  17. package/dist/pg/schema/builder.d.ts +1432 -0
  18. package/dist/pg/schema/builder.d.ts.map +1 -0
  19. package/dist/pg/schema/builder.js +160 -0
  20. package/dist/pg/schema/builder.js.map +1 -0
  21. package/dist/pg/schema/channels.d.ts +441 -0
  22. package/dist/pg/schema/channels.d.ts.map +1 -0
  23. package/dist/pg/schema/channels.js +62 -0
  24. package/dist/pg/schema/channels.js.map +1 -0
  25. package/dist/pg/schema/chat-messages.d.ts +184 -0
  26. package/dist/pg/schema/chat-messages.d.ts.map +1 -0
  27. package/dist/pg/schema/chat-messages.js +26 -0
  28. package/dist/pg/schema/chat-messages.js.map +1 -0
  29. package/dist/pg/schema/device-identities.d.ts +111 -0
  30. package/dist/pg/schema/device-identities.d.ts.map +1 -0
  31. package/dist/pg/schema/device-identities.js +11 -0
  32. package/dist/pg/schema/device-identities.js.map +1 -0
  33. package/dist/pg/schema/files.d.ts +162 -0
  34. package/dist/pg/schema/files.d.ts.map +1 -0
  35. package/dist/pg/schema/files.js +15 -0
  36. package/dist/pg/schema/files.js.map +1 -0
  37. package/dist/pg/schema/index.d.ts +19 -0
  38. package/dist/pg/schema/index.d.ts.map +1 -1
  39. package/dist/pg/schema/index.js +20 -0
  40. package/dist/pg/schema/index.js.map +1 -1
  41. package/dist/pg/schema/marketplace.d.ts +459 -0
  42. package/dist/pg/schema/marketplace.d.ts.map +1 -0
  43. package/dist/pg/schema/marketplace.js +42 -0
  44. package/dist/pg/schema/marketplace.js.map +1 -0
  45. package/dist/pg/schema/messages.d.ts +391 -0
  46. package/dist/pg/schema/messages.d.ts.map +1 -0
  47. package/dist/pg/schema/messages.js +44 -0
  48. package/dist/pg/schema/messages.js.map +1 -0
  49. package/dist/pg/schema/missions.d.ts +361 -0
  50. package/dist/pg/schema/missions.d.ts.map +1 -0
  51. package/dist/pg/schema/missions.js +48 -0
  52. package/dist/pg/schema/missions.js.map +1 -0
  53. package/dist/pg/schema/personal-agents.d.ts +285 -0
  54. package/dist/pg/schema/personal-agents.d.ts.map +1 -0
  55. package/dist/pg/schema/personal-agents.js +40 -0
  56. package/dist/pg/schema/personal-agents.js.map +1 -0
  57. package/dist/pg/schema/profiles.d.ts +17 -0
  58. package/dist/pg/schema/profiles.d.ts.map +1 -1
  59. package/dist/pg/schema/profiles.js +2 -0
  60. package/dist/pg/schema/profiles.js.map +1 -1
  61. package/dist/pg/schema/server-ops.d.ts +836 -0
  62. package/dist/pg/schema/server-ops.d.ts.map +1 -0
  63. package/dist/pg/schema/server-ops.js +88 -0
  64. package/dist/pg/schema/server-ops.js.map +1 -0
  65. package/dist/pg/schema/sessions.d.ts +395 -0
  66. package/dist/pg/schema/sessions.d.ts.map +1 -0
  67. package/dist/pg/schema/sessions.js +50 -0
  68. package/dist/pg/schema/sessions.js.map +1 -0
  69. package/dist/pg/schema/settings.d.ts +111 -0
  70. package/dist/pg/schema/settings.d.ts.map +1 -0
  71. package/dist/pg/schema/settings.js +17 -0
  72. package/dist/pg/schema/settings.js.map +1 -0
  73. package/dist/pg/schema/skills.d.ts +395 -0
  74. package/dist/pg/schema/skills.d.ts.map +1 -0
  75. package/dist/pg/schema/skills.js +45 -0
  76. package/dist/pg/schema/skills.js.map +1 -0
  77. package/dist/pg/schema/user-agents.d.ts +80 -0
  78. package/dist/pg/schema/user-agents.d.ts.map +1 -0
  79. package/dist/pg/schema/user-agents.js +21 -0
  80. package/dist/pg/schema/user-agents.js.map +1 -0
  81. package/dist/pg/schema/user-identities.d.ts +1 -1
  82. package/dist/pg/schema/user-preferences.d.ts +97 -0
  83. package/dist/pg/schema/user-preferences.d.ts.map +1 -0
  84. package/dist/pg/schema/user-preferences.js +19 -0
  85. package/dist/pg/schema/user-preferences.js.map +1 -0
  86. package/dist/pg/schema/workshop-saves.d.ts +145 -0
  87. package/dist/pg/schema/workshop-saves.d.ts.map +1 -0
  88. package/dist/pg/schema/workshop-saves.js +13 -0
  89. package/dist/pg/schema/workshop-saves.js.map +1 -0
  90. package/dist/pg/schema/workspace-membership.d.ts +83 -0
  91. package/dist/pg/schema/workspace-membership.d.ts.map +1 -0
  92. package/dist/pg/schema/workspace-membership.js +19 -0
  93. package/dist/pg/schema/workspace-membership.js.map +1 -0
  94. package/dist/schema/flows.d.ts +36 -0
  95. package/dist/schema/flows.d.ts.map +1 -1
  96. package/dist/schema/flows.js +2 -0
  97. package/dist/schema/flows.js.map +1 -1
  98. package/dist/schema/index.d.ts +2 -0
  99. package/dist/schema/index.d.ts.map +1 -1
  100. package/dist/schema/index.js +1 -0
  101. package/dist/schema/index.js.map +1 -1
  102. package/dist/schema/join-requests.d.ts +188 -0
  103. package/dist/schema/join-requests.d.ts.map +1 -0
  104. package/dist/schema/join-requests.js +35 -0
  105. package/dist/schema/join-requests.js.map +1 -0
  106. package/dist/schema/personal-agents.d.ts +1 -1
  107. package/dist/schema/reliability-events.d.ts +1 -1
  108. package/dist/schema/skill-execution-stats.d.ts +1 -1
  109. package/package.json +15 -12
  110. package/src/crypto.test.ts +33 -0
  111. package/src/crypto.ts +73 -0
  112. package/src/pg/crypto.ts +4 -44
  113. package/src/pg/schema/agent-groups.ts +30 -0
  114. package/src/pg/schema/builder.ts +205 -0
  115. package/src/pg/schema/channels.ts +77 -0
  116. package/src/pg/schema/chat-messages.ts +30 -0
  117. package/src/pg/schema/device-identities.ts +11 -0
  118. package/src/pg/schema/files.ts +19 -0
  119. package/src/pg/schema/index.ts +36 -0
  120. package/src/pg/schema/marketplace.ts +47 -0
  121. package/src/pg/schema/messages.ts +48 -0
  122. package/src/pg/schema/missions.ts +58 -0
  123. package/src/pg/schema/personal-agents.ts +44 -0
  124. package/src/pg/schema/profiles.ts +2 -0
  125. package/src/pg/schema/server-ops.ts +126 -0
  126. package/src/pg/schema/sessions.ts +60 -0
  127. package/src/pg/schema/settings.ts +21 -0
  128. package/src/pg/schema/skills.ts +65 -0
  129. package/src/pg/schema/user-agents.ts +25 -0
  130. package/src/pg/schema/user-preferences.ts +23 -0
  131. package/src/pg/schema/workshop-saves.ts +13 -0
  132. package/src/pg/schema/workspace-membership.ts +26 -0
  133. package/src/schema/flows.ts +2 -0
  134. package/src/schema/index.ts +2 -0
  135. package/src/schema/join-requests.ts +42 -0
@@ -0,0 +1,205 @@
1
+ import { pgTable, uuid, text, integer, real, timestamp, index } from 'drizzle-orm/pg-core';
2
+ import { gateway } from './gateway.js';
3
+
4
+ /**
5
+ * Visual builder (Workshop) tables. Mirrors Turso `built_*` / `agent_built_skills`.
6
+ * FK remap on migration:
7
+ * server_id → gateway_id (gateway.id, matched via gateway.legacy_server_id)
8
+ * tenant_id → organizations.id (plain uuid, soft ref — enforced via RLS)
9
+ * created_by → kept as text (loose audit field, may be a legacy user id)
10
+ * created_at / updated_at / published_at (integer epoch) → timestamptz
11
+ */
12
+
13
+ // ── Built Skills ──────────────────────────────────────────────────────
14
+ export const builtSkills = pgTable(
15
+ 'built_skills',
16
+ {
17
+ id: text('id').primaryKey(),
18
+ name: text('name').notNull(),
19
+ description: text('description').default(''),
20
+ emoji: text('emoji').default('📖'),
21
+ status: text('status', { enum: ['draft', 'published'] })
22
+ .notNull()
23
+ .default('draft'),
24
+ maxCycles: integer('max_cycles').notNull().default(3),
25
+ gatewayId: uuid('gateway_id').references(() => gateway.id, { onDelete: 'cascade' }),
26
+ tenantId: uuid('tenant_id'),
27
+ createdBy: text('created_by'),
28
+ publishedAt: timestamp('published_at', { withTimezone: true }),
29
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
30
+ updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
31
+ },
32
+ (t) => [
33
+ index('idx_built_skills_gateway').on(t.gatewayId),
34
+ index('idx_built_skills_tenant').on(t.tenantId),
35
+ ],
36
+ );
37
+
38
+ // ── Skill Tool Pool (junction: skill → gateway tool IDs) ─────────────
39
+ export const builtSkillTools = pgTable(
40
+ 'built_skill_tools',
41
+ {
42
+ id: text('id').primaryKey(),
43
+ skillId: text('skill_id')
44
+ .notNull()
45
+ .references(() => builtSkills.id, { onDelete: 'cascade' }),
46
+ toolId: text('tool_id').notNull(),
47
+ },
48
+ (t) => [index('idx_built_skill_tools_skill').on(t.skillId)],
49
+ );
50
+
51
+ // ── Chapters (subprocess nodes in the DAG) ───────────────────────────
52
+ export const builtChapters = pgTable(
53
+ 'built_chapters',
54
+ {
55
+ id: text('id').primaryKey(),
56
+ skillId: text('skill_id')
57
+ .notNull()
58
+ .references(() => builtSkills.id, { onDelete: 'cascade' }),
59
+ type: text('type', { enum: ['chapter', 'condition'] })
60
+ .notNull()
61
+ .default('chapter'),
62
+ name: text('name').notNull(),
63
+ description: text('description').default(''),
64
+ guide: text('guide').default(''),
65
+ context: text('context').default(''),
66
+ outputDef: text('output_def').default(''),
67
+ conditionText: text('condition_text').default(''),
68
+ positionX: real('position_x').notNull().default(0),
69
+ positionY: real('position_y').notNull().default(0),
70
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
71
+ updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
72
+ },
73
+ (t) => [index('idx_built_chapters_skill').on(t.skillId)],
74
+ );
75
+
76
+ // ── Chapter Edges (DAG connections between chapters) ─────────────────
77
+ export const builtChapterEdges = pgTable(
78
+ 'built_chapter_edges',
79
+ {
80
+ id: text('id').primaryKey(),
81
+ skillId: text('skill_id')
82
+ .notNull()
83
+ .references(() => builtSkills.id, { onDelete: 'cascade' }),
84
+ sourceChapterId: text('source_chapter_id')
85
+ .notNull()
86
+ .references(() => builtChapters.id, { onDelete: 'cascade' }),
87
+ targetChapterId: text('target_chapter_id')
88
+ .notNull()
89
+ .references(() => builtChapters.id, { onDelete: 'cascade' }),
90
+ label: text('label'),
91
+ },
92
+ (t) => [index('idx_built_chapter_edges_skill').on(t.skillId)],
93
+ );
94
+
95
+ // ── Chapter Tools (junction: chapter → subset of skill's tool pool) ──
96
+ export const builtChapterTools = pgTable(
97
+ 'built_chapter_tools',
98
+ {
99
+ id: text('id').primaryKey(),
100
+ chapterId: text('chapter_id')
101
+ .notNull()
102
+ .references(() => builtChapters.id, { onDelete: 'cascade' }),
103
+ toolId: text('tool_id').notNull(),
104
+ },
105
+ (t) => [index('idx_built_chapter_tools_chapter').on(t.chapterId)],
106
+ );
107
+
108
+ // ── Built Agents ─────────────────────────────────────────────────────
109
+ export const builtAgents = pgTable(
110
+ 'built_agents',
111
+ {
112
+ id: text('id').primaryKey(),
113
+ name: text('name').notNull(),
114
+ emoji: text('emoji').default('🤖'),
115
+ description: text('description').default(''),
116
+ model: text('model'),
117
+ systemPrompt: text('system_prompt').default(''),
118
+ temperature: real('temperature').default(0.7),
119
+ maxTokens: integer('max_tokens').default(4096),
120
+ retryPolicy: text('retry_policy').default('{}'),
121
+ fallbackAgentId: text('fallback_agent_id'),
122
+ status: text('status', { enum: ['draft', 'published'] })
123
+ .notNull()
124
+ .default('draft'),
125
+ gatewayId: uuid('gateway_id').references(() => gateway.id, { onDelete: 'cascade' }),
126
+ tenantId: uuid('tenant_id'),
127
+ createdBy: text('created_by'),
128
+ publishedAt: timestamp('published_at', { withTimezone: true }),
129
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
130
+ updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
131
+ },
132
+ (t) => [
133
+ index('idx_built_agents_gateway').on(t.gatewayId),
134
+ index('idx_built_agents_tenant').on(t.tenantId),
135
+ ],
136
+ );
137
+
138
+ // ── Agent Skill Slots (junction: agent → skill with order) ───────────
139
+ export const builtAgentSkills = pgTable(
140
+ 'built_agent_skills',
141
+ {
142
+ id: text('id').primaryKey(),
143
+ agentId: text('agent_id')
144
+ .notNull()
145
+ .references(() => builtAgents.id, { onDelete: 'cascade' }),
146
+ skillId: text('skill_id')
147
+ .notNull()
148
+ .references(() => builtSkills.id, { onDelete: 'cascade' }),
149
+ position: integer('position').notNull().default(0),
150
+ configOverrides: text('config_overrides').default('{}'),
151
+ },
152
+ (t) => [index('idx_built_agent_skills_agent').on(t.agentId)],
153
+ );
154
+
155
+ // ── Agent Built Skills (junction: gateway agent → built skill) ────────
156
+ export const agentBuiltSkills = pgTable(
157
+ 'agent_built_skills',
158
+ {
159
+ id: text('id').primaryKey(),
160
+ gatewayAgentId: text('gateway_agent_id').notNull(),
161
+ gatewayId: uuid('gateway_id')
162
+ .notNull()
163
+ .references(() => gateway.id, { onDelete: 'cascade' }),
164
+ tenantId: uuid('tenant_id').notNull(),
165
+ skillId: text('skill_id')
166
+ .notNull()
167
+ .references(() => builtSkills.id, { onDelete: 'cascade' }),
168
+ position: integer('position').notNull().default(0),
169
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
170
+ },
171
+ (t) => [
172
+ index('idx_agent_built_skills_gateway_agent').on(t.gatewayAgentId),
173
+ index('idx_agent_built_skills_tenant').on(t.tenantId),
174
+ ],
175
+ );
176
+
177
+ // ── Built Tools (admin-only playground) ──────────────────────────────
178
+ export const builtTools = pgTable(
179
+ 'built_tools',
180
+ {
181
+ id: text('id').primaryKey(),
182
+ name: text('name').notNull(),
183
+ description: text('description').default(''),
184
+ scriptCode: text('script_code').default(''),
185
+ scriptLang: text('script_lang', { enum: ['javascript', 'python', 'bash'] })
186
+ .notNull()
187
+ .default('javascript'),
188
+ envVars: text('env_vars').default('{}'),
189
+ validationRules: text('validation_rules').default('{}'),
190
+ executionConfig: text('execution_config').default('{}'),
191
+ status: text('status', { enum: ['draft', 'published'] })
192
+ .notNull()
193
+ .default('draft'),
194
+ gatewayId: uuid('gateway_id').references(() => gateway.id, { onDelete: 'cascade' }),
195
+ tenantId: uuid('tenant_id'),
196
+ createdBy: text('created_by'),
197
+ publishedAt: timestamp('published_at', { withTimezone: true }),
198
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
199
+ updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
200
+ },
201
+ (t) => [
202
+ index('idx_built_tools_gateway').on(t.gatewayId),
203
+ index('idx_built_tools_tenant').on(t.tenantId),
204
+ ],
205
+ );
@@ -0,0 +1,77 @@
1
+ import { pgTable, uuid, text, timestamp, index, uniqueIndex } from 'drizzle-orm/pg-core';
2
+ import { gateway } from './gateway.js';
3
+ import { profiles } from './profiles.js';
4
+
5
+ /**
6
+ * Channel connections + assignments + identity mappings.
7
+ * Mirrors Turso `channels` / `channel_assignments` / `channel_identities`.
8
+ * FK remap: server_id → gateway_id (gateway.id via legacy_server_id),
9
+ * tenant_id → organizations.id (plain uuid soft-ref, RLS-enforced),
10
+ * user_id → profiles.id (matched via profiles.legacy_user_id).
11
+ */
12
+
13
+ export const channels = pgTable(
14
+ 'channels',
15
+ {
16
+ id: text('id').primaryKey(),
17
+ tenantId: uuid('tenant_id').notNull(),
18
+ gatewayId: uuid('gateway_id')
19
+ .notNull()
20
+ .references(() => gateway.id, { onDelete: 'cascade' }),
21
+ type: text('type', { enum: ['discord', 'whatsapp', 'telegram'] }).notNull(),
22
+ label: text('label').notNull(),
23
+ credentials: text('credentials').notNull().default(''),
24
+ credentialsIv: text('credentials_iv').notNull().default(''),
25
+ credentialsMeta: text('credentials_meta').notNull().default('{}'),
26
+ status: text('status', { enum: ['active', 'inactive', 'pairing'] })
27
+ .notNull()
28
+ .default('inactive'),
29
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
30
+ updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
31
+ },
32
+ (t) => [
33
+ index('idx_channels_tenant_gateway').on(t.tenantId, t.gatewayId),
34
+ uniqueIndex('channels_uniq_type_label').on(t.tenantId, t.gatewayId, t.type, t.label),
35
+ ],
36
+ );
37
+
38
+ export const channelAssignments = pgTable(
39
+ 'channel_assignments',
40
+ {
41
+ id: text('id').primaryKey(),
42
+ tenantId: uuid('tenant_id').notNull(),
43
+ channelId: text('channel_id')
44
+ .notNull()
45
+ .references(() => channels.id, { onDelete: 'cascade' }),
46
+ targetType: text('target_type', { enum: ['user', 'session'] }).notNull(),
47
+ targetId: text('target_id').notNull(),
48
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
49
+ },
50
+ (t) => [
51
+ index('idx_channel_assign_channel').on(t.channelId),
52
+ uniqueIndex('channel_assign_uniq').on(t.channelId, t.targetType, t.targetId),
53
+ ],
54
+ );
55
+
56
+ /**
57
+ * Maps channel sender IDs (e.g. telegram:12345) to hub users.
58
+ * Used by the gateway to resolve user identity from channel messages.
59
+ */
60
+ export const channelIdentities = pgTable(
61
+ 'channel_identities',
62
+ {
63
+ id: text('id').primaryKey(),
64
+ userId: uuid('user_id')
65
+ .notNull()
66
+ .references(() => profiles.id, { onDelete: 'cascade' }),
67
+ channel: text('channel').notNull(),
68
+ channelUserId: text('channel_user_id').notNull(),
69
+ displayName: text('display_name'),
70
+ verifiedAt: timestamp('verified_at', { withTimezone: true }),
71
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
72
+ },
73
+ (t) => [
74
+ uniqueIndex('idx_channel_identity_unique').on(t.channel, t.channelUserId),
75
+ index('idx_channel_identity_user').on(t.userId),
76
+ ],
77
+ );
@@ -0,0 +1,30 @@
1
+ import { pgTable, uuid, text, bigserial, timestamp, index } from 'drizzle-orm/pg-core';
2
+ import { gateway } from './gateway.js';
3
+
4
+ /**
5
+ * Persisted chat transcript. Mirrors Turso `chat_messages`.
6
+ * FK remap: server_id → gateway_id, tenant_id → organizations.id (soft-ref).
7
+ * id: SQLite autoincrement integer → Postgres bigserial.
8
+ * timestamp / created_at: integer epoch (ms) → timestamptz.
9
+ */
10
+ export const chatMessages = pgTable(
11
+ 'chat_messages',
12
+ {
13
+ id: bigserial('id', { mode: 'number' }).primaryKey(),
14
+ tenantId: uuid('tenant_id').notNull(),
15
+ gatewayId: uuid('gateway_id')
16
+ .notNull()
17
+ .references(() => gateway.id, { onDelete: 'cascade' }),
18
+ agentId: text('agent_id').notNull(),
19
+ sessionKey: text('session_key').notNull(),
20
+ role: text('role', { enum: ['user', 'assistant'] }).notNull(),
21
+ content: text('content').notNull(),
22
+ runId: text('run_id'),
23
+ timestamp: timestamp('timestamp', { withTimezone: true }).notNull(),
24
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
25
+ },
26
+ (t) => [
27
+ index('idx_chat_tenant').on(t.tenantId),
28
+ index('idx_chat_by_agent').on(t.agentId, t.sessionKey, t.timestamp),
29
+ ],
30
+ );
@@ -0,0 +1,11 @@
1
+ import { pgTable, uuid, text, timestamp } from 'drizzle-orm/pg-core';
2
+
3
+ /** Per-tenant device keypair. Mirrors Turso `device_identities`. tenant_id → organizations.id. */
4
+ export const deviceIdentities = pgTable('device_identities', {
5
+ id: text('id').primaryKey(),
6
+ tenantId: uuid('tenant_id').notNull().unique(),
7
+ deviceId: text('device_id').notNull(),
8
+ publicKeyPem: text('public_key_pem').notNull(),
9
+ privateKeyPem: text('private_key_pem').notNull(),
10
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
11
+ });
@@ -0,0 +1,19 @@
1
+ import { pgTable, uuid, text, bigint, timestamp, index } from 'drizzle-orm/pg-core';
2
+ import { profiles } from './profiles.js';
3
+
4
+ /** B2-backed file records. Mirrors Turso `files`. tenant_id → organizations.id, uploaded_by → profiles.id. */
5
+ export const files = pgTable(
6
+ 'files',
7
+ {
8
+ id: text('id').primaryKey(),
9
+ tenantId: uuid('tenant_id').notNull(),
10
+ uploadedBy: uuid('uploaded_by').references(() => profiles.id, { onDelete: 'set null' }),
11
+ b2FileKey: text('b2_file_key').notNull(),
12
+ fileName: text('file_name').notNull(),
13
+ contentType: text('content_type').notNull(),
14
+ sizeBytes: bigint('size_bytes', { mode: 'number' }).notNull(),
15
+ category: text('category').notNull().default('general'),
16
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
17
+ },
18
+ (t) => [index('idx_files_tenant').on(t.tenantId)],
19
+ );
@@ -12,3 +12,39 @@ export type {
12
12
  } from '../identity-mapper.js';
13
13
  export { sealSecret, openSecret } from '../crypto.js';
14
14
  export { gateway, userGateway } from './gateway.js';
15
+ export { messages } from './messages.js';
16
+ // App tables migrated off Turso (telemetry/app split) — see
17
+ // docs/superpowers/specs/2026-06-05-turso-supabase-split-migration.md
18
+ export { userPreferences } from './user-preferences.js';
19
+ export { personalAgents } from './personal-agents.js';
20
+ export { settings } from './settings.js';
21
+ export { workshopSaves } from './workshop-saves.js';
22
+ export { deviceIdentities } from './device-identities.js';
23
+ export { files } from './files.js';
24
+ export { agentGroups, agentGroupMembers } from './agent-groups.js';
25
+ export { marketplaceAgents, marketplaceInstalls } from './marketplace.js';
26
+ export {
27
+ builtSkills,
28
+ builtSkillTools,
29
+ builtChapters,
30
+ builtChapterEdges,
31
+ builtChapterTools,
32
+ builtAgents,
33
+ builtAgentSkills,
34
+ agentBuiltSkills,
35
+ builtTools,
36
+ } from './builder.js';
37
+ export { channels, channelAssignments, channelIdentities } from './channels.js';
38
+ export { sessions, sessionTasks } from './sessions.js';
39
+ export { missions, tasks } from './missions.js';
40
+ export { chatMessages } from './chat-messages.js';
41
+ export { userAgents } from './user-agents.js';
42
+ export { skills, skillExecutionStats } from './skills.js';
43
+ export {
44
+ serverBackups,
45
+ serverProvisionConfigs,
46
+ backupConfigs,
47
+ configSnapshots,
48
+ } from './server-ops.js';
49
+ export { workspaceMembership } from './workspace-membership.js';
50
+ export type { WorkspaceMembership, NewWorkspaceMembership } from './workspace-membership.js';
@@ -0,0 +1,47 @@
1
+ import { pgTable, uuid, text, integer, timestamp, index } from 'drizzle-orm/pg-core';
2
+ import { gateway } from './gateway.js';
3
+
4
+ /** Marketplace agent catalog. Mirrors Turso `marketplace_agents`. */
5
+ export const marketplaceAgents = pgTable('marketplace_agents', {
6
+ id: text('id').primaryKey(),
7
+ name: text('name').notNull(),
8
+ role: text('role').notNull(),
9
+ category: text('category').notNull(),
10
+ tags: text('tags').notNull(),
11
+ description: text('description').notNull(),
12
+ catchphrase: text('catchphrase'),
13
+ version: text('version').notNull(),
14
+ model: text('model'),
15
+ avatarSeed: text('avatar_seed').notNull(),
16
+ githubPath: text('github_path').notNull(),
17
+ soulMd: text('soul_md'),
18
+ identityMd: text('identity_md'),
19
+ userMd: text('user_md'),
20
+ contextMd: text('context_md'),
21
+ skillsMd: text('skills_md'),
22
+ installCount: integer('install_count').default(0),
23
+ syncedAt: timestamp('synced_at', { withTimezone: true }).notNull().defaultNow(),
24
+ filesLoadedAt: timestamp('files_loaded_at', { withTimezone: true }),
25
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
26
+ updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
27
+ });
28
+
29
+ /** Per-tenant marketplace installs. tenant_id → organizations.id, server_id → gateway.id. */
30
+ export const marketplaceInstalls = pgTable(
31
+ 'marketplace_installs',
32
+ {
33
+ id: text('id').primaryKey(),
34
+ tenantId: uuid('tenant_id').notNull(),
35
+ agentId: text('agent_id')
36
+ .notNull()
37
+ .references(() => marketplaceAgents.id, { onDelete: 'cascade' }),
38
+ gatewayId: uuid('gateway_id')
39
+ .notNull()
40
+ .references(() => gateway.id, { onDelete: 'cascade' }),
41
+ installedAt: timestamp('installed_at', { withTimezone: true }).notNull().defaultNow(),
42
+ },
43
+ (t) => [
44
+ index('idx_marketplace_installs_tenant').on(t.tenantId),
45
+ index('idx_marketplace_installs_agent').on(t.agentId),
46
+ ],
47
+ );
@@ -0,0 +1,48 @@
1
+ import { pgTable, uuid, text, boolean, timestamp, jsonb, index, uniqueIndex } from 'drizzle-orm/pg-core';
2
+
3
+ /**
4
+ * Universal, org-scoped message ledger. Every comms channel writes here via the
5
+ * gateway outbox → hub ingest path. Standard columns are the cross-channel
6
+ * intersection; anything channel-specific goes in `metadata`.
7
+ *
8
+ * RLS (org isolation) is added in the hand-written companion migration
9
+ * `<ts>_messages_rls.sql` (role app_ledger + app.current_org_id GUC). Drizzle
10
+ * does not manage roles/policies.
11
+ */
12
+ export const messages = pgTable(
13
+ 'messages',
14
+ {
15
+ id: uuid('id').primaryKey().defaultRandom(),
16
+ // Ingest idempotency key, generated by the gateway per row.
17
+ clientId: text('client_id').notNull(),
18
+ // RLS pivot. Better Auth org id (text), matches flows.tenant_id convention.
19
+ orgId: text('org_id').notNull(),
20
+ // Producing gateway/server id (hub servers.id; text — not a PG uuid).
21
+ gatewayId: text('gateway_id'),
22
+ direction: text('direction', { enum: ['inbound', 'outbound'] }).notNull(),
23
+ channel: text('channel').notNull(),
24
+ accountId: text('account_id'),
25
+ chatId: text('chat_id'),
26
+ isGroup: boolean('is_group'),
27
+ senderId: text('sender_id'),
28
+ senderName: text('sender_name'),
29
+ senderHandle: text('sender_handle'),
30
+ isBot: boolean('is_bot'),
31
+ content: text('content'),
32
+ messageId: text('message_id'),
33
+ agentId: text('agent_id'),
34
+ sessionKey: text('session_key'),
35
+ success: boolean('success'),
36
+ error: text('error'),
37
+ occurredAt: timestamp('occurred_at', { withTimezone: true }),
38
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
39
+ metadata: jsonb('metadata').notNull().default({}),
40
+ },
41
+ (t) => ({
42
+ clientIdUnique: uniqueIndex('messages_client_id_uniq').on(t.clientId),
43
+ orgChatIdx: index('messages_org_chat_idx').on(t.orgId, t.channel, t.chatId, t.occurredAt),
44
+ orgTimeIdx: index('messages_org_time_idx').on(t.orgId, t.occurredAt),
45
+ orgAgentIdx: index('messages_org_agent_idx').on(t.orgId, t.agentId),
46
+ messageIdIdx: index('messages_message_id_idx').on(t.messageId),
47
+ }),
48
+ );
@@ -0,0 +1,58 @@
1
+ import { pgTable, uuid, text, integer, timestamp, index } from 'drizzle-orm/pg-core';
2
+ import { gateway } from './gateway.js';
3
+ import { sessions } from './sessions.js';
4
+
5
+ /**
6
+ * Missions (per-session goals) + their tasks.
7
+ * Mirrors Turso `missions` / `tasks`.
8
+ * FK remap: server_id → gateway_id, tenant_id → organizations.id (soft-ref),
9
+ * session_id → sessions.id, integer epoch timestamps → timestamptz.
10
+ */
11
+
12
+ export const missions = pgTable(
13
+ 'missions',
14
+ {
15
+ id: text('id').primaryKey(),
16
+ tenantId: uuid('tenant_id').notNull(),
17
+ gatewayId: uuid('gateway_id')
18
+ .notNull()
19
+ .references(() => gateway.id, { onDelete: 'cascade' }),
20
+ sessionId: text('session_id')
21
+ .notNull()
22
+ .references(() => sessions.id, { onDelete: 'cascade' }),
23
+ title: text('title').notNull(),
24
+ description: text('description'),
25
+ status: text('status', { enum: ['active', 'completed', 'cancelled'] })
26
+ .notNull()
27
+ .default('active'),
28
+ metadata: text('metadata'),
29
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
30
+ updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
31
+ },
32
+ (t) => [
33
+ index('idx_missions_tenant').on(t.tenantId),
34
+ index('idx_missions_session').on(t.sessionId),
35
+ index('idx_missions_gateway').on(t.gatewayId),
36
+ ],
37
+ );
38
+
39
+ export const tasks = pgTable(
40
+ 'tasks',
41
+ {
42
+ id: text('id').primaryKey(),
43
+ tenantId: uuid('tenant_id').notNull(),
44
+ missionId: text('mission_id')
45
+ .notNull()
46
+ .references(() => missions.id, { onDelete: 'cascade' }),
47
+ title: text('title').notNull(),
48
+ description: text('description'),
49
+ status: text('status', { enum: ['backlog', 'todo', 'in_progress', 'done'] })
50
+ .notNull()
51
+ .default('backlog'),
52
+ sortOrder: integer('sort_order').notNull().default(0),
53
+ metadata: text('metadata'),
54
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
55
+ updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
56
+ },
57
+ (t) => [index('idx_tasks_tenant').on(t.tenantId), index('idx_tasks_mission').on(t.missionId)],
58
+ );
@@ -0,0 +1,44 @@
1
+ import { pgTable, uuid, text, boolean, integer, timestamp, index } from 'drizzle-orm/pg-core';
2
+ import { profiles } from './profiles.js';
3
+ import { gateway } from './gateway.js';
4
+
5
+ /**
6
+ * Per-user personal agent. Mirrors Turso `personal_agents`.
7
+ * FK remap on migration: user_id → profile_id (profiles.id),
8
+ * server_id → gateway_id (gateway.id, matched via gateway.legacy_server_id).
9
+ */
10
+ export const personalAgents = pgTable(
11
+ 'personal_agents',
12
+ {
13
+ id: text('id').primaryKey(),
14
+ profileId: uuid('profile_id')
15
+ .notNull()
16
+ .unique()
17
+ .references(() => profiles.id, { onDelete: 'cascade' }),
18
+ agentId: text('agent_id').notNull(),
19
+ gatewayId: uuid('gateway_id').references(() => gateway.id, { onDelete: 'set null' }),
20
+ displayName: text('display_name').notNull(),
21
+ conversationName: text('conversation_name'),
22
+ avatarUrl: text('avatar_url'),
23
+ personalityPreset: text('personality_preset', {
24
+ enum: ['professional', 'casual', 'creative', 'technical'],
25
+ }),
26
+ personalityText: text('personality_text'),
27
+ personalityConfigured: boolean('personality_configured').notNull().default(false),
28
+ provisioningStatus: text('provisioning_status', {
29
+ enum: ['pending', 'provisioning', 'active', 'error'],
30
+ })
31
+ .notNull()
32
+ .default('pending'),
33
+ provisioningError: text('provisioning_error'),
34
+ lastRetryAt: timestamp('last_retry_at', { withTimezone: true }),
35
+ retryCount: integer('retry_count').notNull().default(0),
36
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
37
+ updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
38
+ },
39
+ (t) => [
40
+ index('idx_personal_agents_profile').on(t.profileId),
41
+ index('idx_personal_agents_agent').on(t.agentId),
42
+ index('idx_personal_agents_status').on(t.provisioningStatus),
43
+ ],
44
+ );
@@ -11,6 +11,8 @@ export const profiles = pgTable('profiles', {
11
11
  id: uuid('id').primaryKey(), // == auth.users.id
12
12
  email: text('email').notNull(),
13
13
  displayName: text('display_name'),
14
+ // Public avatar URL (B2-served signed URL or external provider image).
15
+ avatarUrl: text('avatar_url'),
14
16
  role: text('role', { enum: ['user', 'admin'] })
15
17
  .notNull()
16
18
  .default('user'),