siclaw 0.1.2 → 0.1.4

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 (215) hide show
  1. package/dist/agentbox/gateway-client.d.ts +4 -0
  2. package/dist/agentbox/gateway-client.js +9 -1
  3. package/dist/agentbox/gateway-client.js.map +1 -1
  4. package/dist/agentbox/http-server.js +25 -1
  5. package/dist/agentbox/http-server.js.map +1 -1
  6. package/dist/agentbox/session.d.ts +2 -0
  7. package/dist/agentbox/session.js +11 -7
  8. package/dist/agentbox/session.js.map +1 -1
  9. package/dist/agentbox-main.js +10 -0
  10. package/dist/agentbox-main.js.map +1 -1
  11. package/dist/cli-main.js +19 -3
  12. package/dist/cli-main.js.map +1 -1
  13. package/dist/core/agent-factory.d.ts +2 -0
  14. package/dist/core/agent-factory.js +87 -21
  15. package/dist/core/agent-factory.js.map +1 -1
  16. package/dist/core/compaction.d.ts +80 -0
  17. package/dist/core/compaction.js +442 -0
  18. package/dist/core/compaction.js.map +1 -0
  19. package/dist/core/config.d.ts +7 -0
  20. package/dist/core/config.js +27 -1
  21. package/dist/core/config.js.map +1 -1
  22. package/dist/core/extensions/compaction-safeguard.d.ts +2 -0
  23. package/dist/core/extensions/compaction-safeguard.js +681 -0
  24. package/dist/core/extensions/compaction-safeguard.js.map +1 -0
  25. package/dist/core/extensions/deep-investigation.js +47 -73
  26. package/dist/core/extensions/deep-investigation.js.map +1 -1
  27. package/dist/core/extensions/memory-flush.d.ts +2 -10
  28. package/dist/core/extensions/memory-flush.js +4 -86
  29. package/dist/core/extensions/memory-flush.js.map +1 -1
  30. package/dist/core/llm-proxy.js +25 -6
  31. package/dist/core/llm-proxy.js.map +1 -1
  32. package/dist/core/message-utils.d.ts +18 -0
  33. package/dist/core/message-utils.js +28 -0
  34. package/dist/core/message-utils.js.map +1 -0
  35. package/dist/core/prompt.js +4 -5
  36. package/dist/core/prompt.js.map +1 -1
  37. package/dist/core/session-tool-result-guard.d.ts +2 -0
  38. package/dist/core/session-tool-result-guard.js +159 -0
  39. package/dist/core/session-tool-result-guard.js.map +1 -0
  40. package/dist/core/stream-wrappers.d.ts +41 -0
  41. package/dist/core/stream-wrappers.js +369 -0
  42. package/dist/core/stream-wrappers.js.map +1 -0
  43. package/dist/core/thinking-blocks.d.ts +20 -0
  44. package/dist/core/thinking-blocks.js +45 -0
  45. package/dist/core/thinking-blocks.js.map +1 -0
  46. package/dist/core/tool-call-id.d.ts +22 -0
  47. package/dist/core/tool-call-id.js +226 -0
  48. package/dist/core/tool-call-id.js.map +1 -0
  49. package/dist/core/tool-call-repair.d.ts +18 -0
  50. package/dist/core/tool-call-repair.js +73 -0
  51. package/dist/core/tool-call-repair.js.map +1 -0
  52. package/dist/core/tool-result-context-guard.d.ts +36 -0
  53. package/dist/core/tool-result-context-guard.js +272 -0
  54. package/dist/core/tool-result-context-guard.js.map +1 -0
  55. package/dist/cron/cron-limits.d.ts +16 -0
  56. package/dist/cron/cron-limits.js +17 -0
  57. package/dist/cron/cron-limits.js.map +1 -0
  58. package/dist/cron/cron-matcher.d.ts +14 -0
  59. package/dist/cron/cron-matcher.js +29 -0
  60. package/dist/cron/cron-matcher.js.map +1 -1
  61. package/dist/gateway/agentbox/client.d.ts +0 -2
  62. package/dist/gateway/agentbox/client.js.map +1 -1
  63. package/dist/gateway/agentbox/k8s-spawner.d.ts +10 -10
  64. package/dist/gateway/agentbox/k8s-spawner.js +27 -55
  65. package/dist/gateway/agentbox/k8s-spawner.js.map +1 -1
  66. package/dist/gateway/agentbox/local-spawner.d.ts +5 -0
  67. package/dist/gateway/agentbox/local-spawner.js +10 -0
  68. package/dist/gateway/agentbox/local-spawner.js.map +1 -1
  69. package/dist/gateway/cron/cron-service.js +7 -0
  70. package/dist/gateway/cron/cron-service.js.map +1 -1
  71. package/dist/gateway/db/index.js +9 -1
  72. package/dist/gateway/db/index.js.map +1 -1
  73. package/dist/gateway/db/init-schema.js +65 -16
  74. package/dist/gateway/db/init-schema.js.map +1 -1
  75. package/dist/gateway/db/migrate-sqlite.js +73 -20
  76. package/dist/gateway/db/migrate-sqlite.js.map +1 -1
  77. package/dist/gateway/db/repositories/cluster-repo.d.ts +59 -0
  78. package/dist/gateway/db/repositories/cluster-repo.js +107 -0
  79. package/dist/gateway/db/repositories/cluster-repo.js.map +1 -0
  80. package/dist/gateway/db/repositories/config-repo.d.ts +4 -5
  81. package/dist/gateway/db/repositories/config-repo.js +17 -0
  82. package/dist/gateway/db/repositories/config-repo.js.map +1 -1
  83. package/dist/gateway/db/repositories/feedback-repo.d.ts +71 -0
  84. package/dist/gateway/db/repositories/feedback-repo.js +52 -0
  85. package/dist/gateway/db/repositories/feedback-repo.js.map +1 -0
  86. package/dist/gateway/db/repositories/knowledge-doc-repo.d.ts +37 -0
  87. package/dist/gateway/db/repositories/knowledge-doc-repo.js +48 -0
  88. package/dist/gateway/db/repositories/knowledge-doc-repo.js.map +1 -0
  89. package/dist/gateway/db/repositories/user-cluster-config-repo.d.ts +45 -0
  90. package/dist/gateway/db/repositories/user-cluster-config-repo.js +90 -0
  91. package/dist/gateway/db/repositories/user-cluster-config-repo.js.map +1 -0
  92. package/dist/gateway/db/repositories/workspace-repo.d.ts +2 -2
  93. package/dist/gateway/db/repositories/workspace-repo.js +12 -12
  94. package/dist/gateway/db/repositories/workspace-repo.js.map +1 -1
  95. package/dist/gateway/db/schema-mysql.d.ts +437 -44
  96. package/dist/gateway/db/schema-mysql.js +36 -9
  97. package/dist/gateway/db/schema-mysql.js.map +1 -1
  98. package/dist/gateway/db/schema-sqlite.d.ts +459 -46
  99. package/dist/gateway/db/schema-sqlite.js +36 -9
  100. package/dist/gateway/db/schema-sqlite.js.map +1 -1
  101. package/dist/gateway/db/schema.d.ts +435 -44
  102. package/dist/gateway/db/schema.js +1 -1
  103. package/dist/gateway/db/schema.js.map +1 -1
  104. package/dist/gateway/plugins/channel-bridge.js +1 -1
  105. package/dist/gateway/plugins/channel-bridge.js.map +1 -1
  106. package/dist/gateway/rpc-methods.d.ts +2 -1
  107. package/dist/gateway/rpc-methods.js +507 -172
  108. package/dist/gateway/rpc-methods.js.map +1 -1
  109. package/dist/gateway/server.js +191 -51
  110. package/dist/gateway/server.js.map +1 -1
  111. package/dist/gateway/web/dist/assets/index-DTD0P9j8.css +1 -0
  112. package/dist/gateway/web/dist/assets/index-DhqsS2E0.js +756 -0
  113. package/dist/gateway/web/dist/assets/index-DhqsS2E0.js.map +1 -0
  114. package/dist/gateway/web/dist/index.html +2 -2
  115. package/dist/gateway-main.js +1 -3
  116. package/dist/gateway-main.js.map +1 -1
  117. package/dist/memory/indexer.d.ts +13 -0
  118. package/dist/memory/indexer.js +91 -1
  119. package/dist/memory/indexer.js.map +1 -1
  120. package/dist/memory/knowledge-extractor.d.ts +47 -0
  121. package/dist/memory/knowledge-extractor.js +165 -0
  122. package/dist/memory/knowledge-extractor.js.map +1 -0
  123. package/dist/memory/overview-generator.d.ts +16 -0
  124. package/dist/memory/overview-generator.js +233 -0
  125. package/dist/memory/overview-generator.js.map +1 -0
  126. package/dist/memory/session-summarizer.d.ts +28 -0
  127. package/dist/memory/session-summarizer.js +20 -2
  128. package/dist/memory/session-summarizer.js.map +1 -1
  129. package/dist/memory/temporal-decay.js +2 -2
  130. package/dist/memory/temporal-decay.js.map +1 -1
  131. package/dist/memory/topic-consolidator.d.ts +52 -0
  132. package/dist/memory/topic-consolidator.js +197 -0
  133. package/dist/memory/topic-consolidator.js.map +1 -0
  134. package/dist/tools/cluster-info.d.ts +9 -0
  135. package/dist/tools/cluster-info.js +74 -0
  136. package/dist/tools/cluster-info.js.map +1 -0
  137. package/dist/tools/command-sets.js +15 -5
  138. package/dist/tools/command-sets.js.map +1 -1
  139. package/dist/tools/create-skill.js +1 -1
  140. package/dist/tools/create-skill.js.map +1 -1
  141. package/dist/tools/debug-pod.d.ts +217 -0
  142. package/dist/tools/debug-pod.js +603 -0
  143. package/dist/tools/debug-pod.js.map +1 -0
  144. package/dist/tools/deep-search/engine.d.ts +0 -5
  145. package/dist/tools/deep-search/engine.js +68 -28
  146. package/dist/tools/deep-search/engine.js.map +1 -1
  147. package/dist/tools/deep-search/format.d.ts +1 -1
  148. package/dist/tools/deep-search/format.js +1 -2
  149. package/dist/tools/deep-search/format.js.map +1 -1
  150. package/dist/tools/deep-search/prompts.d.ts +4 -1
  151. package/dist/tools/deep-search/prompts.js +47 -29
  152. package/dist/tools/deep-search/prompts.js.map +1 -1
  153. package/dist/tools/deep-search/quality-gate.d.ts +25 -0
  154. package/dist/tools/deep-search/quality-gate.js +81 -0
  155. package/dist/tools/deep-search/quality-gate.js.map +1 -0
  156. package/dist/tools/deep-search/schemas.d.ts +25 -0
  157. package/dist/tools/deep-search/schemas.js +26 -1
  158. package/dist/tools/deep-search/schemas.js.map +1 -1
  159. package/dist/tools/deep-search/sre-knowledge.d.ts +6 -10
  160. package/dist/tools/deep-search/sre-knowledge.js +21 -52
  161. package/dist/tools/deep-search/sre-knowledge.js.map +1 -1
  162. package/dist/tools/deep-search/sub-agent.js +24 -8
  163. package/dist/tools/deep-search/sub-agent.js.map +1 -1
  164. package/dist/tools/deep-search/tool.js +3 -6
  165. package/dist/tools/deep-search/tool.js.map +1 -1
  166. package/dist/tools/deep-search/types.d.ts +13 -0
  167. package/dist/tools/deep-search/types.js +4 -4
  168. package/dist/tools/deep-search/types.js.map +1 -1
  169. package/dist/tools/dp-tools.d.ts +9 -6
  170. package/dist/tools/dp-tools.js +26 -55
  171. package/dist/tools/dp-tools.js.map +1 -1
  172. package/dist/tools/exec-utils.d.ts +8 -21
  173. package/dist/tools/exec-utils.js +11 -95
  174. package/dist/tools/exec-utils.js.map +1 -1
  175. package/dist/tools/fork-skill.js +1 -1
  176. package/dist/tools/fork-skill.js.map +1 -1
  177. package/dist/tools/k8s-checks.d.ts +11 -5
  178. package/dist/tools/k8s-checks.js +28 -9
  179. package/dist/tools/k8s-checks.js.map +1 -1
  180. package/dist/tools/knowledge-search.d.ts +3 -0
  181. package/dist/tools/knowledge-search.js +115 -0
  182. package/dist/tools/knowledge-search.js.map +1 -0
  183. package/dist/tools/kubeconfig-resolver.d.ts +22 -0
  184. package/dist/tools/kubeconfig-resolver.js +98 -18
  185. package/dist/tools/kubeconfig-resolver.js.map +1 -1
  186. package/dist/tools/manage-schedule.js +23 -1
  187. package/dist/tools/manage-schedule.js.map +1 -1
  188. package/dist/tools/netns-script.d.ts +1 -1
  189. package/dist/tools/netns-script.js +19 -7
  190. package/dist/tools/netns-script.js.map +1 -1
  191. package/dist/tools/node-exec.d.ts +1 -1
  192. package/dist/tools/node-exec.js +19 -7
  193. package/dist/tools/node-exec.js.map +1 -1
  194. package/dist/tools/node-script.d.ts +1 -1
  195. package/dist/tools/node-script.js +19 -7
  196. package/dist/tools/node-script.js.map +1 -1
  197. package/dist/tools/pod-exec.js +12 -1
  198. package/dist/tools/pod-exec.js.map +1 -1
  199. package/dist/tools/pod-nsenter-exec.d.ts +1 -1
  200. package/dist/tools/pod-nsenter-exec.js +19 -7
  201. package/dist/tools/pod-nsenter-exec.js.map +1 -1
  202. package/dist/tools/pod-script.js +12 -1
  203. package/dist/tools/pod-script.js.map +1 -1
  204. package/dist/tools/restricted-bash.js +10 -3
  205. package/dist/tools/restricted-bash.js.map +1 -1
  206. package/dist/tools/run-skill.js +14 -2
  207. package/dist/tools/run-skill.js.map +1 -1
  208. package/dist/tools/save-feedback.d.ts +7 -0
  209. package/dist/tools/save-feedback.js +125 -0
  210. package/dist/tools/save-feedback.js.map +1 -0
  211. package/dist/tools/update-skill.js +1 -1
  212. package/dist/tools/update-skill.js.map +1 -1
  213. package/package.json +1 -1
  214. package/skills/core/deep-investigation/SKILL.md +11 -14
  215. package/skills/core/session-feedback/SKILL.md +146 -0
