@deeplake/hivemind 0.7.35 → 0.7.36
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.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/bundle/cli.js +152 -67
- package/codex/bundle/capture.js +152 -67
- package/codex/bundle/commands/auth-login.js +152 -67
- package/codex/bundle/pre-tool-use.js +152 -67
- package/codex/bundle/session-start-setup.js +152 -67
- package/codex/bundle/session-start.js +152 -67
- package/codex/bundle/shell/deeplake-shell.js +152 -67
- package/codex/bundle/skillify-worker.js +146 -14
- package/codex/bundle/stop.js +152 -67
- package/cursor/bundle/capture.js +152 -67
- package/cursor/bundle/commands/auth-login.js +152 -67
- package/cursor/bundle/pre-tool-use.js +152 -67
- package/cursor/bundle/session-start.js +152 -67
- package/cursor/bundle/shell/deeplake-shell.js +152 -67
- package/cursor/bundle/skillify-worker.js +146 -14
- package/hermes/bundle/capture.js +152 -67
- package/hermes/bundle/commands/auth-login.js +152 -67
- package/hermes/bundle/pre-tool-use.js +152 -67
- package/hermes/bundle/session-start.js +152 -67
- package/hermes/bundle/shell/deeplake-shell.js +152 -67
- package/hermes/bundle/skillify-worker.js +146 -14
- package/mcp/bundle/server.js +154 -69
- package/openclaw/dist/index.js +151 -74
- package/openclaw/dist/skillify-worker.js +146 -14
- package/openclaw/openclaw.plugin.json +1 -1
- package/openclaw/package.json +1 -1
- package/package.json +1 -1
|
@@ -150,7 +150,123 @@ function sqlIdent(name) {
|
|
|
150
150
|
|
|
151
151
|
// dist/src/embeddings/columns.js
|
|
152
152
|
var SUMMARY_EMBEDDING_COL = "summary_embedding";
|
|
153
|
-
|
|
153
|
+
|
|
154
|
+
// dist/src/deeplake-schema.js
|
|
155
|
+
var MEMORY_COLUMNS = Object.freeze([
|
|
156
|
+
{ name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
157
|
+
{ name: "path", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
158
|
+
{ name: "filename", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
159
|
+
{ name: "summary", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
160
|
+
{ name: "summary_embedding", sql: "FLOAT4[]" },
|
|
161
|
+
{ name: "author", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
162
|
+
{ name: "mime_type", sql: "TEXT NOT NULL DEFAULT 'text/plain'" },
|
|
163
|
+
{ name: "size_bytes", sql: "BIGINT NOT NULL DEFAULT 0" },
|
|
164
|
+
{ name: "project", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
165
|
+
{ name: "description", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
166
|
+
{ name: "agent", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
167
|
+
{ name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
168
|
+
{ name: "creation_date", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
169
|
+
{ name: "last_update_date", sql: "TEXT NOT NULL DEFAULT ''" }
|
|
170
|
+
]);
|
|
171
|
+
var SESSIONS_COLUMNS = Object.freeze([
|
|
172
|
+
{ name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
173
|
+
{ name: "path", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
174
|
+
{ name: "filename", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
175
|
+
{ name: "message", sql: "JSONB" },
|
|
176
|
+
{ name: "message_embedding", sql: "FLOAT4[]" },
|
|
177
|
+
{ name: "author", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
178
|
+
{ name: "mime_type", sql: "TEXT NOT NULL DEFAULT 'application/json'" },
|
|
179
|
+
{ name: "size_bytes", sql: "BIGINT NOT NULL DEFAULT 0" },
|
|
180
|
+
{ name: "project", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
181
|
+
{ name: "description", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
182
|
+
{ name: "agent", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
183
|
+
{ name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
184
|
+
{ name: "creation_date", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
185
|
+
{ name: "last_update_date", sql: "TEXT NOT NULL DEFAULT ''" }
|
|
186
|
+
]);
|
|
187
|
+
var SKILLS_COLUMNS = Object.freeze([
|
|
188
|
+
{ name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
189
|
+
{ name: "name", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
190
|
+
{ name: "project", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
191
|
+
{ name: "project_key", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
192
|
+
{ name: "local_path", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
193
|
+
{ name: "install", sql: "TEXT NOT NULL DEFAULT 'project'" },
|
|
194
|
+
{ name: "source_sessions", sql: "TEXT NOT NULL DEFAULT '[]'" },
|
|
195
|
+
{ name: "source_agent", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
196
|
+
{ name: "scope", sql: "TEXT NOT NULL DEFAULT 'me'" },
|
|
197
|
+
{ name: "author", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
198
|
+
{ name: "contributors", sql: "TEXT NOT NULL DEFAULT '[]'" },
|
|
199
|
+
{ name: "description", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
200
|
+
{ name: "trigger_text", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
201
|
+
{ name: "body", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
202
|
+
{ name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
|
|
203
|
+
{ name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
204
|
+
{ name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" }
|
|
205
|
+
]);
|
|
206
|
+
function validateSchema(label, cols) {
|
|
207
|
+
const seen = /* @__PURE__ */ new Set();
|
|
208
|
+
for (const col of cols) {
|
|
209
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(col.name)) {
|
|
210
|
+
throw new Error(`${label}: column name "${col.name}" is not a valid SQL identifier`);
|
|
211
|
+
}
|
|
212
|
+
if (seen.has(col.name)) {
|
|
213
|
+
throw new Error(`${label}: duplicate column "${col.name}"`);
|
|
214
|
+
}
|
|
215
|
+
seen.add(col.name);
|
|
216
|
+
const notNull = /\bNOT\s+NULL\b/i.test(col.sql);
|
|
217
|
+
const hasDefault = /\bDEFAULT\b/i.test(col.sql);
|
|
218
|
+
if (notNull && !hasDefault) {
|
|
219
|
+
throw new Error(`${label}: column "${col.name}" is NOT NULL but has no DEFAULT \u2014 ALTER TABLE ADD COLUMN on a populated table would fail.`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
validateSchema("MEMORY_COLUMNS", MEMORY_COLUMNS);
|
|
224
|
+
validateSchema("SESSIONS_COLUMNS", SESSIONS_COLUMNS);
|
|
225
|
+
validateSchema("SKILLS_COLUMNS", SKILLS_COLUMNS);
|
|
226
|
+
function buildCreateTableSql(tableName, cols) {
|
|
227
|
+
const safe = sqlIdent(tableName);
|
|
228
|
+
const colSql = cols.map((c) => `${c.name} ${c.sql}`).join(", ");
|
|
229
|
+
return `CREATE TABLE IF NOT EXISTS "${safe}" (${colSql}) USING deeplake`;
|
|
230
|
+
}
|
|
231
|
+
function buildIntrospectionSql(tableName, workspaceId) {
|
|
232
|
+
return `SELECT column_name FROM information_schema.columns WHERE table_name = '${sqlStr(tableName)}' AND table_schema = '${sqlStr(workspaceId)}'`;
|
|
233
|
+
}
|
|
234
|
+
async function healMissingColumns(args) {
|
|
235
|
+
const safeTable = sqlIdent(args.tableName);
|
|
236
|
+
const introspectSql = buildIntrospectionSql(args.tableName, args.workspaceId);
|
|
237
|
+
const rows = await args.query(introspectSql);
|
|
238
|
+
const existing = /* @__PURE__ */ new Set();
|
|
239
|
+
for (const row of rows) {
|
|
240
|
+
const v = row?.column_name;
|
|
241
|
+
if (typeof v === "string")
|
|
242
|
+
existing.add(v.toLowerCase());
|
|
243
|
+
}
|
|
244
|
+
const missingCols = args.columns.filter((c) => !existing.has(c.name.toLowerCase()));
|
|
245
|
+
const missing = missingCols.map((c) => c.name);
|
|
246
|
+
if (missingCols.length === 0)
|
|
247
|
+
return { missing, altered: [] };
|
|
248
|
+
const altered = [];
|
|
249
|
+
for (const col of missingCols) {
|
|
250
|
+
try {
|
|
251
|
+
await args.query(`ALTER TABLE "${safeTable}" ADD COLUMN ${col.name} ${col.sql}`);
|
|
252
|
+
altered.push(col.name);
|
|
253
|
+
args.log?.(`schema-heal: added "${args.tableName}"."${col.name}"`);
|
|
254
|
+
} catch (e) {
|
|
255
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
256
|
+
if (!/already exists/i.test(msg))
|
|
257
|
+
throw e;
|
|
258
|
+
const recheck = await args.query(introspectSql);
|
|
259
|
+
const present = recheck.some((r) => {
|
|
260
|
+
const v = r?.column_name;
|
|
261
|
+
return typeof v === "string" && v.toLowerCase() === col.name.toLowerCase();
|
|
262
|
+
});
|
|
263
|
+
if (!present)
|
|
264
|
+
throw e;
|
|
265
|
+
args.log?.(`schema-heal: "${args.tableName}"."${col.name}" appeared via race, treating as success`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return { missing, altered };
|
|
269
|
+
}
|
|
154
270
|
|
|
155
271
|
// dist/src/notifications/queue.js
|
|
156
272
|
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, renameSync, mkdirSync as mkdirSync2, openSync, closeSync, unlinkSync as unlinkSync2, statSync } from "node:fs";
|
|
@@ -516,64 +632,33 @@ var DeeplakeApi = class {
|
|
|
516
632
|
}
|
|
517
633
|
}
|
|
518
634
|
/**
|
|
519
|
-
*
|
|
520
|
-
*
|
|
521
|
-
*
|
|
522
|
-
*
|
|
523
|
-
*
|
|
524
|
-
* in the log and a wasted round-trip. Worse, the very first call after the
|
|
525
|
-
* column is genuinely added triggers Deeplake's post-ALTER `vector::at`
|
|
526
|
-
* window (~30s) during which subsequent INSERTs fail; minimising the
|
|
527
|
-
* number of ALTER calls minimises exposure to that window.
|
|
528
|
-
*
|
|
529
|
-
* New flow:
|
|
530
|
-
* 1. Check the local marker file (mirrors ensureLookupIndex). If fresh,
|
|
531
|
-
* return — zero network calls.
|
|
532
|
-
* 2. SELECT 1 FROM information_schema.columns WHERE table_name = T AND
|
|
533
|
-
* column_name = C. Read-only, idempotent, can't tickle the post-ALTER
|
|
534
|
-
* bug. If the column is present → mark + return.
|
|
535
|
-
* 3. Only if step 2 says the column is missing, fall back to ALTER ADD
|
|
536
|
-
* COLUMN IF NOT EXISTS. Mark on success, also mark if Deeplake reports
|
|
537
|
-
* "already exists" (race: another client added it between our SELECT
|
|
538
|
-
* and ALTER).
|
|
635
|
+
* Heal any missing columns on a table so it matches one of the schema
|
|
636
|
+
* definitions in `deeplake-schema.ts`. One SELECT against
|
|
637
|
+
* `information_schema.columns` per call, then `ALTER TABLE ADD COLUMN`
|
|
638
|
+
* only the genuinely missing ones — never blanket, never `IF NOT
|
|
639
|
+
* EXISTS`.
|
|
539
640
|
*
|
|
540
|
-
*
|
|
541
|
-
*
|
|
641
|
+
* History: an earlier path used a local marker file (`col_<name>` under
|
|
642
|
+
* the index-marker dir) to skip even the SELECT after the first
|
|
643
|
+
* confirmation, plus per-column ALTERs for `summary_embedding`,
|
|
644
|
+
* `message_embedding`, `agent`, `plugin_version`. The marker existed
|
|
645
|
+
* because Deeplake used to expose a ~30s post-ALTER bug where
|
|
646
|
+
* subsequent INSERTs failed, so we wanted to keep ALTER traffic to a
|
|
647
|
+
* minimum. The bug was re-verified on 2026-05-18 against
|
|
648
|
+
* `api.deeplake.ai` (`test_plugin` org) and no longer reproduces
|
|
649
|
+
* (71/71 INSERTs OK, first success 2ms after ALTER). The single SELECT
|
|
650
|
+
* + targeted ALTER pattern survives the marker removal because: each
|
|
651
|
+
* ALTER still costs ~800ms (so blanket sweeps are wasteful) and the
|
|
652
|
+
* diff produces clearer logs than "ALTER all with IF NOT EXISTS".
|
|
542
653
|
*/
|
|
543
|
-
async
|
|
544
|
-
await
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
* the `agent` column (added 2026-04-11) — the latter has no fallback if
|
|
552
|
-
* a user upgraded over a pre-2026-04-11 table, so every INSERT fails
|
|
553
|
-
* with `column "agent" does not exist`.
|
|
554
|
-
*/
|
|
555
|
-
async ensureColumn(table, column, sqlType) {
|
|
556
|
-
const markers = await getIndexMarkerStore();
|
|
557
|
-
const markerPath = markers.buildIndexMarkerPath(this.workspaceId, this.orgId, table, `col_${column}`);
|
|
558
|
-
if (markers.hasFreshIndexMarker(markerPath))
|
|
559
|
-
return;
|
|
560
|
-
const colCheck = `SELECT 1 FROM information_schema.columns WHERE table_name = '${sqlStr(table)}' AND column_name = '${sqlStr(column)}' AND table_schema = '${sqlStr(this.workspaceId)}' LIMIT 1`;
|
|
561
|
-
const rows = await this.query(colCheck);
|
|
562
|
-
if (rows.length > 0) {
|
|
563
|
-
markers.writeIndexMarker(markerPath);
|
|
564
|
-
return;
|
|
565
|
-
}
|
|
566
|
-
try {
|
|
567
|
-
await this.query(`ALTER TABLE "${table}" ADD COLUMN ${column} ${sqlType}`);
|
|
568
|
-
} catch (e) {
|
|
569
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
570
|
-
if (!/already exists/i.test(msg))
|
|
571
|
-
throw e;
|
|
572
|
-
const recheck = await this.query(colCheck);
|
|
573
|
-
if (recheck.length === 0)
|
|
574
|
-
throw e;
|
|
575
|
-
}
|
|
576
|
-
markers.writeIndexMarker(markerPath);
|
|
654
|
+
async healSchema(table, columns) {
|
|
655
|
+
await healMissingColumns({
|
|
656
|
+
query: (sql) => this.query(sql),
|
|
657
|
+
tableName: table,
|
|
658
|
+
workspaceId: this.workspaceId,
|
|
659
|
+
columns,
|
|
660
|
+
log: log3
|
|
661
|
+
});
|
|
577
662
|
}
|
|
578
663
|
/** List all tables in the workspace (with retry). */
|
|
579
664
|
async listTables(forceRefresh = false) {
|
|
@@ -644,20 +729,21 @@ var DeeplakeApi = class {
|
|
|
644
729
|
}
|
|
645
730
|
throw lastErr;
|
|
646
731
|
}
|
|
647
|
-
/** Create the memory table if it doesn't already exist.
|
|
732
|
+
/** Create the memory table if it doesn't already exist. Heal missing columns on existing tables. */
|
|
648
733
|
async ensureTable(name) {
|
|
734
|
+
if (!MEMORY_COLUMNS.some((c) => c.name === SUMMARY_EMBEDDING_COL)) {
|
|
735
|
+
throw new Error(`MEMORY_COLUMNS missing "${SUMMARY_EMBEDDING_COL}" (embeddings/columns.ts drift)`);
|
|
736
|
+
}
|
|
649
737
|
const tbl = sqlIdent(name ?? this.tableName);
|
|
650
738
|
const tables = await this.listTables();
|
|
651
739
|
if (!tables.includes(tbl)) {
|
|
652
740
|
log3(`table "${tbl}" not found, creating`);
|
|
653
|
-
await this.createTableWithRetry(
|
|
741
|
+
await this.createTableWithRetry(buildCreateTableSql(tbl, MEMORY_COLUMNS), tbl);
|
|
654
742
|
log3(`table "${tbl}" created`);
|
|
655
743
|
if (!tables.includes(tbl))
|
|
656
744
|
this._tablesCache = [...tables, tbl];
|
|
657
745
|
}
|
|
658
|
-
await this.
|
|
659
|
-
await this.ensureColumn(tbl, "agent", "TEXT NOT NULL DEFAULT ''");
|
|
660
|
-
await this.ensureColumn(tbl, "plugin_version", "TEXT NOT NULL DEFAULT ''");
|
|
746
|
+
await this.healSchema(tbl, MEMORY_COLUMNS);
|
|
661
747
|
}
|
|
662
748
|
/** Create the sessions table (uses JSONB for message since every row is a JSON event). */
|
|
663
749
|
async ensureSessionsTable(name) {
|
|
@@ -665,14 +751,12 @@ var DeeplakeApi = class {
|
|
|
665
751
|
const tables = await this.listTables();
|
|
666
752
|
if (!tables.includes(safe)) {
|
|
667
753
|
log3(`table "${safe}" not found, creating`);
|
|
668
|
-
await this.createTableWithRetry(
|
|
754
|
+
await this.createTableWithRetry(buildCreateTableSql(safe, SESSIONS_COLUMNS), safe);
|
|
669
755
|
log3(`table "${safe}" created`);
|
|
670
756
|
if (!tables.includes(safe))
|
|
671
757
|
this._tablesCache = [...tables, safe];
|
|
672
758
|
}
|
|
673
|
-
await this.
|
|
674
|
-
await this.ensureColumn(safe, "agent", "TEXT NOT NULL DEFAULT ''");
|
|
675
|
-
await this.ensureColumn(safe, "plugin_version", "TEXT NOT NULL DEFAULT ''");
|
|
759
|
+
await this.healSchema(safe, SESSIONS_COLUMNS);
|
|
676
760
|
await this.ensureLookupIndex(safe, "path_creation_date", `("path", "creation_date")`);
|
|
677
761
|
}
|
|
678
762
|
/**
|
|
@@ -690,11 +774,12 @@ var DeeplakeApi = class {
|
|
|
690
774
|
const tables = await this.listTables();
|
|
691
775
|
if (!tables.includes(safe)) {
|
|
692
776
|
log3(`table "${safe}" not found, creating`);
|
|
693
|
-
await this.createTableWithRetry(
|
|
777
|
+
await this.createTableWithRetry(buildCreateTableSql(safe, SKILLS_COLUMNS), safe);
|
|
694
778
|
log3(`table "${safe}" created`);
|
|
695
779
|
if (!tables.includes(safe))
|
|
696
780
|
this._tablesCache = [...tables, safe];
|
|
697
781
|
}
|
|
782
|
+
await this.healSchema(safe, SKILLS_COLUMNS);
|
|
698
783
|
await this.ensureLookupIndex(safe, "project_key_name", `("project_key", "name")`);
|
|
699
784
|
}
|
|
700
785
|
};
|
|
@@ -66830,7 +66830,6 @@ function sqlIdent(name) {
|
|
|
66830
66830
|
|
|
66831
66831
|
// dist/src/embeddings/columns.js
|
|
66832
66832
|
var SUMMARY_EMBEDDING_COL = "summary_embedding";
|
|
66833
|
-
var MESSAGE_EMBEDDING_COL = "message_embedding";
|
|
66834
66833
|
|
|
66835
66834
|
// dist/src/utils/client-header.js
|
|
66836
66835
|
var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client";
|
|
@@ -66841,6 +66840,123 @@ function deeplakeClientHeader() {
|
|
|
66841
66840
|
return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() };
|
|
66842
66841
|
}
|
|
66843
66842
|
|
|
66843
|
+
// dist/src/deeplake-schema.js
|
|
66844
|
+
var MEMORY_COLUMNS = Object.freeze([
|
|
66845
|
+
{ name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66846
|
+
{ name: "path", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66847
|
+
{ name: "filename", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66848
|
+
{ name: "summary", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66849
|
+
{ name: "summary_embedding", sql: "FLOAT4[]" },
|
|
66850
|
+
{ name: "author", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66851
|
+
{ name: "mime_type", sql: "TEXT NOT NULL DEFAULT 'text/plain'" },
|
|
66852
|
+
{ name: "size_bytes", sql: "BIGINT NOT NULL DEFAULT 0" },
|
|
66853
|
+
{ name: "project", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66854
|
+
{ name: "description", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66855
|
+
{ name: "agent", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66856
|
+
{ name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66857
|
+
{ name: "creation_date", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66858
|
+
{ name: "last_update_date", sql: "TEXT NOT NULL DEFAULT ''" }
|
|
66859
|
+
]);
|
|
66860
|
+
var SESSIONS_COLUMNS = Object.freeze([
|
|
66861
|
+
{ name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66862
|
+
{ name: "path", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66863
|
+
{ name: "filename", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66864
|
+
{ name: "message", sql: "JSONB" },
|
|
66865
|
+
{ name: "message_embedding", sql: "FLOAT4[]" },
|
|
66866
|
+
{ name: "author", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66867
|
+
{ name: "mime_type", sql: "TEXT NOT NULL DEFAULT 'application/json'" },
|
|
66868
|
+
{ name: "size_bytes", sql: "BIGINT NOT NULL DEFAULT 0" },
|
|
66869
|
+
{ name: "project", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66870
|
+
{ name: "description", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66871
|
+
{ name: "agent", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66872
|
+
{ name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66873
|
+
{ name: "creation_date", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66874
|
+
{ name: "last_update_date", sql: "TEXT NOT NULL DEFAULT ''" }
|
|
66875
|
+
]);
|
|
66876
|
+
var SKILLS_COLUMNS = Object.freeze([
|
|
66877
|
+
{ name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66878
|
+
{ name: "name", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66879
|
+
{ name: "project", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66880
|
+
{ name: "project_key", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66881
|
+
{ name: "local_path", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66882
|
+
{ name: "install", sql: "TEXT NOT NULL DEFAULT 'project'" },
|
|
66883
|
+
{ name: "source_sessions", sql: "TEXT NOT NULL DEFAULT '[]'" },
|
|
66884
|
+
{ name: "source_agent", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66885
|
+
{ name: "scope", sql: "TEXT NOT NULL DEFAULT 'me'" },
|
|
66886
|
+
{ name: "author", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66887
|
+
{ name: "contributors", sql: "TEXT NOT NULL DEFAULT '[]'" },
|
|
66888
|
+
{ name: "description", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66889
|
+
{ name: "trigger_text", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66890
|
+
{ name: "body", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66891
|
+
{ name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
|
|
66892
|
+
{ name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66893
|
+
{ name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" }
|
|
66894
|
+
]);
|
|
66895
|
+
function validateSchema(label, cols) {
|
|
66896
|
+
const seen = /* @__PURE__ */ new Set();
|
|
66897
|
+
for (const col of cols) {
|
|
66898
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(col.name)) {
|
|
66899
|
+
throw new Error(`${label}: column name "${col.name}" is not a valid SQL identifier`);
|
|
66900
|
+
}
|
|
66901
|
+
if (seen.has(col.name)) {
|
|
66902
|
+
throw new Error(`${label}: duplicate column "${col.name}"`);
|
|
66903
|
+
}
|
|
66904
|
+
seen.add(col.name);
|
|
66905
|
+
const notNull = /\bNOT\s+NULL\b/i.test(col.sql);
|
|
66906
|
+
const hasDefault = /\bDEFAULT\b/i.test(col.sql);
|
|
66907
|
+
if (notNull && !hasDefault) {
|
|
66908
|
+
throw new Error(`${label}: column "${col.name}" is NOT NULL but has no DEFAULT \u2014 ALTER TABLE ADD COLUMN on a populated table would fail.`);
|
|
66909
|
+
}
|
|
66910
|
+
}
|
|
66911
|
+
}
|
|
66912
|
+
validateSchema("MEMORY_COLUMNS", MEMORY_COLUMNS);
|
|
66913
|
+
validateSchema("SESSIONS_COLUMNS", SESSIONS_COLUMNS);
|
|
66914
|
+
validateSchema("SKILLS_COLUMNS", SKILLS_COLUMNS);
|
|
66915
|
+
function buildCreateTableSql(tableName, cols) {
|
|
66916
|
+
const safe = sqlIdent(tableName);
|
|
66917
|
+
const colSql = cols.map((c15) => `${c15.name} ${c15.sql}`).join(", ");
|
|
66918
|
+
return `CREATE TABLE IF NOT EXISTS "${safe}" (${colSql}) USING deeplake`;
|
|
66919
|
+
}
|
|
66920
|
+
function buildIntrospectionSql(tableName, workspaceId) {
|
|
66921
|
+
return `SELECT column_name FROM information_schema.columns WHERE table_name = '${sqlStr(tableName)}' AND table_schema = '${sqlStr(workspaceId)}'`;
|
|
66922
|
+
}
|
|
66923
|
+
async function healMissingColumns(args) {
|
|
66924
|
+
const safeTable = sqlIdent(args.tableName);
|
|
66925
|
+
const introspectSql = buildIntrospectionSql(args.tableName, args.workspaceId);
|
|
66926
|
+
const rows = await args.query(introspectSql);
|
|
66927
|
+
const existing = /* @__PURE__ */ new Set();
|
|
66928
|
+
for (const row of rows) {
|
|
66929
|
+
const v27 = row?.column_name;
|
|
66930
|
+
if (typeof v27 === "string")
|
|
66931
|
+
existing.add(v27.toLowerCase());
|
|
66932
|
+
}
|
|
66933
|
+
const missingCols = args.columns.filter((c15) => !existing.has(c15.name.toLowerCase()));
|
|
66934
|
+
const missing = missingCols.map((c15) => c15.name);
|
|
66935
|
+
if (missingCols.length === 0)
|
|
66936
|
+
return { missing, altered: [] };
|
|
66937
|
+
const altered = [];
|
|
66938
|
+
for (const col of missingCols) {
|
|
66939
|
+
try {
|
|
66940
|
+
await args.query(`ALTER TABLE "${safeTable}" ADD COLUMN ${col.name} ${col.sql}`);
|
|
66941
|
+
altered.push(col.name);
|
|
66942
|
+
args.log?.(`schema-heal: added "${args.tableName}"."${col.name}"`);
|
|
66943
|
+
} catch (e6) {
|
|
66944
|
+
const msg = e6 instanceof Error ? e6.message : String(e6);
|
|
66945
|
+
if (!/already exists/i.test(msg))
|
|
66946
|
+
throw e6;
|
|
66947
|
+
const recheck = await args.query(introspectSql);
|
|
66948
|
+
const present = recheck.some((r10) => {
|
|
66949
|
+
const v27 = r10?.column_name;
|
|
66950
|
+
return typeof v27 === "string" && v27.toLowerCase() === col.name.toLowerCase();
|
|
66951
|
+
});
|
|
66952
|
+
if (!present)
|
|
66953
|
+
throw e6;
|
|
66954
|
+
args.log?.(`schema-heal: "${args.tableName}"."${col.name}" appeared via race, treating as success`);
|
|
66955
|
+
}
|
|
66956
|
+
}
|
|
66957
|
+
return { missing, altered };
|
|
66958
|
+
}
|
|
66959
|
+
|
|
66844
66960
|
// dist/src/notifications/queue.js
|
|
66845
66961
|
import { readFileSync as readFileSync2, writeFileSync, renameSync, mkdirSync, openSync, closeSync, unlinkSync, statSync as statSync2 } from "node:fs";
|
|
66846
66962
|
import { join as join6, resolve as resolve4 } from "node:path";
|
|
@@ -67223,64 +67339,33 @@ var DeeplakeApi = class {
|
|
|
67223
67339
|
}
|
|
67224
67340
|
}
|
|
67225
67341
|
/**
|
|
67226
|
-
*
|
|
67227
|
-
*
|
|
67228
|
-
*
|
|
67229
|
-
*
|
|
67230
|
-
*
|
|
67231
|
-
* in the log and a wasted round-trip. Worse, the very first call after the
|
|
67232
|
-
* column is genuinely added triggers Deeplake's post-ALTER `vector::at`
|
|
67233
|
-
* window (~30s) during which subsequent INSERTs fail; minimising the
|
|
67234
|
-
* number of ALTER calls minimises exposure to that window.
|
|
67342
|
+
* Heal any missing columns on a table so it matches one of the schema
|
|
67343
|
+
* definitions in `deeplake-schema.ts`. One SELECT against
|
|
67344
|
+
* `information_schema.columns` per call, then `ALTER TABLE ADD COLUMN`
|
|
67345
|
+
* only the genuinely missing ones — never blanket, never `IF NOT
|
|
67346
|
+
* EXISTS`.
|
|
67235
67347
|
*
|
|
67236
|
-
*
|
|
67237
|
-
*
|
|
67238
|
-
*
|
|
67239
|
-
*
|
|
67240
|
-
*
|
|
67241
|
-
*
|
|
67242
|
-
*
|
|
67243
|
-
*
|
|
67244
|
-
*
|
|
67245
|
-
*
|
|
67246
|
-
*
|
|
67247
|
-
*
|
|
67248
|
-
* caches share an opt-out (HIVEMIND_INDEX_MARKER_DIR) and a TTL knob.
|
|
67348
|
+
* History: an earlier path used a local marker file (`col_<name>` under
|
|
67349
|
+
* the index-marker dir) to skip even the SELECT after the first
|
|
67350
|
+
* confirmation, plus per-column ALTERs for `summary_embedding`,
|
|
67351
|
+
* `message_embedding`, `agent`, `plugin_version`. The marker existed
|
|
67352
|
+
* because Deeplake used to expose a ~30s post-ALTER bug where
|
|
67353
|
+
* subsequent INSERTs failed, so we wanted to keep ALTER traffic to a
|
|
67354
|
+
* minimum. The bug was re-verified on 2026-05-18 against
|
|
67355
|
+
* `api.deeplake.ai` (`test_plugin` org) and no longer reproduces
|
|
67356
|
+
* (71/71 INSERTs OK, first success 2ms after ALTER). The single SELECT
|
|
67357
|
+
* + targeted ALTER pattern survives the marker removal because: each
|
|
67358
|
+
* ALTER still costs ~800ms (so blanket sweeps are wasteful) and the
|
|
67359
|
+
* diff produces clearer logs than "ALTER all with IF NOT EXISTS".
|
|
67249
67360
|
*/
|
|
67250
|
-
async
|
|
67251
|
-
await
|
|
67252
|
-
|
|
67253
|
-
|
|
67254
|
-
|
|
67255
|
-
|
|
67256
|
-
|
|
67257
|
-
|
|
67258
|
-
* the `agent` column (added 2026-04-11) — the latter has no fallback if
|
|
67259
|
-
* a user upgraded over a pre-2026-04-11 table, so every INSERT fails
|
|
67260
|
-
* with `column "agent" does not exist`.
|
|
67261
|
-
*/
|
|
67262
|
-
async ensureColumn(table, column, sqlType) {
|
|
67263
|
-
const markers = await getIndexMarkerStore();
|
|
67264
|
-
const markerPath = markers.buildIndexMarkerPath(this.workspaceId, this.orgId, table, `col_${column}`);
|
|
67265
|
-
if (markers.hasFreshIndexMarker(markerPath))
|
|
67266
|
-
return;
|
|
67267
|
-
const colCheck = `SELECT 1 FROM information_schema.columns WHERE table_name = '${sqlStr(table)}' AND column_name = '${sqlStr(column)}' AND table_schema = '${sqlStr(this.workspaceId)}' LIMIT 1`;
|
|
67268
|
-
const rows = await this.query(colCheck);
|
|
67269
|
-
if (rows.length > 0) {
|
|
67270
|
-
markers.writeIndexMarker(markerPath);
|
|
67271
|
-
return;
|
|
67272
|
-
}
|
|
67273
|
-
try {
|
|
67274
|
-
await this.query(`ALTER TABLE "${table}" ADD COLUMN ${column} ${sqlType}`);
|
|
67275
|
-
} catch (e6) {
|
|
67276
|
-
const msg = e6 instanceof Error ? e6.message : String(e6);
|
|
67277
|
-
if (!/already exists/i.test(msg))
|
|
67278
|
-
throw e6;
|
|
67279
|
-
const recheck = await this.query(colCheck);
|
|
67280
|
-
if (recheck.length === 0)
|
|
67281
|
-
throw e6;
|
|
67282
|
-
}
|
|
67283
|
-
markers.writeIndexMarker(markerPath);
|
|
67361
|
+
async healSchema(table, columns) {
|
|
67362
|
+
await healMissingColumns({
|
|
67363
|
+
query: (sql) => this.query(sql),
|
|
67364
|
+
tableName: table,
|
|
67365
|
+
workspaceId: this.workspaceId,
|
|
67366
|
+
columns,
|
|
67367
|
+
log: log3
|
|
67368
|
+
});
|
|
67284
67369
|
}
|
|
67285
67370
|
/** List all tables in the workspace (with retry). */
|
|
67286
67371
|
async listTables(forceRefresh = false) {
|
|
@@ -67351,20 +67436,21 @@ var DeeplakeApi = class {
|
|
|
67351
67436
|
}
|
|
67352
67437
|
throw lastErr;
|
|
67353
67438
|
}
|
|
67354
|
-
/** Create the memory table if it doesn't already exist.
|
|
67439
|
+
/** Create the memory table if it doesn't already exist. Heal missing columns on existing tables. */
|
|
67355
67440
|
async ensureTable(name) {
|
|
67441
|
+
if (!MEMORY_COLUMNS.some((c15) => c15.name === SUMMARY_EMBEDDING_COL)) {
|
|
67442
|
+
throw new Error(`MEMORY_COLUMNS missing "${SUMMARY_EMBEDDING_COL}" (embeddings/columns.ts drift)`);
|
|
67443
|
+
}
|
|
67356
67444
|
const tbl = sqlIdent(name ?? this.tableName);
|
|
67357
67445
|
const tables = await this.listTables();
|
|
67358
67446
|
if (!tables.includes(tbl)) {
|
|
67359
67447
|
log3(`table "${tbl}" not found, creating`);
|
|
67360
|
-
await this.createTableWithRetry(
|
|
67448
|
+
await this.createTableWithRetry(buildCreateTableSql(tbl, MEMORY_COLUMNS), tbl);
|
|
67361
67449
|
log3(`table "${tbl}" created`);
|
|
67362
67450
|
if (!tables.includes(tbl))
|
|
67363
67451
|
this._tablesCache = [...tables, tbl];
|
|
67364
67452
|
}
|
|
67365
|
-
await this.
|
|
67366
|
-
await this.ensureColumn(tbl, "agent", "TEXT NOT NULL DEFAULT ''");
|
|
67367
|
-
await this.ensureColumn(tbl, "plugin_version", "TEXT NOT NULL DEFAULT ''");
|
|
67453
|
+
await this.healSchema(tbl, MEMORY_COLUMNS);
|
|
67368
67454
|
}
|
|
67369
67455
|
/** Create the sessions table (uses JSONB for message since every row is a JSON event). */
|
|
67370
67456
|
async ensureSessionsTable(name) {
|
|
@@ -67372,14 +67458,12 @@ var DeeplakeApi = class {
|
|
|
67372
67458
|
const tables = await this.listTables();
|
|
67373
67459
|
if (!tables.includes(safe)) {
|
|
67374
67460
|
log3(`table "${safe}" not found, creating`);
|
|
67375
|
-
await this.createTableWithRetry(
|
|
67461
|
+
await this.createTableWithRetry(buildCreateTableSql(safe, SESSIONS_COLUMNS), safe);
|
|
67376
67462
|
log3(`table "${safe}" created`);
|
|
67377
67463
|
if (!tables.includes(safe))
|
|
67378
67464
|
this._tablesCache = [...tables, safe];
|
|
67379
67465
|
}
|
|
67380
|
-
await this.
|
|
67381
|
-
await this.ensureColumn(safe, "agent", "TEXT NOT NULL DEFAULT ''");
|
|
67382
|
-
await this.ensureColumn(safe, "plugin_version", "TEXT NOT NULL DEFAULT ''");
|
|
67466
|
+
await this.healSchema(safe, SESSIONS_COLUMNS);
|
|
67383
67467
|
await this.ensureLookupIndex(safe, "path_creation_date", `("path", "creation_date")`);
|
|
67384
67468
|
}
|
|
67385
67469
|
/**
|
|
@@ -67397,11 +67481,12 @@ var DeeplakeApi = class {
|
|
|
67397
67481
|
const tables = await this.listTables();
|
|
67398
67482
|
if (!tables.includes(safe)) {
|
|
67399
67483
|
log3(`table "${safe}" not found, creating`);
|
|
67400
|
-
await this.createTableWithRetry(
|
|
67484
|
+
await this.createTableWithRetry(buildCreateTableSql(safe, SKILLS_COLUMNS), safe);
|
|
67401
67485
|
log3(`table "${safe}" created`);
|
|
67402
67486
|
if (!tables.includes(safe))
|
|
67403
67487
|
this._tablesCache = [...tables, safe];
|
|
67404
67488
|
}
|
|
67489
|
+
await this.healSchema(safe, SKILLS_COLUMNS);
|
|
67405
67490
|
await this.ensureLookupIndex(safe, "project_key_name", `("project_key", "name")`);
|
|
67406
67491
|
}
|
|
67407
67492
|
};
|