@minion-stack/db 0.4.0 → 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 (115) hide show
  1. package/dist/pg/schema/agent-groups.d.ts +169 -0
  2. package/dist/pg/schema/agent-groups.d.ts.map +1 -0
  3. package/dist/pg/schema/agent-groups.js +21 -0
  4. package/dist/pg/schema/agent-groups.js.map +1 -0
  5. package/dist/pg/schema/builder.d.ts +1432 -0
  6. package/dist/pg/schema/builder.d.ts.map +1 -0
  7. package/dist/pg/schema/builder.js +160 -0
  8. package/dist/pg/schema/builder.js.map +1 -0
  9. package/dist/pg/schema/channels.d.ts +441 -0
  10. package/dist/pg/schema/channels.d.ts.map +1 -0
  11. package/dist/pg/schema/channels.js +62 -0
  12. package/dist/pg/schema/channels.js.map +1 -0
  13. package/dist/pg/schema/chat-messages.d.ts +184 -0
  14. package/dist/pg/schema/chat-messages.d.ts.map +1 -0
  15. package/dist/pg/schema/chat-messages.js +26 -0
  16. package/dist/pg/schema/chat-messages.js.map +1 -0
  17. package/dist/pg/schema/device-identities.d.ts +111 -0
  18. package/dist/pg/schema/device-identities.d.ts.map +1 -0
  19. package/dist/pg/schema/device-identities.js +11 -0
  20. package/dist/pg/schema/device-identities.js.map +1 -0
  21. package/dist/pg/schema/files.d.ts +162 -0
  22. package/dist/pg/schema/files.d.ts.map +1 -0
  23. package/dist/pg/schema/files.js +15 -0
  24. package/dist/pg/schema/files.js.map +1 -0
  25. package/dist/pg/schema/index.d.ts +19 -0
  26. package/dist/pg/schema/index.d.ts.map +1 -1
  27. package/dist/pg/schema/index.js +20 -0
  28. package/dist/pg/schema/index.js.map +1 -1
  29. package/dist/pg/schema/marketplace.d.ts +459 -0
  30. package/dist/pg/schema/marketplace.d.ts.map +1 -0
  31. package/dist/pg/schema/marketplace.js +42 -0
  32. package/dist/pg/schema/marketplace.js.map +1 -0
  33. package/dist/pg/schema/messages.d.ts +391 -0
  34. package/dist/pg/schema/messages.d.ts.map +1 -0
  35. package/dist/pg/schema/messages.js +44 -0
  36. package/dist/pg/schema/messages.js.map +1 -0
  37. package/dist/pg/schema/missions.d.ts +361 -0
  38. package/dist/pg/schema/missions.d.ts.map +1 -0
  39. package/dist/pg/schema/missions.js +48 -0
  40. package/dist/pg/schema/missions.js.map +1 -0
  41. package/dist/pg/schema/personal-agents.d.ts +285 -0
  42. package/dist/pg/schema/personal-agents.d.ts.map +1 -0
  43. package/dist/pg/schema/personal-agents.js +40 -0
  44. package/dist/pg/schema/personal-agents.js.map +1 -0
  45. package/dist/pg/schema/profiles.d.ts +17 -0
  46. package/dist/pg/schema/profiles.d.ts.map +1 -1
  47. package/dist/pg/schema/profiles.js +2 -0
  48. package/dist/pg/schema/profiles.js.map +1 -1
  49. package/dist/pg/schema/server-ops.d.ts +836 -0
  50. package/dist/pg/schema/server-ops.d.ts.map +1 -0
  51. package/dist/pg/schema/server-ops.js +88 -0
  52. package/dist/pg/schema/server-ops.js.map +1 -0
  53. package/dist/pg/schema/sessions.d.ts +395 -0
  54. package/dist/pg/schema/sessions.d.ts.map +1 -0
  55. package/dist/pg/schema/sessions.js +50 -0
  56. package/dist/pg/schema/sessions.js.map +1 -0
  57. package/dist/pg/schema/settings.d.ts +111 -0
  58. package/dist/pg/schema/settings.d.ts.map +1 -0
  59. package/dist/pg/schema/settings.js +17 -0
  60. package/dist/pg/schema/settings.js.map +1 -0
  61. package/dist/pg/schema/skills.d.ts +395 -0
  62. package/dist/pg/schema/skills.d.ts.map +1 -0
  63. package/dist/pg/schema/skills.js +45 -0
  64. package/dist/pg/schema/skills.js.map +1 -0
  65. package/dist/pg/schema/user-agents.d.ts +80 -0
  66. package/dist/pg/schema/user-agents.d.ts.map +1 -0
  67. package/dist/pg/schema/user-agents.js +21 -0
  68. package/dist/pg/schema/user-agents.js.map +1 -0
  69. package/dist/pg/schema/user-identities.d.ts +1 -1
  70. package/dist/pg/schema/user-preferences.d.ts +97 -0
  71. package/dist/pg/schema/user-preferences.d.ts.map +1 -0
  72. package/dist/pg/schema/user-preferences.js +19 -0
  73. package/dist/pg/schema/user-preferences.js.map +1 -0
  74. package/dist/pg/schema/workshop-saves.d.ts +145 -0
  75. package/dist/pg/schema/workshop-saves.d.ts.map +1 -0
  76. package/dist/pg/schema/workshop-saves.js +13 -0
  77. package/dist/pg/schema/workshop-saves.js.map +1 -0
  78. package/dist/pg/schema/workspace-membership.d.ts +83 -0
  79. package/dist/pg/schema/workspace-membership.d.ts.map +1 -0
  80. package/dist/pg/schema/workspace-membership.js +19 -0
  81. package/dist/pg/schema/workspace-membership.js.map +1 -0
  82. package/dist/schema/index.d.ts +2 -0
  83. package/dist/schema/index.d.ts.map +1 -1
  84. package/dist/schema/index.js +1 -0
  85. package/dist/schema/index.js.map +1 -1
  86. package/dist/schema/join-requests.d.ts +188 -0
  87. package/dist/schema/join-requests.d.ts.map +1 -0
  88. package/dist/schema/join-requests.js +35 -0
  89. package/dist/schema/join-requests.js.map +1 -0
  90. package/dist/schema/personal-agents.d.ts +1 -1
  91. package/dist/schema/reliability-events.d.ts +1 -1
  92. package/dist/schema/skill-execution-stats.d.ts +1 -1
  93. package/package.json +1 -1
  94. package/src/pg/schema/agent-groups.ts +30 -0
  95. package/src/pg/schema/builder.ts +205 -0
  96. package/src/pg/schema/channels.ts +77 -0
  97. package/src/pg/schema/chat-messages.ts +30 -0
  98. package/src/pg/schema/device-identities.ts +11 -0
  99. package/src/pg/schema/files.ts +19 -0
  100. package/src/pg/schema/index.ts +36 -0
  101. package/src/pg/schema/marketplace.ts +47 -0
  102. package/src/pg/schema/messages.ts +48 -0
  103. package/src/pg/schema/missions.ts +58 -0
  104. package/src/pg/schema/personal-agents.ts +44 -0
  105. package/src/pg/schema/profiles.ts +2 -0
  106. package/src/pg/schema/server-ops.ts +126 -0
  107. package/src/pg/schema/sessions.ts +60 -0
  108. package/src/pg/schema/settings.ts +21 -0
  109. package/src/pg/schema/skills.ts +65 -0
  110. package/src/pg/schema/user-agents.ts +25 -0
  111. package/src/pg/schema/user-preferences.ts +23 -0
  112. package/src/pg/schema/workshop-saves.ts +13 -0
  113. package/src/pg/schema/workspace-membership.ts +26 -0
  114. package/src/schema/index.ts +2 -0
  115. package/src/schema/join-requests.ts +42 -0
