open-walnut 0.3.0 → 0.3.2
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/dist/cli.js +47 -13
- package/dist/daemon-binaries/acp-worker.js.version +1 -1
- package/dist/web/server.js +47 -13
- package/dist/workers/qmd-index-worker.js +44 -12
- package/package.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -7234,9 +7234,11 @@ const SESSION_IDLE_KILL_MS = 2 * 60 * 60 * 1000; // 2 hours
|
|
|
7234
7234
|
const SESSION_CRON_IDLE_KILL_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
7235
7235
|
// Sessions with a running background task: wait-style bash tasks write to
|
|
7236
7236
|
// output_file, not the JSONL, so the session looks idle for the task's whole
|
|
7237
|
-
// lifetime (incident inc-1786222771315).
|
|
7238
|
-
//
|
|
7239
|
-
|
|
7237
|
+
// lifetime (incident inc-1786222771315). PRINCIPLE: never reap running bg
|
|
7238
|
+
// work \u2014 this 3-day cap exists only for a wedged task framework that will
|
|
7239
|
+
// never emit a terminal event (immortal-process backstop). See
|
|
7240
|
+
// daemon-standalone.ts for the full rationale.
|
|
7241
|
+
const SESSION_BG_IDLE_KILL_MS = 3 * 24 * 60 * 60 * 1000; // 3 days
|
|
7240
7242
|
const SESSION_SCAN_INTERVAL_MS = 60000; // every 60s
|
|
7241
7243
|
|
|
7242
7244
|
// Last-resort cron evidence: the CLI scheduler's own debug log in HOME
|
|
@@ -14048,6 +14050,16 @@ var init_acp_session = __esm({
|
|
|
14048
14050
|
...configId === "model" ? { acpModel: value } : {},
|
|
14049
14051
|
acpConfig: { ...record?.acpConfig ?? this.cfg.acpConfig ?? {}, [configId]: value }
|
|
14050
14052
|
});
|
|
14053
|
+
if (configId === "mode" && value === "agent-full-access" && this._pendingPermissions.size > 0) {
|
|
14054
|
+
const pending2 = [...this._pendingPermissions.keys()];
|
|
14055
|
+
log.session.info("acp: full access selected \u2014 auto-allowing pending permissions", {
|
|
14056
|
+
sessionId: this.trackingId(),
|
|
14057
|
+
requestIds: pending2
|
|
14058
|
+
});
|
|
14059
|
+
for (const requestId of pending2) {
|
|
14060
|
+
await this.resolvePermissionRequest(requestId, true).catch(() => false);
|
|
14061
|
+
}
|
|
14062
|
+
}
|
|
14051
14063
|
return true;
|
|
14052
14064
|
}
|
|
14053
14065
|
/** Switch the model for the next Codex turn through standard ACP config.
|
|
@@ -18022,12 +18034,31 @@ __export(qmd_store_exports, {
|
|
|
18022
18034
|
getSessionStore: () => getSessionStore,
|
|
18023
18035
|
getTaskStore: () => getTaskStore,
|
|
18024
18036
|
initQmdStores: () => initQmdStores,
|
|
18037
|
+
isQmdAvailable: () => isQmdAvailable,
|
|
18025
18038
|
qmdStoresRequireModelReset: () => qmdStoresRequireModelReset
|
|
18026
18039
|
});
|
|
18027
|
-
import { createStore } from "@tobilu/qmd";
|
|
18028
18040
|
import Database from "better-sqlite3";
|
|
18029
18041
|
import fs25 from "fs";
|
|
18030
18042
|
import path27 from "path";
|
|
18043
|
+
async function loadQmd() {
|
|
18044
|
+
if (!qmdModulePromise) {
|
|
18045
|
+
qmdModulePromise = import("@tobilu/qmd").catch((err2) => {
|
|
18046
|
+
qmdModulePromise = null;
|
|
18047
|
+
throw new Error(
|
|
18048
|
+
`semantic search unavailable: @tobilu/qmd failed to load (${err2 instanceof Error ? err2.message : err2}). This host may lack glibc \u2265 2.28 or the optional dependency was skipped at install.`
|
|
18049
|
+
);
|
|
18050
|
+
});
|
|
18051
|
+
}
|
|
18052
|
+
return qmdModulePromise;
|
|
18053
|
+
}
|
|
18054
|
+
async function isQmdAvailable() {
|
|
18055
|
+
try {
|
|
18056
|
+
await loadQmd();
|
|
18057
|
+
return true;
|
|
18058
|
+
} catch {
|
|
18059
|
+
return false;
|
|
18060
|
+
}
|
|
18061
|
+
}
|
|
18031
18062
|
function qmdStoresRequireModelReset(currentModel) {
|
|
18032
18063
|
const expectedDimensions = KNOWN_QMD_MODEL_DIMENSIONS[currentModel];
|
|
18033
18064
|
for (const filename of QMD_DB_FILES) {
|
|
@@ -18178,7 +18209,7 @@ async function embedQmdStore(store3, label, options) {
|
|
|
18178
18209
|
async function getMemoryStore() {
|
|
18179
18210
|
if (memoryStore) return memoryStore;
|
|
18180
18211
|
if (!memoryStorePromise) {
|
|
18181
|
-
const model = await initializeQmdRuntimeModel();
|
|
18212
|
+
const [{ createStore }, model] = await Promise.all([loadQmd(), initializeQmdRuntimeModel()]);
|
|
18182
18213
|
if (memoryStore) return memoryStore;
|
|
18183
18214
|
if (memoryStorePromise) return memoryStorePromise;
|
|
18184
18215
|
memoryStorePromise = createStore({
|
|
@@ -18217,7 +18248,7 @@ async function getMemoryStore() {
|
|
|
18217
18248
|
async function getNotesStore() {
|
|
18218
18249
|
if (notesStore) return notesStore;
|
|
18219
18250
|
if (!notesStorePromise) {
|
|
18220
|
-
const model = await initializeQmdRuntimeModel();
|
|
18251
|
+
const [{ createStore }, model] = await Promise.all([loadQmd(), initializeQmdRuntimeModel()]);
|
|
18221
18252
|
if (notesStore) return notesStore;
|
|
18222
18253
|
if (notesStorePromise) return notesStorePromise;
|
|
18223
18254
|
notesStorePromise = createStore({
|
|
@@ -18250,7 +18281,7 @@ async function getNotesStore() {
|
|
|
18250
18281
|
async function getTaskStore() {
|
|
18251
18282
|
if (taskStore) return taskStore;
|
|
18252
18283
|
if (!taskStorePromise) {
|
|
18253
|
-
const model = await initializeQmdRuntimeModel();
|
|
18284
|
+
const [{ createStore }, model] = await Promise.all([loadQmd(), initializeQmdRuntimeModel()]);
|
|
18254
18285
|
if (taskStore) return taskStore;
|
|
18255
18286
|
if (taskStorePromise) return taskStorePromise;
|
|
18256
18287
|
taskStorePromise = createStore({
|
|
@@ -18275,7 +18306,7 @@ async function getTaskStore() {
|
|
|
18275
18306
|
async function getSessionStore() {
|
|
18276
18307
|
if (sessionStore) return sessionStore;
|
|
18277
18308
|
if (!sessionStorePromise) {
|
|
18278
|
-
const model = await initializeQmdRuntimeModel();
|
|
18309
|
+
const [{ createStore }, model] = await Promise.all([loadQmd(), initializeQmdRuntimeModel()]);
|
|
18279
18310
|
if (sessionStore) return sessionStore;
|
|
18280
18311
|
if (sessionStorePromise) return sessionStorePromise;
|
|
18281
18312
|
sessionStorePromise = createStore({
|
|
@@ -18418,7 +18449,7 @@ async function closeQmdStores() {
|
|
|
18418
18449
|
taskStorePromise = null;
|
|
18419
18450
|
sessionStorePromise = null;
|
|
18420
18451
|
}
|
|
18421
|
-
var KNOWN_QMD_MODEL_DIMENSIONS, EMBED_RUN_TABLE, QMD_DB_FILES, memoryStore, memoryStorePromise, notesStore, notesStorePromise, taskStore, taskStorePromise, sessionStore, sessionStorePromise;
|
|
18452
|
+
var KNOWN_QMD_MODEL_DIMENSIONS, EMBED_RUN_TABLE, QMD_DB_FILES, qmdModulePromise, memoryStore, memoryStorePromise, notesStore, notesStorePromise, taskStore, taskStorePromise, sessionStore, sessionStorePromise;
|
|
18422
18453
|
var init_qmd_store = __esm({
|
|
18423
18454
|
"src/core/qmd-store.ts"() {
|
|
18424
18455
|
"use strict";
|
|
@@ -18438,6 +18469,7 @@ var init_qmd_store = __esm({
|
|
|
18438
18469
|
"task-search.sqlite",
|
|
18439
18470
|
"session-search.sqlite"
|
|
18440
18471
|
];
|
|
18472
|
+
qmdModulePromise = null;
|
|
18441
18473
|
memoryStore = null;
|
|
18442
18474
|
memoryStorePromise = null;
|
|
18443
18475
|
notesStore = null;
|
|
@@ -27559,7 +27591,6 @@ __export(qmd_maintenance_exports, {
|
|
|
27559
27591
|
rebuildQmdCorpus: () => rebuildQmdCorpus,
|
|
27560
27592
|
runQmdIncrementalWork: () => runQmdIncrementalWork
|
|
27561
27593
|
});
|
|
27562
|
-
import { Maintenance } from "@tobilu/qmd";
|
|
27563
27594
|
async function rebuildQmdCorpus(options = {}) {
|
|
27564
27595
|
const onProgress = options.onProgress;
|
|
27565
27596
|
if (options.initialize) {
|
|
@@ -27649,7 +27680,7 @@ async function runQmdIncrementalWork(work, options = {}) {
|
|
|
27649
27680
|
});
|
|
27650
27681
|
}
|
|
27651
27682
|
}
|
|
27652
|
-
function compactQmdStoreIfNeeded(store3, label) {
|
|
27683
|
+
async function compactQmdStoreIfNeeded(store3, label) {
|
|
27653
27684
|
const db5 = store3.internal.db;
|
|
27654
27685
|
const pageCount = db5.pragma("page_count", { simple: true });
|
|
27655
27686
|
const freePages = db5.pragma("freelist_count", { simple: true });
|
|
@@ -27661,6 +27692,7 @@ function compactQmdStoreIfNeeded(store3, label) {
|
|
|
27661
27692
|
return null;
|
|
27662
27693
|
}
|
|
27663
27694
|
const startedAt = Date.now();
|
|
27695
|
+
const { Maintenance } = await import("@tobilu/qmd");
|
|
27664
27696
|
new Maintenance(store3.internal).vacuum();
|
|
27665
27697
|
const afterBytes = db5.pragma("page_count", { simple: true }) * pageSize;
|
|
27666
27698
|
const stats = {
|
|
@@ -27692,7 +27724,7 @@ async function cleanupQmdCorpus(options = {}) {
|
|
|
27692
27724
|
const cleanup = cleanupOrphanedQmdData(store3);
|
|
27693
27725
|
if (!options.compact) return cleanup;
|
|
27694
27726
|
try {
|
|
27695
|
-
const compaction = compactQmdStoreIfNeeded(store3, name);
|
|
27727
|
+
const compaction = await compactQmdStoreIfNeeded(store3, name);
|
|
27696
27728
|
return compaction ? { ...cleanup, compaction } : cleanup;
|
|
27697
27729
|
} catch (error) {
|
|
27698
27730
|
log.memory.warn("QMD store compaction failed", {
|
|
@@ -102680,7 +102712,7 @@ ${trimmed.slice(0, 500)}`
|
|
|
102680
102712
|
const startDate = snap(validLocalDueDate(parsed.start_date));
|
|
102681
102713
|
if (startDate) output.start_date = startDate;
|
|
102682
102714
|
const endDate = snap(validLocalDueDate(parsed.end_date));
|
|
102683
|
-
if (endDate && startDate) output.end_date = endDate;
|
|
102715
|
+
if (endDate && startDate && endDate > startDate) output.end_date = endDate;
|
|
102684
102716
|
if (parsed.pinTier === "focus" || parsed.pinTier === "satellite" || parsed.pinTier === "backlog" || parsed.pinTier === "wait") {
|
|
102685
102717
|
output.pinTier = parsed.pinTier;
|
|
102686
102718
|
} else if (typeof parsed.pinTier === "string" && opts.customTiers?.length) {
|
|
@@ -134433,6 +134465,8 @@ async function startServer(options = {}) {
|
|
|
134433
134465
|
log.memory.info("QMD search disabled via WALNUT_DISABLE_SEARCH=1 \u2014 skipping embedding model init");
|
|
134434
134466
|
} else if (CLOUD_MODE) {
|
|
134435
134467
|
log.memory.info("cloud mode: skipping QMD semantic index init");
|
|
134468
|
+
} else if (!await (await Promise.resolve().then(() => (init_qmd_store(), qmd_store_exports))).isQmdAvailable()) {
|
|
134469
|
+
log.memory.warn("QMD semantic search unavailable on this host (optional dependency not installed) \u2014 keyword search only");
|
|
134436
134470
|
} else try {
|
|
134437
134471
|
const { startQmdWatcher: startQmdWatcher2 } = await Promise.resolve().then(() => (init_qmd_watcher(), qmd_watcher_exports));
|
|
134438
134472
|
const {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
walnut-daemon-
|
|
1
|
+
walnut-daemon-9df902e189a2
|
package/dist/web/server.js
CHANGED
|
@@ -10999,9 +10999,11 @@ const SESSION_IDLE_KILL_MS = 2 * 60 * 60 * 1000; // 2 hours
|
|
|
10999
10999
|
const SESSION_CRON_IDLE_KILL_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
11000
11000
|
// Sessions with a running background task: wait-style bash tasks write to
|
|
11001
11001
|
// output_file, not the JSONL, so the session looks idle for the task's whole
|
|
11002
|
-
// lifetime (incident inc-1786222771315).
|
|
11003
|
-
//
|
|
11004
|
-
|
|
11002
|
+
// lifetime (incident inc-1786222771315). PRINCIPLE: never reap running bg
|
|
11003
|
+
// work \u2014 this 3-day cap exists only for a wedged task framework that will
|
|
11004
|
+
// never emit a terminal event (immortal-process backstop). See
|
|
11005
|
+
// daemon-standalone.ts for the full rationale.
|
|
11006
|
+
const SESSION_BG_IDLE_KILL_MS = 3 * 24 * 60 * 60 * 1000; // 3 days
|
|
11005
11007
|
const SESSION_SCAN_INTERVAL_MS = 60000; // every 60s
|
|
11006
11008
|
|
|
11007
11009
|
// Last-resort cron evidence: the CLI scheduler's own debug log in HOME
|
|
@@ -17813,6 +17815,16 @@ var init_acp_session = __esm({
|
|
|
17813
17815
|
...configId === "model" ? { acpModel: value } : {},
|
|
17814
17816
|
acpConfig: { ...record?.acpConfig ?? this.cfg.acpConfig ?? {}, [configId]: value }
|
|
17815
17817
|
});
|
|
17818
|
+
if (configId === "mode" && value === "agent-full-access" && this._pendingPermissions.size > 0) {
|
|
17819
|
+
const pending2 = [...this._pendingPermissions.keys()];
|
|
17820
|
+
log.session.info("acp: full access selected \u2014 auto-allowing pending permissions", {
|
|
17821
|
+
sessionId: this.trackingId(),
|
|
17822
|
+
requestIds: pending2
|
|
17823
|
+
});
|
|
17824
|
+
for (const requestId of pending2) {
|
|
17825
|
+
await this.resolvePermissionRequest(requestId, true).catch(() => false);
|
|
17826
|
+
}
|
|
17827
|
+
}
|
|
17816
17828
|
return true;
|
|
17817
17829
|
}
|
|
17818
17830
|
/** Switch the model for the next Codex turn through standard ACP config.
|
|
@@ -21787,12 +21799,31 @@ __export(qmd_store_exports, {
|
|
|
21787
21799
|
getSessionStore: () => getSessionStore,
|
|
21788
21800
|
getTaskStore: () => getTaskStore,
|
|
21789
21801
|
initQmdStores: () => initQmdStores,
|
|
21802
|
+
isQmdAvailable: () => isQmdAvailable,
|
|
21790
21803
|
qmdStoresRequireModelReset: () => qmdStoresRequireModelReset
|
|
21791
21804
|
});
|
|
21792
|
-
import { createStore } from "@tobilu/qmd";
|
|
21793
21805
|
import Database2 from "better-sqlite3";
|
|
21794
21806
|
import fs29 from "fs";
|
|
21795
21807
|
import path32 from "path";
|
|
21808
|
+
async function loadQmd() {
|
|
21809
|
+
if (!qmdModulePromise) {
|
|
21810
|
+
qmdModulePromise = import("@tobilu/qmd").catch((err2) => {
|
|
21811
|
+
qmdModulePromise = null;
|
|
21812
|
+
throw new Error(
|
|
21813
|
+
`semantic search unavailable: @tobilu/qmd failed to load (${err2 instanceof Error ? err2.message : err2}). This host may lack glibc \u2265 2.28 or the optional dependency was skipped at install.`
|
|
21814
|
+
);
|
|
21815
|
+
});
|
|
21816
|
+
}
|
|
21817
|
+
return qmdModulePromise;
|
|
21818
|
+
}
|
|
21819
|
+
async function isQmdAvailable() {
|
|
21820
|
+
try {
|
|
21821
|
+
await loadQmd();
|
|
21822
|
+
return true;
|
|
21823
|
+
} catch {
|
|
21824
|
+
return false;
|
|
21825
|
+
}
|
|
21826
|
+
}
|
|
21796
21827
|
function qmdStoresRequireModelReset(currentModel) {
|
|
21797
21828
|
const expectedDimensions = KNOWN_QMD_MODEL_DIMENSIONS[currentModel];
|
|
21798
21829
|
for (const filename of QMD_DB_FILES) {
|
|
@@ -21943,7 +21974,7 @@ async function embedQmdStore(store3, label, options) {
|
|
|
21943
21974
|
async function getMemoryStore() {
|
|
21944
21975
|
if (memoryStore) return memoryStore;
|
|
21945
21976
|
if (!memoryStorePromise) {
|
|
21946
|
-
const model = await initializeQmdRuntimeModel();
|
|
21977
|
+
const [{ createStore }, model] = await Promise.all([loadQmd(), initializeQmdRuntimeModel()]);
|
|
21947
21978
|
if (memoryStore) return memoryStore;
|
|
21948
21979
|
if (memoryStorePromise) return memoryStorePromise;
|
|
21949
21980
|
memoryStorePromise = createStore({
|
|
@@ -21982,7 +22013,7 @@ async function getMemoryStore() {
|
|
|
21982
22013
|
async function getNotesStore() {
|
|
21983
22014
|
if (notesStore) return notesStore;
|
|
21984
22015
|
if (!notesStorePromise) {
|
|
21985
|
-
const model = await initializeQmdRuntimeModel();
|
|
22016
|
+
const [{ createStore }, model] = await Promise.all([loadQmd(), initializeQmdRuntimeModel()]);
|
|
21986
22017
|
if (notesStore) return notesStore;
|
|
21987
22018
|
if (notesStorePromise) return notesStorePromise;
|
|
21988
22019
|
notesStorePromise = createStore({
|
|
@@ -22015,7 +22046,7 @@ async function getNotesStore() {
|
|
|
22015
22046
|
async function getTaskStore() {
|
|
22016
22047
|
if (taskStore) return taskStore;
|
|
22017
22048
|
if (!taskStorePromise) {
|
|
22018
|
-
const model = await initializeQmdRuntimeModel();
|
|
22049
|
+
const [{ createStore }, model] = await Promise.all([loadQmd(), initializeQmdRuntimeModel()]);
|
|
22019
22050
|
if (taskStore) return taskStore;
|
|
22020
22051
|
if (taskStorePromise) return taskStorePromise;
|
|
22021
22052
|
taskStorePromise = createStore({
|
|
@@ -22040,7 +22071,7 @@ async function getTaskStore() {
|
|
|
22040
22071
|
async function getSessionStore() {
|
|
22041
22072
|
if (sessionStore) return sessionStore;
|
|
22042
22073
|
if (!sessionStorePromise) {
|
|
22043
|
-
const model = await initializeQmdRuntimeModel();
|
|
22074
|
+
const [{ createStore }, model] = await Promise.all([loadQmd(), initializeQmdRuntimeModel()]);
|
|
22044
22075
|
if (sessionStore) return sessionStore;
|
|
22045
22076
|
if (sessionStorePromise) return sessionStorePromise;
|
|
22046
22077
|
sessionStorePromise = createStore({
|
|
@@ -22183,7 +22214,7 @@ async function closeQmdStores() {
|
|
|
22183
22214
|
taskStorePromise = null;
|
|
22184
22215
|
sessionStorePromise = null;
|
|
22185
22216
|
}
|
|
22186
|
-
var KNOWN_QMD_MODEL_DIMENSIONS, EMBED_RUN_TABLE, QMD_DB_FILES, memoryStore, memoryStorePromise, notesStore, notesStorePromise, taskStore, taskStorePromise, sessionStore, sessionStorePromise;
|
|
22217
|
+
var KNOWN_QMD_MODEL_DIMENSIONS, EMBED_RUN_TABLE, QMD_DB_FILES, qmdModulePromise, memoryStore, memoryStorePromise, notesStore, notesStorePromise, taskStore, taskStorePromise, sessionStore, sessionStorePromise;
|
|
22187
22218
|
var init_qmd_store = __esm({
|
|
22188
22219
|
"src/core/qmd-store.ts"() {
|
|
22189
22220
|
"use strict";
|
|
@@ -22203,6 +22234,7 @@ var init_qmd_store = __esm({
|
|
|
22203
22234
|
"task-search.sqlite",
|
|
22204
22235
|
"session-search.sqlite"
|
|
22205
22236
|
];
|
|
22237
|
+
qmdModulePromise = null;
|
|
22206
22238
|
memoryStore = null;
|
|
22207
22239
|
memoryStorePromise = null;
|
|
22208
22240
|
notesStore = null;
|
|
@@ -31324,7 +31356,6 @@ __export(qmd_maintenance_exports, {
|
|
|
31324
31356
|
rebuildQmdCorpus: () => rebuildQmdCorpus,
|
|
31325
31357
|
runQmdIncrementalWork: () => runQmdIncrementalWork
|
|
31326
31358
|
});
|
|
31327
|
-
import { Maintenance } from "@tobilu/qmd";
|
|
31328
31359
|
async function rebuildQmdCorpus(options = {}) {
|
|
31329
31360
|
const onProgress = options.onProgress;
|
|
31330
31361
|
if (options.initialize) {
|
|
@@ -31414,7 +31445,7 @@ async function runQmdIncrementalWork(work, options = {}) {
|
|
|
31414
31445
|
});
|
|
31415
31446
|
}
|
|
31416
31447
|
}
|
|
31417
|
-
function compactQmdStoreIfNeeded(store3, label) {
|
|
31448
|
+
async function compactQmdStoreIfNeeded(store3, label) {
|
|
31418
31449
|
const db5 = store3.internal.db;
|
|
31419
31450
|
const pageCount = db5.pragma("page_count", { simple: true });
|
|
31420
31451
|
const freePages = db5.pragma("freelist_count", { simple: true });
|
|
@@ -31426,6 +31457,7 @@ function compactQmdStoreIfNeeded(store3, label) {
|
|
|
31426
31457
|
return null;
|
|
31427
31458
|
}
|
|
31428
31459
|
const startedAt = Date.now();
|
|
31460
|
+
const { Maintenance } = await import("@tobilu/qmd");
|
|
31429
31461
|
new Maintenance(store3.internal).vacuum();
|
|
31430
31462
|
const afterBytes = db5.pragma("page_count", { simple: true }) * pageSize;
|
|
31431
31463
|
const stats = {
|
|
@@ -31457,7 +31489,7 @@ async function cleanupQmdCorpus(options = {}) {
|
|
|
31457
31489
|
const cleanup = cleanupOrphanedQmdData(store3);
|
|
31458
31490
|
if (!options.compact) return cleanup;
|
|
31459
31491
|
try {
|
|
31460
|
-
const compaction = compactQmdStoreIfNeeded(store3, name);
|
|
31492
|
+
const compaction = await compactQmdStoreIfNeeded(store3, name);
|
|
31461
31493
|
return compaction ? { ...cleanup, compaction } : cleanup;
|
|
31462
31494
|
} catch (error) {
|
|
31463
31495
|
log.memory.warn("QMD store compaction failed", {
|
|
@@ -101421,7 +101453,7 @@ ${trimmed.slice(0, 500)}`
|
|
|
101421
101453
|
const startDate = snap(validLocalDueDate(parsed.start_date));
|
|
101422
101454
|
if (startDate) output.start_date = startDate;
|
|
101423
101455
|
const endDate = snap(validLocalDueDate(parsed.end_date));
|
|
101424
|
-
if (endDate && startDate) output.end_date = endDate;
|
|
101456
|
+
if (endDate && startDate && endDate > startDate) output.end_date = endDate;
|
|
101425
101457
|
if (parsed.pinTier === "focus" || parsed.pinTier === "satellite" || parsed.pinTier === "backlog" || parsed.pinTier === "wait") {
|
|
101426
101458
|
output.pinTier = parsed.pinTier;
|
|
101427
101459
|
} else if (typeof parsed.pinTier === "string" && opts.customTiers?.length) {
|
|
@@ -133367,6 +133399,8 @@ async function startServer(options = {}) {
|
|
|
133367
133399
|
log.memory.info("QMD search disabled via WALNUT_DISABLE_SEARCH=1 \u2014 skipping embedding model init");
|
|
133368
133400
|
} else if (CLOUD_MODE) {
|
|
133369
133401
|
log.memory.info("cloud mode: skipping QMD semantic index init");
|
|
133402
|
+
} else if (!await (await Promise.resolve().then(() => (init_qmd_store(), qmd_store_exports))).isQmdAvailable()) {
|
|
133403
|
+
log.memory.warn("QMD semantic search unavailable on this host (optional dependency not installed) \u2014 keyword search only");
|
|
133370
133404
|
} else try {
|
|
133371
133405
|
const { startQmdWatcher: startQmdWatcher2 } = await Promise.resolve().then(() => (init_qmd_watcher(), qmd_watcher_exports));
|
|
133372
133406
|
const {
|
|
@@ -1794,12 +1794,31 @@ __export(qmd_store_exports, {
|
|
|
1794
1794
|
getSessionStore: () => getSessionStore,
|
|
1795
1795
|
getTaskStore: () => getTaskStore,
|
|
1796
1796
|
initQmdStores: () => initQmdStores,
|
|
1797
|
+
isQmdAvailable: () => isQmdAvailable,
|
|
1797
1798
|
qmdStoresRequireModelReset: () => qmdStoresRequireModelReset
|
|
1798
1799
|
});
|
|
1799
|
-
import { createStore } from "@tobilu/qmd";
|
|
1800
1800
|
import Database from "better-sqlite3";
|
|
1801
1801
|
import fs5 from "fs";
|
|
1802
1802
|
import path4 from "path";
|
|
1803
|
+
async function loadQmd() {
|
|
1804
|
+
if (!qmdModulePromise) {
|
|
1805
|
+
qmdModulePromise = import("@tobilu/qmd").catch((err2) => {
|
|
1806
|
+
qmdModulePromise = null;
|
|
1807
|
+
throw new Error(
|
|
1808
|
+
`semantic search unavailable: @tobilu/qmd failed to load (${err2 instanceof Error ? err2.message : err2}). This host may lack glibc \u2265 2.28 or the optional dependency was skipped at install.`
|
|
1809
|
+
);
|
|
1810
|
+
});
|
|
1811
|
+
}
|
|
1812
|
+
return qmdModulePromise;
|
|
1813
|
+
}
|
|
1814
|
+
async function isQmdAvailable() {
|
|
1815
|
+
try {
|
|
1816
|
+
await loadQmd();
|
|
1817
|
+
return true;
|
|
1818
|
+
} catch {
|
|
1819
|
+
return false;
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1803
1822
|
function qmdStoresRequireModelReset(currentModel) {
|
|
1804
1823
|
const expectedDimensions = KNOWN_QMD_MODEL_DIMENSIONS[currentModel];
|
|
1805
1824
|
for (const filename of QMD_DB_FILES) {
|
|
@@ -1950,7 +1969,7 @@ async function embedQmdStore(store3, label, options) {
|
|
|
1950
1969
|
async function getMemoryStore() {
|
|
1951
1970
|
if (memoryStore) return memoryStore;
|
|
1952
1971
|
if (!memoryStorePromise) {
|
|
1953
|
-
const model = await initializeQmdRuntimeModel();
|
|
1972
|
+
const [{ createStore }, model] = await Promise.all([loadQmd(), initializeQmdRuntimeModel()]);
|
|
1954
1973
|
if (memoryStore) return memoryStore;
|
|
1955
1974
|
if (memoryStorePromise) return memoryStorePromise;
|
|
1956
1975
|
memoryStorePromise = createStore({
|
|
@@ -1989,7 +2008,7 @@ async function getMemoryStore() {
|
|
|
1989
2008
|
async function getNotesStore() {
|
|
1990
2009
|
if (notesStore) return notesStore;
|
|
1991
2010
|
if (!notesStorePromise) {
|
|
1992
|
-
const model = await initializeQmdRuntimeModel();
|
|
2011
|
+
const [{ createStore }, model] = await Promise.all([loadQmd(), initializeQmdRuntimeModel()]);
|
|
1993
2012
|
if (notesStore) return notesStore;
|
|
1994
2013
|
if (notesStorePromise) return notesStorePromise;
|
|
1995
2014
|
notesStorePromise = createStore({
|
|
@@ -2022,7 +2041,7 @@ async function getNotesStore() {
|
|
|
2022
2041
|
async function getTaskStore() {
|
|
2023
2042
|
if (taskStore) return taskStore;
|
|
2024
2043
|
if (!taskStorePromise) {
|
|
2025
|
-
const model = await initializeQmdRuntimeModel();
|
|
2044
|
+
const [{ createStore }, model] = await Promise.all([loadQmd(), initializeQmdRuntimeModel()]);
|
|
2026
2045
|
if (taskStore) return taskStore;
|
|
2027
2046
|
if (taskStorePromise) return taskStorePromise;
|
|
2028
2047
|
taskStorePromise = createStore({
|
|
@@ -2047,7 +2066,7 @@ async function getTaskStore() {
|
|
|
2047
2066
|
async function getSessionStore() {
|
|
2048
2067
|
if (sessionStore) return sessionStore;
|
|
2049
2068
|
if (!sessionStorePromise) {
|
|
2050
|
-
const model = await initializeQmdRuntimeModel();
|
|
2069
|
+
const [{ createStore }, model] = await Promise.all([loadQmd(), initializeQmdRuntimeModel()]);
|
|
2051
2070
|
if (sessionStore) return sessionStore;
|
|
2052
2071
|
if (sessionStorePromise) return sessionStorePromise;
|
|
2053
2072
|
sessionStorePromise = createStore({
|
|
@@ -2190,7 +2209,7 @@ async function closeQmdStores() {
|
|
|
2190
2209
|
taskStorePromise = null;
|
|
2191
2210
|
sessionStorePromise = null;
|
|
2192
2211
|
}
|
|
2193
|
-
var KNOWN_QMD_MODEL_DIMENSIONS, EMBED_RUN_TABLE, QMD_DB_FILES, memoryStore, memoryStorePromise, notesStore, notesStorePromise, taskStore, taskStorePromise, sessionStore, sessionStorePromise;
|
|
2212
|
+
var KNOWN_QMD_MODEL_DIMENSIONS, EMBED_RUN_TABLE, QMD_DB_FILES, qmdModulePromise, memoryStore, memoryStorePromise, notesStore, notesStorePromise, taskStore, taskStorePromise, sessionStore, sessionStorePromise;
|
|
2194
2213
|
var init_qmd_store = __esm({
|
|
2195
2214
|
"src/core/qmd-store.ts"() {
|
|
2196
2215
|
"use strict";
|
|
@@ -2210,6 +2229,7 @@ var init_qmd_store = __esm({
|
|
|
2210
2229
|
"task-search.sqlite",
|
|
2211
2230
|
"session-search.sqlite"
|
|
2212
2231
|
];
|
|
2232
|
+
qmdModulePromise = null;
|
|
2213
2233
|
memoryStore = null;
|
|
2214
2234
|
memoryStorePromise = null;
|
|
2215
2235
|
notesStore = null;
|
|
@@ -7771,9 +7791,11 @@ const SESSION_IDLE_KILL_MS = 2 * 60 * 60 * 1000; // 2 hours
|
|
|
7771
7791
|
const SESSION_CRON_IDLE_KILL_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
7772
7792
|
// Sessions with a running background task: wait-style bash tasks write to
|
|
7773
7793
|
// output_file, not the JSONL, so the session looks idle for the task's whole
|
|
7774
|
-
// lifetime (incident inc-1786222771315).
|
|
7775
|
-
//
|
|
7776
|
-
|
|
7794
|
+
// lifetime (incident inc-1786222771315). PRINCIPLE: never reap running bg
|
|
7795
|
+
// work \u2014 this 3-day cap exists only for a wedged task framework that will
|
|
7796
|
+
// never emit a terminal event (immortal-process backstop). See
|
|
7797
|
+
// daemon-standalone.ts for the full rationale.
|
|
7798
|
+
const SESSION_BG_IDLE_KILL_MS = 3 * 24 * 60 * 60 * 1000; // 3 days
|
|
7777
7799
|
const SESSION_SCAN_INTERVAL_MS = 60000; // every 60s
|
|
7778
7800
|
|
|
7779
7801
|
// Last-resort cron evidence: the CLI scheduler's own debug log in HOME
|
|
@@ -13151,6 +13173,16 @@ var init_acp_session = __esm({
|
|
|
13151
13173
|
...configId === "model" ? { acpModel: value } : {},
|
|
13152
13174
|
acpConfig: { ...record?.acpConfig ?? this.cfg.acpConfig ?? {}, [configId]: value }
|
|
13153
13175
|
});
|
|
13176
|
+
if (configId === "mode" && value === "agent-full-access" && this._pendingPermissions.size > 0) {
|
|
13177
|
+
const pending2 = [...this._pendingPermissions.keys()];
|
|
13178
|
+
log.session.info("acp: full access selected \u2014 auto-allowing pending permissions", {
|
|
13179
|
+
sessionId: this.trackingId(),
|
|
13180
|
+
requestIds: pending2
|
|
13181
|
+
});
|
|
13182
|
+
for (const requestId of pending2) {
|
|
13183
|
+
await this.resolvePermissionRequest(requestId, true).catch(() => false);
|
|
13184
|
+
}
|
|
13185
|
+
}
|
|
13154
13186
|
return true;
|
|
13155
13187
|
}
|
|
13156
13188
|
/** Switch the model for the next Codex turn through standard ACP config.
|
|
@@ -96905,7 +96937,6 @@ __export(qmd_maintenance_exports, {
|
|
|
96905
96937
|
rebuildQmdCorpus: () => rebuildQmdCorpus,
|
|
96906
96938
|
runQmdIncrementalWork: () => runQmdIncrementalWork
|
|
96907
96939
|
});
|
|
96908
|
-
import { Maintenance } from "@tobilu/qmd";
|
|
96909
96940
|
async function rebuildQmdCorpus(options = {}) {
|
|
96910
96941
|
const onProgress = options.onProgress;
|
|
96911
96942
|
if (options.initialize) {
|
|
@@ -96995,7 +97026,7 @@ async function runQmdIncrementalWork(work, options = {}) {
|
|
|
96995
97026
|
});
|
|
96996
97027
|
}
|
|
96997
97028
|
}
|
|
96998
|
-
function compactQmdStoreIfNeeded(store3, label) {
|
|
97029
|
+
async function compactQmdStoreIfNeeded(store3, label) {
|
|
96999
97030
|
const db4 = store3.internal.db;
|
|
97000
97031
|
const pageCount = db4.pragma("page_count", { simple: true });
|
|
97001
97032
|
const freePages = db4.pragma("freelist_count", { simple: true });
|
|
@@ -97007,6 +97038,7 @@ function compactQmdStoreIfNeeded(store3, label) {
|
|
|
97007
97038
|
return null;
|
|
97008
97039
|
}
|
|
97009
97040
|
const startedAt = Date.now();
|
|
97041
|
+
const { Maintenance } = await import("@tobilu/qmd");
|
|
97010
97042
|
new Maintenance(store3.internal).vacuum();
|
|
97011
97043
|
const afterBytes = db4.pragma("page_count", { simple: true }) * pageSize;
|
|
97012
97044
|
const stats = {
|
|
@@ -97038,7 +97070,7 @@ async function cleanupQmdCorpus(options = {}) {
|
|
|
97038
97070
|
const cleanup = cleanupOrphanedQmdData(store3);
|
|
97039
97071
|
if (!options.compact) return cleanup;
|
|
97040
97072
|
try {
|
|
97041
|
-
const compaction = compactQmdStoreIfNeeded(store3, name);
|
|
97073
|
+
const compaction = await compactQmdStoreIfNeeded(store3, name);
|
|
97042
97074
|
return compaction ? { ...cleanup, compaction } : cleanup;
|
|
97043
97075
|
} catch (error) {
|
|
97044
97076
|
log.memory.warn("QMD store compaction failed", {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "open-walnut",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "Personal AI butler powered by Claude — task management, Claude Code sessions, memory system, and web UI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/EvanZhang008/open-walnut",
|
|
@@ -92,11 +92,9 @@
|
|
|
92
92
|
"@aws-sdk/client-sts": "^3.996.0",
|
|
93
93
|
"@azure/msal-node": "^5.0.3",
|
|
94
94
|
"@google/generative-ai": "^0.24.1",
|
|
95
|
-
"@homebridge/node-pty-prebuilt-multiarch": "^0.12.0",
|
|
96
95
|
"@mozilla/readability": "^0.6.0",
|
|
97
96
|
"@slack/web-api": "^7.14.0",
|
|
98
97
|
"@tiptap/extension-image": "^3.20.1",
|
|
99
|
-
"@tobilu/qmd": "2.1.0",
|
|
100
98
|
"better-sqlite3": "^12.6.2",
|
|
101
99
|
"chalk": "^5.4.1",
|
|
102
100
|
"commander": "^14.0.0",
|
|
@@ -115,6 +113,8 @@
|
|
|
115
113
|
"ws": "^8.19.0"
|
|
116
114
|
},
|
|
117
115
|
"optionalDependencies": {
|
|
116
|
+
"@homebridge/node-pty-prebuilt-multiarch": "^0.12.0",
|
|
117
|
+
"@tobilu/qmd": "2.1.0",
|
|
118
118
|
"screencapturekit-audio-capture": "^1.3.6"
|
|
119
119
|
},
|
|
120
120
|
"devDependencies": {
|