@goondocks/myco 0.3.7 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +9 -4
- package/commands/init.md +63 -39
- package/commands/setup-llm.md +69 -44
- package/commands/status.md +28 -10
- package/dist/{chunk-YFG2O5HR.js → chunk-2GJFTIWX.js} +2 -2
- package/dist/chunk-4FCFRJIQ.js +147 -0
- package/dist/chunk-4FCFRJIQ.js.map +1 -0
- package/dist/{chunk-PA3VMINE.js → chunk-AK6GNLPV.js} +6 -1
- package/dist/chunk-AK6GNLPV.js.map +1 -0
- package/dist/{chunk-JKOALBZC.js → chunk-BNIYWCST.js} +2 -2
- package/dist/{chunk-ISCT2SI6.js → chunk-G6ZMTQMJ.js} +7357 -60
- package/dist/chunk-G6ZMTQMJ.js.map +1 -0
- package/dist/{chunk-7WNE22W7.js → chunk-IVS5MYBL.js} +3 -3
- package/dist/{chunk-7WNE22W7.js.map → chunk-IVS5MYBL.js.map} +1 -1
- package/dist/{chunk-7VPJK56U.js → chunk-JBD5KP5G.js} +31 -16
- package/dist/chunk-JBD5KP5G.js.map +1 -0
- package/dist/chunk-NUA7UTIY.js +37 -0
- package/dist/chunk-NUA7UTIY.js.map +1 -0
- package/dist/{chunk-NYAWCMRZ.js → chunk-OUFSLZTX.js} +4 -4
- package/dist/chunk-P7RNAYU7.js +242 -0
- package/dist/chunk-P7RNAYU7.js.map +1 -0
- package/dist/chunk-QQ36XEJP.js +38 -0
- package/dist/chunk-QQ36XEJP.js.map +1 -0
- package/dist/chunk-RDXTQ436.js +49 -0
- package/dist/chunk-RDXTQ436.js.map +1 -0
- package/dist/{chunk-AWF3M57N.js → chunk-S7EIHYE7.js} +8 -8
- package/dist/{chunk-AWF3M57N.js.map → chunk-S7EIHYE7.js.map} +1 -1
- package/dist/{chunk-QWU7QLZI.js → chunk-TZDDXRHG.js} +10 -10
- package/dist/chunk-TZDDXRHG.js.map +1 -0
- package/dist/chunk-VYV5IFD6.js +99 -0
- package/dist/chunk-VYV5IFD6.js.map +1 -0
- package/dist/{chunk-LR7RQCOB.js → chunk-XCPQHC4X.js} +2 -2
- package/dist/{chunk-CCIV47S4.js → chunk-XHWIIU5D.js} +8 -9
- package/dist/chunk-XHWIIU5D.js.map +1 -0
- package/dist/{chunk-FFQNE6CT.js → chunk-YZO22BBI.js} +45 -31
- package/dist/chunk-YZO22BBI.js.map +1 -0
- package/dist/{chunk-ZBNT6E22.js → chunk-ZCBL5HER.js} +2 -2
- package/dist/{cli-3WQSDSW6.js → cli-ZN6VBA7V.js} +23 -17
- package/dist/cli-ZN6VBA7V.js.map +1 -0
- package/dist/{client-5T4M42UQ.js → client-5SUO2UYH.js} +5 -5
- package/dist/{config-MD4XMLUS.js → config-4GGMWGAF.js} +4 -4
- package/dist/{detect-providers-LNOLBICR.js → detect-providers-5FU3BN5Q.js} +3 -3
- package/dist/{init-RALMQKOQ.js → init-7UXGDOFS.js} +51 -60
- package/dist/init-7UXGDOFS.js.map +1 -0
- package/dist/{main-S3WSUF5T.js → main-6UPAIDGS.js} +648 -228
- package/dist/main-6UPAIDGS.js.map +1 -0
- package/dist/{rebuild-JW6BCHHZ.js → rebuild-QDSYYCS7.js} +10 -10
- package/dist/rebuild-QDSYYCS7.js.map +1 -0
- package/dist/{reprocess-SNXFNKBN.js → reprocess-ZNUQCIS3.js} +18 -18
- package/dist/reprocess-ZNUQCIS3.js.map +1 -0
- package/dist/{restart-YE2IGOYT.js → restart-5UY2KV54.js} +6 -6
- package/dist/{search-2HMG3ON7.js → search-2VEN3XIG.js} +9 -9
- package/dist/{server-JM3TM7D2.js → server-OR5B4B7K.js} +77 -54
- package/dist/{server-JM3TM7D2.js.map → server-OR5B4B7K.js.map} +1 -1
- package/dist/{session-5GI2YU6R.js → session-QF6MILAC.js} +2 -2
- package/dist/{session-start-2UEEEO52.js → session-start-TUITIUMB.js} +29 -28
- package/dist/session-start-TUITIUMB.js.map +1 -0
- package/dist/setup-digest-ETCZAUIU.js +15 -0
- package/dist/setup-llm-DWEJE3JE.js +15 -0
- package/dist/setup-llm-DWEJE3JE.js.map +1 -0
- package/dist/src/cli.js +4 -4
- package/dist/src/daemon/main.js +4 -4
- package/dist/src/hooks/post-tool-use.js +5 -5
- package/dist/src/hooks/session-end.js +5 -5
- package/dist/src/hooks/session-start.js +4 -4
- package/dist/src/hooks/stop.js +7 -7
- package/dist/src/hooks/user-prompt-submit.js +5 -5
- package/dist/src/hooks/user-prompt-submit.js.map +1 -1
- package/dist/src/mcp/server.js +4 -4
- package/dist/src/prompts/classification.md +1 -0
- package/dist/src/prompts/digest-10000.md +74 -0
- package/dist/src/prompts/digest-1500.md +25 -0
- package/dist/src/prompts/digest-3000.md +32 -0
- package/dist/src/prompts/digest-5000.md +43 -0
- package/dist/src/prompts/digest-system.md +32 -0
- package/dist/src/prompts/extraction.md +11 -10
- package/dist/src/prompts/summary.md +11 -1
- package/dist/src/prompts/title.md +1 -1
- package/dist/{stats-IOWXG576.js → stats-IVIXIKTS.js} +12 -12
- package/dist/stats-IVIXIKTS.js.map +1 -0
- package/dist/{verify-7MWOV72E.js → verify-4H6CEE5T.js} +6 -6
- package/dist/{version-S7MHLD5P.js → version-5B2TWXQJ.js} +4 -4
- package/dist/version-5B2TWXQJ.js.map +1 -0
- package/package.json +1 -1
- package/skills/myco/SKILL.md +20 -20
- package/skills/myco/references/wisdom.md +14 -14
- package/skills/rules/SKILL.md +4 -4
- package/dist/chunk-7VPJK56U.js.map +0 -1
- package/dist/chunk-BA23DROX.js +0 -160
- package/dist/chunk-BA23DROX.js.map +0 -1
- package/dist/chunk-CCIV47S4.js.map +0 -1
- package/dist/chunk-EF4JVH24.js +0 -7299
- package/dist/chunk-EF4JVH24.js.map +0 -1
- package/dist/chunk-FFQNE6CT.js.map +0 -1
- package/dist/chunk-ISCT2SI6.js.map +0 -1
- package/dist/chunk-PA3VMINE.js.map +0 -1
- package/dist/chunk-QWU7QLZI.js.map +0 -1
- package/dist/chunk-YMYJ7FNH.js +0 -19
- package/dist/chunk-YMYJ7FNH.js.map +0 -1
- package/dist/cli-3WQSDSW6.js.map +0 -1
- package/dist/init-RALMQKOQ.js.map +0 -1
- package/dist/main-S3WSUF5T.js.map +0 -1
- package/dist/rebuild-JW6BCHHZ.js.map +0 -1
- package/dist/reprocess-SNXFNKBN.js.map +0 -1
- package/dist/session-start-2UEEEO52.js.map +0 -1
- package/dist/stats-IOWXG576.js.map +0 -1
- /package/dist/{chunk-YFG2O5HR.js.map → chunk-2GJFTIWX.js.map} +0 -0
- /package/dist/{chunk-JKOALBZC.js.map → chunk-BNIYWCST.js.map} +0 -0
- /package/dist/{chunk-NYAWCMRZ.js.map → chunk-OUFSLZTX.js.map} +0 -0
- /package/dist/{chunk-LR7RQCOB.js.map → chunk-XCPQHC4X.js.map} +0 -0
- /package/dist/{chunk-ZBNT6E22.js.map → chunk-ZCBL5HER.js.map} +0 -0
- /package/dist/{client-5T4M42UQ.js.map → client-5SUO2UYH.js.map} +0 -0
- /package/dist/{config-MD4XMLUS.js.map → config-4GGMWGAF.js.map} +0 -0
- /package/dist/{detect-providers-LNOLBICR.js.map → detect-providers-5FU3BN5Q.js.map} +0 -0
- /package/dist/{restart-YE2IGOYT.js.map → restart-5UY2KV54.js.map} +0 -0
- /package/dist/{search-2HMG3ON7.js.map → search-2VEN3XIG.js.map} +0 -0
- /package/dist/{session-5GI2YU6R.js.map → session-QF6MILAC.js.map} +0 -0
- /package/dist/{version-S7MHLD5P.js.map → setup-digest-ETCZAUIU.js.map} +0 -0
- /package/dist/{verify-7MWOV72E.js.map → verify-4H6CEE5T.js.map} +0 -0
|
@@ -5,8 +5,16 @@ import {
|
|
|
5
5
|
buildSimilarityPrompt,
|
|
6
6
|
extractNumber,
|
|
7
7
|
extractTurnsFromBuffer,
|
|
8
|
+
loadPrompt,
|
|
9
|
+
stripReasoningTokens,
|
|
8
10
|
writeObservationNotes
|
|
9
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-YZO22BBI.js";
|
|
12
|
+
import {
|
|
13
|
+
handleMycoContext
|
|
14
|
+
} from "./chunk-RDXTQ436.js";
|
|
15
|
+
import {
|
|
16
|
+
DaemonLogger
|
|
17
|
+
} from "./chunk-5EZ7QF6J.js";
|
|
10
18
|
import {
|
|
11
19
|
VaultWriter,
|
|
12
20
|
bareSessionId,
|
|
@@ -14,64 +22,69 @@ import {
|
|
|
14
22
|
sessionNoteId,
|
|
15
23
|
sessionRelativePath,
|
|
16
24
|
sessionWikilink
|
|
17
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-TZDDXRHG.js";
|
|
18
26
|
import {
|
|
19
27
|
indexNote,
|
|
20
28
|
rebuildIndex
|
|
21
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-S7EIHYE7.js";
|
|
22
30
|
import {
|
|
23
31
|
generateEmbedding
|
|
24
32
|
} from "./chunk-RGVBGTD6.js";
|
|
33
|
+
import {
|
|
34
|
+
createEmbeddingProvider,
|
|
35
|
+
createLlmProvider
|
|
36
|
+
} from "./chunk-IVS5MYBL.js";
|
|
25
37
|
import {
|
|
26
38
|
VectorIndex
|
|
27
39
|
} from "./chunk-XQXXF6MU.js";
|
|
28
40
|
import {
|
|
29
|
-
|
|
30
|
-
} from "./chunk-
|
|
41
|
+
stripFrontmatter
|
|
42
|
+
} from "./chunk-NUA7UTIY.js";
|
|
31
43
|
import {
|
|
32
44
|
initFts
|
|
33
45
|
} from "./chunk-6FQISQNA.js";
|
|
34
46
|
import {
|
|
35
47
|
MycoIndex
|
|
36
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-AK6GNLPV.js";
|
|
49
|
+
import "./chunk-P7RNAYU7.js";
|
|
37
50
|
import {
|
|
38
|
-
createEmbeddingProvider,
|
|
39
|
-
createLlmProvider
|
|
40
|
-
} from "./chunk-7WNE22W7.js";
|
|
41
|
-
import "./chunk-BA23DROX.js";
|
|
42
|
-
import {
|
|
43
|
-
external_exports,
|
|
44
51
|
loadConfig
|
|
45
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-QQ36XEJP.js";
|
|
46
53
|
import {
|
|
54
|
+
external_exports,
|
|
47
55
|
require_dist
|
|
48
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-G6ZMTQMJ.js";
|
|
49
57
|
import {
|
|
50
58
|
EventBuffer
|
|
51
59
|
} from "./chunk-HIN3UVOG.js";
|
|
52
60
|
import {
|
|
53
61
|
getPluginVersion
|
|
54
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-2GJFTIWX.js";
|
|
55
63
|
import {
|
|
56
64
|
claudeCodeAdapter,
|
|
57
65
|
createPerProjectAdapter,
|
|
58
66
|
extensionForMimeType
|
|
59
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-BNIYWCST.js";
|
|
60
68
|
import {
|
|
61
69
|
CANDIDATE_CONTENT_PREVIEW,
|
|
70
|
+
CHARS_PER_TOKEN,
|
|
62
71
|
CONTENT_SNIPPET_CHARS,
|
|
63
72
|
CONTEXT_SESSION_PREVIEW_CHARS,
|
|
73
|
+
DIGEST_LLM_REQUEST_TIMEOUT_MS,
|
|
74
|
+
DIGEST_SUBSTRATE_TYPE_WEIGHTS,
|
|
75
|
+
DIGEST_TIER_MIN_CONTEXT,
|
|
64
76
|
EMBEDDING_INPUT_LIMIT,
|
|
65
77
|
FILE_WATCH_STABILITY_MS,
|
|
66
78
|
LINEAGE_RECENT_SESSIONS_LIMIT,
|
|
67
79
|
MAX_SLUG_LENGTH,
|
|
68
|
-
|
|
80
|
+
PROMPT_CONTEXT_MAX_SPORES,
|
|
69
81
|
PROMPT_CONTEXT_MIN_LENGTH,
|
|
70
82
|
PROMPT_CONTEXT_MIN_SIMILARITY,
|
|
71
|
-
|
|
83
|
+
RELATED_SPORES_LIMIT,
|
|
72
84
|
SESSION_CONTEXT_MAX_PLANS,
|
|
73
|
-
STALE_BUFFER_MAX_AGE_MS
|
|
74
|
-
|
|
85
|
+
STALE_BUFFER_MAX_AGE_MS,
|
|
86
|
+
estimateTokens
|
|
87
|
+
} from "./chunk-JBD5KP5G.js";
|
|
75
88
|
import {
|
|
76
89
|
__toESM
|
|
77
90
|
} from "./chunk-PZUWP5VK.js";
|
|
@@ -483,7 +496,7 @@ var ReaddirpStream = class extends Readable {
|
|
|
483
496
|
this._directoryFilter = normalizeFilter(opts.directoryFilter);
|
|
484
497
|
const statMethod = opts.lstat ? lstat : stat;
|
|
485
498
|
if (wantBigintFsStats) {
|
|
486
|
-
this._stat = (
|
|
499
|
+
this._stat = (path8) => statMethod(path8, { bigint: true });
|
|
487
500
|
} else {
|
|
488
501
|
this._stat = statMethod;
|
|
489
502
|
}
|
|
@@ -508,8 +521,8 @@ var ReaddirpStream = class extends Readable {
|
|
|
508
521
|
const par = this.parent;
|
|
509
522
|
const fil = par && par.files;
|
|
510
523
|
if (fil && fil.length > 0) {
|
|
511
|
-
const { path:
|
|
512
|
-
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent,
|
|
524
|
+
const { path: path8, depth } = par;
|
|
525
|
+
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path8));
|
|
513
526
|
const awaited = await Promise.all(slice);
|
|
514
527
|
for (const entry of awaited) {
|
|
515
528
|
if (!entry)
|
|
@@ -549,20 +562,20 @@ var ReaddirpStream = class extends Readable {
|
|
|
549
562
|
this.reading = false;
|
|
550
563
|
}
|
|
551
564
|
}
|
|
552
|
-
async _exploreDir(
|
|
565
|
+
async _exploreDir(path8, depth) {
|
|
553
566
|
let files;
|
|
554
567
|
try {
|
|
555
|
-
files = await readdir(
|
|
568
|
+
files = await readdir(path8, this._rdOptions);
|
|
556
569
|
} catch (error) {
|
|
557
570
|
this._onError(error);
|
|
558
571
|
}
|
|
559
|
-
return { files, depth, path:
|
|
572
|
+
return { files, depth, path: path8 };
|
|
560
573
|
}
|
|
561
|
-
async _formatEntry(dirent,
|
|
574
|
+
async _formatEntry(dirent, path8) {
|
|
562
575
|
let entry;
|
|
563
576
|
const basename3 = this._isDirent ? dirent.name : dirent;
|
|
564
577
|
try {
|
|
565
|
-
const fullPath = presolve(pjoin(
|
|
578
|
+
const fullPath = presolve(pjoin(path8, basename3));
|
|
566
579
|
entry = { path: prelative(this._root, fullPath), fullPath, basename: basename3 };
|
|
567
580
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
568
581
|
} catch (err) {
|
|
@@ -962,16 +975,16 @@ var delFromSet = (main2, prop, item) => {
|
|
|
962
975
|
};
|
|
963
976
|
var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
|
|
964
977
|
var FsWatchInstances = /* @__PURE__ */ new Map();
|
|
965
|
-
function createFsWatchInstance(
|
|
978
|
+
function createFsWatchInstance(path8, options, listener, errHandler, emitRaw) {
|
|
966
979
|
const handleEvent = (rawEvent, evPath) => {
|
|
967
|
-
listener(
|
|
968
|
-
emitRaw(rawEvent, evPath, { watchedPath:
|
|
969
|
-
if (evPath &&
|
|
970
|
-
fsWatchBroadcast(sp.resolve(
|
|
980
|
+
listener(path8);
|
|
981
|
+
emitRaw(rawEvent, evPath, { watchedPath: path8 });
|
|
982
|
+
if (evPath && path8 !== evPath) {
|
|
983
|
+
fsWatchBroadcast(sp.resolve(path8, evPath), KEY_LISTENERS, sp.join(path8, evPath));
|
|
971
984
|
}
|
|
972
985
|
};
|
|
973
986
|
try {
|
|
974
|
-
return fs_watch(
|
|
987
|
+
return fs_watch(path8, {
|
|
975
988
|
persistent: options.persistent
|
|
976
989
|
}, handleEvent);
|
|
977
990
|
} catch (error) {
|
|
@@ -987,12 +1000,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
|
|
|
987
1000
|
listener(val1, val2, val3);
|
|
988
1001
|
});
|
|
989
1002
|
};
|
|
990
|
-
var setFsWatchListener = (
|
|
1003
|
+
var setFsWatchListener = (path8, fullPath, options, handlers) => {
|
|
991
1004
|
const { listener, errHandler, rawEmitter } = handlers;
|
|
992
1005
|
let cont = FsWatchInstances.get(fullPath);
|
|
993
1006
|
let watcher;
|
|
994
1007
|
if (!options.persistent) {
|
|
995
|
-
watcher = createFsWatchInstance(
|
|
1008
|
+
watcher = createFsWatchInstance(path8, options, listener, errHandler, rawEmitter);
|
|
996
1009
|
if (!watcher)
|
|
997
1010
|
return;
|
|
998
1011
|
return watcher.close.bind(watcher);
|
|
@@ -1003,7 +1016,7 @@ var setFsWatchListener = (path7, fullPath, options, handlers) => {
|
|
|
1003
1016
|
addAndConvert(cont, KEY_RAW, rawEmitter);
|
|
1004
1017
|
} else {
|
|
1005
1018
|
watcher = createFsWatchInstance(
|
|
1006
|
-
|
|
1019
|
+
path8,
|
|
1007
1020
|
options,
|
|
1008
1021
|
fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
|
|
1009
1022
|
errHandler,
|
|
@@ -1018,7 +1031,7 @@ var setFsWatchListener = (path7, fullPath, options, handlers) => {
|
|
|
1018
1031
|
cont.watcherUnusable = true;
|
|
1019
1032
|
if (isWindows && error.code === "EPERM") {
|
|
1020
1033
|
try {
|
|
1021
|
-
const fd = await open(
|
|
1034
|
+
const fd = await open(path8, "r");
|
|
1022
1035
|
await fd.close();
|
|
1023
1036
|
broadcastErr(error);
|
|
1024
1037
|
} catch (err) {
|
|
@@ -1049,7 +1062,7 @@ var setFsWatchListener = (path7, fullPath, options, handlers) => {
|
|
|
1049
1062
|
};
|
|
1050
1063
|
};
|
|
1051
1064
|
var FsWatchFileInstances = /* @__PURE__ */ new Map();
|
|
1052
|
-
var setFsWatchFileListener = (
|
|
1065
|
+
var setFsWatchFileListener = (path8, fullPath, options, handlers) => {
|
|
1053
1066
|
const { listener, rawEmitter } = handlers;
|
|
1054
1067
|
let cont = FsWatchFileInstances.get(fullPath);
|
|
1055
1068
|
const copts = cont && cont.options;
|
|
@@ -1071,7 +1084,7 @@ var setFsWatchFileListener = (path7, fullPath, options, handlers) => {
|
|
|
1071
1084
|
});
|
|
1072
1085
|
const currmtime = curr.mtimeMs;
|
|
1073
1086
|
if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
|
|
1074
|
-
foreach(cont.listeners, (listener2) => listener2(
|
|
1087
|
+
foreach(cont.listeners, (listener2) => listener2(path8, curr));
|
|
1075
1088
|
}
|
|
1076
1089
|
})
|
|
1077
1090
|
};
|
|
@@ -1101,13 +1114,13 @@ var NodeFsHandler = class {
|
|
|
1101
1114
|
* @param listener on fs change
|
|
1102
1115
|
* @returns closer for the watcher instance
|
|
1103
1116
|
*/
|
|
1104
|
-
_watchWithNodeFs(
|
|
1117
|
+
_watchWithNodeFs(path8, listener) {
|
|
1105
1118
|
const opts = this.fsw.options;
|
|
1106
|
-
const directory = sp.dirname(
|
|
1107
|
-
const basename3 = sp.basename(
|
|
1119
|
+
const directory = sp.dirname(path8);
|
|
1120
|
+
const basename3 = sp.basename(path8);
|
|
1108
1121
|
const parent = this.fsw._getWatchedDir(directory);
|
|
1109
1122
|
parent.add(basename3);
|
|
1110
|
-
const absolutePath = sp.resolve(
|
|
1123
|
+
const absolutePath = sp.resolve(path8);
|
|
1111
1124
|
const options = {
|
|
1112
1125
|
persistent: opts.persistent
|
|
1113
1126
|
};
|
|
@@ -1117,12 +1130,12 @@ var NodeFsHandler = class {
|
|
|
1117
1130
|
if (opts.usePolling) {
|
|
1118
1131
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
1119
1132
|
options.interval = enableBin && isBinaryPath(basename3) ? opts.binaryInterval : opts.interval;
|
|
1120
|
-
closer = setFsWatchFileListener(
|
|
1133
|
+
closer = setFsWatchFileListener(path8, absolutePath, options, {
|
|
1121
1134
|
listener,
|
|
1122
1135
|
rawEmitter: this.fsw._emitRaw
|
|
1123
1136
|
});
|
|
1124
1137
|
} else {
|
|
1125
|
-
closer = setFsWatchListener(
|
|
1138
|
+
closer = setFsWatchListener(path8, absolutePath, options, {
|
|
1126
1139
|
listener,
|
|
1127
1140
|
errHandler: this._boundHandleError,
|
|
1128
1141
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -1144,7 +1157,7 @@ var NodeFsHandler = class {
|
|
|
1144
1157
|
let prevStats = stats;
|
|
1145
1158
|
if (parent.has(basename3))
|
|
1146
1159
|
return;
|
|
1147
|
-
const listener = async (
|
|
1160
|
+
const listener = async (path8, newStats) => {
|
|
1148
1161
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
|
|
1149
1162
|
return;
|
|
1150
1163
|
if (!newStats || newStats.mtimeMs === 0) {
|
|
@@ -1158,11 +1171,11 @@ var NodeFsHandler = class {
|
|
|
1158
1171
|
this.fsw._emit(EV.CHANGE, file, newStats2);
|
|
1159
1172
|
}
|
|
1160
1173
|
if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
|
|
1161
|
-
this.fsw._closeFile(
|
|
1174
|
+
this.fsw._closeFile(path8);
|
|
1162
1175
|
prevStats = newStats2;
|
|
1163
1176
|
const closer2 = this._watchWithNodeFs(file, listener);
|
|
1164
1177
|
if (closer2)
|
|
1165
|
-
this.fsw._addPathCloser(
|
|
1178
|
+
this.fsw._addPathCloser(path8, closer2);
|
|
1166
1179
|
} else {
|
|
1167
1180
|
prevStats = newStats2;
|
|
1168
1181
|
}
|
|
@@ -1194,7 +1207,7 @@ var NodeFsHandler = class {
|
|
|
1194
1207
|
* @param item basename of this item
|
|
1195
1208
|
* @returns true if no more processing is needed for this entry.
|
|
1196
1209
|
*/
|
|
1197
|
-
async _handleSymlink(entry, directory,
|
|
1210
|
+
async _handleSymlink(entry, directory, path8, item) {
|
|
1198
1211
|
if (this.fsw.closed) {
|
|
1199
1212
|
return;
|
|
1200
1213
|
}
|
|
@@ -1204,7 +1217,7 @@ var NodeFsHandler = class {
|
|
|
1204
1217
|
this.fsw._incrReadyCount();
|
|
1205
1218
|
let linkPath;
|
|
1206
1219
|
try {
|
|
1207
|
-
linkPath = await fsrealpath(
|
|
1220
|
+
linkPath = await fsrealpath(path8);
|
|
1208
1221
|
} catch (e) {
|
|
1209
1222
|
this.fsw._emitReady();
|
|
1210
1223
|
return true;
|
|
@@ -1214,12 +1227,12 @@ var NodeFsHandler = class {
|
|
|
1214
1227
|
if (dir.has(item)) {
|
|
1215
1228
|
if (this.fsw._symlinkPaths.get(full) !== linkPath) {
|
|
1216
1229
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
1217
|
-
this.fsw._emit(EV.CHANGE,
|
|
1230
|
+
this.fsw._emit(EV.CHANGE, path8, entry.stats);
|
|
1218
1231
|
}
|
|
1219
1232
|
} else {
|
|
1220
1233
|
dir.add(item);
|
|
1221
1234
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
1222
|
-
this.fsw._emit(EV.ADD,
|
|
1235
|
+
this.fsw._emit(EV.ADD, path8, entry.stats);
|
|
1223
1236
|
}
|
|
1224
1237
|
this.fsw._emitReady();
|
|
1225
1238
|
return true;
|
|
@@ -1249,9 +1262,9 @@ var NodeFsHandler = class {
|
|
|
1249
1262
|
return;
|
|
1250
1263
|
}
|
|
1251
1264
|
const item = entry.path;
|
|
1252
|
-
let
|
|
1265
|
+
let path8 = sp.join(directory, item);
|
|
1253
1266
|
current.add(item);
|
|
1254
|
-
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory,
|
|
1267
|
+
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path8, item)) {
|
|
1255
1268
|
return;
|
|
1256
1269
|
}
|
|
1257
1270
|
if (this.fsw.closed) {
|
|
@@ -1260,8 +1273,8 @@ var NodeFsHandler = class {
|
|
|
1260
1273
|
}
|
|
1261
1274
|
if (item === target || !target && !previous.has(item)) {
|
|
1262
1275
|
this.fsw._incrReadyCount();
|
|
1263
|
-
|
|
1264
|
-
this._addToNodeFs(
|
|
1276
|
+
path8 = sp.join(dir, sp.relative(dir, path8));
|
|
1277
|
+
this._addToNodeFs(path8, initialAdd, wh, depth + 1);
|
|
1265
1278
|
}
|
|
1266
1279
|
}).on(EV.ERROR, this._boundHandleError);
|
|
1267
1280
|
return new Promise((resolve3, reject) => {
|
|
@@ -1330,13 +1343,13 @@ var NodeFsHandler = class {
|
|
|
1330
1343
|
* @param depth Child path actually targeted for watch
|
|
1331
1344
|
* @param target Child path actually targeted for watch
|
|
1332
1345
|
*/
|
|
1333
|
-
async _addToNodeFs(
|
|
1346
|
+
async _addToNodeFs(path8, initialAdd, priorWh, depth, target) {
|
|
1334
1347
|
const ready = this.fsw._emitReady;
|
|
1335
|
-
if (this.fsw._isIgnored(
|
|
1348
|
+
if (this.fsw._isIgnored(path8) || this.fsw.closed) {
|
|
1336
1349
|
ready();
|
|
1337
1350
|
return false;
|
|
1338
1351
|
}
|
|
1339
|
-
const wh = this.fsw._getWatchHelpers(
|
|
1352
|
+
const wh = this.fsw._getWatchHelpers(path8);
|
|
1340
1353
|
if (priorWh) {
|
|
1341
1354
|
wh.filterPath = (entry) => priorWh.filterPath(entry);
|
|
1342
1355
|
wh.filterDir = (entry) => priorWh.filterDir(entry);
|
|
@@ -1352,8 +1365,8 @@ var NodeFsHandler = class {
|
|
|
1352
1365
|
const follow = this.fsw.options.followSymlinks;
|
|
1353
1366
|
let closer;
|
|
1354
1367
|
if (stats.isDirectory()) {
|
|
1355
|
-
const absPath = sp.resolve(
|
|
1356
|
-
const targetPath = follow ? await fsrealpath(
|
|
1368
|
+
const absPath = sp.resolve(path8);
|
|
1369
|
+
const targetPath = follow ? await fsrealpath(path8) : path8;
|
|
1357
1370
|
if (this.fsw.closed)
|
|
1358
1371
|
return;
|
|
1359
1372
|
closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
|
|
@@ -1363,29 +1376,29 @@ var NodeFsHandler = class {
|
|
|
1363
1376
|
this.fsw._symlinkPaths.set(absPath, targetPath);
|
|
1364
1377
|
}
|
|
1365
1378
|
} else if (stats.isSymbolicLink()) {
|
|
1366
|
-
const targetPath = follow ? await fsrealpath(
|
|
1379
|
+
const targetPath = follow ? await fsrealpath(path8) : path8;
|
|
1367
1380
|
if (this.fsw.closed)
|
|
1368
1381
|
return;
|
|
1369
1382
|
const parent = sp.dirname(wh.watchPath);
|
|
1370
1383
|
this.fsw._getWatchedDir(parent).add(wh.watchPath);
|
|
1371
1384
|
this.fsw._emit(EV.ADD, wh.watchPath, stats);
|
|
1372
|
-
closer = await this._handleDir(parent, stats, initialAdd, depth,
|
|
1385
|
+
closer = await this._handleDir(parent, stats, initialAdd, depth, path8, wh, targetPath);
|
|
1373
1386
|
if (this.fsw.closed)
|
|
1374
1387
|
return;
|
|
1375
1388
|
if (targetPath !== void 0) {
|
|
1376
|
-
this.fsw._symlinkPaths.set(sp.resolve(
|
|
1389
|
+
this.fsw._symlinkPaths.set(sp.resolve(path8), targetPath);
|
|
1377
1390
|
}
|
|
1378
1391
|
} else {
|
|
1379
1392
|
closer = this._handleFile(wh.watchPath, stats, initialAdd);
|
|
1380
1393
|
}
|
|
1381
1394
|
ready();
|
|
1382
1395
|
if (closer)
|
|
1383
|
-
this.fsw._addPathCloser(
|
|
1396
|
+
this.fsw._addPathCloser(path8, closer);
|
|
1384
1397
|
return false;
|
|
1385
1398
|
} catch (error) {
|
|
1386
1399
|
if (this.fsw._handleError(error)) {
|
|
1387
1400
|
ready();
|
|
1388
|
-
return
|
|
1401
|
+
return path8;
|
|
1389
1402
|
}
|
|
1390
1403
|
}
|
|
1391
1404
|
}
|
|
@@ -1428,24 +1441,24 @@ function createPattern(matcher) {
|
|
|
1428
1441
|
}
|
|
1429
1442
|
return () => false;
|
|
1430
1443
|
}
|
|
1431
|
-
function normalizePath(
|
|
1432
|
-
if (typeof
|
|
1444
|
+
function normalizePath(path8) {
|
|
1445
|
+
if (typeof path8 !== "string")
|
|
1433
1446
|
throw new Error("string expected");
|
|
1434
|
-
|
|
1435
|
-
|
|
1447
|
+
path8 = sp2.normalize(path8);
|
|
1448
|
+
path8 = path8.replace(/\\/g, "/");
|
|
1436
1449
|
let prepend = false;
|
|
1437
|
-
if (
|
|
1450
|
+
if (path8.startsWith("//"))
|
|
1438
1451
|
prepend = true;
|
|
1439
|
-
|
|
1452
|
+
path8 = path8.replace(DOUBLE_SLASH_RE, "/");
|
|
1440
1453
|
if (prepend)
|
|
1441
|
-
|
|
1442
|
-
return
|
|
1454
|
+
path8 = "/" + path8;
|
|
1455
|
+
return path8;
|
|
1443
1456
|
}
|
|
1444
1457
|
function matchPatterns(patterns, testString, stats) {
|
|
1445
|
-
const
|
|
1458
|
+
const path8 = normalizePath(testString);
|
|
1446
1459
|
for (let index = 0; index < patterns.length; index++) {
|
|
1447
1460
|
const pattern = patterns[index];
|
|
1448
|
-
if (pattern(
|
|
1461
|
+
if (pattern(path8, stats)) {
|
|
1449
1462
|
return true;
|
|
1450
1463
|
}
|
|
1451
1464
|
}
|
|
@@ -1483,19 +1496,19 @@ var toUnix = (string) => {
|
|
|
1483
1496
|
}
|
|
1484
1497
|
return str;
|
|
1485
1498
|
};
|
|
1486
|
-
var normalizePathToUnix = (
|
|
1487
|
-
var normalizeIgnored = (cwd = "") => (
|
|
1488
|
-
if (typeof
|
|
1489
|
-
return normalizePathToUnix(sp2.isAbsolute(
|
|
1499
|
+
var normalizePathToUnix = (path8) => toUnix(sp2.normalize(toUnix(path8)));
|
|
1500
|
+
var normalizeIgnored = (cwd = "") => (path8) => {
|
|
1501
|
+
if (typeof path8 === "string") {
|
|
1502
|
+
return normalizePathToUnix(sp2.isAbsolute(path8) ? path8 : sp2.join(cwd, path8));
|
|
1490
1503
|
} else {
|
|
1491
|
-
return
|
|
1504
|
+
return path8;
|
|
1492
1505
|
}
|
|
1493
1506
|
};
|
|
1494
|
-
var getAbsolutePath = (
|
|
1495
|
-
if (sp2.isAbsolute(
|
|
1496
|
-
return
|
|
1507
|
+
var getAbsolutePath = (path8, cwd) => {
|
|
1508
|
+
if (sp2.isAbsolute(path8)) {
|
|
1509
|
+
return path8;
|
|
1497
1510
|
}
|
|
1498
|
-
return sp2.join(cwd,
|
|
1511
|
+
return sp2.join(cwd, path8);
|
|
1499
1512
|
};
|
|
1500
1513
|
var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
|
|
1501
1514
|
var DirEntry = class {
|
|
@@ -1560,10 +1573,10 @@ var WatchHelper = class {
|
|
|
1560
1573
|
dirParts;
|
|
1561
1574
|
followSymlinks;
|
|
1562
1575
|
statMethod;
|
|
1563
|
-
constructor(
|
|
1576
|
+
constructor(path8, follow, fsw) {
|
|
1564
1577
|
this.fsw = fsw;
|
|
1565
|
-
const watchPath =
|
|
1566
|
-
this.path =
|
|
1578
|
+
const watchPath = path8;
|
|
1579
|
+
this.path = path8 = path8.replace(REPLACER_RE, "");
|
|
1567
1580
|
this.watchPath = watchPath;
|
|
1568
1581
|
this.fullWatchPath = sp2.resolve(watchPath);
|
|
1569
1582
|
this.dirParts = [];
|
|
@@ -1703,20 +1716,20 @@ var FSWatcher = class extends EventEmitter {
|
|
|
1703
1716
|
this._closePromise = void 0;
|
|
1704
1717
|
let paths = unifyPaths(paths_);
|
|
1705
1718
|
if (cwd) {
|
|
1706
|
-
paths = paths.map((
|
|
1707
|
-
const absPath = getAbsolutePath(
|
|
1719
|
+
paths = paths.map((path8) => {
|
|
1720
|
+
const absPath = getAbsolutePath(path8, cwd);
|
|
1708
1721
|
return absPath;
|
|
1709
1722
|
});
|
|
1710
1723
|
}
|
|
1711
|
-
paths.forEach((
|
|
1712
|
-
this._removeIgnoredPath(
|
|
1724
|
+
paths.forEach((path8) => {
|
|
1725
|
+
this._removeIgnoredPath(path8);
|
|
1713
1726
|
});
|
|
1714
1727
|
this._userIgnored = void 0;
|
|
1715
1728
|
if (!this._readyCount)
|
|
1716
1729
|
this._readyCount = 0;
|
|
1717
1730
|
this._readyCount += paths.length;
|
|
1718
|
-
Promise.all(paths.map(async (
|
|
1719
|
-
const res = await this._nodeFsHandler._addToNodeFs(
|
|
1731
|
+
Promise.all(paths.map(async (path8) => {
|
|
1732
|
+
const res = await this._nodeFsHandler._addToNodeFs(path8, !_internal, void 0, 0, _origAdd);
|
|
1720
1733
|
if (res)
|
|
1721
1734
|
this._emitReady();
|
|
1722
1735
|
return res;
|
|
@@ -1738,17 +1751,17 @@ var FSWatcher = class extends EventEmitter {
|
|
|
1738
1751
|
return this;
|
|
1739
1752
|
const paths = unifyPaths(paths_);
|
|
1740
1753
|
const { cwd } = this.options;
|
|
1741
|
-
paths.forEach((
|
|
1742
|
-
if (!sp2.isAbsolute(
|
|
1754
|
+
paths.forEach((path8) => {
|
|
1755
|
+
if (!sp2.isAbsolute(path8) && !this._closers.has(path8)) {
|
|
1743
1756
|
if (cwd)
|
|
1744
|
-
|
|
1745
|
-
|
|
1757
|
+
path8 = sp2.join(cwd, path8);
|
|
1758
|
+
path8 = sp2.resolve(path8);
|
|
1746
1759
|
}
|
|
1747
|
-
this._closePath(
|
|
1748
|
-
this._addIgnoredPath(
|
|
1749
|
-
if (this._watched.has(
|
|
1760
|
+
this._closePath(path8);
|
|
1761
|
+
this._addIgnoredPath(path8);
|
|
1762
|
+
if (this._watched.has(path8)) {
|
|
1750
1763
|
this._addIgnoredPath({
|
|
1751
|
-
path:
|
|
1764
|
+
path: path8,
|
|
1752
1765
|
recursive: true
|
|
1753
1766
|
});
|
|
1754
1767
|
}
|
|
@@ -1812,38 +1825,38 @@ var FSWatcher = class extends EventEmitter {
|
|
|
1812
1825
|
* @param stats arguments to be passed with event
|
|
1813
1826
|
* @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
|
|
1814
1827
|
*/
|
|
1815
|
-
async _emit(event,
|
|
1828
|
+
async _emit(event, path8, stats) {
|
|
1816
1829
|
if (this.closed)
|
|
1817
1830
|
return;
|
|
1818
1831
|
const opts = this.options;
|
|
1819
1832
|
if (isWindows)
|
|
1820
|
-
|
|
1833
|
+
path8 = sp2.normalize(path8);
|
|
1821
1834
|
if (opts.cwd)
|
|
1822
|
-
|
|
1823
|
-
const args = [
|
|
1835
|
+
path8 = sp2.relative(opts.cwd, path8);
|
|
1836
|
+
const args = [path8];
|
|
1824
1837
|
if (stats != null)
|
|
1825
1838
|
args.push(stats);
|
|
1826
1839
|
const awf = opts.awaitWriteFinish;
|
|
1827
1840
|
let pw;
|
|
1828
|
-
if (awf && (pw = this._pendingWrites.get(
|
|
1841
|
+
if (awf && (pw = this._pendingWrites.get(path8))) {
|
|
1829
1842
|
pw.lastChange = /* @__PURE__ */ new Date();
|
|
1830
1843
|
return this;
|
|
1831
1844
|
}
|
|
1832
1845
|
if (opts.atomic) {
|
|
1833
1846
|
if (event === EVENTS.UNLINK) {
|
|
1834
|
-
this._pendingUnlinks.set(
|
|
1847
|
+
this._pendingUnlinks.set(path8, [event, ...args]);
|
|
1835
1848
|
setTimeout(() => {
|
|
1836
|
-
this._pendingUnlinks.forEach((entry,
|
|
1849
|
+
this._pendingUnlinks.forEach((entry, path9) => {
|
|
1837
1850
|
this.emit(...entry);
|
|
1838
1851
|
this.emit(EVENTS.ALL, ...entry);
|
|
1839
|
-
this._pendingUnlinks.delete(
|
|
1852
|
+
this._pendingUnlinks.delete(path9);
|
|
1840
1853
|
});
|
|
1841
1854
|
}, typeof opts.atomic === "number" ? opts.atomic : 100);
|
|
1842
1855
|
return this;
|
|
1843
1856
|
}
|
|
1844
|
-
if (event === EVENTS.ADD && this._pendingUnlinks.has(
|
|
1857
|
+
if (event === EVENTS.ADD && this._pendingUnlinks.has(path8)) {
|
|
1845
1858
|
event = EVENTS.CHANGE;
|
|
1846
|
-
this._pendingUnlinks.delete(
|
|
1859
|
+
this._pendingUnlinks.delete(path8);
|
|
1847
1860
|
}
|
|
1848
1861
|
}
|
|
1849
1862
|
if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
|
|
@@ -1861,16 +1874,16 @@ var FSWatcher = class extends EventEmitter {
|
|
|
1861
1874
|
this.emitWithAll(event, args);
|
|
1862
1875
|
}
|
|
1863
1876
|
};
|
|
1864
|
-
this._awaitWriteFinish(
|
|
1877
|
+
this._awaitWriteFinish(path8, awf.stabilityThreshold, event, awfEmit);
|
|
1865
1878
|
return this;
|
|
1866
1879
|
}
|
|
1867
1880
|
if (event === EVENTS.CHANGE) {
|
|
1868
|
-
const isThrottled = !this._throttle(EVENTS.CHANGE,
|
|
1881
|
+
const isThrottled = !this._throttle(EVENTS.CHANGE, path8, 50);
|
|
1869
1882
|
if (isThrottled)
|
|
1870
1883
|
return this;
|
|
1871
1884
|
}
|
|
1872
1885
|
if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
|
|
1873
|
-
const fullPath = opts.cwd ? sp2.join(opts.cwd,
|
|
1886
|
+
const fullPath = opts.cwd ? sp2.join(opts.cwd, path8) : path8;
|
|
1874
1887
|
let stats2;
|
|
1875
1888
|
try {
|
|
1876
1889
|
stats2 = await stat3(fullPath);
|
|
@@ -1901,23 +1914,23 @@ var FSWatcher = class extends EventEmitter {
|
|
|
1901
1914
|
* @param timeout duration of time to suppress duplicate actions
|
|
1902
1915
|
* @returns tracking object or false if action should be suppressed
|
|
1903
1916
|
*/
|
|
1904
|
-
_throttle(actionType,
|
|
1917
|
+
_throttle(actionType, path8, timeout) {
|
|
1905
1918
|
if (!this._throttled.has(actionType)) {
|
|
1906
1919
|
this._throttled.set(actionType, /* @__PURE__ */ new Map());
|
|
1907
1920
|
}
|
|
1908
1921
|
const action = this._throttled.get(actionType);
|
|
1909
1922
|
if (!action)
|
|
1910
1923
|
throw new Error("invalid throttle");
|
|
1911
|
-
const actionPath = action.get(
|
|
1924
|
+
const actionPath = action.get(path8);
|
|
1912
1925
|
if (actionPath) {
|
|
1913
1926
|
actionPath.count++;
|
|
1914
1927
|
return false;
|
|
1915
1928
|
}
|
|
1916
1929
|
let timeoutObject;
|
|
1917
1930
|
const clear = () => {
|
|
1918
|
-
const item = action.get(
|
|
1931
|
+
const item = action.get(path8);
|
|
1919
1932
|
const count = item ? item.count : 0;
|
|
1920
|
-
action.delete(
|
|
1933
|
+
action.delete(path8);
|
|
1921
1934
|
clearTimeout(timeoutObject);
|
|
1922
1935
|
if (item)
|
|
1923
1936
|
clearTimeout(item.timeoutObject);
|
|
@@ -1925,7 +1938,7 @@ var FSWatcher = class extends EventEmitter {
|
|
|
1925
1938
|
};
|
|
1926
1939
|
timeoutObject = setTimeout(clear, timeout);
|
|
1927
1940
|
const thr = { timeoutObject, clear, count: 0 };
|
|
1928
|
-
action.set(
|
|
1941
|
+
action.set(path8, thr);
|
|
1929
1942
|
return thr;
|
|
1930
1943
|
}
|
|
1931
1944
|
_incrReadyCount() {
|
|
@@ -1939,44 +1952,44 @@ var FSWatcher = class extends EventEmitter {
|
|
|
1939
1952
|
* @param event
|
|
1940
1953
|
* @param awfEmit Callback to be called when ready for event to be emitted.
|
|
1941
1954
|
*/
|
|
1942
|
-
_awaitWriteFinish(
|
|
1955
|
+
_awaitWriteFinish(path8, threshold, event, awfEmit) {
|
|
1943
1956
|
const awf = this.options.awaitWriteFinish;
|
|
1944
1957
|
if (typeof awf !== "object")
|
|
1945
1958
|
return;
|
|
1946
1959
|
const pollInterval = awf.pollInterval;
|
|
1947
1960
|
let timeoutHandler;
|
|
1948
|
-
let fullPath =
|
|
1949
|
-
if (this.options.cwd && !sp2.isAbsolute(
|
|
1950
|
-
fullPath = sp2.join(this.options.cwd,
|
|
1961
|
+
let fullPath = path8;
|
|
1962
|
+
if (this.options.cwd && !sp2.isAbsolute(path8)) {
|
|
1963
|
+
fullPath = sp2.join(this.options.cwd, path8);
|
|
1951
1964
|
}
|
|
1952
1965
|
const now = /* @__PURE__ */ new Date();
|
|
1953
1966
|
const writes = this._pendingWrites;
|
|
1954
1967
|
function awaitWriteFinishFn(prevStat) {
|
|
1955
1968
|
statcb(fullPath, (err, curStat) => {
|
|
1956
|
-
if (err || !writes.has(
|
|
1969
|
+
if (err || !writes.has(path8)) {
|
|
1957
1970
|
if (err && err.code !== "ENOENT")
|
|
1958
1971
|
awfEmit(err);
|
|
1959
1972
|
return;
|
|
1960
1973
|
}
|
|
1961
1974
|
const now2 = Number(/* @__PURE__ */ new Date());
|
|
1962
1975
|
if (prevStat && curStat.size !== prevStat.size) {
|
|
1963
|
-
writes.get(
|
|
1976
|
+
writes.get(path8).lastChange = now2;
|
|
1964
1977
|
}
|
|
1965
|
-
const pw = writes.get(
|
|
1978
|
+
const pw = writes.get(path8);
|
|
1966
1979
|
const df = now2 - pw.lastChange;
|
|
1967
1980
|
if (df >= threshold) {
|
|
1968
|
-
writes.delete(
|
|
1981
|
+
writes.delete(path8);
|
|
1969
1982
|
awfEmit(void 0, curStat);
|
|
1970
1983
|
} else {
|
|
1971
1984
|
timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
|
|
1972
1985
|
}
|
|
1973
1986
|
});
|
|
1974
1987
|
}
|
|
1975
|
-
if (!writes.has(
|
|
1976
|
-
writes.set(
|
|
1988
|
+
if (!writes.has(path8)) {
|
|
1989
|
+
writes.set(path8, {
|
|
1977
1990
|
lastChange: now,
|
|
1978
1991
|
cancelWait: () => {
|
|
1979
|
-
writes.delete(
|
|
1992
|
+
writes.delete(path8);
|
|
1980
1993
|
clearTimeout(timeoutHandler);
|
|
1981
1994
|
return event;
|
|
1982
1995
|
}
|
|
@@ -1987,8 +2000,8 @@ var FSWatcher = class extends EventEmitter {
|
|
|
1987
2000
|
/**
|
|
1988
2001
|
* Determines whether user has asked to ignore this path.
|
|
1989
2002
|
*/
|
|
1990
|
-
_isIgnored(
|
|
1991
|
-
if (this.options.atomic && DOT_RE.test(
|
|
2003
|
+
_isIgnored(path8, stats) {
|
|
2004
|
+
if (this.options.atomic && DOT_RE.test(path8))
|
|
1992
2005
|
return true;
|
|
1993
2006
|
if (!this._userIgnored) {
|
|
1994
2007
|
const { cwd } = this.options;
|
|
@@ -1998,17 +2011,17 @@ var FSWatcher = class extends EventEmitter {
|
|
|
1998
2011
|
const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
|
|
1999
2012
|
this._userIgnored = anymatch(list, void 0);
|
|
2000
2013
|
}
|
|
2001
|
-
return this._userIgnored(
|
|
2014
|
+
return this._userIgnored(path8, stats);
|
|
2002
2015
|
}
|
|
2003
|
-
_isntIgnored(
|
|
2004
|
-
return !this._isIgnored(
|
|
2016
|
+
_isntIgnored(path8, stat4) {
|
|
2017
|
+
return !this._isIgnored(path8, stat4);
|
|
2005
2018
|
}
|
|
2006
2019
|
/**
|
|
2007
2020
|
* Provides a set of common helpers and properties relating to symlink handling.
|
|
2008
2021
|
* @param path file or directory pattern being watched
|
|
2009
2022
|
*/
|
|
2010
|
-
_getWatchHelpers(
|
|
2011
|
-
return new WatchHelper(
|
|
2023
|
+
_getWatchHelpers(path8) {
|
|
2024
|
+
return new WatchHelper(path8, this.options.followSymlinks, this);
|
|
2012
2025
|
}
|
|
2013
2026
|
// Directory helpers
|
|
2014
2027
|
// -----------------
|
|
@@ -2040,63 +2053,63 @@ var FSWatcher = class extends EventEmitter {
|
|
|
2040
2053
|
* @param item base path of item/directory
|
|
2041
2054
|
*/
|
|
2042
2055
|
_remove(directory, item, isDirectory) {
|
|
2043
|
-
const
|
|
2044
|
-
const fullPath = sp2.resolve(
|
|
2045
|
-
isDirectory = isDirectory != null ? isDirectory : this._watched.has(
|
|
2046
|
-
if (!this._throttle("remove",
|
|
2056
|
+
const path8 = sp2.join(directory, item);
|
|
2057
|
+
const fullPath = sp2.resolve(path8);
|
|
2058
|
+
isDirectory = isDirectory != null ? isDirectory : this._watched.has(path8) || this._watched.has(fullPath);
|
|
2059
|
+
if (!this._throttle("remove", path8, 100))
|
|
2047
2060
|
return;
|
|
2048
2061
|
if (!isDirectory && this._watched.size === 1) {
|
|
2049
2062
|
this.add(directory, item, true);
|
|
2050
2063
|
}
|
|
2051
|
-
const wp = this._getWatchedDir(
|
|
2064
|
+
const wp = this._getWatchedDir(path8);
|
|
2052
2065
|
const nestedDirectoryChildren = wp.getChildren();
|
|
2053
|
-
nestedDirectoryChildren.forEach((nested) => this._remove(
|
|
2066
|
+
nestedDirectoryChildren.forEach((nested) => this._remove(path8, nested));
|
|
2054
2067
|
const parent = this._getWatchedDir(directory);
|
|
2055
2068
|
const wasTracked = parent.has(item);
|
|
2056
2069
|
parent.remove(item);
|
|
2057
2070
|
if (this._symlinkPaths.has(fullPath)) {
|
|
2058
2071
|
this._symlinkPaths.delete(fullPath);
|
|
2059
2072
|
}
|
|
2060
|
-
let relPath =
|
|
2073
|
+
let relPath = path8;
|
|
2061
2074
|
if (this.options.cwd)
|
|
2062
|
-
relPath = sp2.relative(this.options.cwd,
|
|
2075
|
+
relPath = sp2.relative(this.options.cwd, path8);
|
|
2063
2076
|
if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
|
|
2064
2077
|
const event = this._pendingWrites.get(relPath).cancelWait();
|
|
2065
2078
|
if (event === EVENTS.ADD)
|
|
2066
2079
|
return;
|
|
2067
2080
|
}
|
|
2068
|
-
this._watched.delete(
|
|
2081
|
+
this._watched.delete(path8);
|
|
2069
2082
|
this._watched.delete(fullPath);
|
|
2070
2083
|
const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
|
|
2071
|
-
if (wasTracked && !this._isIgnored(
|
|
2072
|
-
this._emit(eventName,
|
|
2073
|
-
this._closePath(
|
|
2084
|
+
if (wasTracked && !this._isIgnored(path8))
|
|
2085
|
+
this._emit(eventName, path8);
|
|
2086
|
+
this._closePath(path8);
|
|
2074
2087
|
}
|
|
2075
2088
|
/**
|
|
2076
2089
|
* Closes all watchers for a path
|
|
2077
2090
|
*/
|
|
2078
|
-
_closePath(
|
|
2079
|
-
this._closeFile(
|
|
2080
|
-
const dir = sp2.dirname(
|
|
2081
|
-
this._getWatchedDir(dir).remove(sp2.basename(
|
|
2091
|
+
_closePath(path8) {
|
|
2092
|
+
this._closeFile(path8);
|
|
2093
|
+
const dir = sp2.dirname(path8);
|
|
2094
|
+
this._getWatchedDir(dir).remove(sp2.basename(path8));
|
|
2082
2095
|
}
|
|
2083
2096
|
/**
|
|
2084
2097
|
* Closes only file-specific watchers
|
|
2085
2098
|
*/
|
|
2086
|
-
_closeFile(
|
|
2087
|
-
const closers = this._closers.get(
|
|
2099
|
+
_closeFile(path8) {
|
|
2100
|
+
const closers = this._closers.get(path8);
|
|
2088
2101
|
if (!closers)
|
|
2089
2102
|
return;
|
|
2090
2103
|
closers.forEach((closer) => closer());
|
|
2091
|
-
this._closers.delete(
|
|
2104
|
+
this._closers.delete(path8);
|
|
2092
2105
|
}
|
|
2093
|
-
_addPathCloser(
|
|
2106
|
+
_addPathCloser(path8, closer) {
|
|
2094
2107
|
if (!closer)
|
|
2095
2108
|
return;
|
|
2096
|
-
let list = this._closers.get(
|
|
2109
|
+
let list = this._closers.get(path8);
|
|
2097
2110
|
if (!list) {
|
|
2098
2111
|
list = [];
|
|
2099
|
-
this._closers.set(
|
|
2112
|
+
this._closers.set(path8, list);
|
|
2100
2113
|
}
|
|
2101
2114
|
list.push(closer);
|
|
2102
2115
|
}
|
|
@@ -2192,10 +2205,358 @@ var PlanWatcher = class {
|
|
|
2192
2205
|
}
|
|
2193
2206
|
};
|
|
2194
2207
|
|
|
2195
|
-
// src/
|
|
2196
|
-
|
|
2208
|
+
// src/daemon/digest.ts
|
|
2209
|
+
var import_yaml = __toESM(require_dist(), 1);
|
|
2197
2210
|
import fs3 from "fs";
|
|
2198
2211
|
import path4 from "path";
|
|
2212
|
+
import crypto from "crypto";
|
|
2213
|
+
var PREVIOUS_EXTRACT_OVERHEAD_TOKENS = 50;
|
|
2214
|
+
var CONTEXT_SAFETY_MARGIN = 0.7;
|
|
2215
|
+
var EXTRACT_TYPE = "extract";
|
|
2216
|
+
var DigestEngine = class {
|
|
2217
|
+
vaultDir;
|
|
2218
|
+
index;
|
|
2219
|
+
llm;
|
|
2220
|
+
config;
|
|
2221
|
+
log;
|
|
2222
|
+
lastCycleTimestampCache = void 0;
|
|
2223
|
+
cycleInProgress = false;
|
|
2224
|
+
modelReady = false;
|
|
2225
|
+
constructor(engineConfig) {
|
|
2226
|
+
this.vaultDir = engineConfig.vaultDir;
|
|
2227
|
+
this.index = engineConfig.index;
|
|
2228
|
+
this.llm = engineConfig.llmProvider;
|
|
2229
|
+
this.config = engineConfig.config;
|
|
2230
|
+
this.log = engineConfig.log ?? (() => {
|
|
2231
|
+
});
|
|
2232
|
+
}
|
|
2233
|
+
/**
|
|
2234
|
+
* Query index for recent vault notes to feed into the digest.
|
|
2235
|
+
* Filters out extract notes (our own output) and caps at max_notes_per_cycle.
|
|
2236
|
+
*/
|
|
2237
|
+
discoverSubstrate(lastCycleTimestamp) {
|
|
2238
|
+
const maxNotes = this.config.digest.substrate.max_notes_per_cycle;
|
|
2239
|
+
const notes = lastCycleTimestamp ? this.index.query({ updatedSince: lastCycleTimestamp, limit: maxNotes }) : this.index.query({ limit: maxNotes });
|
|
2240
|
+
const filtered = notes.filter((n) => n.type !== EXTRACT_TYPE);
|
|
2241
|
+
filtered.sort((a, b) => {
|
|
2242
|
+
const weightA = DIGEST_SUBSTRATE_TYPE_WEIGHTS[a.type] ?? 0;
|
|
2243
|
+
const weightB = DIGEST_SUBSTRATE_TYPE_WEIGHTS[b.type] ?? 0;
|
|
2244
|
+
if (weightB !== weightA) return weightB - weightA;
|
|
2245
|
+
return b.created.localeCompare(a.created);
|
|
2246
|
+
});
|
|
2247
|
+
return filtered.slice(0, maxNotes);
|
|
2248
|
+
}
|
|
2249
|
+
/**
|
|
2250
|
+
* Filter configured tiers by the context window available.
|
|
2251
|
+
* Only tiers whose minimum context requirement is met are eligible.
|
|
2252
|
+
*/
|
|
2253
|
+
getEligibleTiers() {
|
|
2254
|
+
const contextWindow = this.config.digest.intelligence.context_window;
|
|
2255
|
+
return this.config.digest.tiers.filter((tier) => {
|
|
2256
|
+
const minContext = DIGEST_TIER_MIN_CONTEXT[tier];
|
|
2257
|
+
return minContext !== void 0 && minContext <= contextWindow;
|
|
2258
|
+
});
|
|
2259
|
+
}
|
|
2260
|
+
/**
|
|
2261
|
+
* Format notes compactly for inclusion in the digest prompt.
|
|
2262
|
+
* Stops adding notes once the token budget is exceeded.
|
|
2263
|
+
*/
|
|
2264
|
+
formatSubstrate(notes, tokenBudget) {
|
|
2265
|
+
const charBudget = tokenBudget * CHARS_PER_TOKEN;
|
|
2266
|
+
const parts = [];
|
|
2267
|
+
let usedChars = 0;
|
|
2268
|
+
for (const note of notes) {
|
|
2269
|
+
const entry = `### [${note.type}] ${note.id} \u2014 "${note.title}"
|
|
2270
|
+
${note.content}`;
|
|
2271
|
+
if (usedChars + entry.length > charBudget && parts.length > 0) break;
|
|
2272
|
+
parts.push(entry);
|
|
2273
|
+
usedChars += entry.length;
|
|
2274
|
+
}
|
|
2275
|
+
return parts.join("\n\n");
|
|
2276
|
+
}
|
|
2277
|
+
/**
|
|
2278
|
+
* Read a previously generated extract for a given tier.
|
|
2279
|
+
* Returns the body (stripped of YAML frontmatter), or null if not found.
|
|
2280
|
+
*/
|
|
2281
|
+
readPreviousExtract(tier) {
|
|
2282
|
+
const extractPath = path4.join(this.vaultDir, "digest", `extract-${tier}.md`);
|
|
2283
|
+
let content;
|
|
2284
|
+
try {
|
|
2285
|
+
content = fs3.readFileSync(extractPath, "utf-8");
|
|
2286
|
+
} catch {
|
|
2287
|
+
return null;
|
|
2288
|
+
}
|
|
2289
|
+
return stripFrontmatter(content).body;
|
|
2290
|
+
}
|
|
2291
|
+
/**
|
|
2292
|
+
* Write a digest extract to the vault with YAML frontmatter.
|
|
2293
|
+
* Uses atomic write pattern (temp file + rename).
|
|
2294
|
+
*/
|
|
2295
|
+
writeExtract(tier, body, cycleId, model, substrateCount) {
|
|
2296
|
+
const digestDir = path4.join(this.vaultDir, "digest");
|
|
2297
|
+
fs3.mkdirSync(digestDir, { recursive: true });
|
|
2298
|
+
const frontmatter = {
|
|
2299
|
+
type: EXTRACT_TYPE,
|
|
2300
|
+
tier,
|
|
2301
|
+
generated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2302
|
+
cycle_id: cycleId,
|
|
2303
|
+
substrate_count: substrateCount,
|
|
2304
|
+
model
|
|
2305
|
+
};
|
|
2306
|
+
const fmYaml = import_yaml.default.stringify(frontmatter, {
|
|
2307
|
+
defaultStringType: "QUOTE_DOUBLE",
|
|
2308
|
+
defaultKeyType: "PLAIN"
|
|
2309
|
+
}).trim();
|
|
2310
|
+
const file = `---
|
|
2311
|
+
${fmYaml}
|
|
2312
|
+
---
|
|
2313
|
+
|
|
2314
|
+
${body}
|
|
2315
|
+
`;
|
|
2316
|
+
const fullPath = path4.join(digestDir, `extract-${tier}.md`);
|
|
2317
|
+
const tmpPath = `${fullPath}.tmp`;
|
|
2318
|
+
fs3.writeFileSync(tmpPath, file, "utf-8");
|
|
2319
|
+
fs3.renameSync(tmpPath, fullPath);
|
|
2320
|
+
}
|
|
2321
|
+
/**
|
|
2322
|
+
* Append a digest cycle result as a JSON line to trace.jsonl.
|
|
2323
|
+
*/
|
|
2324
|
+
appendTrace(record) {
|
|
2325
|
+
const digestDir = path4.join(this.vaultDir, "digest");
|
|
2326
|
+
fs3.mkdirSync(digestDir, { recursive: true });
|
|
2327
|
+
const tracePath = path4.join(digestDir, "trace.jsonl");
|
|
2328
|
+
fs3.appendFileSync(tracePath, JSON.stringify(record) + "\n", "utf-8");
|
|
2329
|
+
this.lastCycleTimestampCache = record.timestamp;
|
|
2330
|
+
}
|
|
2331
|
+
/**
|
|
2332
|
+
* Read the last cycle timestamp from trace.jsonl.
|
|
2333
|
+
* Cached in memory after first read — subsequent calls are O(1).
|
|
2334
|
+
*/
|
|
2335
|
+
getLastCycleTimestamp() {
|
|
2336
|
+
if (this.lastCycleTimestampCache !== void 0) return this.lastCycleTimestampCache;
|
|
2337
|
+
const tracePath = path4.join(this.vaultDir, "digest", "trace.jsonl");
|
|
2338
|
+
let content;
|
|
2339
|
+
try {
|
|
2340
|
+
content = fs3.readFileSync(tracePath, "utf-8").trim();
|
|
2341
|
+
} catch {
|
|
2342
|
+
this.lastCycleTimestampCache = null;
|
|
2343
|
+
return null;
|
|
2344
|
+
}
|
|
2345
|
+
if (!content) {
|
|
2346
|
+
this.lastCycleTimestampCache = null;
|
|
2347
|
+
return null;
|
|
2348
|
+
}
|
|
2349
|
+
const lines = content.split("\n");
|
|
2350
|
+
const lastLine = lines[lines.length - 1];
|
|
2351
|
+
try {
|
|
2352
|
+
const record = JSON.parse(lastLine);
|
|
2353
|
+
this.lastCycleTimestampCache = record.timestamp;
|
|
2354
|
+
return record.timestamp;
|
|
2355
|
+
} catch {
|
|
2356
|
+
this.lastCycleTimestampCache = null;
|
|
2357
|
+
return null;
|
|
2358
|
+
}
|
|
2359
|
+
}
|
|
2360
|
+
/**
|
|
2361
|
+
* Run a full digest cycle: discover substrate, generate extracts for each tier.
|
|
2362
|
+
* Returns the cycle result, or null if no substrate was found.
|
|
2363
|
+
*/
|
|
2364
|
+
async runCycle() {
|
|
2365
|
+
if (this.cycleInProgress) {
|
|
2366
|
+
this.log("debug", "Cycle already in progress \u2014 skipping");
|
|
2367
|
+
return null;
|
|
2368
|
+
}
|
|
2369
|
+
this.cycleInProgress = true;
|
|
2370
|
+
try {
|
|
2371
|
+
return await this.runCycleInternal();
|
|
2372
|
+
} finally {
|
|
2373
|
+
this.cycleInProgress = false;
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2376
|
+
async runCycleInternal() {
|
|
2377
|
+
if (!this.modelReady && this.llm.ensureLoaded) {
|
|
2378
|
+
const { context_window: contextWindow, gpu_kv_cache: gpuKvCache } = this.config.digest.intelligence;
|
|
2379
|
+
this.log("info", "Loading digest model", { contextWindow, gpuKvCache });
|
|
2380
|
+
await this.llm.ensureLoaded(contextWindow, gpuKvCache);
|
|
2381
|
+
this.modelReady = true;
|
|
2382
|
+
}
|
|
2383
|
+
const startTime = Date.now();
|
|
2384
|
+
const lastTimestamp = this.getLastCycleTimestamp();
|
|
2385
|
+
const substrate = this.discoverSubstrate(lastTimestamp);
|
|
2386
|
+
this.log("debug", "Discovering substrate", { lastTimestamp: lastTimestamp ?? "cold start", substrateCount: substrate.length });
|
|
2387
|
+
if (substrate.length === 0) {
|
|
2388
|
+
this.log("debug", "No substrate found \u2014 skipping cycle");
|
|
2389
|
+
return null;
|
|
2390
|
+
}
|
|
2391
|
+
this.log("info", `Starting digest cycle`, { substrateCount: substrate.length });
|
|
2392
|
+
const cycleId = crypto.randomUUID();
|
|
2393
|
+
const eligibleTiers = this.getEligibleTiers();
|
|
2394
|
+
this.log("debug", `Eligible tiers: [${eligibleTiers.join(", ")}]`);
|
|
2395
|
+
const tiersGenerated = [];
|
|
2396
|
+
let totalTokensUsed = 0;
|
|
2397
|
+
let model = "";
|
|
2398
|
+
const typeToKey = {
|
|
2399
|
+
session: "sessions",
|
|
2400
|
+
spore: "spores",
|
|
2401
|
+
plan: "plans",
|
|
2402
|
+
artifact: "artifacts",
|
|
2403
|
+
"team-member": "team"
|
|
2404
|
+
};
|
|
2405
|
+
const substrateIndex = {
|
|
2406
|
+
sessions: [],
|
|
2407
|
+
spores: [],
|
|
2408
|
+
plans: [],
|
|
2409
|
+
artifacts: [],
|
|
2410
|
+
team: []
|
|
2411
|
+
};
|
|
2412
|
+
for (const note of substrate) {
|
|
2413
|
+
const key = typeToKey[note.type];
|
|
2414
|
+
if (key) {
|
|
2415
|
+
substrateIndex[key].push(note.id);
|
|
2416
|
+
}
|
|
2417
|
+
}
|
|
2418
|
+
const systemPrompt = loadPrompt("digest-system");
|
|
2419
|
+
for (const tier of eligibleTiers) {
|
|
2420
|
+
const tierPrompt = loadPrompt(`digest-${tier}`);
|
|
2421
|
+
const previousExtract = this.readPreviousExtract(tier);
|
|
2422
|
+
const contextWindow = this.config.digest.intelligence.context_window;
|
|
2423
|
+
const systemPromptTokens = estimateTokens(systemPrompt);
|
|
2424
|
+
const tierPromptTokens = estimateTokens(tierPrompt);
|
|
2425
|
+
const previousExtractTokens = previousExtract ? estimateTokens(previousExtract) + PREVIOUS_EXTRACT_OVERHEAD_TOKENS : 0;
|
|
2426
|
+
const availableTokens = Math.floor(contextWindow * CONTEXT_SAFETY_MARGIN);
|
|
2427
|
+
const substrateBudget = availableTokens - tier - systemPromptTokens - tierPromptTokens - previousExtractTokens;
|
|
2428
|
+
if (substrateBudget <= 0) continue;
|
|
2429
|
+
const formattedSubstrate = this.formatSubstrate(substrate, substrateBudget);
|
|
2430
|
+
const promptParts = [tierPrompt];
|
|
2431
|
+
if (previousExtract) {
|
|
2432
|
+
promptParts.push("", "## Previous Synthesis", "", previousExtract);
|
|
2433
|
+
}
|
|
2434
|
+
promptParts.push("", "## New Substrate", "", formattedSubstrate);
|
|
2435
|
+
promptParts.push(
|
|
2436
|
+
"",
|
|
2437
|
+
"---",
|
|
2438
|
+
"Produce your updated synthesis now. Stay within the token budget specified above."
|
|
2439
|
+
);
|
|
2440
|
+
const userPrompt = promptParts.join("\n");
|
|
2441
|
+
const promptTokens = estimateTokens(systemPrompt + userPrompt);
|
|
2442
|
+
this.log("debug", `Tier ${tier}: sending LLM request`, { promptTokens, maxTokens: tier, substrateBudget });
|
|
2443
|
+
const tierStart = Date.now();
|
|
2444
|
+
const digestConfig = this.config.digest.intelligence;
|
|
2445
|
+
const opts = {
|
|
2446
|
+
maxTokens: tier,
|
|
2447
|
+
timeoutMs: DIGEST_LLM_REQUEST_TIMEOUT_MS,
|
|
2448
|
+
contextLength: contextWindow,
|
|
2449
|
+
reasoning: "off",
|
|
2450
|
+
systemPrompt,
|
|
2451
|
+
keepAlive: digestConfig.keep_alive ?? void 0
|
|
2452
|
+
};
|
|
2453
|
+
const response = await this.llm.summarize(userPrompt, opts);
|
|
2454
|
+
const tierDuration = Date.now() - tierStart;
|
|
2455
|
+
const extractText = stripReasoningTokens(response.text);
|
|
2456
|
+
model = response.model;
|
|
2457
|
+
const responseTokens = estimateTokens(extractText);
|
|
2458
|
+
totalTokensUsed += promptTokens + responseTokens;
|
|
2459
|
+
this.log("info", `Tier ${tier}: completed`, { durationMs: tierDuration, responseTokens, model: response.model });
|
|
2460
|
+
this.writeExtract(tier, extractText, cycleId, response.model, substrate.length);
|
|
2461
|
+
tiersGenerated.push(tier);
|
|
2462
|
+
}
|
|
2463
|
+
const result = {
|
|
2464
|
+
cycleId,
|
|
2465
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2466
|
+
substrate: substrateIndex,
|
|
2467
|
+
tiersGenerated,
|
|
2468
|
+
model,
|
|
2469
|
+
durationMs: Date.now() - startTime,
|
|
2470
|
+
tokensUsed: totalTokensUsed
|
|
2471
|
+
};
|
|
2472
|
+
this.appendTrace(result);
|
|
2473
|
+
return result;
|
|
2474
|
+
}
|
|
2475
|
+
};
|
|
2476
|
+
var MS_PER_SECOND2 = 1e3;
|
|
2477
|
+
var Metabolism = class {
|
|
2478
|
+
state = "active";
|
|
2479
|
+
currentIntervalMs;
|
|
2480
|
+
cooldownStep = 0;
|
|
2481
|
+
lastSubstrateTime;
|
|
2482
|
+
timer = null;
|
|
2483
|
+
activeIntervalMs;
|
|
2484
|
+
cooldownIntervalsMs;
|
|
2485
|
+
dormancyThresholdMs;
|
|
2486
|
+
constructor(config) {
|
|
2487
|
+
this.activeIntervalMs = config.active_interval * MS_PER_SECOND2;
|
|
2488
|
+
this.cooldownIntervalsMs = config.cooldown_intervals.map((s) => s * MS_PER_SECOND2);
|
|
2489
|
+
this.dormancyThresholdMs = config.dormancy_threshold * MS_PER_SECOND2;
|
|
2490
|
+
this.currentIntervalMs = this.activeIntervalMs;
|
|
2491
|
+
this.lastSubstrateTime = Date.now();
|
|
2492
|
+
}
|
|
2493
|
+
/** Reset to active state when new substrate is found. */
|
|
2494
|
+
onSubstrateFound() {
|
|
2495
|
+
this.state = "active";
|
|
2496
|
+
this.cooldownStep = 0;
|
|
2497
|
+
this.currentIntervalMs = this.activeIntervalMs;
|
|
2498
|
+
this.lastSubstrateTime = Date.now();
|
|
2499
|
+
}
|
|
2500
|
+
/** Advance cooldown when a cycle finds no new substrate. */
|
|
2501
|
+
onEmptyCycle() {
|
|
2502
|
+
if (this.state === "dormant") return;
|
|
2503
|
+
this.state = "cooling";
|
|
2504
|
+
if (this.cooldownStep < this.cooldownIntervalsMs.length) {
|
|
2505
|
+
this.currentIntervalMs = this.cooldownIntervalsMs[this.cooldownStep];
|
|
2506
|
+
this.cooldownStep++;
|
|
2507
|
+
}
|
|
2508
|
+
this.checkDormancy();
|
|
2509
|
+
}
|
|
2510
|
+
/** Enter dormant state if enough time has elapsed since last substrate. */
|
|
2511
|
+
checkDormancy() {
|
|
2512
|
+
const elapsed = Date.now() - this.lastSubstrateTime;
|
|
2513
|
+
if (elapsed >= this.dormancyThresholdMs) {
|
|
2514
|
+
this.state = "dormant";
|
|
2515
|
+
}
|
|
2516
|
+
}
|
|
2517
|
+
/** Return to active from any state, resetting timers and rescheduling immediately. */
|
|
2518
|
+
activate() {
|
|
2519
|
+
this.onSubstrateFound();
|
|
2520
|
+
if (this.callback) {
|
|
2521
|
+
this.reschedule();
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2524
|
+
/** Set lastSubstrateTime explicitly (for testing). */
|
|
2525
|
+
markLastSubstrate(time) {
|
|
2526
|
+
this.lastSubstrateTime = time;
|
|
2527
|
+
}
|
|
2528
|
+
/** Begin scheduling digest cycles with adaptive intervals. */
|
|
2529
|
+
start(callback) {
|
|
2530
|
+
this.callback = callback;
|
|
2531
|
+
this.reschedule();
|
|
2532
|
+
}
|
|
2533
|
+
/** Stop the timer. */
|
|
2534
|
+
stop() {
|
|
2535
|
+
if (this.timer) {
|
|
2536
|
+
clearTimeout(this.timer);
|
|
2537
|
+
this.timer = null;
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2540
|
+
callback = null;
|
|
2541
|
+
reschedule() {
|
|
2542
|
+
this.stop();
|
|
2543
|
+
if (!this.callback) return;
|
|
2544
|
+
const cb = this.callback;
|
|
2545
|
+
const schedule = () => {
|
|
2546
|
+
this.timer = setTimeout(async () => {
|
|
2547
|
+
await cb();
|
|
2548
|
+
schedule();
|
|
2549
|
+
}, this.currentIntervalMs);
|
|
2550
|
+
this.timer.unref();
|
|
2551
|
+
};
|
|
2552
|
+
schedule();
|
|
2553
|
+
}
|
|
2554
|
+
};
|
|
2555
|
+
|
|
2556
|
+
// src/artifacts/candidates.ts
|
|
2557
|
+
import { execFileSync } from "child_process";
|
|
2558
|
+
import fs4 from "fs";
|
|
2559
|
+
import path5 from "path";
|
|
2199
2560
|
var EXCLUDED_FILENAMES = /* @__PURE__ */ new Set([
|
|
2200
2561
|
"claude.md",
|
|
2201
2562
|
"agents.md",
|
|
@@ -2216,7 +2577,7 @@ var EXCLUDED_PREFIXES = [
|
|
|
2216
2577
|
".github/"
|
|
2217
2578
|
];
|
|
2218
2579
|
function isExcludedPath(relativePath) {
|
|
2219
|
-
const basename3 =
|
|
2580
|
+
const basename3 = path5.basename(relativePath).toLowerCase();
|
|
2220
2581
|
if (EXCLUDED_FILENAMES.has(basename3)) return true;
|
|
2221
2582
|
const normalized = relativePath.replace(/\\/g, "/");
|
|
2222
2583
|
return EXCLUDED_PREFIXES.some((prefix) => normalized.startsWith(prefix));
|
|
@@ -2224,7 +2585,7 @@ function isExcludedPath(relativePath) {
|
|
|
2224
2585
|
function collectArtifactCandidates(filePaths, config, projectRoot) {
|
|
2225
2586
|
if (filePaths.size === 0) return [];
|
|
2226
2587
|
const extFiltered = [...filePaths].filter(
|
|
2227
|
-
(absPath) => config.artifact_extensions.includes(
|
|
2588
|
+
(absPath) => config.artifact_extensions.includes(path5.extname(absPath))
|
|
2228
2589
|
);
|
|
2229
2590
|
if (extFiltered.length === 0) return [];
|
|
2230
2591
|
const ignoredSet = getGitIgnored(extFiltered, projectRoot);
|
|
@@ -2232,8 +2593,8 @@ function collectArtifactCandidates(filePaths, config, projectRoot) {
|
|
|
2232
2593
|
for (const absPath of extFiltered) {
|
|
2233
2594
|
if (ignoredSet.has(absPath)) continue;
|
|
2234
2595
|
try {
|
|
2235
|
-
const content =
|
|
2236
|
-
const relativePath =
|
|
2596
|
+
const content = fs4.readFileSync(absPath, "utf-8");
|
|
2597
|
+
const relativePath = path5.relative(projectRoot, absPath);
|
|
2237
2598
|
if (isExcludedPath(relativePath)) continue;
|
|
2238
2599
|
candidates.push({ path: relativePath, content });
|
|
2239
2600
|
} catch {
|
|
@@ -2255,23 +2616,23 @@ function getGitIgnored(filePaths, cwd) {
|
|
|
2255
2616
|
}
|
|
2256
2617
|
|
|
2257
2618
|
// src/artifacts/slugify.ts
|
|
2258
|
-
import
|
|
2259
|
-
import
|
|
2619
|
+
import crypto2 from "crypto";
|
|
2620
|
+
import path6 from "path";
|
|
2260
2621
|
function slugifyPath(relativePath) {
|
|
2261
|
-
const ext =
|
|
2622
|
+
const ext = path6.extname(relativePath);
|
|
2262
2623
|
const withoutExt = ext ? relativePath.slice(0, -ext.length) : relativePath;
|
|
2263
2624
|
let slug = withoutExt.replace(/[/\\]/g, "-").toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "");
|
|
2264
2625
|
if (slug.length > MAX_SLUG_LENGTH) {
|
|
2265
|
-
const hash =
|
|
2626
|
+
const hash = crypto2.createHash("sha256").update(relativePath).digest("hex").slice(0, 6);
|
|
2266
2627
|
slug = slug.slice(0, MAX_SLUG_LENGTH) + "-" + hash;
|
|
2267
2628
|
}
|
|
2268
2629
|
return slug;
|
|
2269
2630
|
}
|
|
2270
2631
|
|
|
2271
2632
|
// src/daemon/main.ts
|
|
2272
|
-
var
|
|
2273
|
-
import
|
|
2274
|
-
import
|
|
2633
|
+
var import_yaml2 = __toESM(require_dist(), 1);
|
|
2634
|
+
import fs5 from "fs";
|
|
2635
|
+
import path7 from "path";
|
|
2275
2636
|
function indexAndEmbed(relativePath, noteId, embeddingText, metadata, deps) {
|
|
2276
2637
|
indexNote(deps.index, deps.vaultDir, relativePath);
|
|
2277
2638
|
if (deps.vectorIndex && embeddingText) {
|
|
@@ -2286,7 +2647,7 @@ function writeObservations(observations, sessionId, deps) {
|
|
|
2286
2647
|
note.id,
|
|
2287
2648
|
`${note.observation.title}
|
|
2288
2649
|
${note.observation.content}`,
|
|
2289
|
-
{ type: "
|
|
2650
|
+
{ type: "spore", importance: "high", session_id: sessionId },
|
|
2290
2651
|
deps
|
|
2291
2652
|
);
|
|
2292
2653
|
deps.logger.info("processor", "Observation written", { type: note.observation.type, title: note.observation.title, session_id: sessionId });
|
|
@@ -2323,29 +2684,29 @@ ${candidate.content}`,
|
|
|
2323
2684
|
lineage?.registerArtifactForSession(sessionId, artifactId);
|
|
2324
2685
|
}
|
|
2325
2686
|
}
|
|
2326
|
-
function
|
|
2327
|
-
const
|
|
2328
|
-
if (!
|
|
2687
|
+
function migrateSporeFiles(vaultDir) {
|
|
2688
|
+
const sporesDir = path7.join(vaultDir, "spores");
|
|
2689
|
+
if (!fs5.existsSync(sporesDir)) return 0;
|
|
2329
2690
|
let moved = 0;
|
|
2330
|
-
const entries =
|
|
2691
|
+
const entries = fs5.readdirSync(sporesDir);
|
|
2331
2692
|
for (const entry of entries) {
|
|
2332
|
-
const fullPath =
|
|
2693
|
+
const fullPath = path7.join(sporesDir, entry);
|
|
2333
2694
|
if (!entry.endsWith(".md")) continue;
|
|
2334
|
-
if (
|
|
2695
|
+
if (fs5.statSync(fullPath).isDirectory()) continue;
|
|
2335
2696
|
try {
|
|
2336
|
-
const content =
|
|
2697
|
+
const content = fs5.readFileSync(fullPath, "utf-8");
|
|
2337
2698
|
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
2338
2699
|
if (!fmMatch) continue;
|
|
2339
|
-
const parsed =
|
|
2700
|
+
const parsed = import_yaml2.default.parse(fmMatch[1]);
|
|
2340
2701
|
const obsType = parsed.observation_type;
|
|
2341
2702
|
if (!obsType) continue;
|
|
2342
2703
|
const normalizedType = obsType.replace(/_/g, "-");
|
|
2343
|
-
const targetDir =
|
|
2344
|
-
|
|
2345
|
-
const targetPath =
|
|
2346
|
-
|
|
2704
|
+
const targetDir = path7.join(sporesDir, normalizedType);
|
|
2705
|
+
fs5.mkdirSync(targetDir, { recursive: true });
|
|
2706
|
+
const targetPath = path7.join(targetDir, entry);
|
|
2707
|
+
fs5.renameSync(fullPath, targetPath);
|
|
2347
2708
|
const now = /* @__PURE__ */ new Date();
|
|
2348
|
-
|
|
2709
|
+
fs5.utimesSync(targetPath, now, now);
|
|
2349
2710
|
moved++;
|
|
2350
2711
|
} catch {
|
|
2351
2712
|
}
|
|
@@ -2358,9 +2719,9 @@ async function main() {
|
|
|
2358
2719
|
process.stderr.write("Usage: mycod --vault <path>\n");
|
|
2359
2720
|
process.exit(1);
|
|
2360
2721
|
}
|
|
2361
|
-
const vaultDir =
|
|
2722
|
+
const vaultDir = path7.resolve(vaultArg);
|
|
2362
2723
|
const config = loadConfig(vaultDir);
|
|
2363
|
-
const logger = new DaemonLogger(
|
|
2724
|
+
const logger = new DaemonLogger(path7.join(vaultDir, "logs"), {
|
|
2364
2725
|
level: config.daemon.log_level,
|
|
2365
2726
|
maxSize: config.daemon.max_log_size
|
|
2366
2727
|
});
|
|
@@ -2369,6 +2730,7 @@ async function main() {
|
|
|
2369
2730
|
gracePeriod: config.daemon.grace_period,
|
|
2370
2731
|
onEmpty: async () => {
|
|
2371
2732
|
logger.info("daemon", "Grace period expired, shutting down");
|
|
2733
|
+
metabolism?.stop();
|
|
2372
2734
|
planWatcher.stopFileWatcher();
|
|
2373
2735
|
await server.stop();
|
|
2374
2736
|
vectorIndex?.close();
|
|
@@ -2382,14 +2744,14 @@ async function main() {
|
|
|
2382
2744
|
let vectorIndex = null;
|
|
2383
2745
|
try {
|
|
2384
2746
|
const testEmbed = await embeddingProvider.embed("test");
|
|
2385
|
-
vectorIndex = new VectorIndex(
|
|
2747
|
+
vectorIndex = new VectorIndex(path7.join(vaultDir, "vectors.db"), testEmbed.dimensions);
|
|
2386
2748
|
logger.info("embeddings", "Vector index initialized", { dimensions: testEmbed.dimensions });
|
|
2387
2749
|
} catch (error) {
|
|
2388
2750
|
logger.warn("embeddings", "Vector index unavailable", { error: error.message });
|
|
2389
2751
|
}
|
|
2390
|
-
const processor = new BufferProcessor(llmProvider, config.intelligence.llm.context_window);
|
|
2752
|
+
const processor = new BufferProcessor(llmProvider, config.intelligence.llm.context_window, config.capture);
|
|
2391
2753
|
const vault = new VaultWriter(vaultDir);
|
|
2392
|
-
const index = new MycoIndex(
|
|
2754
|
+
const index = new MycoIndex(path7.join(vaultDir, "index.db"));
|
|
2393
2755
|
const lineageGraph = new LineageGraph(vaultDir);
|
|
2394
2756
|
const transcriptMiner = new TranscriptMiner({
|
|
2395
2757
|
additionalAdapters: config.capture.transcript_paths.map(
|
|
@@ -2398,24 +2760,24 @@ async function main() {
|
|
|
2398
2760
|
});
|
|
2399
2761
|
let activeStopProcessing = null;
|
|
2400
2762
|
const indexDeps = { index, vaultDir, vectorIndex, embeddingProvider, logger };
|
|
2401
|
-
const bufferDir =
|
|
2763
|
+
const bufferDir = path7.join(vaultDir, "buffer");
|
|
2402
2764
|
const sessionBuffers = /* @__PURE__ */ new Map();
|
|
2403
2765
|
const sessionFilePaths = /* @__PURE__ */ new Map();
|
|
2404
2766
|
const capturedArtifactPaths = /* @__PURE__ */ new Map();
|
|
2405
|
-
if (
|
|
2767
|
+
if (fs5.existsSync(bufferDir)) {
|
|
2406
2768
|
const cutoff = Date.now() - STALE_BUFFER_MAX_AGE_MS;
|
|
2407
|
-
for (const file of
|
|
2408
|
-
const filePath =
|
|
2409
|
-
const stat4 =
|
|
2769
|
+
for (const file of fs5.readdirSync(bufferDir)) {
|
|
2770
|
+
const filePath = path7.join(bufferDir, file);
|
|
2771
|
+
const stat4 = fs5.statSync(filePath);
|
|
2410
2772
|
if (stat4.mtimeMs < cutoff) {
|
|
2411
|
-
|
|
2773
|
+
fs5.unlinkSync(filePath);
|
|
2412
2774
|
logger.debug("daemon", "Cleaned stale buffer", { file });
|
|
2413
2775
|
}
|
|
2414
2776
|
}
|
|
2415
2777
|
}
|
|
2416
|
-
const migrated =
|
|
2778
|
+
const migrated = migrateSporeFiles(vaultDir);
|
|
2417
2779
|
if (migrated > 0) {
|
|
2418
|
-
logger.info("daemon", "Migrated
|
|
2780
|
+
logger.info("daemon", "Migrated spore files to type subdirectories", { count: migrated });
|
|
2419
2781
|
initFts(index);
|
|
2420
2782
|
rebuildIndex(index, vaultDir);
|
|
2421
2783
|
}
|
|
@@ -2444,10 +2806,10 @@ async function main() {
|
|
|
2444
2806
|
logger.info("watcher", "Plan detected", { source: event.source, file: event.filePath });
|
|
2445
2807
|
if (event.filePath) {
|
|
2446
2808
|
try {
|
|
2447
|
-
const content =
|
|
2448
|
-
const relativePath =
|
|
2449
|
-
const title = content.match(/^#\s+(.+)$/m)?.[1] ??
|
|
2450
|
-
const planId = `plan-${
|
|
2809
|
+
const content = fs5.readFileSync(event.filePath, "utf-8");
|
|
2810
|
+
const relativePath = path7.relative(vaultDir, event.filePath);
|
|
2811
|
+
const title = content.match(/^#\s+(.+)$/m)?.[1] ?? path7.basename(event.filePath);
|
|
2812
|
+
const planId = `plan-${path7.basename(event.filePath, ".md")}`;
|
|
2451
2813
|
indexAndEmbed(
|
|
2452
2814
|
relativePath,
|
|
2453
2815
|
planId,
|
|
@@ -2468,6 +2830,51 @@ ${content}`,
|
|
|
2468
2830
|
}
|
|
2469
2831
|
});
|
|
2470
2832
|
planWatcher.startFileWatcher();
|
|
2833
|
+
let metabolism = null;
|
|
2834
|
+
if (config.digest.enabled) {
|
|
2835
|
+
const digestLlmConfig = {
|
|
2836
|
+
provider: config.digest.intelligence.provider ?? config.intelligence.llm.provider,
|
|
2837
|
+
model: config.digest.intelligence.model ?? config.intelligence.llm.model,
|
|
2838
|
+
base_url: config.digest.intelligence.base_url ?? config.intelligence.llm.base_url,
|
|
2839
|
+
context_window: config.digest.intelligence.context_window
|
|
2840
|
+
};
|
|
2841
|
+
logger.debug("digest", "Digest LLM config", digestLlmConfig);
|
|
2842
|
+
const digestLlm = config.digest.intelligence.model || config.digest.intelligence.provider ? createLlmProvider(digestLlmConfig) : llmProvider;
|
|
2843
|
+
logger.debug("digest", `Using ${digestLlm.name} provider for digest`);
|
|
2844
|
+
const digestEngine = new DigestEngine({
|
|
2845
|
+
vaultDir,
|
|
2846
|
+
index,
|
|
2847
|
+
llmProvider: digestLlm,
|
|
2848
|
+
config,
|
|
2849
|
+
log: (level, message, data) => logger[level]("digest", message, data)
|
|
2850
|
+
});
|
|
2851
|
+
metabolism = new Metabolism(config.digest.metabolism);
|
|
2852
|
+
logger.debug("digest", "Firing initial digest cycle (background)");
|
|
2853
|
+
digestEngine.runCycle().then((result) => {
|
|
2854
|
+
if (result) {
|
|
2855
|
+
metabolism.onSubstrateFound();
|
|
2856
|
+
logger.info("digest", `Initial digest cycle: ${result.tiersGenerated.length} tiers, ${result.durationMs}ms`);
|
|
2857
|
+
}
|
|
2858
|
+
}).catch((err) => {
|
|
2859
|
+
logger.warn("digest", "Initial digest cycle failed", { error: err.message });
|
|
2860
|
+
});
|
|
2861
|
+
metabolism.start(async () => {
|
|
2862
|
+
try {
|
|
2863
|
+
const cycleResult = await digestEngine.runCycle();
|
|
2864
|
+
if (cycleResult) {
|
|
2865
|
+
metabolism.onSubstrateFound();
|
|
2866
|
+
logger.info("digest", `Digest cycle ${cycleResult.cycleId}: ${cycleResult.tiersGenerated.length} tiers`);
|
|
2867
|
+
} else {
|
|
2868
|
+
metabolism.onEmptyCycle();
|
|
2869
|
+
logger.debug("digest", "No substrate, backing off");
|
|
2870
|
+
}
|
|
2871
|
+
} catch (err) {
|
|
2872
|
+
logger.warn("digest", "Digest cycle failed", { error: err.message });
|
|
2873
|
+
metabolism.onEmptyCycle();
|
|
2874
|
+
}
|
|
2875
|
+
});
|
|
2876
|
+
logger.info("digest", "Digest enabled \u2014 starting metabolism");
|
|
2877
|
+
}
|
|
2471
2878
|
const batchManager = new BatchManager(async (closedBatch) => {
|
|
2472
2879
|
if (closedBatch.length === 0) return;
|
|
2473
2880
|
const sessionId = closedBatch[0].session_id;
|
|
@@ -2498,7 +2905,7 @@ ${content}`,
|
|
|
2498
2905
|
}
|
|
2499
2906
|
const captured = capturedArtifactPaths.get(sessionId);
|
|
2500
2907
|
for (const c of candidates) {
|
|
2501
|
-
const absPath =
|
|
2908
|
+
const absPath = path7.resolve(process.cwd(), c.path);
|
|
2502
2909
|
captured.add(absPath);
|
|
2503
2910
|
}
|
|
2504
2911
|
}).catch((err) => logger.warn("processor", "Incremental artifact capture failed", {
|
|
@@ -2529,6 +2936,7 @@ ${content}`,
|
|
|
2529
2936
|
} catch (err) {
|
|
2530
2937
|
logger.debug("lineage", "Heuristic detection failed", { error: err.message });
|
|
2531
2938
|
}
|
|
2939
|
+
metabolism?.activate();
|
|
2532
2940
|
logger.info("lifecycle", "Session registered", { session_id, branch });
|
|
2533
2941
|
return { ok: true, sessions: registry.sessions };
|
|
2534
2942
|
});
|
|
@@ -2537,14 +2945,14 @@ ${content}`,
|
|
|
2537
2945
|
registry.unregister(session_id);
|
|
2538
2946
|
try {
|
|
2539
2947
|
const cutoff = Date.now() - STALE_BUFFER_MAX_AGE_MS;
|
|
2540
|
-
for (const file of
|
|
2948
|
+
for (const file of fs5.readdirSync(bufferDir)) {
|
|
2541
2949
|
if (!file.endsWith(".jsonl")) continue;
|
|
2542
2950
|
const bufferSessionId = file.replace(".jsonl", "");
|
|
2543
2951
|
if (bufferSessionId === session_id) continue;
|
|
2544
|
-
const filePath =
|
|
2545
|
-
const stat4 =
|
|
2952
|
+
const filePath = path7.join(bufferDir, file);
|
|
2953
|
+
const stat4 = fs5.statSync(filePath);
|
|
2546
2954
|
if (stat4.mtimeMs < cutoff) {
|
|
2547
|
-
|
|
2955
|
+
fs5.unlinkSync(filePath);
|
|
2548
2956
|
logger.debug("daemon", "Cleaned stale buffer", { file });
|
|
2549
2957
|
}
|
|
2550
2958
|
}
|
|
@@ -2639,15 +3047,15 @@ ${content}`,
|
|
|
2639
3047
|
}
|
|
2640
3048
|
const ended = (/* @__PURE__ */ new Date()).toISOString();
|
|
2641
3049
|
let started = allTurns.length > 0 && allTurns[0].timestamp ? allTurns[0].timestamp : ended;
|
|
2642
|
-
const sessionsDir =
|
|
3050
|
+
const sessionsDir = path7.join(vaultDir, "sessions");
|
|
2643
3051
|
const sessionFileName = `${sessionNoteId(sessionId)}.md`;
|
|
2644
3052
|
let existingContent;
|
|
2645
3053
|
const duplicatePaths = [];
|
|
2646
3054
|
try {
|
|
2647
|
-
for (const dateDir of
|
|
2648
|
-
const candidate =
|
|
3055
|
+
for (const dateDir of fs5.readdirSync(sessionsDir)) {
|
|
3056
|
+
const candidate = path7.join(sessionsDir, dateDir, sessionFileName);
|
|
2649
3057
|
try {
|
|
2650
|
-
const content =
|
|
3058
|
+
const content = fs5.readFileSync(candidate, "utf-8");
|
|
2651
3059
|
if (!existingContent || content.length > existingContent.length) {
|
|
2652
3060
|
existingContent = content;
|
|
2653
3061
|
}
|
|
@@ -2707,20 +3115,20 @@ ${conversationText}`;
|
|
|
2707
3115
|
}
|
|
2708
3116
|
const date = started.slice(0, 10);
|
|
2709
3117
|
const relativePath = sessionRelativePath(sessionId, date);
|
|
2710
|
-
const targetFullPath =
|
|
3118
|
+
const targetFullPath = path7.join(vaultDir, relativePath);
|
|
2711
3119
|
for (const dup of duplicatePaths) {
|
|
2712
3120
|
if (dup !== targetFullPath) {
|
|
2713
3121
|
try {
|
|
2714
|
-
|
|
3122
|
+
fs5.unlinkSync(dup);
|
|
2715
3123
|
logger.debug("lifecycle", "Removed duplicate session file", { path: dup });
|
|
2716
3124
|
} catch {
|
|
2717
3125
|
}
|
|
2718
3126
|
}
|
|
2719
3127
|
}
|
|
2720
|
-
const attachmentsDir =
|
|
3128
|
+
const attachmentsDir = path7.join(vaultDir, "attachments");
|
|
2721
3129
|
const hasImages = allTurns.some((t) => t.images?.length);
|
|
2722
3130
|
if (hasImages) {
|
|
2723
|
-
|
|
3131
|
+
fs5.mkdirSync(attachmentsDir, { recursive: true });
|
|
2724
3132
|
}
|
|
2725
3133
|
const turnImageNames = /* @__PURE__ */ new Map();
|
|
2726
3134
|
for (let i = 0; i < allTurns.length; i++) {
|
|
@@ -2731,9 +3139,9 @@ ${conversationText}`;
|
|
|
2731
3139
|
const img = turn.images[j];
|
|
2732
3140
|
const ext = extensionForMimeType(img.mediaType);
|
|
2733
3141
|
const filename = `${bareSessionId(sessionId)}-t${i + 1}-${j + 1}.${ext}`;
|
|
2734
|
-
const filePath =
|
|
2735
|
-
if (!
|
|
2736
|
-
|
|
3142
|
+
const filePath = path7.join(attachmentsDir, filename);
|
|
3143
|
+
if (!fs5.existsSync(filePath)) {
|
|
3144
|
+
fs5.writeFileSync(filePath, Buffer.from(img.data, "base64"));
|
|
2737
3145
|
logger.debug("processor", "Image saved", { filename, turn: i + 1 });
|
|
2738
3146
|
}
|
|
2739
3147
|
names.push(filename);
|
|
@@ -2746,7 +3154,7 @@ ${conversationText}`;
|
|
|
2746
3154
|
title = summaryResult.title;
|
|
2747
3155
|
narrative = summaryResult.summary;
|
|
2748
3156
|
}
|
|
2749
|
-
const relatedMemories = index.query({ type: "
|
|
3157
|
+
const relatedMemories = index.query({ type: "spore", limit: RELATED_SPORES_LIMIT }).filter((n) => {
|
|
2750
3158
|
const fm = n.frontmatter;
|
|
2751
3159
|
return fm.session === sessionNoteId(sessionId) || fm.session === sessionId;
|
|
2752
3160
|
}).map((n) => ({ id: n.id, title: n.title }));
|
|
@@ -2838,6 +3246,17 @@ ${conversationText}`;
|
|
|
2838
3246
|
const { session_id, branch } = ContextBody.parse(body);
|
|
2839
3247
|
logger.debug("hooks", "Session context query", { session_id });
|
|
2840
3248
|
try {
|
|
3249
|
+
if (config.digest.enabled && config.digest.inject_tier) {
|
|
3250
|
+
const result = handleMycoContext(vaultDir, { tier: config.digest.inject_tier });
|
|
3251
|
+
if (result.generated !== void 0) {
|
|
3252
|
+
const meta = [result.content];
|
|
3253
|
+
if (branch) meta.push(`
|
|
3254
|
+
Branch:: \`${branch}\``);
|
|
3255
|
+
meta.push(`Session:: \`${session_id}\``);
|
|
3256
|
+
logger.debug("context", `Injecting digest extract (tier ${result.tier})`, { session_id, fallback: result.fallback });
|
|
3257
|
+
return { text: meta.join("\n\n"), source: "digest", tier: result.tier };
|
|
3258
|
+
}
|
|
3259
|
+
}
|
|
2841
3260
|
const parts = [];
|
|
2842
3261
|
const plans = index.query({ type: "plan" });
|
|
2843
3262
|
const activePlans = plans.filter((p) => {
|
|
@@ -2888,8 +3307,8 @@ ${planLines.join("\n")}`);
|
|
|
2888
3307
|
try {
|
|
2889
3308
|
const emb = await generateEmbedding(embeddingProvider, prompt.slice(0, EMBEDDING_INPUT_LIMIT));
|
|
2890
3309
|
const results = vectorIndex.search(emb.embedding, {
|
|
2891
|
-
limit:
|
|
2892
|
-
type: "
|
|
3310
|
+
limit: PROMPT_CONTEXT_MAX_SPORES,
|
|
3311
|
+
type: "spore",
|
|
2893
3312
|
relativeThreshold: PROMPT_CONTEXT_MIN_SIMILARITY
|
|
2894
3313
|
});
|
|
2895
3314
|
if (results.length === 0) return { text: "" };
|
|
@@ -2906,11 +3325,11 @@ ${planLines.join("\n")}`);
|
|
|
2906
3325
|
lines.push(`- [${obsType}] ${note.title}: ${note.content.slice(0, CONTENT_SNIPPET_CHARS)} \`[${note.id}]\``);
|
|
2907
3326
|
}
|
|
2908
3327
|
if (lines.length === 0) return { text: "" };
|
|
2909
|
-
const injected = `**Relevant
|
|
3328
|
+
const injected = `**Relevant spores for this task:**
|
|
2910
3329
|
${lines.join("\n")}`;
|
|
2911
3330
|
logger.debug("context", "Prompt context injected", {
|
|
2912
3331
|
session_id,
|
|
2913
|
-
|
|
3332
|
+
spores: lines.length,
|
|
2914
3333
|
prompt_preview: prompt.slice(0, 50)
|
|
2915
3334
|
});
|
|
2916
3335
|
return { text: injected };
|
|
@@ -2927,6 +3346,7 @@ ${lines.join("\n")}`;
|
|
|
2927
3346
|
logger.info("daemon", "Waiting for active stop processing to complete...");
|
|
2928
3347
|
await activeStopProcessing;
|
|
2929
3348
|
}
|
|
3349
|
+
metabolism?.stop();
|
|
2930
3350
|
planWatcher.stopFileWatcher();
|
|
2931
3351
|
registry.destroy();
|
|
2932
3352
|
await server.stop();
|
|
@@ -2940,11 +3360,11 @@ ${lines.join("\n")}`;
|
|
|
2940
3360
|
}
|
|
2941
3361
|
export {
|
|
2942
3362
|
main,
|
|
2943
|
-
|
|
3363
|
+
migrateSporeFiles
|
|
2944
3364
|
};
|
|
2945
3365
|
/*! Bundled license information:
|
|
2946
3366
|
|
|
2947
3367
|
chokidar/index.js:
|
|
2948
3368
|
(*! chokidar - MIT License (c) 2012 Paul Miller (paulmillr.com) *)
|
|
2949
3369
|
*/
|
|
2950
|
-
//# sourceMappingURL=main-
|
|
3370
|
+
//# sourceMappingURL=main-6UPAIDGS.js.map
|