@@ -0,0 +1,35 @@
1
+ import { sqliteTable, text, integer, index } from 'drizzle-orm/sqlite-core';
2
+ import { user } from './auth/index.js';
3
+ import { organization } from './auth/index.js';
4
+ /**
5
+ * join_requests — users requesting to join an organization.
6
+ *
7
+ * When a user not-yet-in-an-org wants access, they submit a join request.
8
+ * Org admins review (approve/deny). On approval the user is added as a member.
9
+ *
10
+ * Used by:
11
+ * - /join page (submission)
12
+ * - /api/join-requests/* (listing, counting, review)
13
+ * - notifications panel
14
+ */
15
+ export const joinRequests = sqliteTable('join_requests', {
16
+ id: text('id').primaryKey(),
17
+ userId: text('user_id')
18
+ .notNull()
19
+ .references(() => user.id, { onDelete: 'cascade' }),
20
+ orgId: text('org_id')
21
+ .notNull()
22
+ .references(() => organization.id, { onDelete: 'cascade' }),
23
+ email: text('email').notNull(),
24
+ message: text('message'),
25
+ status: text('status', { enum: ['pending', 'approved', 'denied'] })
26
+ .notNull()
27
+ .default('pending'),
28
+ reviewedBy: text('reviewed_by'),
29
+ reviewedAt: integer('reviewed_at'),
30
+ createdAt: integer('created_at').notNull(),
31
+ }, (t) => [
32
+ index('idx_join_requests_user').on(t.userId),
33
+ index('idx_join_requests_org_status').on(t.orgId, t.status),
34
+ ]);
35
+ //# sourceMappingURL=join-requests.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"join-requests.js","sourceRoot":"","sources":["../../src/schema/join-requests.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAC5E,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,WAAW,CACrC,eAAe,EACf;IACE,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE;IAC3B,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC;SACpB,OAAO,EAAE;SACT,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;IACrD,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC;SAClB,OAAO,EAAE;SACT,UAAU,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;IAC7D,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE;IAC9B,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC;IACxB,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,SAAS,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,CAAC;SAChE,OAAO,EAAE;SACT,OAAO,CAAC,SAAS,CAAC;IACrB,UAAU,EAAE,IAAI,CAAC,aAAa,CAAC;IAC/B,UAAU,EAAE,OAAO,CAAC,aAAa,CAAC;IAClC,SAAS,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE;CAC3C,EACD,CAAC,CAAC,EAAE,EAAE,CAAC;IACL,KAAK,CAAC,wBAAwB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IAC5C,KAAK,CAAC,8BAA8B,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;CAC5D,CACF,CAAC"}
@@ -195,7 +195,7 @@ export declare const personalAgents: import("drizzle-orm/sqlite-core").SQLiteTab
195
195
  tableName: "personal_agents";