@@ -97,7 +97,6 @@ const DDL_STATEMENTS = [
97
97
  assigned_to VARCHAR(64),
98
98
  locked_by VARCHAR(64),
99
99
  locked_at TIMESTAMP NULL,
100
- env_id VARCHAR(64),
101
100
  workspace_id VARCHAR(64),
102
101
  FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
103
102
  )`,
@@ -138,27 +137,29 @@ const DDL_STATEMENTS = [
138
137
  FOREIGN KEY (skill_id) REFERENCES skills(id) ON DELETE CASCADE,
139
138
  FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
140
139
  )`,
141
- `CREATE TABLE IF NOT EXISTS environments (
140
+ `CREATE TABLE IF NOT EXISTS clusters (
142
141
  id VARCHAR(64) PRIMARY KEY,
143
142
  name VARCHAR(255) NOT NULL,
143
+ infra_context TEXT,
144
144
  is_test BOOLEAN NOT NULL DEFAULT FALSE,
145
145
  api_server VARCHAR(512) NOT NULL DEFAULT '',
146
146
  created_by VARCHAR(32),
147
147
  allowed_servers TEXT,
148
148
  default_kubeconfig LONGTEXT,
149
+ debug_image TEXT,
149
150
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
150
151
  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
151
152
  )`,
152
- `CREATE TABLE IF NOT EXISTS user_env_configs (
153
+ `CREATE TABLE IF NOT EXISTS user_cluster_configs (
153
154
  id VARCHAR(64) PRIMARY KEY,
154
155
  user_id VARCHAR(32) NOT NULL,
155
- env_id VARCHAR(64) NOT NULL,
156
+ cluster_id VARCHAR(64) NOT NULL,
156
157
  kubeconfig TEXT NOT NULL,
157
158
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
158
159
  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
159
160
  FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
160
- FOREIGN KEY (env_id) REFERENCES environments(id) ON DELETE CASCADE,
161
- UNIQUE KEY uk_user_env (user_id, env_id)
161
+ FOREIGN KEY (cluster_id) REFERENCES clusters(id) ON DELETE CASCADE,
162
+ UNIQUE KEY uk_user_cluster (user_id, cluster_id)
162
163
  )`,
163
164
  `CREATE TABLE IF NOT EXISTS user_disabled_skills (
164
165
  user_id VARCHAR(32) NOT NULL,
@@ -278,12 +279,12 @@ const DDL_STATEMENTS = [
278
279
  PRIMARY KEY (workspace_id, tool_name),
279
280
  FOREIGN KEY (workspace_id) REFERENCES workspaces(id) ON DELETE CASCADE
280
281
  )`,
281
- `CREATE TABLE IF NOT EXISTS workspace_environments (
282
+ `CREATE TABLE IF NOT EXISTS workspace_clusters (
282
283
  workspace_id VARCHAR(64) NOT NULL,
283
- env_id VARCHAR(64) NOT NULL,
284
- PRIMARY KEY (workspace_id, env_id),
284
+ cluster_id VARCHAR(64) NOT NULL,
285
+ PRIMARY KEY (workspace_id, cluster_id),
285
286
  FOREIGN KEY (workspace_id) REFERENCES workspaces(id) ON DELETE CASCADE,
286
- FOREIGN KEY (env_id) REFERENCES environments(id) ON DELETE CASCADE
287
+ FOREIGN KEY (cluster_id) REFERENCES clusters(id) ON DELETE CASCADE
287
288
  )`,
288
289
  `CREATE TABLE IF NOT EXISTS workspace_credentials (
289
290
  workspace_id VARCHAR(64) NOT NULL,
@@ -314,6 +315,17 @@ const DDL_STATEMENTS = [
314
315
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
315
316
  FOREIGN KEY (provider_id) REFERENCES model_providers(id) ON DELETE CASCADE,
316
317
  UNIQUE KEY uk_provider_model (provider_id, model_id)
318
+ )`,
319
+ `CREATE TABLE IF NOT EXISTS knowledge_docs (
320
+ id VARCHAR(64) PRIMARY KEY,
321
+ name VARCHAR(500) NOT NULL,
322
+ file_path VARCHAR(500) NOT NULL,
323
+ size_bytes INT NOT NULL DEFAULT 0,
324
+ chunk_count INT NOT NULL DEFAULT 0,
325
+ uploaded_by VARCHAR(32),
326
+ created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
327
+ updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
328
+ FOREIGN KEY (uploaded_by) REFERENCES users(id) ON DELETE SET NULL
317
329
  )`,
318
330
  `CREATE TABLE IF NOT EXISTS mcp_servers (
319
331
  id VARCHAR(64) PRIMARY KEY,
@@ -348,6 +360,20 @@ const DDL_STATEMENTS = [
348
360
  skill_call_count INT DEFAULT 0,
349
361
  created_at BIGINT NOT NULL
350
362
  )`,
363
+ `CREATE TABLE IF NOT EXISTS feedback_reports (
364
+ id VARCHAR(64) PRIMARY KEY,
365
+ session_id VARCHAR(64) NOT NULL,
366
+ user_id VARCHAR(32) NOT NULL,
367
+ workspace_id VARCHAR(64),
368
+ overall_rating INT CHECK(overall_rating BETWEEN 1 AND 5),
369
+ summary TEXT NOT NULL,
370
+ decision_points JSON,
371
+ strengths JSON,
372
+ improvements JSON,
373
+ tags JSON,
374
+ feedback_conversation JSON,
375
+ created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
376
+ )`,
351
377
  ];
352
378
  // Indexes — handled separately since MySQL lacks CREATE INDEX IF NOT EXISTS
353
379
  const INDEX_STATEMENTS = [
@@ -360,8 +386,8 @@ const INDEX_STATEMENTS = [
360
386
  `ALTER TABLE notifications ADD INDEX idx_notifications_user (user_id, is_read, created_at)`,
361
387
  `ALTER TABLE skill_reviews ADD INDEX idx_skill_reviews_skill (skill_id, created_at)`,
362
388
  `ALTER TABLE user_permissions ADD INDEX idx_user_permissions_perm (permission)`,
363
- `ALTER TABLE user_env_configs ADD INDEX idx_user_env_configs_user (user_id)`,
364
- `ALTER TABLE user_env_configs ADD INDEX idx_user_env_configs_env (env_id)`,
389
+ `ALTER TABLE user_cluster_configs ADD INDEX idx_user_cluster_configs_user (user_id)`,
390
+ `ALTER TABLE user_cluster_configs ADD INDEX idx_user_cluster_configs_cluster (cluster_id)`,
365
391
  `ALTER TABLE skill_versions ADD INDEX idx_skill_versions_skill (skill_id, version)`,
366
392
  `ALTER TABLE skill_contents ADD INDEX idx_skill_contents_skill (skill_id)`,
367
393
  `ALTER TABLE credentials ADD INDEX idx_credentials_user (user_id, type)`,
@@ -372,15 +398,19 @@ const INDEX_STATEMENTS = [
372
398
  `ALTER TABLE cron_job_runs ADD INDEX idx_cron_job_runs_job (job_id, created_at)`,
373
399
  `ALTER TABLE cron_jobs ADD INDEX idx_cron_jobs_status_assigned (status, assigned_to)`,
374
400
  `ALTER TABLE cron_instances ADD INDEX idx_cron_instances_heartbeat (heartbeat_at)`,
401
+ `ALTER TABLE knowledge_docs ADD INDEX idx_knowledge_docs_name (name(255))`,
402
+ `ALTER TABLE feedback_reports ADD INDEX idx_feedback_reports_user (user_id, created_at)`,
403
+ `ALTER TABLE feedback_reports ADD INDEX idx_feedback_reports_session (session_id)`,
375
404
  ];
376
405
  export async function initSchema(db) {
377
406
  if (isSqlite())
378
407
  return runSqliteMigrations(db);
379
408
  console.log("[db] Initialising schema...");
380
- for (const ddl of DDL_STATEMENTS) {
381
- await db.execute(sql.raw(ddl));
382
- }
383
- // Schema migrations run after DDL to handle existing databases
409
+ // Schema migrations run FIRST — existing databases need column adds and table
410
+ // renames BEFORE DDL_STATEMENTS, because DDL uses new table names (clusters,
411
+ // user_cluster_configs, workspace_clusters). If DDL ran first, CREATE TABLE
412
+ // IF NOT EXISTS would create empty tables with new names, blocking the RENAME
413
+ // and leaving data stranded in old tables.
384
414
  const MIGRATIONS = [
385
415
  // skill_versions: s3_key NOT NULL → NULL, add specs + scripts_json columns
386
416
  `ALTER TABLE skill_versions MODIFY COLUMN s3_key VARCHAR(500) NULL`,
@@ -393,8 +423,21 @@ export async function initSchema(db) {
393
423
  // ADR-011: environment isolation
394
424
  `ALTER TABLE workspaces ADD COLUMN env_type VARCHAR(10) NOT NULL DEFAULT 'prod' AFTER is_default`,
395
425
  `ALTER TABLE environments ADD COLUMN api_server VARCHAR(512) NOT NULL DEFAULT '' AFTER is_test`,
426
+ `ALTER TABLE environments ADD COLUMN description TEXT AFTER name`,
427
+ // Rename environments → clusters
428
+ `RENAME TABLE environments TO clusters`,
429
+ `RENAME TABLE user_env_configs TO user_cluster_configs`,
430
+ `RENAME TABLE workspace_environments TO workspace_clusters`,
431
+ `ALTER TABLE user_cluster_configs CHANGE COLUMN env_id cluster_id VARCHAR(64) NOT NULL`,
432
+ `ALTER TABLE workspace_clusters CHANGE COLUMN env_id cluster_id VARCHAR(64) NOT NULL`,
433
+ // Rename description → infra_context
434
+ `ALTER TABLE clusters CHANGE COLUMN description infra_context TEXT`,
396
435
  `ALTER TABLE cron_jobs ADD COLUMN workspace_id VARCHAR(64)`,
397
436
  `ALTER TABLE cron_jobs ADD CONSTRAINT fk_cron_jobs_workspace FOREIGN KEY (workspace_id) REFERENCES workspaces(id)`,
437
+ // Knowledge docs: drop description column
438
+ `ALTER TABLE knowledge_docs DROP COLUMN description`,
439
+ // Per-cluster debug image
440
+ `ALTER TABLE clusters ADD COLUMN debug_image TEXT`,
398
441
  ];
399
442
  for (const stmt of MIGRATIONS) {
400
443
  try {
@@ -408,10 +451,16 @@ export async function initSchema(db) {
408
451
  // Ignore if column type already matches
409
452
  if (String(err).includes("ER_DUP_FIELDNAME"))
410
453
  continue;
454
+ // Ignore "table doesn't exist" (fresh install) and "already renamed"
455
+ if (code === "ER_NO_SUCH_TABLE" || code === "ER_TABLE_EXISTS_ERROR")
456
+ continue;
411
457
  // Log but don't fail
412
458
  console.warn("[db] Migration warning:", String(err).slice(0, 200));
413
459
  }
414
460
  }
461
+ for (const ddl of DDL_STATEMENTS) {
462
+ await db.execute(sql.raw(ddl));
463
+ }
415
464
  // Create indexes (ignore ER_DUP_KEYNAME if already exist)
416
465
  for (const ddl of INDEX_STATEMENTS) {
417
466
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"init-schema.js","sourceRoot":"","sources":["../../../src/gateway/db/init-schema.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"init-schema.js","sourceRoot":"","sources":["../../../src/gateway/db/init-schema.ts"],"names":[],"mappings":"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"}
@@ -91,7 +91,6 @@ const DDL_STATEMENTS = [
91
91
  assigned_to TEXT,
92
92
  locked_by TEXT,
93
93
  locked_at INTEGER,
94
- env_id TEXT,
95
94
  workspace_id TEXT
96
95
  )`,
97
96
  `CREATE TABLE IF NOT EXISTS cron_job_runs (
@@ -127,25 +126,27 @@ const DDL_STATEMENTS = [
127
126
  vote INTEGER NOT NULL,
128
127
  created_at INTEGER NOT NULL DEFAULT (unixepoch())
129
128
  )`,
130
- `CREATE TABLE IF NOT EXISTS environments (
129
+ `CREATE TABLE IF NOT EXISTS clusters (
131
130
  id TEXT PRIMARY KEY,
132
131
  name TEXT NOT NULL,
132
+ infra_context TEXT,
133
133
  is_test INTEGER NOT NULL DEFAULT 0,
134
134
  api_server TEXT NOT NULL DEFAULT '',
135
135
  created_by TEXT,
136
136
  allowed_servers TEXT,
137
137
  default_kubeconfig TEXT,
138
+ debug_image TEXT,
138
139
  created_at INTEGER NOT NULL DEFAULT (unixepoch()),
139
140
  updated_at INTEGER NOT NULL DEFAULT (unixepoch())
140
141
  )`,
141
- `CREATE TABLE IF NOT EXISTS user_env_configs (
142
+ `CREATE TABLE IF NOT EXISTS user_cluster_configs (
142
143
  id TEXT PRIMARY KEY,
143
144
  user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
144
- env_id TEXT NOT NULL REFERENCES environments(id) ON DELETE CASCADE,
145
+ cluster_id TEXT NOT NULL REFERENCES clusters(id) ON DELETE CASCADE,
145
146
  kubeconfig TEXT NOT NULL,
146
147
  created_at INTEGER NOT NULL DEFAULT (unixepoch()),
147
148
  updated_at INTEGER NOT NULL DEFAULT (unixepoch()),
148
- UNIQUE (user_id, env_id)
149
+ UNIQUE (user_id, cluster_id)
149
150
  )`,
150
151
  `CREATE TABLE IF NOT EXISTS user_disabled_skills (
151
152
  user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
@@ -255,10 +256,10 @@ const DDL_STATEMENTS = [
255
256
  tool_name TEXT NOT NULL,
256
257
  PRIMARY KEY (workspace_id, tool_name)
257
258
  )`,
258
- `CREATE TABLE IF NOT EXISTS workspace_environments (
259
+ `CREATE TABLE IF NOT EXISTS workspace_clusters (
259
260
  workspace_id TEXT NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
260
- env_id TEXT NOT NULL REFERENCES environments(id) ON DELETE CASCADE,
261
- PRIMARY KEY (workspace_id, env_id)
261
+ cluster_id TEXT NOT NULL REFERENCES clusters(id) ON DELETE CASCADE,
262
+ PRIMARY KEY (workspace_id, cluster_id)
262
263
  )`,
263
264
  `CREATE TABLE IF NOT EXISTS workspace_credentials (
264
265
  workspace_id TEXT NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
@@ -302,6 +303,16 @@ const DDL_STATEMENTS = [
302
303
  tool_call_count INTEGER DEFAULT 0,
303
304
  skill_call_count INTEGER DEFAULT 0,
304
305
  created_at INTEGER NOT NULL
306
+ )`,
307
+ `CREATE TABLE IF NOT EXISTS knowledge_docs (
308
+ id TEXT PRIMARY KEY,
309
+ name TEXT NOT NULL,
310
+ file_path TEXT NOT NULL,
311
+ size_bytes INTEGER NOT NULL DEFAULT 0,
312
+ chunk_count INTEGER NOT NULL DEFAULT 0,
313
+ uploaded_by TEXT REFERENCES users(id) ON DELETE SET NULL,
314
+ created_at INTEGER NOT NULL DEFAULT (unixepoch()),
315
+ updated_at INTEGER NOT NULL DEFAULT (unixepoch())
305
316
  )`,
306
317
  `CREATE TABLE IF NOT EXISTS mcp_servers (
307
318
  id TEXT PRIMARY KEY,
@@ -319,6 +330,20 @@ const DDL_STATEMENTS = [
319
330
  created_at INTEGER NOT NULL DEFAULT (unixepoch()),
320
331
  updated_at INTEGER NOT NULL DEFAULT (unixepoch())
321
332
  )`,
333
+ `CREATE TABLE IF NOT EXISTS feedback_reports (
334
+ id TEXT PRIMARY KEY,
335
+ session_id TEXT NOT NULL,
336
+ user_id TEXT NOT NULL,
337
+ workspace_id TEXT,
338
+ overall_rating INTEGER CHECK(overall_rating BETWEEN 1 AND 5),
339
+ summary TEXT NOT NULL,
340
+ decision_points TEXT,
341
+ strengths TEXT,
342
+ improvements TEXT,
343
+ tags TEXT,
344
+ feedback_conversation TEXT,
345
+ created_at INTEGER NOT NULL DEFAULT (unixepoch())
346
+ )`,
322
347
  ];
323
348
  const INDEX_STATEMENTS = [
324
349
  `CREATE INDEX IF NOT EXISTS idx_sessions_user ON sessions(user_id, last_active_at)`,
@@ -330,8 +355,8 @@ const INDEX_STATEMENTS = [
330
355
  `CREATE INDEX IF NOT EXISTS idx_notifications_user ON notifications(user_id, is_read, created_at)`,
331
356
  `CREATE INDEX IF NOT EXISTS idx_skill_reviews_skill ON skill_reviews(skill_id, created_at)`,
332
357
  `CREATE INDEX IF NOT EXISTS idx_user_permissions_perm ON user_permissions(permission)`,
333
- `CREATE INDEX IF NOT EXISTS idx_user_env_configs_user ON user_env_configs(user_id)`,
334
- `CREATE INDEX IF NOT EXISTS idx_user_env_configs_env ON user_env_configs(env_id)`,
358
+ `CREATE INDEX IF NOT EXISTS idx_user_cluster_configs_user ON user_cluster_configs(user_id)`,
359
+ `CREATE INDEX IF NOT EXISTS idx_user_cluster_configs_cluster ON user_cluster_configs(cluster_id)`,
335
360
  `CREATE INDEX IF NOT EXISTS idx_skill_versions_skill ON skill_versions(skill_id, version)`,
336
361
  `CREATE INDEX IF NOT EXISTS idx_skill_contents_skill ON skill_contents(skill_id)`,
337
362
  `CREATE INDEX IF NOT EXISTS idx_credentials_user ON credentials(user_id, type)`,
@@ -342,35 +367,55 @@ const INDEX_STATEMENTS = [
342
367
  `CREATE INDEX IF NOT EXISTS idx_cron_job_runs_job ON cron_job_runs(job_id, created_at)`,
343
368
  `CREATE INDEX IF NOT EXISTS idx_cron_jobs_status_assigned ON cron_jobs(status, assigned_to)`,
344
369
  `CREATE INDEX IF NOT EXISTS idx_cron_instances_heartbeat ON cron_instances(heartbeat_at)`,
370
+ `CREATE INDEX IF NOT EXISTS idx_feedback_reports_user ON feedback_reports(user_id, created_at)`,
371
+ `CREATE INDEX IF NOT EXISTS idx_feedback_reports_session ON feedback_reports(session_id)`,
372
+ `CREATE INDEX IF NOT EXISTS idx_knowledge_docs_name ON knowledge_docs(name)`,
345
373
  ];
346
374
  export async function runSqliteMigrations(db) {
347
375
  console.log("[db] Running SQLite migrations...");
348
376
  // sql.js drizzle instance has .run()/.all() but NOT .execute().
349
377
  // Cast to 'any' since db is typed as MySql2Database (the unified type alias).
350
378
  const sdb = db;
351
- for (const ddl of DDL_STATEMENTS) {
352
- sdb.run(sql.raw(ddl));
353
- }
354
- // Schema migrations handle existing databases missing new columns.
355
- // Must run BEFORE index creation, since some indexes reference new columns.
379
+ // Schema migrations run FIRST — existing databases need column adds and table
380
+ // renames BEFORE DDL_STATEMENTS, because DDL uses new table names (clusters,
381
+ // user_cluster_configs, workspace_clusters). If DDL ran first, CREATE TABLE
382
+ // IF NOT EXISTS would create empty tables with new names, blocking the RENAME
383
+ // and leaving data stranded in old tables.
356
384
  const MIGRATIONS = [
357
385
  // ADR-011: environment isolation
358
386
  `ALTER TABLE workspaces ADD COLUMN env_type TEXT NOT NULL DEFAULT 'prod'`,
359
387
  `ALTER TABLE environments ADD COLUMN api_server TEXT NOT NULL DEFAULT ''`,
360
388
  `ALTER TABLE cron_jobs ADD COLUMN workspace_id TEXT`,
361
- ];
362
- // Backfill: copy allowedServers[0] apiServer for rows that haven't been set
363
- const BACKFILLS = [
364
- `UPDATE environments SET api_server = TRIM(SUBSTR(allowed_servers, 1, CASE WHEN INSTR(allowed_servers, ',') > 0 THEN INSTR(allowed_servers, ',') - 1 ELSE LENGTH(allowed_servers) END)) WHERE api_server = '' AND allowed_servers != ''`,
389
+ `ALTER TABLE environments ADD COLUMN description TEXT`,
390
+ // Rename environmentsclusters
391
+ `ALTER TABLE environments RENAME TO clusters`,
392
+ `ALTER TABLE user_env_configs RENAME TO user_cluster_configs`,
393
+ `ALTER TABLE workspace_environments RENAME TO workspace_clusters`,
394
+ `ALTER TABLE user_cluster_configs RENAME COLUMN env_id TO cluster_id`,
395
+ `ALTER TABLE workspace_clusters RENAME COLUMN env_id TO cluster_id`,
396
+ // Rename description → infra_context
397
+ `ALTER TABLE clusters RENAME COLUMN description TO infra_context`,
398
+ // Knowledge docs: drop description column
399
+ `ALTER TABLE knowledge_docs DROP COLUMN description`,
400
+ // Per-cluster debug image
401
+ `ALTER TABLE clusters ADD COLUMN debug_image TEXT`,
365
402
  ];
366
403
  for (const stmt of MIGRATIONS) {
367
404
  try {
368
405
  sdb.run(sql.raw(stmt));
369
406
  }
370
407
  catch (_err) {
371
- // Ignore "duplicate column name" errors (column already exists)
408
+ // Ignore errors: "duplicate column", "no such table" (fresh DB), "already renamed", etc.
372
409
  }
373
410
  }
411
+ // DDL: create tables that don't exist yet (fresh installs, or tables unaffected by migrations).
412
+ for (const ddl of DDL_STATEMENTS) {
413
+ sdb.run(sql.raw(ddl));
414
+ }
415
+ // Backfill: copy allowedServers[0] → apiServer for rows that haven't been set
416
+ const BACKFILLS = [
417
+ `UPDATE clusters SET api_server = TRIM(SUBSTR(allowed_servers, 1, CASE WHEN INSTR(allowed_servers, ',') > 0 THEN INSTR(allowed_servers, ',') - 1 ELSE LENGTH(allowed_servers) END)) WHERE api_server = '' AND allowed_servers != ''`,
418
+ ];
374
419
  for (const stmt of BACKFILLS) {
375
420
  try {
376
421
  sdb.run(sql.raw(stmt));
@@ -390,6 +435,14 @@ export async function runSqliteMigrations(db) {
390
435
  BEGIN
391
436
  UPDATE mcp_servers SET updated_at = unixepoch() WHERE id = NEW.id;
392
437
  END
438
+ `));
439
+ sdb.run(sql.raw(`
440
+ CREATE TRIGGER IF NOT EXISTS trg_knowledge_docs_updated_at
441
+ AFTER UPDATE ON knowledge_docs
442
+ FOR EACH ROW
443
+ BEGIN
444
+ UPDATE knowledge_docs SET updated_at = unixepoch() WHERE id = NEW.id;
445
+ END
393
446
  `));
394
447
  // Seed default embedding config if not present (empty = unconfigured)
395
448
  sdb.run(sql.raw(`INSERT OR IGNORE INTO embedding_config (id, provider_name, model, dimensions, updated_at)
@@ -1 +1 @@
1
- {"version":3,"file":"migrate-sqlite.js","sourceRoot":"","sources":["../../../src/gateway/db/migrate-sqlite.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"migrate-sqlite.js","sourceRoot":"","sources":["../../../src/gateway/db/migrate-sqlite.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAElC,MAAM,cAAc,GAAG;IACrB;;;;;;;;IAQE;IAEF;;;;;;;IAOE;IAEF;;;;;;;;;;;IAWE;IAEF;;;;;;;;;;;;IAYE;IAEF;;;;;;;;;;;;;;;;;;;;;IAqBE;IAEF;;;;;;IAME;IAEF;;;;;;;;;;;;;;IAcE;IAEF;;;;;;;;IAQE;IAEF;;;;;;IAME;IAEF;;;;;;;;;IASE;IAEF;;;;;;IAME;IAEF;;;;;;;;;;;;IAYE;IAEF;;;;;;;;IAQE;IAEF;;;;IAIE;IAEF;;;;;;;;;;IAUE;IAEF;;;;;;;IAOE;IAEF;;;;;;;;;IASE;IAEF;;;;;;;;;;;;IAYE;IAEF;;;;;;;;;IASE;IAEF;;;;;;;;;;;IAWE;IAEF;;;;;;;;;;IAUE;IAEF;;;;;;IAME;IAEF;;;;;;;;;;IAUE;IAEF;;;;IAIE;IAEF;;;;IAIE;IAEF;;;;IAIE;IAEF;;;;IAIE;IAEF;;;;IAIE;IAEF;;;;;;;;;;;;;;;;IAgBE;IAEF;;;;;;;;;;;;;;;IAeE;IAEF;;;;;;;;;IASE;IAEF;;;;;;;;;;;;;;;IAeE;IAEF;;;;;;;;;;;;;IAaE;CACH,CAAC;AAEF,MAAM,gBAAgB,GAAG;IACvB,mFAAmF;IACnF,oFAAoF;IACpF,8DAA8D;IAC9D,mEAAmE;IACnE,4FAA4F;IAC5F,2EAA2E;IAC3E,kGAAkG;IAClG,2FAA2F;IAC3F,sFAAsF;IACtF,2FAA2F;IAC3F,iGAAiG;IACjG,0FAA0F;IAC1F,iFAAiF;IACjF,+EAA+E;IAC/E,mFAAmF;IACnF,yFAAyF;IACzF,yFAAyF;IACzF,0EAA0E;IAC1E,uFAAuF;IACvF,4FAA4F;IAC5F,yFAAyF;IACzF,+FAA+F;IAC/F,yFAAyF;IACzF,4EAA4E;CAC7E,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,EAAY;IACpD,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;IAEjD,gEAAgE;IAChE,8EAA8E;IAC9E,MAAM,GAAG,GAAG,EAAS,CAAC;IAEtB,8EAA8E;IAC9E,6EAA6E;IAC7E,4EAA4E;IAC5E,8EAA8E;IAC9E,2CAA2C;IAC3C,MAAM,UAAU,GAAG;QACjB,iCAAiC;QACjC,yEAAyE;QACzE,yEAAyE;QACzE,oDAAoD;QACpD,sDAAsD;QACtD,iCAAiC;QACjC,6CAA6C;QAC7C,6DAA6D;QAC7D,iEAAiE;QACjE,qEAAqE;QACrE,mEAAmE;QACnE,qCAAqC;QACrC,iEAAiE;QACjE,0CAA0C;QAC1C,oDAAoD;QACpD,0BAA0B;QAC1B,kDAAkD;KACnD,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,IAAI,CAAC;YACH,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;QACzB,CAAC;QAAC,OAAO,IAAS,EAAE,CAAC;YACnB,yFAAyF;QAC3F,CAAC;IACH,CAAC;IAED,gGAAgG;IAChG,KAAK,MAAM,GAAG,IAAI,cAAc,EAAE,CAAC;QACjC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IACxB,CAAC;IAED,8EAA8E;IAC9E,MAAM,SAAS,GAAG;QAChB,oOAAoO;KACrO,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;QACzB,CAAC;QAAC,OAAO,IAAS,EAAE,CAAC;YACnB,qDAAqD;QACvD,CAAC;IACH,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,gBAAgB,EAAE,CAAC;QACnC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IACxB,CAAC;IAED,oGAAoG;IACpG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC;;;;;;;GAOf,CAAC,CAAC,CAAC;IAEJ,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC;;;;;;;GAOf,CAAC,CAAC,CAAC;IAEJ,sEAAsE;IACtE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CACb;wCACoC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CACrE,CAAC,CAAC;IACH,0DAA0D;IAC1D,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CACb;kFAC8E,CAC/E,CAAC,CAAC;IAEH,mEAAmE;IACnE,aAAa,EAAE,CAAC;IAEhB,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;AACjD,CAAC"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Cluster Repository — CRUD for admin-managed K8s clusters
3
+ */
4
+ import type { Database } from "../index.js";
5
+ export declare class ClusterRepository {
6
+ private db;
7
+ constructor(db: Database);
8
+ list(): Promise<{
9
+ id: string;
10
+ name: string;
11
+ infraContext: string | null;
12
+ isTest: boolean;
13
+ apiServer: string;
14
+ allowedServers: string | null;
15
+ defaultKubeconfig: string | null;
16
+ debugImage: string | null;
17
+ createdBy: string | null;
18
+ createdAt: Date;
19
+ updatedAt: Date;
20
+ }[]>;
21
+ getById(id: string): Promise<{
22
+ id: string;
23
+ name: string;
24
+ infraContext: string | null;
25
+ isTest: boolean;
26
+ apiServer: string;
27
+ allowedServers: string | null;
28
+ defaultKubeconfig: string | null;
29
+ debugImage: string | null;
30
+ createdBy: string | null;
31
+ createdAt: Date;
32
+ updatedAt: Date;
33
+ }>;
34
+ listByIds(ids: string[]): Promise<{
35
+ id: string;
36
+ name: string;
37
+ infraContext: string | null;
38
+ isTest: boolean;
39
+ apiServer: string;
40
+ allowedServers: string | null;
41
+ defaultKubeconfig: string | null;
42
+ debugImage: string | null;
43
+ createdBy: string | null;
44
+ createdAt: Date;
45
+ updatedAt: Date;
46
+ }[]>;
47
+ save(cluster: {
48
+ id?: string;
49
+ name: string;
50
+ infraContext?: string | null;
51
+ isTest?: boolean;
52
+ apiServer: string;
53
+ allowedServers?: string | null;
54
+ defaultKubeconfig?: string | null;
55
+ debugImage?: string | null;
56
+ }, createdBy?: string): Promise<string>;
57
+ clearDefaultKubeconfig(clusterId: string): Promise<void>;
58
+ delete(id: string): Promise<void>;
59
+ }
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Cluster Repository — CRUD for admin-managed K8s clusters
3
+ */
4
+ import crypto from "node:crypto";
5
+ import { eq, inArray } from "drizzle-orm";
6
+ import { clusters } from "../schema.js";
7
+ export class ClusterRepository {
8
+ db;
9
+ constructor(db) {
10
+ this.db = db;
11
+ }
12
+ async list() {
13
+ return this.db
14
+ .select({
15
+ id: clusters.id,
16
+ name: clusters.name,
17
+ infraContext: clusters.infraContext,
18
+ isTest: clusters.isTest,
19
+ apiServer: clusters.apiServer,
20
+ allowedServers: clusters.allowedServers,
21
+ defaultKubeconfig: clusters.defaultKubeconfig,
22
+ debugImage: clusters.debugImage,
23
+ createdBy: clusters.createdBy,
24
+ createdAt: clusters.createdAt,
25
+ updatedAt: clusters.updatedAt,
26
+ })
27
+ .from(clusters);
28
+ }
29
+ async getById(id) {
30
+ const rows = await this.db
31
+ .select()
32
+ .from(clusters)
33
+ .where(eq(clusters.id, id))
34
+ .limit(1);
35
+ return rows[0] ?? null;
36
+ }
37
+ async listByIds(ids) {
38
+ if (ids.length === 0)
39
+ return [];
40
+ return this.db
41
+ .select({
42
+ id: clusters.id,
43
+ name: clusters.name,
44
+ infraContext: clusters.infraContext,
45
+ isTest: clusters.isTest,
46
+ apiServer: clusters.apiServer,
47
+ allowedServers: clusters.allowedServers,
48
+ defaultKubeconfig: clusters.defaultKubeconfig,
49
+ debugImage: clusters.debugImage,
50
+ createdBy: clusters.createdBy,
51
+ createdAt: clusters.createdAt,
52
+ updatedAt: clusters.updatedAt,
53
+ })
54
+ .from(clusters)
55
+ .where(inArray(clusters.id, ids));
56
+ }
57
+ async save(cluster, createdBy) {
58
+ if (!cluster.apiServer || typeof cluster.apiServer !== "string" || !cluster.apiServer.trim()) {
59
+ throw new Error("apiServer is required and must be a non-empty string");
60
+ }
61
+ if (cluster.id) {
62
+ // Update existing
63
+ const updates = { name: cluster.name, apiServer: cluster.apiServer };
64
+ if (cluster.infraContext !== undefined)
65
+ updates.infraContext = cluster.infraContext;
66
+ if (cluster.isTest !== undefined)
67
+ updates.isTest = cluster.isTest;
68
+ if (cluster.allowedServers !== undefined)
69
+ updates.allowedServers = cluster.allowedServers;
70
+ if (cluster.defaultKubeconfig !== undefined)
71
+ updates.defaultKubeconfig = cluster.defaultKubeconfig;
72
+ if (cluster.debugImage !== undefined)
73
+ updates.debugImage = cluster.debugImage;
74
+ await this.db
75
+ .update(clusters)
76
+ .set(updates)
77
+ .where(eq(clusters.id, cluster.id));
78
+ return cluster.id;
79
+ }
80
+ // Create new
81
+ const id = crypto.randomBytes(12).toString("hex");
82
+ await this.db.insert(clusters).values({
83
+ id,
84
+ name: cluster.name,
85
+ infraContext: cluster.infraContext ?? null,
86
+ isTest: cluster.isTest ?? false,
87
+ apiServer: cluster.apiServer,
88
+ allowedServers: cluster.allowedServers ?? null,
89
+ defaultKubeconfig: cluster.defaultKubeconfig ?? null,
90
+ debugImage: cluster.debugImage ?? null,
91
+ createdBy: createdBy ?? null,
92
+ });
93
+ return id;
94
+ }
95
+ async clearDefaultKubeconfig(clusterId) {
96
+ await this.db
97
+ .update(clusters)
98
+ .set({ defaultKubeconfig: null })
99
+ .where(eq(clusters.id, clusterId));
100
+ }
101
+ async delete(id) {
102
+ await this.db
103
+ .delete(clusters)
104
+ .where(eq(clusters.id, id));
105
+ }
106
+ }
107
+ //# sourceMappingURL=cluster-repo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cluster-repo.js","sourceRoot":"","sources":["../../../../src/gateway/db/repositories/cluster-repo.ts"],"names":[],"mappings":"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"}
@@ -28,7 +28,6 @@ export declare class ConfigRepository {
28
28
  assignedTo: string | null;
29
29
  lockedBy: string | null;
30
30
  lockedAt: Date | null;
31
- envId: string | null;
32
31
  workspaceId: string | null;
33
32
  }[]>;
34
33
  saveCronJob(userId: string, job: {
@@ -54,7 +53,6 @@ export declare class ConfigRepository {
54
53
  assignedTo: string | null;
55
54
  lockedBy: string | null;
56
55
  lockedAt: Date | null;
57
- envId: string | null;
58
56
  workspaceId: string | null;
59
57
  }>;
60
58
  listAllActiveCronJobs(): Promise<{
@@ -70,7 +68,6 @@ export declare class ConfigRepository {
70
68
  assignedTo: string | null;
71
69
  lockedBy: string | null;
72
70
  lockedAt: Date | null;
73
- envId: string | null;
74
71
  workspaceId: string | null;
75
72
  }[]>;
76
73
  listCronJobsByInstance(instanceId: string): Promise<{
@@ -86,7 +83,6 @@ export declare class ConfigRepository {
86
83
  assignedTo: string | null;
87
84
  lockedBy: string | null;
88
85
  lockedAt: Date | null;
89
- envId: string | null;
90
86
  workspaceId: string | null;
91
87
  }[]>;
92
88
  updateCronJobRun(id: string, result: "success" | "failure"): Promise<void>;
@@ -152,7 +148,6 @@ export declare class ConfigRepository {
152
148
  assignedTo: string | null;
153
149
  lockedBy: string | null;
154
150
  lockedAt: Date | null;
155
- envId: string | null;
156
151
  workspaceId: string | null;
157
152
  }[]>;
158
153
  /** Atomically lock a job for execution — returns true if locked by us */
@@ -161,6 +156,10 @@ export declare class ConfigRepository {
161
156
  unlockJob(jobId: string, executionId: string): Promise<void>;
162
157
  /** Clear locks older than thresholdMs (stale lock cleanup) */
163
158
  clearStaleLocks(thresholdMs: number): Promise<void>;
159
+ /** Count active (non-paused) jobs owned by a user */
160
+ countActiveJobsByUser(userId: string): Promise<number>;
161
+ /** Count jobs currently locked for execution (lockedBy IS NOT NULL) */
162
+ countCurrentlyExecutingJobs(): Promise<number>;
164
163
  listTriggers(userId: string): Promise<{
165
164
  id: string;
166
165
  userId: string;
@@ -261,6 +261,23 @@ export class ConfigRepository {
261
261
  .set({ lockedBy: null, lockedAt: null })
262
262
  .where(and(isNotNull(cronJobs.lockedBy), lte(cronJobs.lockedAt, cutoff)));
263
263
  }
264
+ // ─── Cron Limits Queries ─────────────────────────
265
+ /** Count active (non-paused) jobs owned by a user */
266
+ async countActiveJobsByUser(userId) {
267
+ const rows = await this.db
268
+ .select({ cnt: sql `count(*)` })
269
+ .from(cronJobs)
270
+ .where(and(eq(cronJobs.userId, userId), eq(cronJobs.status, "active")));
271
+ return Number(rows[0]?.cnt ?? 0);
272
+ }
273
+ /** Count jobs currently locked for execution (lockedBy IS NOT NULL) */
274
+ async countCurrentlyExecutingJobs() {
275
+ const rows = await this.db
276
+ .select({ cnt: sql `count(*)` })
277
+ .from(cronJobs)
278
+ .where(isNotNull(cronJobs.lockedBy));
279
+ return Number(rows[0]?.cnt ?? 0);
280
+ }
264
281
  // ─── Triggers ─────────────────────────────────
265
282
  async listTriggers(userId) {
266
283
  return this.db