@deeplake/hivemind 0.7.54 → 0.7.60
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 +3 -3
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +2 -0
- package/bundle/cli.js +63 -31
- package/codex/bundle/capture.js +17 -0
- package/codex/bundle/commands/auth-login.js +17 -0
- package/codex/bundle/graph-pull-worker.js +17 -0
- package/codex/bundle/pre-tool-use.js +17 -0
- package/codex/bundle/session-start-setup.js +17 -0
- package/codex/bundle/session-start.js +59 -24
- package/codex/bundle/shell/deeplake-shell.js +17 -0
- package/codex/bundle/stop.js +17 -0
- package/cursor/bundle/capture.js +17 -0
- package/cursor/bundle/commands/auth-login.js +17 -0
- package/cursor/bundle/graph-pull-worker.js +17 -0
- package/cursor/bundle/pre-tool-use.js +17 -0
- package/cursor/bundle/session-start.js +86 -40
- package/cursor/bundle/shell/deeplake-shell.js +17 -0
- package/hermes/bundle/capture.js +17 -0
- package/hermes/bundle/commands/auth-login.js +17 -0
- package/hermes/bundle/graph-pull-worker.js +17 -0
- package/hermes/bundle/pre-tool-use.js +17 -0
- package/hermes/bundle/session-start.js +86 -40
- package/hermes/bundle/shell/deeplake-shell.js +17 -0
- package/mcp/bundle/server.js +17 -0
- package/openclaw/dist/index.js +16 -1
- package/openclaw/openclaw.plugin.json +1 -1
- package/openclaw/package.json +1 -1
- package/package.json +7 -3
|
@@ -6,18 +6,18 @@
|
|
|
6
6
|
},
|
|
7
7
|
"metadata": {
|
|
8
8
|
"description": "Cloud-backed persistent shared memory for AI agents powered by Deeplake",
|
|
9
|
-
"version": "0.7.
|
|
9
|
+
"version": "0.7.60"
|
|
10
10
|
},
|
|
11
11
|
"plugins": [
|
|
12
12
|
{
|
|
13
13
|
"name": "hivemind",
|
|
14
14
|
"description": "Persistent shared memory powered by Deeplake — captures all session activity and provides cross-session, cross-agent memory search",
|
|
15
|
-
"version": "0.7.
|
|
15
|
+
"version": "0.7.60",
|
|
16
16
|
"source": {
|
|
17
17
|
"source": "git-subdir",
|
|
18
18
|
"url": "https://github.com/activeloopai/hivemind.git",
|
|
19
19
|
"path": "claude-code",
|
|
20
|
-
"sha": "
|
|
20
|
+
"sha": "16a718fb94219d96ad5686ca414504d694643bc9"
|
|
21
21
|
},
|
|
22
22
|
"homepage": "https://github.com/activeloopai/hivemind"
|
|
23
23
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hivemind",
|
|
3
3
|
"description": "Cloud-backed persistent memory powered by Deeplake — read, write, and share memory across Claude Code sessions and agents",
|
|
4
|
-
"version": "0.7.
|
|
4
|
+
"version": "0.7.60",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Activeloop",
|
|
7
7
|
"url": "https://deeplake.ai"
|
package/README.md
CHANGED
|
@@ -279,6 +279,8 @@ This plugin captures session activity and stores it in your Deeplake workspace:
|
|
|
279
279
|
| `HIVEMIND_SESSIONS_TABLE` | `sessions` | SQL table for per-event session capture |
|
|
280
280
|
| `HIVEMIND_MEMORY_PATH` | `~/.deeplake/memory` | Path that triggers interception |
|
|
281
281
|
| `HIVEMIND_CAPTURE` | `true` | Set to `false` to disable capture |
|
|
282
|
+
| `HIVEMIND_CAPTURE_ONLY_CLI` | — | Set to `true` to capture only interactive CLI sessions. Sessions spawned by the Claude Agent SDK (Python/TypeScript) are skipped — their `CLAUDE_CODE_ENTRYPOINT` is `sdk-py` / `sdk-ts`, so they fail the substring check for `cli`. |
|
|
283
|
+
| `HIVEMIND_SKILLIFY_EVERY_N_TURNS` | `20` | Assistant turns between auto skill-mining attempts. Lower = more frequent mining (cheaper sessions, noisier output); higher = fewer attempts on longer histories. |
|
|
282
284
|
| `HIVEMIND_EMBEDDINGS` | `true` | Set to `false` to force lexical-only mode |
|
|
283
285
|
| `HIVEMIND_DEBUG` | — | Set to `1` for verbose hook debug logs |
|
|
284
286
|
|
package/bundle/cli.js
CHANGED
|
@@ -5094,6 +5094,23 @@ var DeeplakeApi = class {
|
|
|
5094
5094
|
this._tablesCache = [...tables];
|
|
5095
5095
|
return tables;
|
|
5096
5096
|
}
|
|
5097
|
+
/**
|
|
5098
|
+
* Like listTables() but returns null when the list could NOT be trusted
|
|
5099
|
+
* (the fetch failed / was non-cacheable). Callers gating a read on table
|
|
5100
|
+
* existence use this to tell a genuinely-empty workspace ([]) apart from a
|
|
5101
|
+
* failed lookup (null): on [] they can safely skip the read (no table → no
|
|
5102
|
+
* 42P01), on null they must fall back to SELECT-then-catch so a transient
|
|
5103
|
+
* lookup blip doesn't drop a read of a table that really exists.
|
|
5104
|
+
*/
|
|
5105
|
+
async knownTablesOrNull() {
|
|
5106
|
+
if (this._tablesCache)
|
|
5107
|
+
return [...this._tablesCache];
|
|
5108
|
+
const { tables, cacheable } = await this._fetchTables();
|
|
5109
|
+
if (!cacheable)
|
|
5110
|
+
return null;
|
|
5111
|
+
this._tablesCache = [...tables];
|
|
5112
|
+
return [...tables];
|
|
5113
|
+
}
|
|
5097
5114
|
async _fetchTables() {
|
|
5098
5115
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
5099
5116
|
try {
|
|
@@ -9044,21 +9061,25 @@ async function runPull(opts) {
|
|
|
9044
9061
|
skillName: opts.skillName
|
|
9045
9062
|
});
|
|
9046
9063
|
let rows = [];
|
|
9047
|
-
|
|
9048
|
-
rows =
|
|
9049
|
-
}
|
|
9050
|
-
|
|
9051
|
-
rows =
|
|
9052
|
-
}
|
|
9053
|
-
|
|
9054
|
-
|
|
9055
|
-
|
|
9056
|
-
|
|
9057
|
-
|
|
9058
|
-
|
|
9059
|
-
|
|
9060
|
-
|
|
9061
|
-
|
|
9064
|
+
if (opts.tableExists && !opts.tableExists(opts.tableName)) {
|
|
9065
|
+
rows = [];
|
|
9066
|
+
} else {
|
|
9067
|
+
try {
|
|
9068
|
+
rows = await opts.query(sql);
|
|
9069
|
+
} catch (e) {
|
|
9070
|
+
if (isMissingTableError2(e?.message)) {
|
|
9071
|
+
rows = [];
|
|
9072
|
+
} else if (isMissingContributorsColumnError(e?.message)) {
|
|
9073
|
+
const legacySql = buildPullSql({
|
|
9074
|
+
tableName: opts.tableName,
|
|
9075
|
+
users: opts.users,
|
|
9076
|
+
skillName: opts.skillName,
|
|
9077
|
+
includeContributors: false
|
|
9078
|
+
});
|
|
9079
|
+
rows = await opts.query(legacySql);
|
|
9080
|
+
} else {
|
|
9081
|
+
throw e;
|
|
9082
|
+
}
|
|
9062
9083
|
}
|
|
9063
9084
|
}
|
|
9064
9085
|
const latest = selectLatestPerName(rows);
|
|
@@ -11221,24 +11242,33 @@ async function renderContextBlock(query, input, opts = {}) {
|
|
|
11221
11242
|
const log8 = opts.log ?? (() => {
|
|
11222
11243
|
});
|
|
11223
11244
|
try {
|
|
11245
|
+
const tableExists = opts.tableExists;
|
|
11224
11246
|
let rules = [];
|
|
11225
|
-
|
|
11226
|
-
rules
|
|
11227
|
-
|
|
11228
|
-
|
|
11229
|
-
|
|
11230
|
-
|
|
11231
|
-
|
|
11232
|
-
|
|
11247
|
+
if (tableExists && !tableExists(input.rulesTable)) {
|
|
11248
|
+
log8(`render-context-block: rules table "${input.rulesTable}" not present \u2014 skipping read`);
|
|
11249
|
+
} else {
|
|
11250
|
+
try {
|
|
11251
|
+
rules = await listRules(query, input.rulesTable, {
|
|
11252
|
+
status: "active",
|
|
11253
|
+
limit: Math.max(maxRules * 4, maxRules + 1)
|
|
11254
|
+
});
|
|
11255
|
+
} catch (rulesErr) {
|
|
11256
|
+
const rmsg = rulesErr instanceof Error ? rulesErr.message : String(rulesErr);
|
|
11257
|
+
log8(`render-context-block: rules unavailable (continuing): ${rmsg}`);
|
|
11258
|
+
}
|
|
11233
11259
|
}
|
|
11234
11260
|
let goals = [];
|
|
11235
|
-
|
|
11236
|
-
goals
|
|
11237
|
-
|
|
11238
|
-
|
|
11239
|
-
|
|
11240
|
-
|
|
11241
|
-
|
|
11261
|
+
if (tableExists && !tableExists(input.goalsTable)) {
|
|
11262
|
+
log8(`render-context-block: goals table "${input.goalsTable}" not present \u2014 skipping read`);
|
|
11263
|
+
} else {
|
|
11264
|
+
try {
|
|
11265
|
+
goals = await listOpenGoals(query, input.goalsTable, input.currentUser, {
|
|
11266
|
+
limit: Math.max(maxGoals * 4, maxGoals + 1)
|
|
11267
|
+
});
|
|
11268
|
+
} catch (goalsErr) {
|
|
11269
|
+
const gmsg = goalsErr instanceof Error ? goalsErr.message : String(goalsErr);
|
|
11270
|
+
log8(`render-context-block: goals unavailable (continuing): ${gmsg}`);
|
|
11271
|
+
}
|
|
11242
11272
|
}
|
|
11243
11273
|
const rulesShown = rules.slice(0, maxRules);
|
|
11244
11274
|
const rulesHidden = Math.max(0, rules.length - maxRules);
|
|
@@ -11353,11 +11383,13 @@ async function runContextCommand(args) {
|
|
|
11353
11383
|
throw new Error("unreachable");
|
|
11354
11384
|
}
|
|
11355
11385
|
const api = new DeeplakeApi(cfg.token, cfg.apiUrl, cfg.orgId, cfg.workspaceId, cfg.tableName);
|
|
11386
|
+
const known = await api.knownTablesOrNull();
|
|
11387
|
+
const tableExists = known ? (name) => known.includes(name) : void 0;
|
|
11356
11388
|
const block = await renderContextBlock((sql) => api.query(sql), {
|
|
11357
11389
|
rulesTable: cfg.rulesTableName,
|
|
11358
11390
|
goalsTable: cfg.goalsTableName,
|
|
11359
11391
|
currentUser: cfg.userName
|
|
11360
|
-
});
|
|
11392
|
+
}, { tableExists });
|
|
11361
11393
|
if (!block) {
|
|
11362
11394
|
console.error("(no active rules or open goals)");
|
|
11363
11395
|
return;
|
package/codex/bundle/capture.js
CHANGED
|
@@ -756,6 +756,23 @@ var DeeplakeApi = class {
|
|
|
756
756
|
this._tablesCache = [...tables];
|
|
757
757
|
return tables;
|
|
758
758
|
}
|
|
759
|
+
/**
|
|
760
|
+
* Like listTables() but returns null when the list could NOT be trusted
|
|
761
|
+
* (the fetch failed / was non-cacheable). Callers gating a read on table
|
|
762
|
+
* existence use this to tell a genuinely-empty workspace ([]) apart from a
|
|
763
|
+
* failed lookup (null): on [] they can safely skip the read (no table → no
|
|
764
|
+
* 42P01), on null they must fall back to SELECT-then-catch so a transient
|
|
765
|
+
* lookup blip doesn't drop a read of a table that really exists.
|
|
766
|
+
*/
|
|
767
|
+
async knownTablesOrNull() {
|
|
768
|
+
if (this._tablesCache)
|
|
769
|
+
return [...this._tablesCache];
|
|
770
|
+
const { tables, cacheable } = await this._fetchTables();
|
|
771
|
+
if (!cacheable)
|
|
772
|
+
return null;
|
|
773
|
+
this._tablesCache = [...tables];
|
|
774
|
+
return [...tables];
|
|
775
|
+
}
|
|
759
776
|
async _fetchTables() {
|
|
760
777
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
761
778
|
try {
|
|
@@ -1019,6 +1019,23 @@ var DeeplakeApi = class {
|
|
|
1019
1019
|
this._tablesCache = [...tables];
|
|
1020
1020
|
return tables;
|
|
1021
1021
|
}
|
|
1022
|
+
/**
|
|
1023
|
+
* Like listTables() but returns null when the list could NOT be trusted
|
|
1024
|
+
* (the fetch failed / was non-cacheable). Callers gating a read on table
|
|
1025
|
+
* existence use this to tell a genuinely-empty workspace ([]) apart from a
|
|
1026
|
+
* failed lookup (null): on [] they can safely skip the read (no table → no
|
|
1027
|
+
* 42P01), on null they must fall back to SELECT-then-catch so a transient
|
|
1028
|
+
* lookup blip doesn't drop a read of a table that really exists.
|
|
1029
|
+
*/
|
|
1030
|
+
async knownTablesOrNull() {
|
|
1031
|
+
if (this._tablesCache)
|
|
1032
|
+
return [...this._tablesCache];
|
|
1033
|
+
const { tables, cacheable } = await this._fetchTables();
|
|
1034
|
+
if (!cacheable)
|
|
1035
|
+
return null;
|
|
1036
|
+
this._tablesCache = [...tables];
|
|
1037
|
+
return [...tables];
|
|
1038
|
+
}
|
|
1022
1039
|
async _fetchTables() {
|
|
1023
1040
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
1024
1041
|
try {
|
|
@@ -746,6 +746,23 @@ var DeeplakeApi = class {
|
|
|
746
746
|
this._tablesCache = [...tables];
|
|
747
747
|
return tables;
|
|
748
748
|
}
|
|
749
|
+
/**
|
|
750
|
+
* Like listTables() but returns null when the list could NOT be trusted
|
|
751
|
+
* (the fetch failed / was non-cacheable). Callers gating a read on table
|
|
752
|
+
* existence use this to tell a genuinely-empty workspace ([]) apart from a
|
|
753
|
+
* failed lookup (null): on [] they can safely skip the read (no table → no
|
|
754
|
+
* 42P01), on null they must fall back to SELECT-then-catch so a transient
|
|
755
|
+
* lookup blip doesn't drop a read of a table that really exists.
|
|
756
|
+
*/
|
|
757
|
+
async knownTablesOrNull() {
|
|
758
|
+
if (this._tablesCache)
|
|
759
|
+
return [...this._tablesCache];
|
|
760
|
+
const { tables, cacheable } = await this._fetchTables();
|
|
761
|
+
if (!cacheable)
|
|
762
|
+
return null;
|
|
763
|
+
this._tablesCache = [...tables];
|
|
764
|
+
return [...tables];
|
|
765
|
+
}
|
|
749
766
|
async _fetchTables() {
|
|
750
767
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
751
768
|
try {
|
|
@@ -762,6 +762,23 @@ var DeeplakeApi = class {
|
|
|
762
762
|
this._tablesCache = [...tables];
|
|
763
763
|
return tables;
|
|
764
764
|
}
|
|
765
|
+
/**
|
|
766
|
+
* Like listTables() but returns null when the list could NOT be trusted
|
|
767
|
+
* (the fetch failed / was non-cacheable). Callers gating a read on table
|
|
768
|
+
* existence use this to tell a genuinely-empty workspace ([]) apart from a
|
|
769
|
+
* failed lookup (null): on [] they can safely skip the read (no table → no
|
|
770
|
+
* 42P01), on null they must fall back to SELECT-then-catch so a transient
|
|
771
|
+
* lookup blip doesn't drop a read of a table that really exists.
|
|
772
|
+
*/
|
|
773
|
+
async knownTablesOrNull() {
|
|
774
|
+
if (this._tablesCache)
|
|
775
|
+
return [...this._tablesCache];
|
|
776
|
+
const { tables, cacheable } = await this._fetchTables();
|
|
777
|
+
if (!cacheable)
|
|
778
|
+
return null;
|
|
779
|
+
this._tablesCache = [...tables];
|
|
780
|
+
return [...tables];
|
|
781
|
+
}
|
|
765
782
|
async _fetchTables() {
|
|
766
783
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
767
784
|
try {
|
|
@@ -757,6 +757,23 @@ var DeeplakeApi = class {
|
|
|
757
757
|
this._tablesCache = [...tables];
|
|
758
758
|
return tables;
|
|
759
759
|
}
|
|
760
|
+
/**
|
|
761
|
+
* Like listTables() but returns null when the list could NOT be trusted
|
|
762
|
+
* (the fetch failed / was non-cacheable). Callers gating a read on table
|
|
763
|
+
* existence use this to tell a genuinely-empty workspace ([]) apart from a
|
|
764
|
+
* failed lookup (null): on [] they can safely skip the read (no table → no
|
|
765
|
+
* 42P01), on null they must fall back to SELECT-then-catch so a transient
|
|
766
|
+
* lookup blip doesn't drop a read of a table that really exists.
|
|
767
|
+
*/
|
|
768
|
+
async knownTablesOrNull() {
|
|
769
|
+
if (this._tablesCache)
|
|
770
|
+
return [...this._tablesCache];
|
|
771
|
+
const { tables, cacheable } = await this._fetchTables();
|
|
772
|
+
if (!cacheable)
|
|
773
|
+
return null;
|
|
774
|
+
this._tablesCache = [...tables];
|
|
775
|
+
return [...tables];
|
|
776
|
+
}
|
|
760
777
|
async _fetchTables() {
|
|
761
778
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
762
779
|
try {
|
|
@@ -996,6 +996,23 @@ var DeeplakeApi = class {
|
|
|
996
996
|
this._tablesCache = [...tables];
|
|
997
997
|
return tables;
|
|
998
998
|
}
|
|
999
|
+
/**
|
|
1000
|
+
* Like listTables() but returns null when the list could NOT be trusted
|
|
1001
|
+
* (the fetch failed / was non-cacheable). Callers gating a read on table
|
|
1002
|
+
* existence use this to tell a genuinely-empty workspace ([]) apart from a
|
|
1003
|
+
* failed lookup (null): on [] they can safely skip the read (no table → no
|
|
1004
|
+
* 42P01), on null they must fall back to SELECT-then-catch so a transient
|
|
1005
|
+
* lookup blip doesn't drop a read of a table that really exists.
|
|
1006
|
+
*/
|
|
1007
|
+
async knownTablesOrNull() {
|
|
1008
|
+
if (this._tablesCache)
|
|
1009
|
+
return [...this._tablesCache];
|
|
1010
|
+
const { tables, cacheable } = await this._fetchTables();
|
|
1011
|
+
if (!cacheable)
|
|
1012
|
+
return null;
|
|
1013
|
+
this._tablesCache = [...tables];
|
|
1014
|
+
return [...tables];
|
|
1015
|
+
}
|
|
999
1016
|
async _fetchTables() {
|
|
1000
1017
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
1001
1018
|
try {
|
|
@@ -1675,21 +1692,25 @@ async function runPull(opts) {
|
|
|
1675
1692
|
skillName: opts.skillName
|
|
1676
1693
|
});
|
|
1677
1694
|
let rows = [];
|
|
1678
|
-
|
|
1679
|
-
rows =
|
|
1680
|
-
}
|
|
1681
|
-
|
|
1682
|
-
rows =
|
|
1683
|
-
}
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1695
|
+
if (opts.tableExists && !opts.tableExists(opts.tableName)) {
|
|
1696
|
+
rows = [];
|
|
1697
|
+
} else {
|
|
1698
|
+
try {
|
|
1699
|
+
rows = await opts.query(sql);
|
|
1700
|
+
} catch (e) {
|
|
1701
|
+
if (isMissingTableError(e?.message)) {
|
|
1702
|
+
rows = [];
|
|
1703
|
+
} else if (isMissingContributorsColumnError(e?.message)) {
|
|
1704
|
+
const legacySql = buildPullSql({
|
|
1705
|
+
tableName: opts.tableName,
|
|
1706
|
+
users: opts.users,
|
|
1707
|
+
skillName: opts.skillName,
|
|
1708
|
+
includeContributors: false
|
|
1709
|
+
});
|
|
1710
|
+
rows = await opts.query(legacySql);
|
|
1711
|
+
} else {
|
|
1712
|
+
throw e;
|
|
1713
|
+
}
|
|
1693
1714
|
}
|
|
1694
1715
|
}
|
|
1695
1716
|
const latest = selectLatestPerName(rows);
|
|
@@ -1832,24 +1853,38 @@ async function autoPullSkills(deps = {}) {
|
|
|
1832
1853
|
return { pulled: 0, skipped: true, reason: "not-logged-in" };
|
|
1833
1854
|
}
|
|
1834
1855
|
let query;
|
|
1856
|
+
let discoverTableExists = async () => void 0;
|
|
1835
1857
|
if (deps.queryFn) {
|
|
1836
1858
|
query = deps.queryFn;
|
|
1837
1859
|
} else {
|
|
1838
1860
|
const api = new DeeplakeApi(config.token, config.apiUrl, config.orgId, config.workspaceId, config.skillsTableName);
|
|
1839
1861
|
query = (sql) => api.query(sql);
|
|
1862
|
+
discoverTableExists = async () => {
|
|
1863
|
+
const known = await api.knownTablesOrNull();
|
|
1864
|
+
return known ? (name) => known.includes(name) : void 0;
|
|
1865
|
+
};
|
|
1840
1866
|
}
|
|
1841
1867
|
const install = deps.install ?? "global";
|
|
1842
1868
|
const timeoutMs = deps.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
1843
1869
|
try {
|
|
1844
|
-
const summary = await withTimeout(
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1870
|
+
const summary = await withTimeout(
|
|
1871
|
+
// Table discovery + pull share one budget: if `GET /tables` hangs the
|
|
1872
|
+
// whole thing times out and we degrade, instead of blocking startup.
|
|
1873
|
+
(async () => {
|
|
1874
|
+
const tableExists = await discoverTableExists();
|
|
1875
|
+
return runPull({
|
|
1876
|
+
query,
|
|
1877
|
+
tableName: config.skillsTableName,
|
|
1878
|
+
install,
|
|
1879
|
+
cwd: install === "project" ? deps.cwd ?? process.cwd() : void 0,
|
|
1880
|
+
users: [],
|
|
1881
|
+
dryRun: false,
|
|
1882
|
+
force: false,
|
|
1883
|
+
tableExists
|
|
1884
|
+
});
|
|
1885
|
+
})(),
|
|
1886
|
+
timeoutMs
|
|
1887
|
+
);
|
|
1853
1888
|
log4(`pulled scanned=${summary.scanned} wrote=${summary.wrote} skipped=${summary.skipped}`);
|
|
1854
1889
|
return { pulled: summary.wrote, skipped: false };
|
|
1855
1890
|
} catch (e) {
|
|
@@ -67450,6 +67450,23 @@ var DeeplakeApi = class {
|
|
|
67450
67450
|
this._tablesCache = [...tables];
|
|
67451
67451
|
return tables;
|
|
67452
67452
|
}
|
|
67453
|
+
/**
|
|
67454
|
+
* Like listTables() but returns null when the list could NOT be trusted
|
|
67455
|
+
* (the fetch failed / was non-cacheable). Callers gating a read on table
|
|
67456
|
+
* existence use this to tell a genuinely-empty workspace ([]) apart from a
|
|
67457
|
+
* failed lookup (null): on [] they can safely skip the read (no table → no
|
|
67458
|
+
* 42P01), on null they must fall back to SELECT-then-catch so a transient
|
|
67459
|
+
* lookup blip doesn't drop a read of a table that really exists.
|
|
67460
|
+
*/
|
|
67461
|
+
async knownTablesOrNull() {
|
|
67462
|
+
if (this._tablesCache)
|
|
67463
|
+
return [...this._tablesCache];
|
|
67464
|
+
const { tables, cacheable } = await this._fetchTables();
|
|
67465
|
+
if (!cacheable)
|
|
67466
|
+
return null;
|
|
67467
|
+
this._tablesCache = [...tables];
|
|
67468
|
+
return [...tables];
|
|
67469
|
+
}
|
|
67453
67470
|
async _fetchTables() {
|
|
67454
67471
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
67455
67472
|
try {
|
package/codex/bundle/stop.js
CHANGED
|
@@ -761,6 +761,23 @@ var DeeplakeApi = class {
|
|
|
761
761
|
this._tablesCache = [...tables];
|
|
762
762
|
return tables;
|
|
763
763
|
}
|
|
764
|
+
/**
|
|
765
|
+
* Like listTables() but returns null when the list could NOT be trusted
|
|
766
|
+
* (the fetch failed / was non-cacheable). Callers gating a read on table
|
|
767
|
+
* existence use this to tell a genuinely-empty workspace ([]) apart from a
|
|
768
|
+
* failed lookup (null): on [] they can safely skip the read (no table → no
|
|
769
|
+
* 42P01), on null they must fall back to SELECT-then-catch so a transient
|
|
770
|
+
* lookup blip doesn't drop a read of a table that really exists.
|
|
771
|
+
*/
|
|
772
|
+
async knownTablesOrNull() {
|
|
773
|
+
if (this._tablesCache)
|
|
774
|
+
return [...this._tablesCache];
|
|
775
|
+
const { tables, cacheable } = await this._fetchTables();
|
|
776
|
+
if (!cacheable)
|
|
777
|
+
return null;
|
|
778
|
+
this._tablesCache = [...tables];
|
|
779
|
+
return [...tables];
|
|
780
|
+
}
|
|
764
781
|
async _fetchTables() {
|
|
765
782
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
766
783
|
try {
|
package/cursor/bundle/capture.js
CHANGED
|
@@ -756,6 +756,23 @@ var DeeplakeApi = class {
|
|
|
756
756
|
this._tablesCache = [...tables];
|
|
757
757
|
return tables;
|
|
758
758
|
}
|
|
759
|
+
/**
|
|
760
|
+
* Like listTables() but returns null when the list could NOT be trusted
|
|
761
|
+
* (the fetch failed / was non-cacheable). Callers gating a read on table
|
|
762
|
+
* existence use this to tell a genuinely-empty workspace ([]) apart from a
|
|
763
|
+
* failed lookup (null): on [] they can safely skip the read (no table → no
|
|
764
|
+
* 42P01), on null they must fall back to SELECT-then-catch so a transient
|
|
765
|
+
* lookup blip doesn't drop a read of a table that really exists.
|
|
766
|
+
*/
|
|
767
|
+
async knownTablesOrNull() {
|
|
768
|
+
if (this._tablesCache)
|
|
769
|
+
return [...this._tablesCache];
|
|
770
|
+
const { tables, cacheable } = await this._fetchTables();
|
|
771
|
+
if (!cacheable)
|
|
772
|
+
return null;
|
|
773
|
+
this._tablesCache = [...tables];
|
|
774
|
+
return [...tables];
|
|
775
|
+
}
|
|
759
776
|
async _fetchTables() {
|
|
760
777
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
761
778
|
try {
|
|
@@ -1019,6 +1019,23 @@ var DeeplakeApi = class {
|
|
|
1019
1019
|
this._tablesCache = [...tables];
|
|
1020
1020
|
return tables;
|
|
1021
1021
|
}
|
|
1022
|
+
/**
|
|
1023
|
+
* Like listTables() but returns null when the list could NOT be trusted
|
|
1024
|
+
* (the fetch failed / was non-cacheable). Callers gating a read on table
|
|
1025
|
+
* existence use this to tell a genuinely-empty workspace ([]) apart from a
|
|
1026
|
+
* failed lookup (null): on [] they can safely skip the read (no table → no
|
|
1027
|
+
* 42P01), on null they must fall back to SELECT-then-catch so a transient
|
|
1028
|
+
* lookup blip doesn't drop a read of a table that really exists.
|
|
1029
|
+
*/
|
|
1030
|
+
async knownTablesOrNull() {
|
|
1031
|
+
if (this._tablesCache)
|
|
1032
|
+
return [...this._tablesCache];
|
|
1033
|
+
const { tables, cacheable } = await this._fetchTables();
|
|
1034
|
+
if (!cacheable)
|
|
1035
|
+
return null;
|
|
1036
|
+
this._tablesCache = [...tables];
|
|
1037
|
+
return [...tables];
|
|
1038
|
+
}
|
|
1022
1039
|
async _fetchTables() {
|
|
1023
1040
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
1024
1041
|
try {
|
|
@@ -746,6 +746,23 @@ var DeeplakeApi = class {
|
|
|
746
746
|
this._tablesCache = [...tables];
|
|
747
747
|
return tables;
|
|
748
748
|
}
|
|
749
|
+
/**
|
|
750
|
+
* Like listTables() but returns null when the list could NOT be trusted
|
|
751
|
+
* (the fetch failed / was non-cacheable). Callers gating a read on table
|
|
752
|
+
* existence use this to tell a genuinely-empty workspace ([]) apart from a
|
|
753
|
+
* failed lookup (null): on [] they can safely skip the read (no table → no
|
|
754
|
+
* 42P01), on null they must fall back to SELECT-then-catch so a transient
|
|
755
|
+
* lookup blip doesn't drop a read of a table that really exists.
|
|
756
|
+
*/
|
|
757
|
+
async knownTablesOrNull() {
|
|
758
|
+
if (this._tablesCache)
|
|
759
|
+
return [...this._tablesCache];
|
|
760
|
+
const { tables, cacheable } = await this._fetchTables();
|
|
761
|
+
if (!cacheable)
|
|
762
|
+
return null;
|
|
763
|
+
this._tablesCache = [...tables];
|
|
764
|
+
return [...tables];
|
|
765
|
+
}
|
|
749
766
|
async _fetchTables() {
|
|
750
767
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
751
768
|
try {
|
|
@@ -755,6 +755,23 @@ var DeeplakeApi = class {
|
|
|
755
755
|
this._tablesCache = [...tables];
|
|
756
756
|
return tables;
|
|
757
757
|
}
|
|
758
|
+
/**
|
|
759
|
+
* Like listTables() but returns null when the list could NOT be trusted
|
|
760
|
+
* (the fetch failed / was non-cacheable). Callers gating a read on table
|
|
761
|
+
* existence use this to tell a genuinely-empty workspace ([]) apart from a
|
|
762
|
+
* failed lookup (null): on [] they can safely skip the read (no table → no
|
|
763
|
+
* 42P01), on null they must fall back to SELECT-then-catch so a transient
|
|
764
|
+
* lookup blip doesn't drop a read of a table that really exists.
|
|
765
|
+
*/
|
|
766
|
+
async knownTablesOrNull() {
|
|
767
|
+
if (this._tablesCache)
|
|
768
|
+
return [...this._tablesCache];
|
|
769
|
+
const { tables, cacheable } = await this._fetchTables();
|
|
770
|
+
if (!cacheable)
|
|
771
|
+
return null;
|
|
772
|
+
this._tablesCache = [...tables];
|
|
773
|
+
return [...tables];
|
|
774
|
+
}
|
|
758
775
|
async _fetchTables() {
|
|
759
776
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
760
777
|
try {
|
|
@@ -811,6 +811,23 @@ var DeeplakeApi = class {
|
|
|
811
811
|
this._tablesCache = [...tables];
|
|
812
812
|
return tables;
|
|
813
813
|
}
|
|
814
|
+
/**
|
|
815
|
+
* Like listTables() but returns null when the list could NOT be trusted
|
|
816
|
+
* (the fetch failed / was non-cacheable). Callers gating a read on table
|
|
817
|
+
* existence use this to tell a genuinely-empty workspace ([]) apart from a
|
|
818
|
+
* failed lookup (null): on [] they can safely skip the read (no table → no
|
|
819
|
+
* 42P01), on null they must fall back to SELECT-then-catch so a transient
|
|
820
|
+
* lookup blip doesn't drop a read of a table that really exists.
|
|
821
|
+
*/
|
|
822
|
+
async knownTablesOrNull() {
|
|
823
|
+
if (this._tablesCache)
|
|
824
|
+
return [...this._tablesCache];
|
|
825
|
+
const { tables, cacheable } = await this._fetchTables();
|
|
826
|
+
if (!cacheable)
|
|
827
|
+
return null;
|
|
828
|
+
this._tablesCache = [...tables];
|
|
829
|
+
return [...tables];
|
|
830
|
+
}
|
|
814
831
|
async _fetchTables() {
|
|
815
832
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
816
833
|
try {
|
|
@@ -1056,24 +1073,33 @@ async function renderContextBlock(query, input, opts = {}) {
|
|
|
1056
1073
|
const log7 = opts.log ?? (() => {
|
|
1057
1074
|
});
|
|
1058
1075
|
try {
|
|
1076
|
+
const tableExists = opts.tableExists;
|
|
1059
1077
|
let rules = [];
|
|
1060
|
-
|
|
1061
|
-
rules
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1078
|
+
if (tableExists && !tableExists(input.rulesTable)) {
|
|
1079
|
+
log7(`render-context-block: rules table "${input.rulesTable}" not present \u2014 skipping read`);
|
|
1080
|
+
} else {
|
|
1081
|
+
try {
|
|
1082
|
+
rules = await listRules(query, input.rulesTable, {
|
|
1083
|
+
status: "active",
|
|
1084
|
+
limit: Math.max(maxRules * 4, maxRules + 1)
|
|
1085
|
+
});
|
|
1086
|
+
} catch (rulesErr) {
|
|
1087
|
+
const rmsg = rulesErr instanceof Error ? rulesErr.message : String(rulesErr);
|
|
1088
|
+
log7(`render-context-block: rules unavailable (continuing): ${rmsg}`);
|
|
1089
|
+
}
|
|
1068
1090
|
}
|
|
1069
1091
|
let goals = [];
|
|
1070
|
-
|
|
1071
|
-
goals
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1092
|
+
if (tableExists && !tableExists(input.goalsTable)) {
|
|
1093
|
+
log7(`render-context-block: goals table "${input.goalsTable}" not present \u2014 skipping read`);
|
|
1094
|
+
} else {
|
|
1095
|
+
try {
|
|
1096
|
+
goals = await listOpenGoals(query, input.goalsTable, input.currentUser, {
|
|
1097
|
+
limit: Math.max(maxGoals * 4, maxGoals + 1)
|
|
1098
|
+
});
|
|
1099
|
+
} catch (goalsErr) {
|
|
1100
|
+
const gmsg = goalsErr instanceof Error ? goalsErr.message : String(goalsErr);
|
|
1101
|
+
log7(`render-context-block: goals unavailable (continuing): ${gmsg}`);
|
|
1102
|
+
}
|
|
1077
1103
|
}
|
|
1078
1104
|
const rulesShown = rules.slice(0, maxRules);
|
|
1079
1105
|
const rulesHidden = Math.max(0, rules.length - maxRules);
|
|
@@ -1912,21 +1938,25 @@ async function runPull(opts) {
|
|
|
1912
1938
|
skillName: opts.skillName
|
|
1913
1939
|
});
|
|
1914
1940
|
let rows = [];
|
|
1915
|
-
|
|
1916
|
-
rows =
|
|
1917
|
-
}
|
|
1918
|
-
|
|
1919
|
-
rows =
|
|
1920
|
-
}
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1941
|
+
if (opts.tableExists && !opts.tableExists(opts.tableName)) {
|
|
1942
|
+
rows = [];
|
|
1943
|
+
} else {
|
|
1944
|
+
try {
|
|
1945
|
+
rows = await opts.query(sql);
|
|
1946
|
+
} catch (e) {
|
|
1947
|
+
if (isMissingTableError(e?.message)) {
|
|
1948
|
+
rows = [];
|
|
1949
|
+
} else if (isMissingContributorsColumnError(e?.message)) {
|
|
1950
|
+
const legacySql = buildPullSql({
|
|
1951
|
+
tableName: opts.tableName,
|
|
1952
|
+
users: opts.users,
|
|
1953
|
+
skillName: opts.skillName,
|
|
1954
|
+
includeContributors: false
|
|
1955
|
+
});
|
|
1956
|
+
rows = await opts.query(legacySql);
|
|
1957
|
+
} else {
|
|
1958
|
+
throw e;
|
|
1959
|
+
}
|
|
1930
1960
|
}
|
|
1931
1961
|
}
|
|
1932
1962
|
const latest = selectLatestPerName(rows);
|
|
@@ -2069,24 +2099,38 @@ async function autoPullSkills(deps = {}) {
|
|
|
2069
2099
|
return { pulled: 0, skipped: true, reason: "not-logged-in" };
|
|
2070
2100
|
}
|
|
2071
2101
|
let query;
|
|
2102
|
+
let discoverTableExists = async () => void 0;
|
|
2072
2103
|
if (deps.queryFn) {
|
|
2073
2104
|
query = deps.queryFn;
|
|
2074
2105
|
} else {
|
|
2075
2106
|
const api = new DeeplakeApi(config.token, config.apiUrl, config.orgId, config.workspaceId, config.skillsTableName);
|
|
2076
2107
|
query = (sql) => api.query(sql);
|
|
2108
|
+
discoverTableExists = async () => {
|
|
2109
|
+
const known = await api.knownTablesOrNull();
|
|
2110
|
+
return known ? (name) => known.includes(name) : void 0;
|
|
2111
|
+
};
|
|
2077
2112
|
}
|
|
2078
2113
|
const install = deps.install ?? "global";
|
|
2079
2114
|
const timeoutMs = deps.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
2080
2115
|
try {
|
|
2081
|
-
const summary = await withTimeout(
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2116
|
+
const summary = await withTimeout(
|
|
2117
|
+
// Table discovery + pull share one budget: if `GET /tables` hangs the
|
|
2118
|
+
// whole thing times out and we degrade, instead of blocking startup.
|
|
2119
|
+
(async () => {
|
|
2120
|
+
const tableExists = await discoverTableExists();
|
|
2121
|
+
return runPull({
|
|
2122
|
+
query,
|
|
2123
|
+
tableName: config.skillsTableName,
|
|
2124
|
+
install,
|
|
2125
|
+
cwd: install === "project" ? deps.cwd ?? process.cwd() : void 0,
|
|
2126
|
+
users: [],
|
|
2127
|
+
dryRun: false,
|
|
2128
|
+
force: false,
|
|
2129
|
+
tableExists
|
|
2130
|
+
});
|
|
2131
|
+
})(),
|
|
2132
|
+
timeoutMs
|
|
2133
|
+
);
|
|
2090
2134
|
log5(`pulled scanned=${summary.scanned} wrote=${summary.wrote} skipped=${summary.skipped}`);
|
|
2091
2135
|
return { pulled: summary.wrote, skipped: false };
|
|
2092
2136
|
} catch (e) {
|
|
@@ -2244,11 +2288,13 @@ async function main() {
|
|
|
2244
2288
|
} else {
|
|
2245
2289
|
log6("placeholder + schema ensure skipped (HIVEMIND_CAPTURE=false)");
|
|
2246
2290
|
}
|
|
2291
|
+
const known = await api.knownTablesOrNull();
|
|
2292
|
+
const tableExists = known ? (name) => known.includes(name) : void 0;
|
|
2247
2293
|
rulesBlock = await renderContextBlock((sql) => api.query(sql), {
|
|
2248
2294
|
rulesTable: config.rulesTableName,
|
|
2249
2295
|
goalsTable: config.goalsTableName,
|
|
2250
2296
|
currentUser: config.userName
|
|
2251
|
-
}, { log: log6 });
|
|
2297
|
+
}, { log: log6, tableExists });
|
|
2252
2298
|
}
|
|
2253
2299
|
} catch (e) {
|
|
2254
2300
|
log6(`placeholder failed: ${e.message}`);
|
|
@@ -67450,6 +67450,23 @@ var DeeplakeApi = class {
|
|
|
67450
67450
|
this._tablesCache = [...tables];
|
|
67451
67451
|
return tables;
|
|
67452
67452
|
}
|
|
67453
|
+
/**
|
|
67454
|
+
* Like listTables() but returns null when the list could NOT be trusted
|
|
67455
|
+
* (the fetch failed / was non-cacheable). Callers gating a read on table
|
|
67456
|
+
* existence use this to tell a genuinely-empty workspace ([]) apart from a
|
|
67457
|
+
* failed lookup (null): on [] they can safely skip the read (no table → no
|
|
67458
|
+
* 42P01), on null they must fall back to SELECT-then-catch so a transient
|
|
67459
|
+
* lookup blip doesn't drop a read of a table that really exists.
|
|
67460
|
+
*/
|
|
67461
|
+
async knownTablesOrNull() {
|
|
67462
|
+
if (this._tablesCache)
|
|
67463
|
+
return [...this._tablesCache];
|
|
67464
|
+
const { tables, cacheable } = await this._fetchTables();
|
|
67465
|
+
if (!cacheable)
|
|
67466
|
+
return null;
|
|
67467
|
+
this._tablesCache = [...tables];
|
|
67468
|
+
return [...tables];
|
|
67469
|
+
}
|
|
67453
67470
|
async _fetchTables() {
|
|
67454
67471
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
67455
67472
|
try {
|
package/hermes/bundle/capture.js
CHANGED
|
@@ -755,6 +755,23 @@ var DeeplakeApi = class {
|
|
|
755
755
|
this._tablesCache = [...tables];
|
|
756
756
|
return tables;
|
|
757
757
|
}
|
|
758
|
+
/**
|
|
759
|
+
* Like listTables() but returns null when the list could NOT be trusted
|
|
760
|
+
* (the fetch failed / was non-cacheable). Callers gating a read on table
|
|
761
|
+
* existence use this to tell a genuinely-empty workspace ([]) apart from a
|
|
762
|
+
* failed lookup (null): on [] they can safely skip the read (no table → no
|
|
763
|
+
* 42P01), on null they must fall back to SELECT-then-catch so a transient
|
|
764
|
+
* lookup blip doesn't drop a read of a table that really exists.
|
|
765
|
+
*/
|
|
766
|
+
async knownTablesOrNull() {
|
|
767
|
+
if (this._tablesCache)
|
|
768
|
+
return [...this._tablesCache];
|
|
769
|
+
const { tables, cacheable } = await this._fetchTables();
|
|
770
|
+
if (!cacheable)
|
|
771
|
+
return null;
|
|
772
|
+
this._tablesCache = [...tables];
|
|
773
|
+
return [...tables];
|
|
774
|
+
}
|
|
758
775
|
async _fetchTables() {
|
|
759
776
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
760
777
|
try {
|
|
@@ -1019,6 +1019,23 @@ var DeeplakeApi = class {
|
|
|
1019
1019
|
this._tablesCache = [...tables];
|
|
1020
1020
|
return tables;
|
|
1021
1021
|
}
|
|
1022
|
+
/**
|
|
1023
|
+
* Like listTables() but returns null when the list could NOT be trusted
|
|
1024
|
+
* (the fetch failed / was non-cacheable). Callers gating a read on table
|
|
1025
|
+
* existence use this to tell a genuinely-empty workspace ([]) apart from a
|
|
1026
|
+
* failed lookup (null): on [] they can safely skip the read (no table → no
|
|
1027
|
+
* 42P01), on null they must fall back to SELECT-then-catch so a transient
|
|
1028
|
+
* lookup blip doesn't drop a read of a table that really exists.
|
|
1029
|
+
*/
|
|
1030
|
+
async knownTablesOrNull() {
|
|
1031
|
+
if (this._tablesCache)
|
|
1032
|
+
return [...this._tablesCache];
|
|
1033
|
+
const { tables, cacheable } = await this._fetchTables();
|
|
1034
|
+
if (!cacheable)
|
|
1035
|
+
return null;
|
|
1036
|
+
this._tablesCache = [...tables];
|
|
1037
|
+
return [...tables];
|
|
1038
|
+
}
|
|
1022
1039
|
async _fetchTables() {
|
|
1023
1040
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
1024
1041
|
try {
|
|
@@ -746,6 +746,23 @@ var DeeplakeApi = class {
|
|
|
746
746
|
this._tablesCache = [...tables];
|
|
747
747
|
return tables;
|
|
748
748
|
}
|
|
749
|
+
/**
|
|
750
|
+
* Like listTables() but returns null when the list could NOT be trusted
|
|
751
|
+
* (the fetch failed / was non-cacheable). Callers gating a read on table
|
|
752
|
+
* existence use this to tell a genuinely-empty workspace ([]) apart from a
|
|
753
|
+
* failed lookup (null): on [] they can safely skip the read (no table → no
|
|
754
|
+
* 42P01), on null they must fall back to SELECT-then-catch so a transient
|
|
755
|
+
* lookup blip doesn't drop a read of a table that really exists.
|
|
756
|
+
*/
|
|
757
|
+
async knownTablesOrNull() {
|
|
758
|
+
if (this._tablesCache)
|
|
759
|
+
return [...this._tablesCache];
|
|
760
|
+
const { tables, cacheable } = await this._fetchTables();
|
|
761
|
+
if (!cacheable)
|
|
762
|
+
return null;
|
|
763
|
+
this._tablesCache = [...tables];
|
|
764
|
+
return [...tables];
|
|
765
|
+
}
|
|
749
766
|
async _fetchTables() {
|
|
750
767
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
751
768
|
try {
|
|
@@ -755,6 +755,23 @@ var DeeplakeApi = class {
|
|
|
755
755
|
this._tablesCache = [...tables];
|
|
756
756
|
return tables;
|
|
757
757
|
}
|
|
758
|
+
/**
|
|
759
|
+
* Like listTables() but returns null when the list could NOT be trusted
|
|
760
|
+
* (the fetch failed / was non-cacheable). Callers gating a read on table
|
|
761
|
+
* existence use this to tell a genuinely-empty workspace ([]) apart from a
|
|
762
|
+
* failed lookup (null): on [] they can safely skip the read (no table → no
|
|
763
|
+
* 42P01), on null they must fall back to SELECT-then-catch so a transient
|
|
764
|
+
* lookup blip doesn't drop a read of a table that really exists.
|
|
765
|
+
*/
|
|
766
|
+
async knownTablesOrNull() {
|
|
767
|
+
if (this._tablesCache)
|
|
768
|
+
return [...this._tablesCache];
|
|
769
|
+
const { tables, cacheable } = await this._fetchTables();
|
|
770
|
+
if (!cacheable)
|
|
771
|
+
return null;
|
|
772
|
+
this._tablesCache = [...tables];
|
|
773
|
+
return [...tables];
|
|
774
|
+
}
|
|
758
775
|
async _fetchTables() {
|
|
759
776
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
760
777
|
try {
|
|
@@ -810,6 +810,23 @@ var DeeplakeApi = class {
|
|
|
810
810
|
this._tablesCache = [...tables];
|
|
811
811
|
return tables;
|
|
812
812
|
}
|
|
813
|
+
/**
|
|
814
|
+
* Like listTables() but returns null when the list could NOT be trusted
|
|
815
|
+
* (the fetch failed / was non-cacheable). Callers gating a read on table
|
|
816
|
+
* existence use this to tell a genuinely-empty workspace ([]) apart from a
|
|
817
|
+
* failed lookup (null): on [] they can safely skip the read (no table → no
|
|
818
|
+
* 42P01), on null they must fall back to SELECT-then-catch so a transient
|
|
819
|
+
* lookup blip doesn't drop a read of a table that really exists.
|
|
820
|
+
*/
|
|
821
|
+
async knownTablesOrNull() {
|
|
822
|
+
if (this._tablesCache)
|
|
823
|
+
return [...this._tablesCache];
|
|
824
|
+
const { tables, cacheable } = await this._fetchTables();
|
|
825
|
+
if (!cacheable)
|
|
826
|
+
return null;
|
|
827
|
+
this._tablesCache = [...tables];
|
|
828
|
+
return [...tables];
|
|
829
|
+
}
|
|
813
830
|
async _fetchTables() {
|
|
814
831
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
815
832
|
try {
|
|
@@ -1055,24 +1072,33 @@ async function renderContextBlock(query, input, opts = {}) {
|
|
|
1055
1072
|
const log7 = opts.log ?? (() => {
|
|
1056
1073
|
});
|
|
1057
1074
|
try {
|
|
1075
|
+
const tableExists = opts.tableExists;
|
|
1058
1076
|
let rules = [];
|
|
1059
|
-
|
|
1060
|
-
rules
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1077
|
+
if (tableExists && !tableExists(input.rulesTable)) {
|
|
1078
|
+
log7(`render-context-block: rules table "${input.rulesTable}" not present \u2014 skipping read`);
|
|
1079
|
+
} else {
|
|
1080
|
+
try {
|
|
1081
|
+
rules = await listRules(query, input.rulesTable, {
|
|
1082
|
+
status: "active",
|
|
1083
|
+
limit: Math.max(maxRules * 4, maxRules + 1)
|
|
1084
|
+
});
|
|
1085
|
+
} catch (rulesErr) {
|
|
1086
|
+
const rmsg = rulesErr instanceof Error ? rulesErr.message : String(rulesErr);
|
|
1087
|
+
log7(`render-context-block: rules unavailable (continuing): ${rmsg}`);
|
|
1088
|
+
}
|
|
1067
1089
|
}
|
|
1068
1090
|
let goals = [];
|
|
1069
|
-
|
|
1070
|
-
goals
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1091
|
+
if (tableExists && !tableExists(input.goalsTable)) {
|
|
1092
|
+
log7(`render-context-block: goals table "${input.goalsTable}" not present \u2014 skipping read`);
|
|
1093
|
+
} else {
|
|
1094
|
+
try {
|
|
1095
|
+
goals = await listOpenGoals(query, input.goalsTable, input.currentUser, {
|
|
1096
|
+
limit: Math.max(maxGoals * 4, maxGoals + 1)
|
|
1097
|
+
});
|
|
1098
|
+
} catch (goalsErr) {
|
|
1099
|
+
const gmsg = goalsErr instanceof Error ? goalsErr.message : String(goalsErr);
|
|
1100
|
+
log7(`render-context-block: goals unavailable (continuing): ${gmsg}`);
|
|
1101
|
+
}
|
|
1076
1102
|
}
|
|
1077
1103
|
const rulesShown = rules.slice(0, maxRules);
|
|
1078
1104
|
const rulesHidden = Math.max(0, rules.length - maxRules);
|
|
@@ -1911,21 +1937,25 @@ async function runPull(opts) {
|
|
|
1911
1937
|
skillName: opts.skillName
|
|
1912
1938
|
});
|
|
1913
1939
|
let rows = [];
|
|
1914
|
-
|
|
1915
|
-
rows =
|
|
1916
|
-
}
|
|
1917
|
-
|
|
1918
|
-
rows =
|
|
1919
|
-
}
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1940
|
+
if (opts.tableExists && !opts.tableExists(opts.tableName)) {
|
|
1941
|
+
rows = [];
|
|
1942
|
+
} else {
|
|
1943
|
+
try {
|
|
1944
|
+
rows = await opts.query(sql);
|
|
1945
|
+
} catch (e) {
|
|
1946
|
+
if (isMissingTableError(e?.message)) {
|
|
1947
|
+
rows = [];
|
|
1948
|
+
} else if (isMissingContributorsColumnError(e?.message)) {
|
|
1949
|
+
const legacySql = buildPullSql({
|
|
1950
|
+
tableName: opts.tableName,
|
|
1951
|
+
users: opts.users,
|
|
1952
|
+
skillName: opts.skillName,
|
|
1953
|
+
includeContributors: false
|
|
1954
|
+
});
|
|
1955
|
+
rows = await opts.query(legacySql);
|
|
1956
|
+
} else {
|
|
1957
|
+
throw e;
|
|
1958
|
+
}
|
|
1929
1959
|
}
|
|
1930
1960
|
}
|
|
1931
1961
|
const latest = selectLatestPerName(rows);
|
|
@@ -2068,24 +2098,38 @@ async function autoPullSkills(deps = {}) {
|
|
|
2068
2098
|
return { pulled: 0, skipped: true, reason: "not-logged-in" };
|
|
2069
2099
|
}
|
|
2070
2100
|
let query;
|
|
2101
|
+
let discoverTableExists = async () => void 0;
|
|
2071
2102
|
if (deps.queryFn) {
|
|
2072
2103
|
query = deps.queryFn;
|
|
2073
2104
|
} else {
|
|
2074
2105
|
const api = new DeeplakeApi(config.token, config.apiUrl, config.orgId, config.workspaceId, config.skillsTableName);
|
|
2075
2106
|
query = (sql) => api.query(sql);
|
|
2107
|
+
discoverTableExists = async () => {
|
|
2108
|
+
const known = await api.knownTablesOrNull();
|
|
2109
|
+
return known ? (name) => known.includes(name) : void 0;
|
|
2110
|
+
};
|
|
2076
2111
|
}
|
|
2077
2112
|
const install = deps.install ?? "global";
|
|
2078
2113
|
const timeoutMs = deps.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
2079
2114
|
try {
|
|
2080
|
-
const summary = await withTimeout(
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2115
|
+
const summary = await withTimeout(
|
|
2116
|
+
// Table discovery + pull share one budget: if `GET /tables` hangs the
|
|
2117
|
+
// whole thing times out and we degrade, instead of blocking startup.
|
|
2118
|
+
(async () => {
|
|
2119
|
+
const tableExists = await discoverTableExists();
|
|
2120
|
+
return runPull({
|
|
2121
|
+
query,
|
|
2122
|
+
tableName: config.skillsTableName,
|
|
2123
|
+
install,
|
|
2124
|
+
cwd: install === "project" ? deps.cwd ?? process.cwd() : void 0,
|
|
2125
|
+
users: [],
|
|
2126
|
+
dryRun: false,
|
|
2127
|
+
force: false,
|
|
2128
|
+
tableExists
|
|
2129
|
+
});
|
|
2130
|
+
})(),
|
|
2131
|
+
timeoutMs
|
|
2132
|
+
);
|
|
2089
2133
|
log5(`pulled scanned=${summary.scanned} wrote=${summary.wrote} skipped=${summary.skipped}`);
|
|
2090
2134
|
return { pulled: summary.wrote, skipped: false };
|
|
2091
2135
|
} catch (e) {
|
|
@@ -2229,11 +2273,13 @@ async function main() {
|
|
|
2229
2273
|
} else {
|
|
2230
2274
|
log6("placeholder + schema ensure skipped (HIVEMIND_CAPTURE=false)");
|
|
2231
2275
|
}
|
|
2276
|
+
const known = await api.knownTablesOrNull();
|
|
2277
|
+
const tableExists = known ? (name) => known.includes(name) : void 0;
|
|
2232
2278
|
rulesBlock = await renderContextBlock((sql) => api.query(sql), {
|
|
2233
2279
|
rulesTable: config.rulesTableName,
|
|
2234
2280
|
goalsTable: config.goalsTableName,
|
|
2235
2281
|
currentUser: config.userName
|
|
2236
|
-
}, { log: log6 });
|
|
2282
|
+
}, { log: log6, tableExists });
|
|
2237
2283
|
}
|
|
2238
2284
|
} catch (e) {
|
|
2239
2285
|
log6(`placeholder failed: ${e.message}`);
|
|
@@ -67450,6 +67450,23 @@ var DeeplakeApi = class {
|
|
|
67450
67450
|
this._tablesCache = [...tables];
|
|
67451
67451
|
return tables;
|
|
67452
67452
|
}
|
|
67453
|
+
/**
|
|
67454
|
+
* Like listTables() but returns null when the list could NOT be trusted
|
|
67455
|
+
* (the fetch failed / was non-cacheable). Callers gating a read on table
|
|
67456
|
+
* existence use this to tell a genuinely-empty workspace ([]) apart from a
|
|
67457
|
+
* failed lookup (null): on [] they can safely skip the read (no table → no
|
|
67458
|
+
* 42P01), on null they must fall back to SELECT-then-catch so a transient
|
|
67459
|
+
* lookup blip doesn't drop a read of a table that really exists.
|
|
67460
|
+
*/
|
|
67461
|
+
async knownTablesOrNull() {
|
|
67462
|
+
if (this._tablesCache)
|
|
67463
|
+
return [...this._tablesCache];
|
|
67464
|
+
const { tables, cacheable } = await this._fetchTables();
|
|
67465
|
+
if (!cacheable)
|
|
67466
|
+
return null;
|
|
67467
|
+
this._tablesCache = [...tables];
|
|
67468
|
+
return [...tables];
|
|
67469
|
+
}
|
|
67453
67470
|
async _fetchTables() {
|
|
67454
67471
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
67455
67472
|
try {
|
package/mcp/bundle/server.js
CHANGED
|
@@ -23961,6 +23961,23 @@ var DeeplakeApi = class {
|
|
|
23961
23961
|
this._tablesCache = [...tables];
|
|
23962
23962
|
return tables;
|
|
23963
23963
|
}
|
|
23964
|
+
/**
|
|
23965
|
+
* Like listTables() but returns null when the list could NOT be trusted
|
|
23966
|
+
* (the fetch failed / was non-cacheable). Callers gating a read on table
|
|
23967
|
+
* existence use this to tell a genuinely-empty workspace ([]) apart from a
|
|
23968
|
+
* failed lookup (null): on [] they can safely skip the read (no table → no
|
|
23969
|
+
* 42P01), on null they must fall back to SELECT-then-catch so a transient
|
|
23970
|
+
* lookup blip doesn't drop a read of a table that really exists.
|
|
23971
|
+
*/
|
|
23972
|
+
async knownTablesOrNull() {
|
|
23973
|
+
if (this._tablesCache)
|
|
23974
|
+
return [...this._tablesCache];
|
|
23975
|
+
const { tables, cacheable } = await this._fetchTables();
|
|
23976
|
+
if (!cacheable)
|
|
23977
|
+
return null;
|
|
23978
|
+
this._tablesCache = [...tables];
|
|
23979
|
+
return [...tables];
|
|
23980
|
+
}
|
|
23964
23981
|
async _fetchTables() {
|
|
23965
23982
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
23966
23983
|
try {
|
package/openclaw/dist/index.js
CHANGED
|
@@ -772,6 +772,21 @@ var DeeplakeApi = class {
|
|
|
772
772
|
if (cacheable) this._tablesCache = [...tables];
|
|
773
773
|
return tables;
|
|
774
774
|
}
|
|
775
|
+
/**
|
|
776
|
+
* Like listTables() but returns null when the list could NOT be trusted
|
|
777
|
+
* (the fetch failed / was non-cacheable). Callers gating a read on table
|
|
778
|
+
* existence use this to tell a genuinely-empty workspace ([]) apart from a
|
|
779
|
+
* failed lookup (null): on [] they can safely skip the read (no table → no
|
|
780
|
+
* 42P01), on null they must fall back to SELECT-then-catch so a transient
|
|
781
|
+
* lookup blip doesn't drop a read of a table that really exists.
|
|
782
|
+
*/
|
|
783
|
+
async knownTablesOrNull() {
|
|
784
|
+
if (this._tablesCache) return [...this._tablesCache];
|
|
785
|
+
const { tables, cacheable } = await this._fetchTables();
|
|
786
|
+
if (!cacheable) return null;
|
|
787
|
+
this._tablesCache = [...tables];
|
|
788
|
+
return [...tables];
|
|
789
|
+
}
|
|
775
790
|
async _fetchTables() {
|
|
776
791
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
777
792
|
try {
|
|
@@ -1780,7 +1795,7 @@ function extractLatestVersion(body) {
|
|
|
1780
1795
|
return typeof v === "string" && v.length > 0 ? v : null;
|
|
1781
1796
|
}
|
|
1782
1797
|
function getInstalledVersion() {
|
|
1783
|
-
return "0.7.
|
|
1798
|
+
return "0.7.60".length > 0 ? "0.7.60" : null;
|
|
1784
1799
|
}
|
|
1785
1800
|
function isNewer(latest, current) {
|
|
1786
1801
|
const parse = (v) => v.replace(/-.*$/, "").split(".").map(Number);
|
package/openclaw/package.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deeplake/hivemind",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.60",
|
|
4
4
|
"description": "Cloud-backed persistent shared memory for AI agents powered by Deeplake",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -41,7 +41,9 @@
|
|
|
41
41
|
"dup": "jscpd src",
|
|
42
42
|
"audit:openclaw": "node scripts/audit-openclaw-bundle.mjs",
|
|
43
43
|
"pack:check": "node scripts/pack-check.mjs",
|
|
44
|
+
"rebuild:native": "node scripts/ensure-tree-sitter.mjs",
|
|
44
45
|
"ci": "npm run typecheck && npm run dup && npm test",
|
|
46
|
+
"postinstall": "node scripts/ensure-tree-sitter.mjs",
|
|
45
47
|
"prepare": "husky && npm run build",
|
|
46
48
|
"prepack": "npm run build"
|
|
47
49
|
},
|
|
@@ -58,11 +60,13 @@
|
|
|
58
60
|
"deeplake": "^0.3.30",
|
|
59
61
|
"js-yaml": "^4.1.1",
|
|
60
62
|
"just-bash": "^2.14.0",
|
|
61
|
-
"tree-sitter": "^0.21.1",
|
|
62
|
-
"tree-sitter-typescript": "^0.23.2",
|
|
63
63
|
"yargs-parser": "^22.0.0",
|
|
64
64
|
"zod": "^4.3.6"
|
|
65
65
|
},
|
|
66
|
+
"optionalDependencies": {
|
|
67
|
+
"tree-sitter": "^0.21.1",
|
|
68
|
+
"tree-sitter-typescript": "^0.23.2"
|
|
69
|
+
},
|
|
66
70
|
"devDependencies": {
|
|
67
71
|
"@types/js-yaml": "^4.0.9",
|
|
68
72
|
"@types/node": "^25.0.0",
|