clawvault 3.0.0 → 3.2.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/README.md +352 -20
- package/bin/clawvault.js +8 -2
- package/bin/command-registration.test.js +3 -1
- package/bin/command-runtime.js +9 -1
- package/bin/register-core-commands.js +23 -10
- package/bin/register-maintenance-commands.js +39 -3
- package/bin/register-query-commands.js +58 -29
- package/bin/register-task-commands.js +18 -1
- package/bin/register-task-commands.test.js +16 -0
- package/bin/register-vault-operations-commands.js +29 -1
- package/bin/register-workgraph-commands.js +1368 -0
- package/dashboard/lib/graph-diff.js +104 -0
- package/dashboard/lib/graph-diff.test.js +75 -0
- package/dashboard/lib/vault-parser.js +556 -0
- package/dashboard/lib/vault-parser.test.js +254 -0
- package/dashboard/public/app.js +796 -0
- package/dashboard/public/index.html +52 -0
- package/dashboard/public/styles.css +221 -0
- package/dashboard/server.js +374 -0
- package/dist/{chunk-F2JEUD4J.js → chunk-23YDQ3QU.js} +6 -8
- package/dist/{chunk-C7OK5WKP.js → chunk-2JQ3O2YL.js} +4 -4
- package/dist/{chunk-VR5NE7PZ.js → chunk-2RAZ4ZFE.js} +1 -1
- package/dist/chunk-2ZDO52B4.js +52 -0
- package/dist/{chunk-ZZA73MFY.js → chunk-33DOSHTA.js} +176 -36
- package/dist/chunk-33VSQP4J.js +37 -0
- package/dist/chunk-4BQTQMJP.js +93 -0
- package/dist/{chunk-GUKMRGM7.js → chunk-4OXMU5S2.js} +1 -1
- package/dist/{chunk-62YTUT6J.js → chunk-4PY655YM.js} +15 -3
- package/dist/chunk-6FH3IULF.js +352 -0
- package/dist/{chunk-3NSBOUT3.js → chunk-77Q5CSPJ.js} +404 -80
- package/dist/{chunk-4VQTUVH7.js → chunk-7YZWHM36.js} +52 -26
- package/dist/chunk-BSJ6RIT7.js +447 -0
- package/dist/chunk-BUEW6IIK.js +364 -0
- package/dist/{chunk-WGRQ6HDV.js → chunk-CLJTREDS.js} +74 -14
- package/dist/chunk-EK6S23ZB.js +469 -0
- package/dist/{chunk-LNJA2UGL.js → chunk-ESFLMDRB.js} +9 -86
- package/dist/{chunk-H34S76MB.js → chunk-ESVS6K2B.js} +6 -6
- package/dist/{chunk-WAZ3NLWL.js → chunk-F55HGNU4.js} +0 -47
- package/dist/{chunk-QK3UCXWL.js → chunk-FHFUXL6G.js} +2 -2
- package/dist/{chunk-YKTA5JOJ.js → chunk-GAOWA7GR.js} +212 -46
- package/dist/chunk-GGA32J2R.js +784 -0
- package/dist/chunk-GNJL4YGR.js +79 -0
- package/dist/chunk-MDIH26GC.js +183 -0
- package/dist/{chunk-LYHGEHXG.js → chunk-MFAWT5O5.js} +0 -1
- package/dist/chunk-MM6QGW3P.js +207 -0
- package/dist/{chunk-P5EPF6MB.js → chunk-MW5C6ZQA.js} +110 -13
- package/dist/chunk-NCKFNBHJ.js +257 -0
- package/dist/{chunk-QBLMXKF2.js → chunk-OIWVQYQF.js} +1 -1
- package/dist/{chunk-42MXU7A6.js → chunk-P62WHA27.js} +58 -47
- package/dist/chunk-PBACDKKP.js +66 -0
- package/dist/{chunk-VGLOTGAS.js → chunk-QSHD36LH.js} +2 -2
- package/dist/{chunk-OZ7RIXTO.js → chunk-QSRRMEYM.js} +2 -2
- package/dist/chunk-QVEERJSP.js +152 -0
- package/dist/{chunk-N2AXRYLC.js → chunk-QWQ3TIKS.js} +1 -1
- package/dist/{chunk-3DHXQHYG.js → chunk-R2MIW5G7.js} +1 -1
- package/dist/{chunk-SJSFRIYS.js → chunk-SLXOR3CC.js} +2 -2
- package/dist/chunk-SS4B7P7V.js +99 -0
- package/dist/{chunk-JY6FYXIT.js → chunk-STCQGCEQ.js} +6 -11
- package/dist/chunk-U4O6C46S.js +154 -0
- package/dist/{chunk-ITPEXLHA.js → chunk-URXDAUVH.js} +24 -5
- package/dist/chunk-VSL7KY3M.js +189 -0
- package/dist/{chunk-U55BGUAU.js → chunk-W4SPAEE7.js} +6 -6
- package/dist/chunk-WMGIIABP.js +15 -0
- package/dist/{chunk-3D6BCTP6.js → chunk-X3SPPUFG.js} +51 -39
- package/dist/{chunk-THRJVD4L.js → chunk-Y6VJKXGL.js} +1 -1
- package/dist/{chunk-ZVVFWOLW.js → chunk-ZN54U2OZ.js} +123 -10
- package/dist/cli/index.js +32 -25
- package/dist/commands/archive.js +3 -3
- package/dist/commands/backlog.js +3 -3
- package/dist/commands/blocked.js +3 -3
- package/dist/commands/canvas.d.ts +15 -0
- package/dist/commands/canvas.js +200 -0
- package/dist/commands/checkpoint.js +2 -2
- package/dist/commands/compat.js +2 -2
- package/dist/commands/context.js +8 -6
- package/dist/commands/doctor.d.ts +11 -7
- package/dist/commands/doctor.js +18 -16
- package/dist/commands/embed.js +5 -6
- package/dist/commands/entities.js +2 -2
- package/dist/commands/graph.js +4 -4
- package/dist/commands/inject.d.ts +1 -1
- package/dist/commands/inject.js +5 -6
- package/dist/commands/kanban.js +4 -4
- package/dist/commands/link.js +5 -5
- package/dist/commands/migrate-observations.js +4 -4
- package/dist/commands/observe.d.ts +0 -1
- package/dist/commands/observe.js +14 -13
- package/dist/commands/project.js +5 -5
- package/dist/commands/rebuild-embeddings.d.ts +21 -0
- package/dist/commands/rebuild-embeddings.js +91 -0
- package/dist/commands/rebuild.js +12 -11
- package/dist/commands/recover.js +3 -3
- package/dist/commands/reflect.js +6 -7
- package/dist/commands/repair-session.js +1 -1
- package/dist/commands/replay.js +14 -14
- package/dist/commands/session-recap.js +1 -1
- package/dist/commands/setup.d.ts +2 -90
- package/dist/commands/setup.js +3 -21
- package/dist/commands/shell-init.js +1 -1
- package/dist/commands/sleep.d.ts +1 -1
- package/dist/commands/sleep.js +20 -19
- package/dist/commands/status.d.ts +2 -0
- package/dist/commands/status.js +57 -35
- package/dist/commands/sync-bd.d.ts +10 -0
- package/dist/commands/sync-bd.js +10 -0
- package/dist/commands/tailscale.js +3 -3
- package/dist/commands/task.js +4 -4
- package/dist/commands/template.js +2 -2
- package/dist/commands/wake.d.ts +1 -1
- package/dist/commands/wake.js +11 -10
- package/dist/commands/workgraph.d.ts +124 -0
- package/dist/commands/workgraph.js +38 -0
- package/dist/index.d.ts +337 -191
- package/dist/index.js +387 -118
- package/dist/{inject-Bzi5E-By.d.cts → inject-DYUrDqQO.d.ts} +3 -3
- package/dist/ledger-B7g7jhqG.d.ts +44 -0
- package/dist/lib/auto-linker.js +2 -2
- package/dist/lib/canvas-layout.d.ts +100 -16
- package/dist/lib/canvas-layout.js +21 -78
- package/dist/lib/config.d.ts +27 -3
- package/dist/lib/config.js +4 -2
- package/dist/lib/entity-index.js +1 -1
- package/dist/lib/project-utils.js +4 -4
- package/dist/lib/session-repair.js +1 -1
- package/dist/lib/session-utils.js +1 -1
- package/dist/lib/tailscale.js +1 -1
- package/dist/lib/task-utils.js +3 -3
- package/dist/lib/template-engine.js +1 -1
- package/dist/lib/webdav.js +1 -1
- package/dist/onnxruntime_binding-5QEF3SUC.node +0 -0
- package/dist/onnxruntime_binding-BKPKNEGC.node +0 -0
- package/dist/onnxruntime_binding-FMOXGIUT.node +0 -0
- package/dist/onnxruntime_binding-OI2KMXC5.node +0 -0
- package/dist/onnxruntime_binding-UX44MLAZ.node +0 -0
- package/dist/onnxruntime_binding-Y2W7N7WY.node +0 -0
- package/dist/openclaw-plugin.d.ts +8 -0
- package/dist/openclaw-plugin.js +14 -0
- package/dist/registry-BR4326o0.d.ts +30 -0
- package/dist/store-CA-6sKCJ.d.ts +34 -0
- package/dist/thread-B9LhXNU0.d.ts +41 -0
- package/dist/transformers.node-A2ZRORSQ.js +46775 -0
- package/dist/{types-Y2_Um2Ls.d.cts → types-BbWJoC1c.d.ts} +1 -44
- package/dist/workgraph/index.d.ts +5 -0
- package/dist/workgraph/index.js +23 -0
- package/dist/workgraph/ledger.d.ts +2 -0
- package/dist/workgraph/ledger.js +25 -0
- package/dist/workgraph/registry.d.ts +2 -0
- package/dist/workgraph/registry.js +19 -0
- package/dist/workgraph/store.d.ts +2 -0
- package/dist/workgraph/store.js +25 -0
- package/dist/workgraph/thread.d.ts +2 -0
- package/dist/workgraph/thread.js +25 -0
- package/dist/workgraph/types.d.ts +54 -0
- package/dist/workgraph/types.js +7 -0
- package/hooks/clawvault/HOOK.md +34 -4
- package/hooks/clawvault/handler.js +760 -78
- package/hooks/clawvault/handler.test.js +235 -79
- package/hooks/clawvault/openclaw.plugin.json +72 -0
- package/openclaw.plugin.json +65 -38
- package/package.json +15 -18
- package/dist/chunk-3RG5ZIWI.js +0 -10
- package/dist/chunk-6U6MK36V.js +0 -205
- package/dist/chunk-7R7O6STJ.js +0 -88
- package/dist/chunk-CMB7UL7C.js +0 -327
- package/dist/chunk-DEFFDRVP.js +0 -938
- package/dist/chunk-E7MFQB6D.js +0 -163
- package/dist/chunk-GAJV4IGR.js +0 -82
- package/dist/chunk-GQSLDZTS.js +0 -560
- package/dist/chunk-K234IDRJ.js +0 -1073
- package/dist/chunk-MFM6K7PU.js +0 -374
- package/dist/chunk-MXSSG3QU.js +0 -42
- package/dist/chunk-PAH27GSN.js +0 -108
- package/dist/cli/index.cjs +0 -10033
- package/dist/cli/index.d.cts +0 -5
- package/dist/commands/archive.cjs +0 -287
- package/dist/commands/archive.d.cts +0 -11
- package/dist/commands/backlog.cjs +0 -721
- package/dist/commands/backlog.d.cts +0 -53
- package/dist/commands/blocked.cjs +0 -204
- package/dist/commands/blocked.d.cts +0 -26
- package/dist/commands/checkpoint.cjs +0 -244
- package/dist/commands/checkpoint.d.cts +0 -41
- package/dist/commands/compat.cjs +0 -369
- package/dist/commands/compat.d.cts +0 -28
- package/dist/commands/context.cjs +0 -2989
- package/dist/commands/context.d.cts +0 -2
- package/dist/commands/doctor.cjs +0 -3062
- package/dist/commands/doctor.d.cts +0 -21
- package/dist/commands/embed.cjs +0 -232
- package/dist/commands/embed.d.cts +0 -17
- package/dist/commands/entities.cjs +0 -141
- package/dist/commands/entities.d.cts +0 -7
- package/dist/commands/graph.cjs +0 -501
- package/dist/commands/graph.d.cts +0 -21
- package/dist/commands/inject.cjs +0 -1636
- package/dist/commands/inject.d.cts +0 -2
- package/dist/commands/kanban.cjs +0 -884
- package/dist/commands/kanban.d.cts +0 -63
- package/dist/commands/link.cjs +0 -965
- package/dist/commands/link.d.cts +0 -11
- package/dist/commands/migrate-observations.cjs +0 -362
- package/dist/commands/migrate-observations.d.cts +0 -19
- package/dist/commands/observe.cjs +0 -4099
- package/dist/commands/observe.d.cts +0 -23
- package/dist/commands/project.cjs +0 -1341
- package/dist/commands/project.d.cts +0 -85
- package/dist/commands/rebuild.cjs +0 -3136
- package/dist/commands/rebuild.d.cts +0 -11
- package/dist/commands/recover.cjs +0 -361
- package/dist/commands/recover.d.cts +0 -38
- package/dist/commands/reflect.cjs +0 -1008
- package/dist/commands/reflect.d.cts +0 -11
- package/dist/commands/repair-session.cjs +0 -457
- package/dist/commands/repair-session.d.cts +0 -38
- package/dist/commands/replay.cjs +0 -4103
- package/dist/commands/replay.d.cts +0 -16
- package/dist/commands/session-recap.cjs +0 -353
- package/dist/commands/session-recap.d.cts +0 -27
- package/dist/commands/setup.cjs +0 -1345
- package/dist/commands/setup.d.cts +0 -100
- package/dist/commands/shell-init.cjs +0 -75
- package/dist/commands/shell-init.d.cts +0 -7
- package/dist/commands/sleep.cjs +0 -6028
- package/dist/commands/sleep.d.cts +0 -36
- package/dist/commands/status.cjs +0 -2736
- package/dist/commands/status.d.cts +0 -52
- package/dist/commands/tailscale.cjs +0 -1532
- package/dist/commands/tailscale.d.cts +0 -52
- package/dist/commands/task.cjs +0 -1236
- package/dist/commands/task.d.cts +0 -97
- package/dist/commands/template.cjs +0 -457
- package/dist/commands/template.d.cts +0 -36
- package/dist/commands/wake.cjs +0 -2626
- package/dist/commands/wake.d.cts +0 -22
- package/dist/context-BUGaWpyL.d.cts +0 -46
- package/dist/index.cjs +0 -14526
- package/dist/index.d.cts +0 -858
- package/dist/inject-Bzi5E-By.d.ts +0 -137
- package/dist/lib/auto-linker.cjs +0 -176
- package/dist/lib/auto-linker.d.cts +0 -26
- package/dist/lib/canvas-layout.cjs +0 -136
- package/dist/lib/canvas-layout.d.cts +0 -31
- package/dist/lib/config.cjs +0 -78
- package/dist/lib/config.d.cts +0 -11
- package/dist/lib/entity-index.cjs +0 -84
- package/dist/lib/entity-index.d.cts +0 -26
- package/dist/lib/project-utils.cjs +0 -864
- package/dist/lib/project-utils.d.cts +0 -97
- package/dist/lib/session-repair.cjs +0 -239
- package/dist/lib/session-repair.d.cts +0 -110
- package/dist/lib/session-utils.cjs +0 -209
- package/dist/lib/session-utils.d.cts +0 -63
- package/dist/lib/tailscale.cjs +0 -1183
- package/dist/lib/tailscale.d.cts +0 -225
- package/dist/lib/task-utils.cjs +0 -1137
- package/dist/lib/task-utils.d.cts +0 -208
- package/dist/lib/template-engine.cjs +0 -47
- package/dist/lib/template-engine.d.cts +0 -11
- package/dist/lib/webdav.cjs +0 -568
- package/dist/lib/webdav.d.cts +0 -109
- package/dist/plugin/index.cjs +0 -1907
- package/dist/plugin/index.d.cts +0 -36
- package/dist/plugin/index.d.ts +0 -36
- package/dist/plugin/index.js +0 -572
- package/dist/plugin/inject.cjs +0 -356
- package/dist/plugin/inject.d.cts +0 -54
- package/dist/plugin/inject.d.ts +0 -54
- package/dist/plugin/inject.js +0 -17
- package/dist/plugin/observe.cjs +0 -631
- package/dist/plugin/observe.d.cts +0 -39
- package/dist/plugin/observe.d.ts +0 -39
- package/dist/plugin/observe.js +0 -18
- package/dist/plugin/templates.cjs +0 -593
- package/dist/plugin/templates.d.cts +0 -52
- package/dist/plugin/templates.d.ts +0 -52
- package/dist/plugin/templates.js +0 -25
- package/dist/plugin/types.cjs +0 -18
- package/dist/plugin/types.d.cts +0 -209
- package/dist/plugin/types.d.ts +0 -209
- package/dist/plugin/types.js +0 -0
- package/dist/plugin/vault.cjs +0 -927
- package/dist/plugin/vault.d.cts +0 -68
- package/dist/plugin/vault.d.ts +0 -68
- package/dist/plugin/vault.js +0 -22
- package/dist/types-Y2_Um2Ls.d.ts +0 -205
- package/templates/memory-event.md +0 -67
- package/templates/party.md +0 -63
- package/templates/primitive-registry.yaml +0 -551
- package/templates/run.md +0 -68
- package/templates/trigger.md +0 -68
- package/templates/workspace.md +0 -50
package/dist/commands/setup.cjs
DELETED
|
@@ -1,1345 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __export = (target, all) => {
|
|
9
|
-
for (var name in all)
|
|
10
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
-
};
|
|
12
|
-
var __copyProps = (to, from, except, desc) => {
|
|
13
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
-
for (let key of __getOwnPropNames(from))
|
|
15
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
-
}
|
|
18
|
-
return to;
|
|
19
|
-
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
-
|
|
30
|
-
// src/commands/setup.ts
|
|
31
|
-
var setup_exports = {};
|
|
32
|
-
__export(setup_exports, {
|
|
33
|
-
extractDecisions: () => extractDecisions,
|
|
34
|
-
extractFromContent: () => extractFromContent,
|
|
35
|
-
extractPeople: () => extractPeople,
|
|
36
|
-
extractPreferences: () => extractPreferences,
|
|
37
|
-
extractTasks: () => extractTasks,
|
|
38
|
-
importToVault: () => importToVault,
|
|
39
|
-
scanAndExtract: () => scanAndExtract,
|
|
40
|
-
setupCommand: () => setupCommand
|
|
41
|
-
});
|
|
42
|
-
module.exports = __toCommonJS(setup_exports);
|
|
43
|
-
var fs2 = __toESM(require("fs"), 1);
|
|
44
|
-
var os = __toESM(require("os"), 1);
|
|
45
|
-
var path2 = __toESM(require("path"), 1);
|
|
46
|
-
var import_child_process2 = require("child_process");
|
|
47
|
-
var import_gray_matter2 = __toESM(require("gray-matter"), 1);
|
|
48
|
-
|
|
49
|
-
// src/types.ts
|
|
50
|
-
var DEFAULT_CATEGORIES = [
|
|
51
|
-
"rules",
|
|
52
|
-
"preferences",
|
|
53
|
-
"decisions",
|
|
54
|
-
"patterns",
|
|
55
|
-
"people",
|
|
56
|
-
"projects",
|
|
57
|
-
"goals",
|
|
58
|
-
"transcripts",
|
|
59
|
-
"inbox",
|
|
60
|
-
"templates",
|
|
61
|
-
"lessons",
|
|
62
|
-
"agents",
|
|
63
|
-
"commitments",
|
|
64
|
-
"handoffs",
|
|
65
|
-
"research",
|
|
66
|
-
"tasks",
|
|
67
|
-
"backlog"
|
|
68
|
-
];
|
|
69
|
-
|
|
70
|
-
// src/lib/search.ts
|
|
71
|
-
var import_child_process = require("child_process");
|
|
72
|
-
var QMD_INSTALL_COMMAND = "bun install -g github:tobi/qmd";
|
|
73
|
-
var QMD_NOT_INSTALLED_MESSAGE = `ClawVault requires qmd. Install: ${QMD_INSTALL_COMMAND}`;
|
|
74
|
-
var QMD_INDEX_ENV_VAR = "CLAWVAULT_QMD_INDEX";
|
|
75
|
-
function resolveQmdIndexName(indexName) {
|
|
76
|
-
const explicit = indexName?.trim();
|
|
77
|
-
if (explicit) {
|
|
78
|
-
return explicit;
|
|
79
|
-
}
|
|
80
|
-
const fromEnv = process.env[QMD_INDEX_ENV_VAR]?.trim();
|
|
81
|
-
return fromEnv || void 0;
|
|
82
|
-
}
|
|
83
|
-
function withQmdIndexArgs(args, indexName) {
|
|
84
|
-
if (args.includes("--index")) {
|
|
85
|
-
return [...args];
|
|
86
|
-
}
|
|
87
|
-
const resolvedIndexName = resolveQmdIndexName(indexName);
|
|
88
|
-
if (!resolvedIndexName) {
|
|
89
|
-
return [...args];
|
|
90
|
-
}
|
|
91
|
-
return ["--index", resolvedIndexName, ...args];
|
|
92
|
-
}
|
|
93
|
-
function hasQmd() {
|
|
94
|
-
const result = (0, import_child_process.spawnSync)("qmd", ["--version"], { stdio: "ignore" });
|
|
95
|
-
return !result.error;
|
|
96
|
-
}
|
|
97
|
-
var MONTH_NAMES = {
|
|
98
|
-
january: 1,
|
|
99
|
-
february: 2,
|
|
100
|
-
march: 3,
|
|
101
|
-
april: 4,
|
|
102
|
-
may: 5,
|
|
103
|
-
june: 6,
|
|
104
|
-
july: 7,
|
|
105
|
-
august: 8,
|
|
106
|
-
september: 9,
|
|
107
|
-
october: 10,
|
|
108
|
-
november: 11,
|
|
109
|
-
december: 12,
|
|
110
|
-
jan: 1,
|
|
111
|
-
feb: 2,
|
|
112
|
-
mar: 3,
|
|
113
|
-
apr: 4,
|
|
114
|
-
jun: 6,
|
|
115
|
-
jul: 7,
|
|
116
|
-
aug: 8,
|
|
117
|
-
sep: 9,
|
|
118
|
-
sept: 9,
|
|
119
|
-
oct: 10,
|
|
120
|
-
nov: 11,
|
|
121
|
-
dec: 12
|
|
122
|
-
};
|
|
123
|
-
var MONTH_RE_PART = Object.keys(MONTH_NAMES).join("|");
|
|
124
|
-
var DATE_MONTH_DAY_YEAR_RE = new RegExp(
|
|
125
|
-
`\\b(${MONTH_RE_PART})\\s+(\\d{1,2})(?:st|nd|rd|th)?,?\\s*(\\d{4})\\b`,
|
|
126
|
-
"gi"
|
|
127
|
-
);
|
|
128
|
-
var DATE_DAY_MONTH_YEAR_RE = new RegExp(
|
|
129
|
-
`\\b(\\d{1,2})(?:st|nd|rd|th)?\\s+(${MONTH_RE_PART}),?\\s*(\\d{4})\\b`,
|
|
130
|
-
"gi"
|
|
131
|
-
);
|
|
132
|
-
var DATE_MONTH_DAY_RE = new RegExp(
|
|
133
|
-
`\\b(${MONTH_RE_PART})\\s+(\\d{1,2})(?:st|nd|rd|th)?\\b`,
|
|
134
|
-
"gi"
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
// src/lib/primitive-templates.ts
|
|
138
|
-
var fs = __toESM(require("fs"), 1);
|
|
139
|
-
var path = __toESM(require("path"), 1);
|
|
140
|
-
var import_url = require("url");
|
|
141
|
-
var import_gray_matter = __toESM(require("gray-matter"), 1);
|
|
142
|
-
|
|
143
|
-
// src/lib/template-engine.ts
|
|
144
|
-
function buildTemplateVariables(input = {}, now = /* @__PURE__ */ new Date()) {
|
|
145
|
-
const datetime = input.datetime ?? now.toISOString();
|
|
146
|
-
const date = input.date ?? datetime.split("T")[0];
|
|
147
|
-
return {
|
|
148
|
-
title: input.title ?? "",
|
|
149
|
-
type: input.type ?? "",
|
|
150
|
-
date,
|
|
151
|
-
datetime
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
function renderTemplate(template, variables) {
|
|
155
|
-
return template.replace(/\{\{\s*([a-zA-Z0-9_-]+)\s*\}\}/g, (match, key) => {
|
|
156
|
-
const value = variables[key];
|
|
157
|
-
return value !== void 0 ? String(value) : match;
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// src/lib/primitive-templates.ts
|
|
162
|
-
var import_meta = {};
|
|
163
|
-
var TEMPLATE_EXTENSION = ".md";
|
|
164
|
-
function isRecord(value) {
|
|
165
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
166
|
-
}
|
|
167
|
-
function normalizeTemplateName(name) {
|
|
168
|
-
const base = path.basename(name, path.extname(name));
|
|
169
|
-
return base.trim();
|
|
170
|
-
}
|
|
171
|
-
function resolveBuiltinTemplatesDir(override) {
|
|
172
|
-
if (override) {
|
|
173
|
-
const resolved = path.resolve(override);
|
|
174
|
-
return fs.existsSync(resolved) && fs.statSync(resolved).isDirectory() ? resolved : null;
|
|
175
|
-
}
|
|
176
|
-
const moduleDir = path.dirname((0, import_url.fileURLToPath)(import_meta.url));
|
|
177
|
-
const candidates = [
|
|
178
|
-
path.resolve(moduleDir, "../templates"),
|
|
179
|
-
path.resolve(moduleDir, "../../templates")
|
|
180
|
-
];
|
|
181
|
-
for (const candidate of candidates) {
|
|
182
|
-
if (fs.existsSync(candidate) && fs.statSync(candidate).isDirectory()) {
|
|
183
|
-
return candidate;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
return null;
|
|
187
|
-
}
|
|
188
|
-
function listTemplateFiles(dir, ignore) {
|
|
189
|
-
const entries = /* @__PURE__ */ new Map();
|
|
190
|
-
if (!fs.existsSync(dir)) return entries;
|
|
191
|
-
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
192
|
-
if (!entry.isFile() || !entry.name.endsWith(TEMPLATE_EXTENSION)) continue;
|
|
193
|
-
const name = normalizeTemplateName(entry.name);
|
|
194
|
-
if (!name) continue;
|
|
195
|
-
if (ignore?.has(name)) continue;
|
|
196
|
-
entries.set(name, path.join(dir, entry.name));
|
|
197
|
-
}
|
|
198
|
-
return entries;
|
|
199
|
-
}
|
|
200
|
-
function buildTemplateIndex(options = {}) {
|
|
201
|
-
const index = /* @__PURE__ */ new Map();
|
|
202
|
-
const builtinDir = resolveBuiltinTemplatesDir(options.builtinDir);
|
|
203
|
-
if (builtinDir) {
|
|
204
|
-
for (const [name, filePath] of listTemplateFiles(builtinDir, options.ignoreBuiltinNames)) {
|
|
205
|
-
index.set(name, filePath);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
if (options.vaultPath) {
|
|
209
|
-
const vaultTemplatesDir = path.join(path.resolve(options.vaultPath), "templates");
|
|
210
|
-
for (const [name, filePath] of listTemplateFiles(vaultTemplatesDir)) {
|
|
211
|
-
index.set(name, filePath);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
return index;
|
|
215
|
-
}
|
|
216
|
-
function inferFieldType(defaultValue) {
|
|
217
|
-
if (Array.isArray(defaultValue)) {
|
|
218
|
-
const uniqueItemTypes = [...new Set(defaultValue.map((value) => typeof value))];
|
|
219
|
-
if (uniqueItemTypes.length === 1 && uniqueItemTypes[0] === "string") {
|
|
220
|
-
return "string[]";
|
|
221
|
-
}
|
|
222
|
-
return "array";
|
|
223
|
-
}
|
|
224
|
-
switch (typeof defaultValue) {
|
|
225
|
-
case "string":
|
|
226
|
-
return "string";
|
|
227
|
-
case "number":
|
|
228
|
-
return "number";
|
|
229
|
-
case "boolean":
|
|
230
|
-
return "boolean";
|
|
231
|
-
case "object":
|
|
232
|
-
if (defaultValue === null) return "string";
|
|
233
|
-
return "object";
|
|
234
|
-
default:
|
|
235
|
-
return "string";
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
function normalizeFieldDefinition(rawField) {
|
|
239
|
-
if (!isRecord(rawField)) {
|
|
240
|
-
return {
|
|
241
|
-
type: inferFieldType(rawField),
|
|
242
|
-
default: rawField
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
const rawType = typeof rawField.type === "string" ? rawField.type.trim() : "";
|
|
246
|
-
const normalized = {
|
|
247
|
-
type: rawType || inferFieldType(rawField.default)
|
|
248
|
-
};
|
|
249
|
-
if (typeof rawField.description === "string" && rawField.description.trim()) {
|
|
250
|
-
normalized.description = rawField.description.trim();
|
|
251
|
-
}
|
|
252
|
-
if (typeof rawField.required === "boolean") {
|
|
253
|
-
normalized.required = rawField.required;
|
|
254
|
-
}
|
|
255
|
-
if (Object.prototype.hasOwnProperty.call(rawField, "default")) {
|
|
256
|
-
normalized.default = rawField.default;
|
|
257
|
-
}
|
|
258
|
-
if (Array.isArray(rawField.enum)) {
|
|
259
|
-
normalized.enum = rawField.enum;
|
|
260
|
-
}
|
|
261
|
-
return normalized;
|
|
262
|
-
}
|
|
263
|
-
function normalizeFieldDefinitions(rawFields) {
|
|
264
|
-
const normalized = {};
|
|
265
|
-
for (const [fieldName, rawField] of Object.entries(rawFields)) {
|
|
266
|
-
const normalizedName = String(fieldName).trim();
|
|
267
|
-
if (!normalizedName) continue;
|
|
268
|
-
normalized[normalizedName] = normalizeFieldDefinition(rawField);
|
|
269
|
-
}
|
|
270
|
-
return normalized;
|
|
271
|
-
}
|
|
272
|
-
function extractSchemaDefinition(frontmatter) {
|
|
273
|
-
const primitive = typeof frontmatter.primitive === "string" ? frontmatter.primitive.trim() : "";
|
|
274
|
-
const description = typeof frontmatter.description === "string" ? frontmatter.description.trim() : void 0;
|
|
275
|
-
if (primitive && isRecord(frontmatter.fields)) {
|
|
276
|
-
return {
|
|
277
|
-
primitive,
|
|
278
|
-
description,
|
|
279
|
-
fields: frontmatter.fields
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
const containerCandidates = [frontmatter.schema, frontmatter.template];
|
|
283
|
-
for (const candidate of containerCandidates) {
|
|
284
|
-
if (!isRecord(candidate)) continue;
|
|
285
|
-
const nestedPrimitive = typeof candidate.primitive === "string" ? candidate.primitive.trim() : primitive;
|
|
286
|
-
if (!nestedPrimitive || !isRecord(candidate.fields)) continue;
|
|
287
|
-
const nestedDescription = typeof candidate.description === "string" ? candidate.description.trim() : description;
|
|
288
|
-
return {
|
|
289
|
-
primitive: nestedPrimitive,
|
|
290
|
-
description: nestedDescription,
|
|
291
|
-
fields: candidate.fields
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
return null;
|
|
295
|
-
}
|
|
296
|
-
function inferLegacyFieldDefinitions(frontmatter) {
|
|
297
|
-
const normalized = {};
|
|
298
|
-
const ignoredKeys = /* @__PURE__ */ new Set(["primitive", "fields", "schema", "template"]);
|
|
299
|
-
for (const [key, value] of Object.entries(frontmatter)) {
|
|
300
|
-
if (ignoredKeys.has(key)) continue;
|
|
301
|
-
normalized[key] = {
|
|
302
|
-
type: inferFieldType(value),
|
|
303
|
-
default: value
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
return normalized;
|
|
307
|
-
}
|
|
308
|
-
function parseTemplateDefinition(rawTemplate, templateName, sourcePath) {
|
|
309
|
-
const normalizedName = normalizeTemplateName(templateName);
|
|
310
|
-
const { data, content } = (0, import_gray_matter.default)(rawTemplate);
|
|
311
|
-
const frontmatter = isRecord(data) ? data : {};
|
|
312
|
-
const extractedSchema = extractSchemaDefinition(frontmatter);
|
|
313
|
-
if (extractedSchema) {
|
|
314
|
-
return {
|
|
315
|
-
name: normalizedName,
|
|
316
|
-
primitive: extractedSchema.primitive,
|
|
317
|
-
description: extractedSchema.description,
|
|
318
|
-
fields: normalizeFieldDefinitions(extractedSchema.fields),
|
|
319
|
-
body: content,
|
|
320
|
-
format: "schema",
|
|
321
|
-
sourcePath
|
|
322
|
-
};
|
|
323
|
-
}
|
|
324
|
-
return {
|
|
325
|
-
name: normalizedName,
|
|
326
|
-
primitive: normalizedName,
|
|
327
|
-
description: typeof frontmatter.description === "string" ? frontmatter.description.trim() : void 0,
|
|
328
|
-
fields: inferLegacyFieldDefinitions(frontmatter),
|
|
329
|
-
body: content,
|
|
330
|
-
format: "legacy",
|
|
331
|
-
sourcePath
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
|
-
function readTemplateDefinitionFromPath(filePath, templateName) {
|
|
335
|
-
try {
|
|
336
|
-
const raw = fs.readFileSync(filePath, "utf-8");
|
|
337
|
-
return parseTemplateDefinition(raw, templateName, filePath);
|
|
338
|
-
} catch {
|
|
339
|
-
return null;
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
function loadTemplateDefinition(templateName, options = {}) {
|
|
343
|
-
const normalizedName = normalizeTemplateName(templateName);
|
|
344
|
-
if (!normalizedName) return null;
|
|
345
|
-
const index = buildTemplateIndex(options);
|
|
346
|
-
const filePath = index.get(normalizedName);
|
|
347
|
-
if (!filePath) return null;
|
|
348
|
-
return readTemplateDefinitionFromPath(filePath, normalizedName);
|
|
349
|
-
}
|
|
350
|
-
function resolveInterpolatedValue(value, variables) {
|
|
351
|
-
if (typeof value === "string") {
|
|
352
|
-
return renderTemplate(value, variables);
|
|
353
|
-
}
|
|
354
|
-
if (Array.isArray(value)) {
|
|
355
|
-
return value.map((item) => resolveInterpolatedValue(item, variables));
|
|
356
|
-
}
|
|
357
|
-
if (isRecord(value)) {
|
|
358
|
-
const resolved = {};
|
|
359
|
-
for (const [key, nested] of Object.entries(value)) {
|
|
360
|
-
resolved[key] = resolveInterpolatedValue(nested, variables);
|
|
361
|
-
}
|
|
362
|
-
return resolved;
|
|
363
|
-
}
|
|
364
|
-
return value;
|
|
365
|
-
}
|
|
366
|
-
function pruneFrontmatter(frontmatter, options) {
|
|
367
|
-
const dropEmptyStrings = options.dropEmptyStrings ?? true;
|
|
368
|
-
const dropEmptyArrays = options.dropEmptyArrays ?? true;
|
|
369
|
-
const pruned = {};
|
|
370
|
-
for (const [key, value] of Object.entries(frontmatter)) {
|
|
371
|
-
if (value === void 0 || value === null) continue;
|
|
372
|
-
if (dropEmptyStrings && typeof value === "string" && value.trim() === "") continue;
|
|
373
|
-
if (dropEmptyArrays && Array.isArray(value) && value.length === 0) continue;
|
|
374
|
-
pruned[key] = value;
|
|
375
|
-
}
|
|
376
|
-
return pruned;
|
|
377
|
-
}
|
|
378
|
-
function buildFrontmatterFromTemplate(definition, variables, overrides = {}, options = {}) {
|
|
379
|
-
const frontmatter = {};
|
|
380
|
-
for (const [fieldName, schema] of Object.entries(definition.fields)) {
|
|
381
|
-
if (!Object.prototype.hasOwnProperty.call(schema, "default")) continue;
|
|
382
|
-
frontmatter[fieldName] = resolveInterpolatedValue(schema.default, variables);
|
|
383
|
-
}
|
|
384
|
-
for (const [fieldName, value] of Object.entries(overrides)) {
|
|
385
|
-
if (value === void 0) continue;
|
|
386
|
-
if (value === null) {
|
|
387
|
-
delete frontmatter[fieldName];
|
|
388
|
-
continue;
|
|
389
|
-
}
|
|
390
|
-
frontmatter[fieldName] = value;
|
|
391
|
-
}
|
|
392
|
-
if (!options.pruneEmpty) {
|
|
393
|
-
return frontmatter;
|
|
394
|
-
}
|
|
395
|
-
return pruneFrontmatter(frontmatter, options);
|
|
396
|
-
}
|
|
397
|
-
function renderDocumentFromTemplate(definition, options = {}) {
|
|
398
|
-
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
399
|
-
const variables = {
|
|
400
|
-
...buildTemplateVariables(
|
|
401
|
-
{
|
|
402
|
-
title: options.title ?? "",
|
|
403
|
-
type: options.type ?? definition.primitive
|
|
404
|
-
},
|
|
405
|
-
now
|
|
406
|
-
),
|
|
407
|
-
...options.variables ?? {}
|
|
408
|
-
};
|
|
409
|
-
const frontmatter = buildFrontmatterFromTemplate(
|
|
410
|
-
definition,
|
|
411
|
-
variables,
|
|
412
|
-
options.overrides,
|
|
413
|
-
options.frontmatter
|
|
414
|
-
);
|
|
415
|
-
const content = renderTemplate(definition.body, variables);
|
|
416
|
-
const markdown = import_gray_matter.default.stringify(content, frontmatter);
|
|
417
|
-
return {
|
|
418
|
-
frontmatter,
|
|
419
|
-
content,
|
|
420
|
-
markdown,
|
|
421
|
-
variables
|
|
422
|
-
};
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
// src/commands/setup.ts
|
|
426
|
-
var CONFIG_FILE = ".clawvault.json";
|
|
427
|
-
function resolveVaultTarget(vaultOverride) {
|
|
428
|
-
if (vaultOverride) {
|
|
429
|
-
const vaultPath = path2.resolve(vaultOverride);
|
|
430
|
-
return { vaultPath, source: "--vault flag", existed: fs2.existsSync(vaultPath) };
|
|
431
|
-
}
|
|
432
|
-
const envPath = process.env.CLAWVAULT_PATH?.trim();
|
|
433
|
-
const home = os.homedir();
|
|
434
|
-
if (envPath) {
|
|
435
|
-
const vaultPath = path2.resolve(envPath);
|
|
436
|
-
return { vaultPath, source: "CLAWVAULT_PATH", existed: fs2.existsSync(vaultPath) };
|
|
437
|
-
}
|
|
438
|
-
const candidates = [
|
|
439
|
-
{ vaultPath: path2.join(home, ".openclaw", "workspace", "memory"), source: "OpenClaw default" },
|
|
440
|
-
{ vaultPath: path2.resolve(process.cwd(), "memory"), source: "./memory" },
|
|
441
|
-
{ vaultPath: path2.join(home, "memory"), source: "~/memory" }
|
|
442
|
-
];
|
|
443
|
-
for (const candidate of candidates) {
|
|
444
|
-
if (fs2.existsSync(candidate.vaultPath)) {
|
|
445
|
-
return { ...candidate, existed: true };
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
const fallback = candidates[0];
|
|
449
|
-
return { ...fallback, existed: false };
|
|
450
|
-
}
|
|
451
|
-
function ensureVaultStructure(vaultPath) {
|
|
452
|
-
fs2.mkdirSync(vaultPath, { recursive: true });
|
|
453
|
-
for (const category of DEFAULT_CATEGORIES) {
|
|
454
|
-
fs2.mkdirSync(path2.join(vaultPath, category), { recursive: true });
|
|
455
|
-
}
|
|
456
|
-
const configPath = path2.join(vaultPath, CONFIG_FILE);
|
|
457
|
-
if (fs2.existsSync(configPath)) return false;
|
|
458
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
459
|
-
const name = path2.basename(vaultPath);
|
|
460
|
-
const meta = {
|
|
461
|
-
name,
|
|
462
|
-
version: "1.0.0",
|
|
463
|
-
created: now,
|
|
464
|
-
lastUpdated: now,
|
|
465
|
-
categories: DEFAULT_CATEGORIES,
|
|
466
|
-
documentCount: 0,
|
|
467
|
-
qmdCollection: name,
|
|
468
|
-
qmdRoot: vaultPath
|
|
469
|
-
};
|
|
470
|
-
fs2.writeFileSync(configPath, JSON.stringify(meta, null, 2));
|
|
471
|
-
return true;
|
|
472
|
-
}
|
|
473
|
-
function writeBases(vaultPath, force) {
|
|
474
|
-
const basesFiles = {
|
|
475
|
-
"all-tasks.base": `filters:
|
|
476
|
-
and:
|
|
477
|
-
- file.inFolder("tasks")
|
|
478
|
-
- status != "done"
|
|
479
|
-
formulas:
|
|
480
|
-
age: (now() - file.ctime).days
|
|
481
|
-
status_icon: if(status == "blocked", "\u{1F534}", if(status == "in-progress", "\u{1F528}", if(status == "open", "\u26AA", "\u2705")))
|
|
482
|
-
views:
|
|
483
|
-
- type: table
|
|
484
|
-
name: All Active Tasks
|
|
485
|
-
groupBy:
|
|
486
|
-
property: status
|
|
487
|
-
direction: ASC
|
|
488
|
-
order:
|
|
489
|
-
- formula.status_icon
|
|
490
|
-
- file.name
|
|
491
|
-
- status
|
|
492
|
-
- owner
|
|
493
|
-
- project
|
|
494
|
-
- priority
|
|
495
|
-
- blocked_by
|
|
496
|
-
- formula.age
|
|
497
|
-
- type: cards
|
|
498
|
-
name: Task Board
|
|
499
|
-
groupBy:
|
|
500
|
-
property: status
|
|
501
|
-
direction: ASC
|
|
502
|
-
order:
|
|
503
|
-
- file.name
|
|
504
|
-
- owner
|
|
505
|
-
- project
|
|
506
|
-
- priority`,
|
|
507
|
-
"blocked.base": `filters:
|
|
508
|
-
and:
|
|
509
|
-
- file.inFolder("tasks")
|
|
510
|
-
- status == "blocked"
|
|
511
|
-
formulas:
|
|
512
|
-
days_blocked: (now() - file.ctime).days
|
|
513
|
-
views:
|
|
514
|
-
- type: table
|
|
515
|
-
name: Blocked Tasks
|
|
516
|
-
order:
|
|
517
|
-
- file.name
|
|
518
|
-
- owner
|
|
519
|
-
- project
|
|
520
|
-
- blocked_by
|
|
521
|
-
- formula.days_blocked
|
|
522
|
-
- priority`,
|
|
523
|
-
"by-project.base": `filters:
|
|
524
|
-
and:
|
|
525
|
-
- file.inFolder("tasks")
|
|
526
|
-
- status != "done"
|
|
527
|
-
formulas:
|
|
528
|
-
status_icon: if(status == "blocked", "\u{1F534}", if(status == "in-progress", "\u{1F528}", "\u26AA"))
|
|
529
|
-
views:
|
|
530
|
-
- type: table
|
|
531
|
-
name: By Project
|
|
532
|
-
groupBy:
|
|
533
|
-
property: project
|
|
534
|
-
direction: ASC
|
|
535
|
-
order:
|
|
536
|
-
- formula.status_icon
|
|
537
|
-
- file.name
|
|
538
|
-
- status
|
|
539
|
-
- owner
|
|
540
|
-
- priority
|
|
541
|
-
- type: cards
|
|
542
|
-
name: Project Cards
|
|
543
|
-
groupBy:
|
|
544
|
-
property: project
|
|
545
|
-
direction: ASC
|
|
546
|
-
order:
|
|
547
|
-
- file.name
|
|
548
|
-
- owner
|
|
549
|
-
- status`,
|
|
550
|
-
"by-owner.base": `filters:
|
|
551
|
-
and:
|
|
552
|
-
- file.inFolder("tasks")
|
|
553
|
-
- status != "done"
|
|
554
|
-
views:
|
|
555
|
-
- type: table
|
|
556
|
-
name: By Owner
|
|
557
|
-
groupBy:
|
|
558
|
-
property: owner
|
|
559
|
-
direction: ASC
|
|
560
|
-
order:
|
|
561
|
-
- file.name
|
|
562
|
-
- status
|
|
563
|
-
- project
|
|
564
|
-
- priority`,
|
|
565
|
-
"backlog.base": `filters:
|
|
566
|
-
and:
|
|
567
|
-
- file.inFolder("backlog")
|
|
568
|
-
views:
|
|
569
|
-
- type: table
|
|
570
|
-
name: Backlog
|
|
571
|
-
order:
|
|
572
|
-
- file.name
|
|
573
|
-
- source
|
|
574
|
-
- project
|
|
575
|
-
- file.ctime`
|
|
576
|
-
};
|
|
577
|
-
let written = 0;
|
|
578
|
-
for (const [filename, content] of Object.entries(basesFiles)) {
|
|
579
|
-
const filePath = path2.join(vaultPath, filename);
|
|
580
|
-
if (force || !fs2.existsSync(filePath)) {
|
|
581
|
-
fs2.writeFileSync(filePath, content);
|
|
582
|
-
written++;
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
return written;
|
|
586
|
-
}
|
|
587
|
-
var NEURAL_GRAPH_CSS = `/* ClawVault Graph Colors \u2014 Neural Neural Style */
|
|
588
|
-
/* Auto-generated by \`clawvault setup --theme neural\` */
|
|
589
|
-
|
|
590
|
-
body.theme-dark .graph-view .graph-view-container { background-color: #0a0a0a; }
|
|
591
|
-
|
|
592
|
-
body.theme-dark .graph-view .node.tag-person circle { fill: #00b4d8 !important; }
|
|
593
|
-
body.theme-dark .graph-view .node.tag-project circle { fill: #2d6a4f !important; }
|
|
594
|
-
body.theme-dark .graph-view .node.tag-decision circle { fill: #e8590c !important; }
|
|
595
|
-
body.theme-dark .graph-view .node.tag-lesson circle { fill: #fcc419 !important; }
|
|
596
|
-
body.theme-dark .graph-view .node.tag-commitment circle { fill: #e03131 !important; }
|
|
597
|
-
body.theme-dark .graph-view .node.tag-task circle { fill: #22b8cf !important; }
|
|
598
|
-
body.theme-dark .graph-view .node.tag-observation circle { fill: #7950f2 !important; }
|
|
599
|
-
body.theme-dark .graph-view .node.tag-handoff circle { fill: #845ef7 !important; }
|
|
600
|
-
body.theme-dark .graph-view .node.tag-daily circle { fill: #495057 !important; }
|
|
601
|
-
|
|
602
|
-
body.theme-dark .graph-view .node.is-focused circle {
|
|
603
|
-
fill: #e8a430 !important; stroke: #e8a430 !important;
|
|
604
|
-
stroke-width: 3px; filter: drop-shadow(0 0 6px #e8a430);
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
body.theme-dark .graph-view .link { stroke: rgba(45, 200, 120, 0.15) !important; }
|
|
608
|
-
body.theme-dark .graph-view .link.is-focused { stroke: rgba(45, 200, 120, 0.6) !important; }
|
|
609
|
-
body.theme-dark .graph-view .node text { fill: #c1c2c5 !important; font-size: 0.8em; }
|
|
610
|
-
`;
|
|
611
|
-
var MINIMAL_GRAPH_CSS = `/* ClawVault Graph Colors \u2014 Minimal */
|
|
612
|
-
/* Auto-generated by \`clawvault setup --theme minimal\` */
|
|
613
|
-
|
|
614
|
-
body.theme-dark .graph-view .node.tag-person circle { fill: #4a90e8 !important; }
|
|
615
|
-
body.theme-dark .graph-view .node.tag-project circle { fill: #4ae85d !important; }
|
|
616
|
-
body.theme-dark .graph-view .node.tag-decision circle { fill: #e85d4a !important; }
|
|
617
|
-
body.theme-dark .graph-view .node.tag-lesson circle { fill: #9b59b6 !important; }
|
|
618
|
-
body.theme-dark .graph-view .node.tag-task circle { fill: #e8a430 !important; }
|
|
619
|
-
`;
|
|
620
|
-
var NEURAL_COLOR_GROUPS = [
|
|
621
|
-
{ query: "path:people", color: { a: 1, rgb: 47316 } },
|
|
622
|
-
{ query: "path:projects", color: { a: 1, rgb: 2976335 } },
|
|
623
|
-
{ query: "path:decisions", color: { a: 1, rgb: 15227916 } },
|
|
624
|
-
{ query: "path:lessons", color: { a: 1, rgb: 16565273 } },
|
|
625
|
-
{ query: "path:tasks", color: { a: 1, rgb: 2275535 } },
|
|
626
|
-
{ query: "path:commitments", color: { a: 1, rgb: 14680369 } },
|
|
627
|
-
{ query: "path:backlog", color: { a: 1, rgb: 9806262 } },
|
|
628
|
-
{ query: "path:inbox", color: { a: 1, rgb: 15964178 } },
|
|
629
|
-
{ query: "path:handoffs", color: { a: 1, rgb: 8675063 } },
|
|
630
|
-
{ query: "path:ledger", color: { a: 1, rgb: 7950066 } }
|
|
631
|
-
];
|
|
632
|
-
var MINIMAL_COLOR_GROUPS = [
|
|
633
|
-
{ query: "path:people", color: { a: 1, rgb: 4886760 } },
|
|
634
|
-
{ query: "path:projects", color: { a: 1, rgb: 4909149 } },
|
|
635
|
-
{ query: "path:decisions", color: { a: 1, rgb: 15228234 } },
|
|
636
|
-
{ query: "path:lessons", color: { a: 1, rgb: 10181046 } },
|
|
637
|
-
{ query: "path:tasks", color: { a: 1, rgb: 15246384 } }
|
|
638
|
-
];
|
|
639
|
-
function writeGraphColors(vaultPath, theme, force) {
|
|
640
|
-
const obsidianDir = path2.join(vaultPath, ".obsidian");
|
|
641
|
-
if (!fs2.existsSync(obsidianDir)) {
|
|
642
|
-
return false;
|
|
643
|
-
}
|
|
644
|
-
const snippetsDir = path2.join(obsidianDir, "snippets");
|
|
645
|
-
fs2.mkdirSync(snippetsDir, { recursive: true });
|
|
646
|
-
const snippetName = "clawvault-graph";
|
|
647
|
-
const snippetPath = path2.join(snippetsDir, `${snippetName}.css`);
|
|
648
|
-
if (!force && fs2.existsSync(snippetPath)) {
|
|
649
|
-
return false;
|
|
650
|
-
}
|
|
651
|
-
const css = theme === "neural" ? NEURAL_GRAPH_CSS : MINIMAL_GRAPH_CSS;
|
|
652
|
-
fs2.writeFileSync(snippetPath, css);
|
|
653
|
-
const appearancePath = path2.join(obsidianDir, "appearance.json");
|
|
654
|
-
let appearance = {};
|
|
655
|
-
if (fs2.existsSync(appearancePath)) {
|
|
656
|
-
try {
|
|
657
|
-
appearance = JSON.parse(fs2.readFileSync(appearancePath, "utf-8"));
|
|
658
|
-
} catch {
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
const snippets = appearance.enabledCssSnippets || [];
|
|
662
|
-
if (!snippets.includes(snippetName)) {
|
|
663
|
-
snippets.push(snippetName);
|
|
664
|
-
appearance.enabledCssSnippets = snippets;
|
|
665
|
-
fs2.writeFileSync(appearancePath, JSON.stringify(appearance, null, 2));
|
|
666
|
-
}
|
|
667
|
-
const graphPath = path2.join(obsidianDir, "graph.json");
|
|
668
|
-
let graphConfig = {};
|
|
669
|
-
if (fs2.existsSync(graphPath)) {
|
|
670
|
-
try {
|
|
671
|
-
graphConfig = JSON.parse(fs2.readFileSync(graphPath, "utf-8"));
|
|
672
|
-
} catch {
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
graphConfig.colorGroups = theme === "neural" ? NEURAL_COLOR_GROUPS : MINIMAL_COLOR_GROUPS;
|
|
676
|
-
if (theme === "neural") {
|
|
677
|
-
graphConfig.showTags = false;
|
|
678
|
-
graphConfig.showAttachments = false;
|
|
679
|
-
graphConfig.nodeSizeMultiplier = 1.2;
|
|
680
|
-
graphConfig.lineSizeMultiplier = 0.8;
|
|
681
|
-
graphConfig.textFadeMultiplier = 0;
|
|
682
|
-
graphConfig.repelStrength = 10;
|
|
683
|
-
graphConfig.linkDistance = 250;
|
|
684
|
-
graphConfig.centerStrength = 0.5;
|
|
685
|
-
}
|
|
686
|
-
fs2.writeFileSync(graphPath, JSON.stringify(graphConfig, null, 2));
|
|
687
|
-
return true;
|
|
688
|
-
}
|
|
689
|
-
function getQmdConfig(vaultPath) {
|
|
690
|
-
const configPath = path2.join(vaultPath, CONFIG_FILE);
|
|
691
|
-
if (fs2.existsSync(configPath)) {
|
|
692
|
-
try {
|
|
693
|
-
const meta = JSON.parse(fs2.readFileSync(configPath, "utf-8"));
|
|
694
|
-
return {
|
|
695
|
-
collection: meta.qmdCollection || meta.name || path2.basename(vaultPath),
|
|
696
|
-
root: meta.qmdRoot || vaultPath
|
|
697
|
-
};
|
|
698
|
-
} catch {
|
|
699
|
-
return { collection: path2.basename(vaultPath), root: vaultPath };
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
return { collection: path2.basename(vaultPath), root: vaultPath };
|
|
703
|
-
}
|
|
704
|
-
function slugify(text) {
|
|
705
|
-
return text.toLowerCase().replace(/[^\w\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "").trim();
|
|
706
|
-
}
|
|
707
|
-
function scanMarkdownFiles(dirPath) {
|
|
708
|
-
const files = [];
|
|
709
|
-
const resolvedPath = path2.resolve(dirPath);
|
|
710
|
-
if (!fs2.existsSync(resolvedPath)) {
|
|
711
|
-
return files;
|
|
712
|
-
}
|
|
713
|
-
const stat = fs2.statSync(resolvedPath);
|
|
714
|
-
if (stat.isFile() && resolvedPath.endsWith(".md")) {
|
|
715
|
-
return [resolvedPath];
|
|
716
|
-
}
|
|
717
|
-
if (!stat.isDirectory()) {
|
|
718
|
-
return files;
|
|
719
|
-
}
|
|
720
|
-
const entries = fs2.readdirSync(resolvedPath, { withFileTypes: true });
|
|
721
|
-
for (const entry of entries) {
|
|
722
|
-
const fullPath = path2.join(resolvedPath, entry.name);
|
|
723
|
-
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
724
|
-
files.push(fullPath);
|
|
725
|
-
} else if (entry.isDirectory()) {
|
|
726
|
-
files.push(...scanMarkdownFiles(fullPath));
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
return files;
|
|
730
|
-
}
|
|
731
|
-
function extractPeople(content) {
|
|
732
|
-
const people = [];
|
|
733
|
-
const seenNames = /* @__PURE__ */ new Set();
|
|
734
|
-
const emailPattern = /([A-Z][a-z]+(?:\s+[A-Z][a-z]+)+)\s*<([^>]+@[^>]+)>/g;
|
|
735
|
-
let match;
|
|
736
|
-
while ((match = emailPattern.exec(content)) !== null) {
|
|
737
|
-
const name = match[1].trim();
|
|
738
|
-
const email = match[2].trim();
|
|
739
|
-
if (!seenNames.has(name.toLowerCase())) {
|
|
740
|
-
seenNames.add(name.toLowerCase());
|
|
741
|
-
people.push({ name, email });
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
const rolePatterns = [
|
|
745
|
-
/([A-Z][a-z]+(?:\s+[A-Z][a-z]+)+)\s*\(([^)]+)\)/g,
|
|
746
|
-
/([A-Z][a-z]+(?:\s+[A-Z][a-z]+)+),\s*(CEO|CTO|CFO|COO|VP|Director|Manager|Engineer|Designer|Lead|Head of [A-Za-z]+)/gi
|
|
747
|
-
];
|
|
748
|
-
for (const pattern of rolePatterns) {
|
|
749
|
-
while ((match = pattern.exec(content)) !== null) {
|
|
750
|
-
const name = match[1].trim();
|
|
751
|
-
const role = match[2].trim();
|
|
752
|
-
if (!seenNames.has(name.toLowerCase())) {
|
|
753
|
-
seenNames.add(name.toLowerCase());
|
|
754
|
-
people.push({ name, role });
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
const contextPatterns = [
|
|
759
|
-
/(?:contact|met with|spoke with|emailed|called|messaged|talked to|meeting with)\s+([A-Z][a-zA-Z]*(?:\s+[A-Z][a-zA-Z]*)+)/g,
|
|
760
|
-
/([A-Z][a-zA-Z]*(?:\s+[A-Z][a-zA-Z]*)+)\s+(?:said|mentioned|suggested|recommended|asked|told me)/g
|
|
761
|
-
];
|
|
762
|
-
for (const pattern of contextPatterns) {
|
|
763
|
-
while ((match = pattern.exec(content)) !== null) {
|
|
764
|
-
const name = match[1].trim();
|
|
765
|
-
if (!seenNames.has(name.toLowerCase()) && name.split(" ").length >= 2) {
|
|
766
|
-
seenNames.add(name.toLowerCase());
|
|
767
|
-
const lineStart = content.lastIndexOf("\n", match.index) + 1;
|
|
768
|
-
const lineEnd = content.indexOf("\n", match.index + match[0].length);
|
|
769
|
-
const context = content.slice(lineStart, lineEnd === -1 ? void 0 : lineEnd).trim();
|
|
770
|
-
people.push({ name, context: context.slice(0, 200) });
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
}
|
|
774
|
-
return people;
|
|
775
|
-
}
|
|
776
|
-
function extractPreferences(content) {
|
|
777
|
-
const preferences = [];
|
|
778
|
-
const seenPrefs = /* @__PURE__ */ new Set();
|
|
779
|
-
const patterns = [
|
|
780
|
-
// "prefers X" / "prefer X" / "I prefer X"
|
|
781
|
-
/(?:I\s+)?prefer(?:s)?\s+(?:to\s+)?([^.,\n]+)/gi,
|
|
782
|
-
// "likes X" / "like X"
|
|
783
|
-
/(?:I\s+)?like(?:s)?\s+(?:to\s+)?([^.,\n]+)/gi,
|
|
784
|
-
// "always use X"
|
|
785
|
-
/always\s+(?:use|uses?)\s+([^.,\n]+)/gi,
|
|
786
|
-
// "never use X"
|
|
787
|
-
/never\s+(?:use|uses?)\s+([^.,\n]+)/gi,
|
|
788
|
-
// "favorite X is Y"
|
|
789
|
-
/(?:my\s+)?favorite\s+(\w+)\s+is\s+([^.,\n]+)/gi,
|
|
790
|
-
// "prefer X over Y"
|
|
791
|
-
/prefer(?:s)?\s+([^.,\n]+)\s+over\s+([^.,\n]+)/gi,
|
|
792
|
-
// "use X instead of Y"
|
|
793
|
-
/use(?:s)?\s+([^.,\n]+)\s+instead\s+of\s+([^.,\n]+)/gi
|
|
794
|
-
];
|
|
795
|
-
for (const pattern of patterns) {
|
|
796
|
-
let match;
|
|
797
|
-
while ((match = pattern.exec(content)) !== null) {
|
|
798
|
-
const fullMatch = match[0].trim();
|
|
799
|
-
const key = fullMatch.toLowerCase();
|
|
800
|
-
if (!seenPrefs.has(key) && fullMatch.length > 5 && fullMatch.length < 200) {
|
|
801
|
-
seenPrefs.add(key);
|
|
802
|
-
const lineStart = content.lastIndexOf("\n", match.index) + 1;
|
|
803
|
-
const lineEnd = content.indexOf("\n", match.index + match[0].length);
|
|
804
|
-
const context = content.slice(lineStart, lineEnd === -1 ? void 0 : lineEnd).trim();
|
|
805
|
-
let subject = "general";
|
|
806
|
-
let preference = fullMatch;
|
|
807
|
-
if (match[2]) {
|
|
808
|
-
subject = match[1].trim();
|
|
809
|
-
preference = match[2].trim();
|
|
810
|
-
} else if (match[1]) {
|
|
811
|
-
preference = match[1].trim();
|
|
812
|
-
}
|
|
813
|
-
preferences.push({ subject, preference, context: context.slice(0, 200) });
|
|
814
|
-
}
|
|
815
|
-
}
|
|
816
|
-
}
|
|
817
|
-
return preferences;
|
|
818
|
-
}
|
|
819
|
-
function extractDecisions(content) {
|
|
820
|
-
const decisions = [];
|
|
821
|
-
const seenDecisions = /* @__PURE__ */ new Set();
|
|
822
|
-
const patterns = [
|
|
823
|
-
// "decided to X"
|
|
824
|
-
/(?:I\s+|we\s+)?decided\s+(?:to\s+)?([^.,\n]+)/gi,
|
|
825
|
-
// "decision: X" or "Decision - X"
|
|
826
|
-
/decision[:\s-]+([^.,\n]+)/gi,
|
|
827
|
-
// "we chose X" / "chose to X"
|
|
828
|
-
/(?:we\s+)?chose\s+(?:to\s+)?([^.,\n]+)/gi,
|
|
829
|
-
// "going with X"
|
|
830
|
-
/going\s+with\s+([^.,\n]+)/gi,
|
|
831
|
-
// "settled on X"
|
|
832
|
-
/settled\s+on\s+([^.,\n]+)/gi,
|
|
833
|
-
// "will use X" / "using X going forward"
|
|
834
|
-
/(?:will\s+use|using)\s+([^.,\n]+)\s+(?:going\s+forward|from\s+now\s+on)/gi
|
|
835
|
-
];
|
|
836
|
-
for (const pattern of patterns) {
|
|
837
|
-
let match;
|
|
838
|
-
while ((match = pattern.exec(content)) !== null) {
|
|
839
|
-
const decision = match[1].trim();
|
|
840
|
-
const key = decision.toLowerCase();
|
|
841
|
-
if (!seenDecisions.has(key) && decision.length > 5 && decision.length < 200) {
|
|
842
|
-
seenDecisions.add(key);
|
|
843
|
-
const lineStart = content.lastIndexOf("\n", match.index) + 1;
|
|
844
|
-
const lineEnd = content.indexOf("\n", match.index + match[0].length);
|
|
845
|
-
const context = content.slice(lineStart, lineEnd === -1 ? void 0 : lineEnd).trim();
|
|
846
|
-
const title = decision.length > 50 ? decision.slice(0, 50).trim() + "..." : decision;
|
|
847
|
-
decisions.push({ title, decision, context: context.slice(0, 200) });
|
|
848
|
-
}
|
|
849
|
-
}
|
|
850
|
-
}
|
|
851
|
-
return decisions;
|
|
852
|
-
}
|
|
853
|
-
function extractTasks(content) {
|
|
854
|
-
const tasks = [];
|
|
855
|
-
const seenTasks = /* @__PURE__ */ new Set();
|
|
856
|
-
const patterns = [
|
|
857
|
-
// Markdown checkbox "- [ ] task"
|
|
858
|
-
/^[\s]*[-*]\s*\[\s*\]\s*(.+)$/gm,
|
|
859
|
-
// "TODO: task" or "TODO - task"
|
|
860
|
-
/TODO[:\s-]+(.+)/gi,
|
|
861
|
-
// "FIXME: task"
|
|
862
|
-
/FIXME[:\s-]+(.+)/gi,
|
|
863
|
-
// "need to X"
|
|
864
|
-
/(?:I\s+|we\s+)?need\s+to\s+([^.,\n]+)/gi,
|
|
865
|
-
// "should X" (but not "should have" which is past)
|
|
866
|
-
/(?:I\s+|we\s+)?should\s+(?!have)([^.,\n]+)/gi,
|
|
867
|
-
// "must X"
|
|
868
|
-
/(?:I\s+|we\s+)?must\s+([^.,\n]+)/gi,
|
|
869
|
-
// "remember to X"
|
|
870
|
-
/remember\s+to\s+([^.,\n]+)/gi,
|
|
871
|
-
// "don't forget to X"
|
|
872
|
-
/don'?t\s+forget\s+to\s+([^.,\n]+)/gi
|
|
873
|
-
];
|
|
874
|
-
for (const pattern of patterns) {
|
|
875
|
-
let match;
|
|
876
|
-
while ((match = pattern.exec(content)) !== null) {
|
|
877
|
-
const taskText = match[1].trim();
|
|
878
|
-
const key = taskText.toLowerCase();
|
|
879
|
-
if (!seenTasks.has(key) && taskText.length > 3 && taskText.length < 200) {
|
|
880
|
-
seenTasks.add(key);
|
|
881
|
-
let priority = "medium";
|
|
882
|
-
const lowerTask = taskText.toLowerCase();
|
|
883
|
-
if (lowerTask.includes("urgent") || lowerTask.includes("asap") || lowerTask.includes("critical")) {
|
|
884
|
-
priority = "critical";
|
|
885
|
-
} else if (lowerTask.includes("important") || lowerTask.includes("high priority")) {
|
|
886
|
-
priority = "high";
|
|
887
|
-
} else if (lowerTask.includes("low priority") || lowerTask.includes("eventually") || lowerTask.includes("someday")) {
|
|
888
|
-
priority = "low";
|
|
889
|
-
}
|
|
890
|
-
tasks.push({ title: taskText, priority });
|
|
891
|
-
}
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
return tasks;
|
|
895
|
-
}
|
|
896
|
-
function extractFromContent(content) {
|
|
897
|
-
return {
|
|
898
|
-
people: extractPeople(content),
|
|
899
|
-
preferences: extractPreferences(content),
|
|
900
|
-
decisions: extractDecisions(content),
|
|
901
|
-
tasks: extractTasks(content)
|
|
902
|
-
};
|
|
903
|
-
}
|
|
904
|
-
function scanAndExtract(sourcePath) {
|
|
905
|
-
const files = scanMarkdownFiles(sourcePath);
|
|
906
|
-
const combined = {
|
|
907
|
-
people: [],
|
|
908
|
-
preferences: [],
|
|
909
|
-
decisions: [],
|
|
910
|
-
tasks: []
|
|
911
|
-
};
|
|
912
|
-
for (const file of files) {
|
|
913
|
-
try {
|
|
914
|
-
const content = fs2.readFileSync(file, "utf-8");
|
|
915
|
-
const extracted = extractFromContent(content);
|
|
916
|
-
combined.people.push(...extracted.people);
|
|
917
|
-
combined.preferences.push(...extracted.preferences);
|
|
918
|
-
combined.decisions.push(...extracted.decisions);
|
|
919
|
-
combined.tasks.push(...extracted.tasks);
|
|
920
|
-
} catch {
|
|
921
|
-
}
|
|
922
|
-
}
|
|
923
|
-
const seenPeople = /* @__PURE__ */ new Set();
|
|
924
|
-
combined.people = combined.people.filter((p) => {
|
|
925
|
-
const key = p.name.toLowerCase();
|
|
926
|
-
if (seenPeople.has(key)) return false;
|
|
927
|
-
seenPeople.add(key);
|
|
928
|
-
return true;
|
|
929
|
-
});
|
|
930
|
-
const seenPrefs = /* @__PURE__ */ new Set();
|
|
931
|
-
combined.preferences = combined.preferences.filter((p) => {
|
|
932
|
-
const key = `${p.subject}:${p.preference}`.toLowerCase();
|
|
933
|
-
if (seenPrefs.has(key)) return false;
|
|
934
|
-
seenPrefs.add(key);
|
|
935
|
-
return true;
|
|
936
|
-
});
|
|
937
|
-
const seenDecisions = /* @__PURE__ */ new Set();
|
|
938
|
-
combined.decisions = combined.decisions.filter((d) => {
|
|
939
|
-
const key = d.decision.toLowerCase();
|
|
940
|
-
if (seenDecisions.has(key)) return false;
|
|
941
|
-
seenDecisions.add(key);
|
|
942
|
-
return true;
|
|
943
|
-
});
|
|
944
|
-
const seenTasks = /* @__PURE__ */ new Set();
|
|
945
|
-
combined.tasks = combined.tasks.filter((t) => {
|
|
946
|
-
const key = t.title.toLowerCase();
|
|
947
|
-
if (seenTasks.has(key)) return false;
|
|
948
|
-
seenTasks.add(key);
|
|
949
|
-
return true;
|
|
950
|
-
});
|
|
951
|
-
return combined;
|
|
952
|
-
}
|
|
953
|
-
function fileExistsWithSimilarName(dir, slug) {
|
|
954
|
-
if (!fs2.existsSync(dir)) return false;
|
|
955
|
-
const files = fs2.readdirSync(dir);
|
|
956
|
-
const targetSlug = slug.toLowerCase();
|
|
957
|
-
return files.some((f) => {
|
|
958
|
-
const fileSlug = path2.basename(f, ".md").toLowerCase();
|
|
959
|
-
return fileSlug === targetSlug || fileSlug.includes(targetSlug) || targetSlug.includes(fileSlug);
|
|
960
|
-
});
|
|
961
|
-
}
|
|
962
|
-
function writePerson(vaultPath, person, force) {
|
|
963
|
-
const peopleDir = path2.join(vaultPath, "people");
|
|
964
|
-
fs2.mkdirSync(peopleDir, { recursive: true });
|
|
965
|
-
const slug = slugify(person.name);
|
|
966
|
-
if (!slug) return null;
|
|
967
|
-
const filePath = path2.join(peopleDir, `${slug}.md`);
|
|
968
|
-
if (!force && (fs2.existsSync(filePath) || fileExistsWithSimilarName(peopleDir, slug))) {
|
|
969
|
-
return null;
|
|
970
|
-
}
|
|
971
|
-
const template = loadTemplateDefinition("person");
|
|
972
|
-
const now = /* @__PURE__ */ new Date();
|
|
973
|
-
const date = now.toISOString().split("T")[0];
|
|
974
|
-
let content;
|
|
975
|
-
if (template) {
|
|
976
|
-
const rendered = renderDocumentFromTemplate(template, {
|
|
977
|
-
title: person.name,
|
|
978
|
-
now,
|
|
979
|
-
overrides: {
|
|
980
|
-
relationship: person.role ? "colleague" : "contact"
|
|
981
|
-
}
|
|
982
|
-
});
|
|
983
|
-
let body = rendered.content;
|
|
984
|
-
if (person.context) {
|
|
985
|
-
body = body.replace(/## Context\n-\s*/, `## Context
|
|
986
|
-
- ${person.context}
|
|
987
|
-
`);
|
|
988
|
-
}
|
|
989
|
-
if (person.email || person.role) {
|
|
990
|
-
const details = [];
|
|
991
|
-
if (person.email) details.push(`- Contact: ${person.email}`);
|
|
992
|
-
if (person.role) details.push(`- Role: ${person.role}`);
|
|
993
|
-
body = body.replace(/## Details\n- Contact:\n- Role:\n- Timezone:/, `## Details
|
|
994
|
-
${details.join("\n")}
|
|
995
|
-
- Timezone:`);
|
|
996
|
-
}
|
|
997
|
-
content = import_gray_matter2.default.stringify(body, rendered.frontmatter);
|
|
998
|
-
} else {
|
|
999
|
-
const frontmatter = {
|
|
1000
|
-
title: person.name,
|
|
1001
|
-
date,
|
|
1002
|
-
type: "person",
|
|
1003
|
-
relationship: person.role ? "colleague" : "contact"
|
|
1004
|
-
};
|
|
1005
|
-
let body = `# ${person.name}
|
|
1006
|
-
|
|
1007
|
-
## Context
|
|
1008
|
-
`;
|
|
1009
|
-
if (person.context) body += `- ${person.context}
|
|
1010
|
-
`;
|
|
1011
|
-
else body += "- \n";
|
|
1012
|
-
body += "\n## Details\n";
|
|
1013
|
-
if (person.email) body += `- Contact: ${person.email}
|
|
1014
|
-
`;
|
|
1015
|
-
else body += "- Contact:\n";
|
|
1016
|
-
if (person.role) body += `- Role: ${person.role}
|
|
1017
|
-
`;
|
|
1018
|
-
else body += "- Role:\n";
|
|
1019
|
-
body += "- Timezone:\n";
|
|
1020
|
-
body += `
|
|
1021
|
-
## History
|
|
1022
|
-
- ${date}: Added from memory import
|
|
1023
|
-
`;
|
|
1024
|
-
content = import_gray_matter2.default.stringify(body, frontmatter);
|
|
1025
|
-
}
|
|
1026
|
-
fs2.writeFileSync(filePath, content);
|
|
1027
|
-
return slug;
|
|
1028
|
-
}
|
|
1029
|
-
function writePreference(vaultPath, pref, force) {
|
|
1030
|
-
const prefsDir = path2.join(vaultPath, "preferences");
|
|
1031
|
-
fs2.mkdirSync(prefsDir, { recursive: true });
|
|
1032
|
-
const slug = slugify(`${pref.subject}-${pref.preference}`.slice(0, 60));
|
|
1033
|
-
if (!slug) return null;
|
|
1034
|
-
const filePath = path2.join(prefsDir, `${slug}.md`);
|
|
1035
|
-
if (!force && (fs2.existsSync(filePath) || fileExistsWithSimilarName(prefsDir, slug))) {
|
|
1036
|
-
return null;
|
|
1037
|
-
}
|
|
1038
|
-
const now = /* @__PURE__ */ new Date();
|
|
1039
|
-
const date = now.toISOString().split("T")[0];
|
|
1040
|
-
const frontmatter = {
|
|
1041
|
-
title: `${pref.subject}: ${pref.preference}`.slice(0, 100),
|
|
1042
|
-
date,
|
|
1043
|
-
type: "preference",
|
|
1044
|
-
category: pref.subject
|
|
1045
|
-
};
|
|
1046
|
-
let body = `# ${frontmatter.title}
|
|
1047
|
-
|
|
1048
|
-
`;
|
|
1049
|
-
body += `## Preference
|
|
1050
|
-
- ${pref.preference}
|
|
1051
|
-
`;
|
|
1052
|
-
if (pref.context) {
|
|
1053
|
-
body += `
|
|
1054
|
-
## Context
|
|
1055
|
-
- ${pref.context}
|
|
1056
|
-
`;
|
|
1057
|
-
}
|
|
1058
|
-
body += `
|
|
1059
|
-
## Source
|
|
1060
|
-
- Imported from memory on ${date}
|
|
1061
|
-
`;
|
|
1062
|
-
const content = import_gray_matter2.default.stringify(body, frontmatter);
|
|
1063
|
-
fs2.writeFileSync(filePath, content);
|
|
1064
|
-
return slug;
|
|
1065
|
-
}
|
|
1066
|
-
function writeDecision(vaultPath, decision, force) {
|
|
1067
|
-
const decisionsDir = path2.join(vaultPath, "decisions");
|
|
1068
|
-
fs2.mkdirSync(decisionsDir, { recursive: true });
|
|
1069
|
-
const slug = slugify(decision.title);
|
|
1070
|
-
if (!slug) return null;
|
|
1071
|
-
const filePath = path2.join(decisionsDir, `${slug}.md`);
|
|
1072
|
-
if (!force && (fs2.existsSync(filePath) || fileExistsWithSimilarName(decisionsDir, slug))) {
|
|
1073
|
-
return null;
|
|
1074
|
-
}
|
|
1075
|
-
const template = loadTemplateDefinition("decision");
|
|
1076
|
-
const now = /* @__PURE__ */ new Date();
|
|
1077
|
-
const date = now.toISOString().split("T")[0];
|
|
1078
|
-
let content;
|
|
1079
|
-
if (template) {
|
|
1080
|
-
const rendered = renderDocumentFromTemplate(template, {
|
|
1081
|
-
title: decision.title,
|
|
1082
|
-
now,
|
|
1083
|
-
overrides: {
|
|
1084
|
-
status: "decided"
|
|
1085
|
-
}
|
|
1086
|
-
});
|
|
1087
|
-
let body = rendered.content;
|
|
1088
|
-
if (decision.context) {
|
|
1089
|
-
body = body.replace(/## Context\n-\s*/, `## Context
|
|
1090
|
-
- ${decision.context}
|
|
1091
|
-
`);
|
|
1092
|
-
}
|
|
1093
|
-
body = body.replace(/## Decision\n-\s*/, `## Decision
|
|
1094
|
-
- ${decision.decision}
|
|
1095
|
-
`);
|
|
1096
|
-
body = body.replace(/## Consequences\n-\s*/, `## Consequences
|
|
1097
|
-
- Imported from memory on ${date}
|
|
1098
|
-
`);
|
|
1099
|
-
content = import_gray_matter2.default.stringify(body, rendered.frontmatter);
|
|
1100
|
-
} else {
|
|
1101
|
-
const frontmatter = {
|
|
1102
|
-
title: decision.title,
|
|
1103
|
-
date,
|
|
1104
|
-
type: "decision",
|
|
1105
|
-
status: "decided"
|
|
1106
|
-
};
|
|
1107
|
-
let body = `# Decision: ${decision.title}
|
|
1108
|
-
|
|
1109
|
-
`;
|
|
1110
|
-
body += `## Context
|
|
1111
|
-
`;
|
|
1112
|
-
if (decision.context) body += `- ${decision.context}
|
|
1113
|
-
`;
|
|
1114
|
-
else body += "- \n";
|
|
1115
|
-
body += `
|
|
1116
|
-
## Decision
|
|
1117
|
-
- ${decision.decision}
|
|
1118
|
-
`;
|
|
1119
|
-
body += `
|
|
1120
|
-
## Consequences
|
|
1121
|
-
- Imported from memory on ${date}
|
|
1122
|
-
`;
|
|
1123
|
-
content = import_gray_matter2.default.stringify(body, frontmatter);
|
|
1124
|
-
}
|
|
1125
|
-
fs2.writeFileSync(filePath, content);
|
|
1126
|
-
return slug;
|
|
1127
|
-
}
|
|
1128
|
-
function writeTask(vaultPath, task, force) {
|
|
1129
|
-
const tasksDir = path2.join(vaultPath, "tasks");
|
|
1130
|
-
fs2.mkdirSync(tasksDir, { recursive: true });
|
|
1131
|
-
const slug = slugify(task.title);
|
|
1132
|
-
if (!slug) return null;
|
|
1133
|
-
const filePath = path2.join(tasksDir, `${slug}.md`);
|
|
1134
|
-
if (!force && (fs2.existsSync(filePath) || fileExistsWithSimilarName(tasksDir, slug))) {
|
|
1135
|
-
return null;
|
|
1136
|
-
}
|
|
1137
|
-
const template = loadTemplateDefinition("task");
|
|
1138
|
-
const now = /* @__PURE__ */ new Date();
|
|
1139
|
-
const datetime = now.toISOString();
|
|
1140
|
-
let content;
|
|
1141
|
-
if (template) {
|
|
1142
|
-
const rendered = renderDocumentFromTemplate(template, {
|
|
1143
|
-
title: task.title,
|
|
1144
|
-
now,
|
|
1145
|
-
overrides: {
|
|
1146
|
-
status: "open",
|
|
1147
|
-
priority: task.priority || "medium",
|
|
1148
|
-
source: "memory-import",
|
|
1149
|
-
description: task.description
|
|
1150
|
-
},
|
|
1151
|
-
frontmatter: { pruneEmpty: true }
|
|
1152
|
-
});
|
|
1153
|
-
content = rendered.markdown;
|
|
1154
|
-
} else {
|
|
1155
|
-
const frontmatter = {
|
|
1156
|
-
status: "open",
|
|
1157
|
-
source: "memory-import",
|
|
1158
|
-
created: datetime,
|
|
1159
|
-
updated: datetime,
|
|
1160
|
-
priority: task.priority || "medium"
|
|
1161
|
-
};
|
|
1162
|
-
if (task.description) frontmatter.description = task.description;
|
|
1163
|
-
const body = `# ${task.title}
|
|
1164
|
-
|
|
1165
|
-
`;
|
|
1166
|
-
content = import_gray_matter2.default.stringify(body, frontmatter);
|
|
1167
|
-
}
|
|
1168
|
-
fs2.writeFileSync(filePath, content);
|
|
1169
|
-
return slug;
|
|
1170
|
-
}
|
|
1171
|
-
function importToVault(vaultPath, extracted, force) {
|
|
1172
|
-
const summary = {
|
|
1173
|
-
created: { people: [], preferences: [], decisions: [], tasks: [] },
|
|
1174
|
-
skipped: { people: [], preferences: [], decisions: [], tasks: [] }
|
|
1175
|
-
};
|
|
1176
|
-
for (const person of extracted.people) {
|
|
1177
|
-
const slug = writePerson(vaultPath, person, force);
|
|
1178
|
-
if (slug) {
|
|
1179
|
-
summary.created.people.push(person.name);
|
|
1180
|
-
} else {
|
|
1181
|
-
summary.skipped.people.push(person.name);
|
|
1182
|
-
}
|
|
1183
|
-
}
|
|
1184
|
-
for (const pref of extracted.preferences) {
|
|
1185
|
-
const slug = writePreference(vaultPath, pref, force);
|
|
1186
|
-
if (slug) {
|
|
1187
|
-
summary.created.preferences.push(`${pref.subject}: ${pref.preference}`.slice(0, 50));
|
|
1188
|
-
} else {
|
|
1189
|
-
summary.skipped.preferences.push(`${pref.subject}: ${pref.preference}`.slice(0, 50));
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
for (const decision of extracted.decisions) {
|
|
1193
|
-
const slug = writeDecision(vaultPath, decision, force);
|
|
1194
|
-
if (slug) {
|
|
1195
|
-
summary.created.decisions.push(decision.title);
|
|
1196
|
-
} else {
|
|
1197
|
-
summary.skipped.decisions.push(decision.title);
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
for (const task of extracted.tasks) {
|
|
1201
|
-
const slug = writeTask(vaultPath, task, force);
|
|
1202
|
-
if (slug) {
|
|
1203
|
-
summary.created.tasks.push(task.title);
|
|
1204
|
-
} else {
|
|
1205
|
-
summary.skipped.tasks.push(task.title);
|
|
1206
|
-
}
|
|
1207
|
-
}
|
|
1208
|
-
return summary;
|
|
1209
|
-
}
|
|
1210
|
-
function printImportSummary(summary) {
|
|
1211
|
-
const totalCreated = summary.created.people.length + summary.created.preferences.length + summary.created.decisions.length + summary.created.tasks.length;
|
|
1212
|
-
const totalSkipped = summary.skipped.people.length + summary.skipped.preferences.length + summary.skipped.decisions.length + summary.skipped.tasks.length;
|
|
1213
|
-
console.log("\n\u{1F4E5} Memory Import Summary");
|
|
1214
|
-
console.log("\u2500".repeat(40));
|
|
1215
|
-
if (summary.created.people.length > 0) {
|
|
1216
|
-
console.log(`\u2713 People (${summary.created.people.length}):`);
|
|
1217
|
-
for (const name of summary.created.people.slice(0, 5)) {
|
|
1218
|
-
console.log(` - ${name}`);
|
|
1219
|
-
}
|
|
1220
|
-
if (summary.created.people.length > 5) {
|
|
1221
|
-
console.log(` ... and ${summary.created.people.length - 5} more`);
|
|
1222
|
-
}
|
|
1223
|
-
}
|
|
1224
|
-
if (summary.created.preferences.length > 0) {
|
|
1225
|
-
console.log(`\u2713 Preferences (${summary.created.preferences.length}):`);
|
|
1226
|
-
for (const pref of summary.created.preferences.slice(0, 5)) {
|
|
1227
|
-
console.log(` - ${pref}`);
|
|
1228
|
-
}
|
|
1229
|
-
if (summary.created.preferences.length > 5) {
|
|
1230
|
-
console.log(` ... and ${summary.created.preferences.length - 5} more`);
|
|
1231
|
-
}
|
|
1232
|
-
}
|
|
1233
|
-
if (summary.created.decisions.length > 0) {
|
|
1234
|
-
console.log(`\u2713 Decisions (${summary.created.decisions.length}):`);
|
|
1235
|
-
for (const dec of summary.created.decisions.slice(0, 5)) {
|
|
1236
|
-
console.log(` - ${dec}`);
|
|
1237
|
-
}
|
|
1238
|
-
if (summary.created.decisions.length > 5) {
|
|
1239
|
-
console.log(` ... and ${summary.created.decisions.length - 5} more`);
|
|
1240
|
-
}
|
|
1241
|
-
}
|
|
1242
|
-
if (summary.created.tasks.length > 0) {
|
|
1243
|
-
console.log(`\u2713 Tasks (${summary.created.tasks.length}):`);
|
|
1244
|
-
for (const task of summary.created.tasks.slice(0, 5)) {
|
|
1245
|
-
console.log(` - ${task}`);
|
|
1246
|
-
}
|
|
1247
|
-
if (summary.created.tasks.length > 5) {
|
|
1248
|
-
console.log(` ... and ${summary.created.tasks.length - 5} more`);
|
|
1249
|
-
}
|
|
1250
|
-
}
|
|
1251
|
-
if (totalSkipped > 0) {
|
|
1252
|
-
console.log(`
|
|
1253
|
-
\u2298 Skipped ${totalSkipped} items (already exist or similar)`);
|
|
1254
|
-
}
|
|
1255
|
-
console.log("\u2500".repeat(40));
|
|
1256
|
-
console.log(`Total: ${totalCreated} created, ${totalSkipped} skipped`);
|
|
1257
|
-
}
|
|
1258
|
-
async function setupCommand(options = {}) {
|
|
1259
|
-
const target = resolveVaultTarget(options.vault);
|
|
1260
|
-
if (target.existed && !fs2.statSync(target.vaultPath).isDirectory()) {
|
|
1261
|
-
throw new Error(`Vault path is not a directory: ${target.vaultPath}`);
|
|
1262
|
-
}
|
|
1263
|
-
if (!target.existed) fs2.mkdirSync(target.vaultPath, { recursive: true });
|
|
1264
|
-
console.log(`${target.existed ? "Found" : "Created"} vault path (${target.source}): ${target.vaultPath}`);
|
|
1265
|
-
const initialized = ensureVaultStructure(target.vaultPath);
|
|
1266
|
-
console.log(initialized ? "\u2713 Initialized vault structure." : "\u2713 Vault structure already present.");
|
|
1267
|
-
const force = options.force ?? false;
|
|
1268
|
-
const theme = options.theme ?? "neural";
|
|
1269
|
-
if (options.from) {
|
|
1270
|
-
const sourcePath = path2.resolve(options.from);
|
|
1271
|
-
if (!fs2.existsSync(sourcePath)) {
|
|
1272
|
-
throw new Error(`Source path does not exist: ${sourcePath}`);
|
|
1273
|
-
}
|
|
1274
|
-
console.log(`
|
|
1275
|
-
\u{1F4C2} Scanning source: ${sourcePath}`);
|
|
1276
|
-
const extracted = scanAndExtract(sourcePath);
|
|
1277
|
-
const totalFound = extracted.people.length + extracted.preferences.length + extracted.decisions.length + extracted.tasks.length;
|
|
1278
|
-
if (totalFound === 0) {
|
|
1279
|
-
console.log("\u2298 No structured data found in source files.");
|
|
1280
|
-
} else {
|
|
1281
|
-
console.log(`Found: ${extracted.people.length} people, ${extracted.preferences.length} preferences, ${extracted.decisions.length} decisions, ${extracted.tasks.length} tasks`);
|
|
1282
|
-
const summary = importToVault(target.vaultPath, extracted, force);
|
|
1283
|
-
printImportSummary(summary);
|
|
1284
|
-
}
|
|
1285
|
-
}
|
|
1286
|
-
const explicitFlags = options.graphColors !== void 0 || options.bases !== void 0;
|
|
1287
|
-
const fromOnly = options.from && !explicitFlags;
|
|
1288
|
-
const doGraphColors = fromOnly ? false : explicitFlags ? options.graphColors !== false : true;
|
|
1289
|
-
const doBases = fromOnly ? false : explicitFlags ? options.bases !== false : true;
|
|
1290
|
-
if (doGraphColors && theme !== "none") {
|
|
1291
|
-
const wrote = writeGraphColors(target.vaultPath, theme, force);
|
|
1292
|
-
if (wrote) {
|
|
1293
|
-
console.log(`\u2713 Graph colors configured (${theme} theme)`);
|
|
1294
|
-
} else {
|
|
1295
|
-
const obsidianDir = path2.join(target.vaultPath, ".obsidian");
|
|
1296
|
-
if (!fs2.existsSync(obsidianDir)) {
|
|
1297
|
-
console.log("\u2298 No .obsidian directory \u2014 skipping graph colors (not an Obsidian vault)");
|
|
1298
|
-
} else {
|
|
1299
|
-
console.log("\u2298 Graph colors already exist (use --force to overwrite)");
|
|
1300
|
-
}
|
|
1301
|
-
}
|
|
1302
|
-
} else if (doGraphColors && theme === "none") {
|
|
1303
|
-
console.log("\u2298 Graph colors skipped (--theme none)");
|
|
1304
|
-
}
|
|
1305
|
-
if (doBases) {
|
|
1306
|
-
const count = writeBases(target.vaultPath, force);
|
|
1307
|
-
if (count > 0) {
|
|
1308
|
-
console.log(`\u2713 Created ${count} Obsidian Bases view${count > 1 ? "s" : ""}`);
|
|
1309
|
-
} else {
|
|
1310
|
-
console.log("\u2298 Bases views already exist (use --force to overwrite)");
|
|
1311
|
-
}
|
|
1312
|
-
}
|
|
1313
|
-
if (hasQmd()) {
|
|
1314
|
-
const { collection, root } = getQmdConfig(target.vaultPath);
|
|
1315
|
-
try {
|
|
1316
|
-
(0, import_child_process2.execFileSync)("qmd", withQmdIndexArgs(["collection", "add", root, "--name", collection, "--mask", "**/*.md"], options.qmdIndexName), {
|
|
1317
|
-
stdio: "ignore"
|
|
1318
|
-
});
|
|
1319
|
-
console.log(`\u2713 qmd collection ready: ${collection}`);
|
|
1320
|
-
} catch {
|
|
1321
|
-
console.log("\u2298 qmd collection already exists.");
|
|
1322
|
-
}
|
|
1323
|
-
} else {
|
|
1324
|
-
console.log("\u2298 qmd not found \u2014 skipping semantic search setup.");
|
|
1325
|
-
}
|
|
1326
|
-
console.log("\nTip: add this to your shell config:");
|
|
1327
|
-
console.log(` export CLAWVAULT_PATH="${target.vaultPath}"`);
|
|
1328
|
-
console.log("\nCustomize further:");
|
|
1329
|
-
console.log(" clawvault setup --theme neural # Neural neural graph colors");
|
|
1330
|
-
console.log(" clawvault setup --theme minimal # Subtle category colors");
|
|
1331
|
-
console.log(" clawvault setup --no-bases --no-graph-colors # Structure only");
|
|
1332
|
-
console.log(" clawvault setup --from <path> # Import from existing memory");
|
|
1333
|
-
console.log(" clawvault setup --force # Overwrite existing configs");
|
|
1334
|
-
}
|
|
1335
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
1336
|
-
0 && (module.exports = {
|
|
1337
|
-
extractDecisions,
|
|
1338
|
-
extractFromContent,
|
|
1339
|
-
extractPeople,
|
|
1340
|
-
extractPreferences,
|
|
1341
|
-
extractTasks,
|
|
1342
|
-
importToVault,
|
|
1343
|
-
scanAndExtract,
|
|
1344
|
-
setupCommand
|
|
1345
|
-
});
|