196
196
  dataType: "string";
197
197
  columnType: "SQLiteText";
198
- data: "pending" | "provisioning" | "active" | "error";
198
+ data: "active" | "error" | "pending" | "provisioning";
199
199
  driverParam: string;
200
200
  notNull: true;
201
201
  hasDefault: true;
@@ -81,7 +81,7 @@ export declare const reliabilityEvents: import("drizzle-orm/sqlite-core").SQLite
81
81
  tableName: "reliability_events";
82
82
  dataType: "string";
83
83
  columnType: "SQLiteText";
84
- data: "general" | "cron" | "browser" | "timezone" | "auth" | "skill" | "agent" | "gateway";
84
+ data: "general" | "gateway" | "cron" | "browser" | "timezone" | "auth" | "skill" | "agent";
85
85
  driverParam: string;
86
86
  notNull: true;
87
87
  hasDefault: false;
@@ -119,7 +119,7 @@ export declare const skillExecutionStats: import("drizzle-orm/sqlite-core").SQLi
119
119
  tableName: "skill_execution_stats";
120
120
  dataType: "string";
121
121
  columnType: "SQLiteText";
122
- data: "ok" | "error" | "auth_error" | "timeout";
122
+ data: "ok" | "auth_error" | "timeout" | "error";
123
123
  driverParam: string;
124
124
  notNull: true;
125
125
  hasDefault: false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@minion-stack/db",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "Drizzle ORM schema for the Minion shared database (LibSQL/Turso).",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -0,0 +1,30 @@
1
+ import { pgTable, uuid, text, integer, timestamp, index, primaryKey } from 'drizzle-orm/pg-core';
2
+ import { profiles } from './profiles.js';
3
+
4
+ /** User-defined agent groupings. Mirrors Turso `agent_groups`. user_id → profile_id, tenant_id → organizations.id. */
5
+ export const agentGroups = pgTable(
6
+ 'agent_groups',
7
+ {
8
+ id: text('id').primaryKey(),
9
+ profileId: uuid('profile_id')
10
+ .notNull()
11
+ .references(() => profiles.id, { onDelete: 'cascade' }),
12
+ tenantId: uuid('tenant_id').notNull(),
13
+ name: text('name').notNull(),
14
+ sortOrder: integer('sort_order').default(0),
15
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
16
+ },
17
+ (t) => [index('idx_agent_groups_profile').on(t.profileId, t.tenantId)],
18
+ );
19
+
20
+ export const agentGroupMembers = pgTable(
21
+ 'agent_group_members',
22
+ {
23
+ groupId: text('group_id')
24
+ .notNull()
25
+ .references(() => agentGroups.id, { onDelete: 'cascade' }),
26
+ agentId: text('agent_id').notNull(),
27
+ sortOrder: integer('sort_order').default(0),
28
+ },
29
+ (t) => [primaryKey({ columns: [t.groupId, t.agentId] })],
30
+ );
@@ -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
+ );