clawvault 3.2.0 → 3.3.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 +54 -14
- package/bin/clawvault.js +0 -2
- package/bin/command-registration.test.js +13 -1
- package/bin/help-contract.test.js +14 -0
- package/bin/register-core-commands.js +88 -0
- package/bin/register-core-commands.test.js +80 -0
- package/bin/register-maintenance-commands.js +57 -6
- package/bin/register-query-commands.js +10 -28
- package/bin/test-helpers/cli-command-fixtures.js +1 -0
- package/dist/chunk-2PKBIKDH.js +130 -0
- package/dist/{chunk-2JQ3O2YL.js → chunk-5EFSWZO6.js} +3 -3
- package/dist/{chunk-77Q5CSPJ.js → chunk-7SWP5FKU.js} +33 -701
- package/dist/{chunk-URXDAUVH.js → chunk-AXSJIFOJ.js} +174 -1
- package/dist/{chunk-23YDQ3QU.js → chunk-BLQXXX7Q.js} +6 -6
- package/dist/chunk-CSHO3PJB.js +684 -0
- package/dist/{chunk-SLXOR3CC.js → chunk-DOIUYIXV.js} +2 -2
- package/dist/{chunk-NCKFNBHJ.js → chunk-DVOUSOR3.js} +79 -5
- package/dist/{chunk-CLJTREDS.js → chunk-ECGJYWNA.js} +193 -41
- package/dist/{chunk-BUEW6IIK.js → chunk-EL6UBSX5.js} +5 -5
- package/dist/{chunk-6FH3IULF.js → chunk-FZ5I2NF7.js} +1 -1
- package/dist/{chunk-ZN54U2OZ.js → chunk-GFCHWMGD.js} +3 -3
- package/dist/{chunk-GNJL4YGR.js → chunk-GJO3CFUN.js} +30 -6
- package/dist/chunk-H3JZIB5O.js +322 -0
- package/dist/chunk-HEHO7SMV.js +51 -0
- package/dist/{chunk-STCQGCEQ.js → chunk-HGDDW24U.js} +3 -3
- package/dist/chunk-J3YUXVID.js +907 -0
- package/dist/{chunk-Y6VJKXGL.js → chunk-KCYWJDDW.js} +1 -1
- package/dist/{chunk-W4SPAEE7.js → chunk-OFOCU2V4.js} +5 -4
- package/dist/chunk-PTWPPVC7.js +972 -0
- package/dist/{chunk-QSHD36LH.js → chunk-QFWERBDP.js} +2 -2
- package/dist/{chunk-QSRRMEYM.js → chunk-S7N7HI5E.js} +1 -1
- package/dist/{chunk-PBACDKKP.js → chunk-T7E764W3.js} +3 -3
- package/dist/chunk-TDWFBDAQ.js +1016 -0
- package/dist/{chunk-ESVS6K2B.js → chunk-TWMI3SNN.js} +6 -5
- package/dist/{chunk-2RAZ4ZFE.js → chunk-VBILES4B.js} +1 -1
- package/dist/{chunk-ESFLMDRB.js → chunk-VXAGOLDP.js} +3 -3
- package/dist/chunk-YCUVAOFC.js +158 -0
- package/dist/{chunk-SS4B7P7V.js → chunk-YIDV4VV2.js} +1 -1
- package/dist/chunk-ZKWPCBYT.js +600 -0
- package/dist/cli/index.js +24 -24
- package/dist/commands/archive.js +2 -2
- package/dist/commands/benchmark.d.ts +12 -0
- package/dist/commands/benchmark.js +12 -0
- package/dist/commands/context.js +6 -5
- package/dist/commands/doctor.d.ts +8 -3
- package/dist/commands/doctor.js +6 -20
- package/dist/commands/embed.js +5 -4
- package/dist/commands/entities.js +1 -1
- package/dist/commands/graph.js +2 -2
- package/dist/commands/inbox.d.ts +23 -0
- package/dist/commands/inbox.js +11 -0
- package/dist/commands/inject.d.ts +1 -1
- package/dist/commands/inject.js +3 -3
- package/dist/commands/link.js +6 -6
- package/dist/commands/maintain.d.ts +32 -0
- package/dist/commands/maintain.js +12 -0
- package/dist/commands/migrate-observations.js +2 -2
- package/dist/commands/observe.js +9 -8
- package/dist/commands/rebuild-embeddings.js +47 -16
- package/dist/commands/rebuild.js +7 -6
- package/dist/commands/reflect.js +5 -5
- package/dist/commands/replay.js +8 -7
- package/dist/commands/setup.js +3 -2
- package/dist/commands/sleep.d.ts +1 -1
- package/dist/commands/sleep.js +17 -15
- package/dist/commands/status.js +26 -24
- package/dist/commands/sync-bd.js +2 -2
- package/dist/commands/tailscale.js +2 -2
- package/dist/commands/wake.d.ts +1 -1
- package/dist/commands/wake.js +8 -7
- package/dist/index.d.ts +168 -16
- package/dist/index.js +271 -108
- package/dist/{inject-DYUrDqQO.d.ts → inject-DEb_jpLi.d.ts} +3 -1
- package/dist/lib/config.js +1 -1
- package/dist/{types-BbWJoC1c.d.ts → types-DslKvCaj.d.ts} +51 -1
- package/hooks/clawvault/HOOK.md +22 -5
- package/hooks/clawvault/handler.js +213 -78
- package/hooks/clawvault/handler.test.js +109 -43
- package/hooks/clawvault/integrity.js +112 -0
- package/hooks/clawvault/integrity.test.js +32 -0
- package/hooks/clawvault/openclaw.plugin.json +133 -15
- package/openclaw.plugin.json +126 -20
- package/package.json +2 -2
- package/bin/register-workgraph-commands.js +0 -1368
- package/dist/chunk-33VSQP4J.js +0 -37
- package/dist/chunk-4BQTQMJP.js +0 -93
- package/dist/chunk-EK6S23ZB.js +0 -469
- package/dist/chunk-GAOWA7GR.js +0 -501
- package/dist/chunk-GGA32J2R.js +0 -784
- package/dist/chunk-MM6QGW3P.js +0 -207
- package/dist/chunk-QVEERJSP.js +0 -152
- package/dist/chunk-U4O6C46S.js +0 -154
- package/dist/chunk-VSL7KY3M.js +0 -189
- package/dist/chunk-WMGIIABP.js +0 -15
- package/dist/commands/workgraph.d.ts +0 -124
- package/dist/commands/workgraph.js +0 -38
- package/dist/ledger-B7g7jhqG.d.ts +0 -44
- package/dist/registry-BR4326o0.d.ts +0 -30
- package/dist/store-CA-6sKCJ.d.ts +0 -34
- package/dist/thread-B9LhXNU0.d.ts +0 -41
- package/dist/workgraph/index.d.ts +0 -5
- package/dist/workgraph/index.js +0 -23
- package/dist/workgraph/ledger.d.ts +0 -2
- package/dist/workgraph/ledger.js +0 -25
- package/dist/workgraph/registry.d.ts +0 -2
- package/dist/workgraph/registry.js +0 -19
- package/dist/workgraph/store.d.ts +0 -2
- package/dist/workgraph/store.js +0 -25
- package/dist/workgraph/thread.d.ts +0 -2
- package/dist/workgraph/thread.js +0 -25
- package/dist/workgraph/types.d.ts +0 -54
- package/dist/workgraph/types.js +0 -7
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
// src/lib/embedding-store.ts
|
|
2
|
+
import * as crypto from "crypto";
|
|
3
|
+
import * as fs from "fs";
|
|
4
|
+
import * as path from "path";
|
|
5
|
+
var CACHE_DIR = ".clawvault";
|
|
6
|
+
var CACHE_FILE = "embeddings.bin.json";
|
|
7
|
+
var LEGACY_BIN_FILE = "embeddings.bin";
|
|
8
|
+
var EmbeddingStore = class {
|
|
9
|
+
vaultPath;
|
|
10
|
+
provider = "none";
|
|
11
|
+
model = "";
|
|
12
|
+
vectors = /* @__PURE__ */ new Map();
|
|
13
|
+
dirty = false;
|
|
14
|
+
constructor(vaultPath) {
|
|
15
|
+
this.vaultPath = path.resolve(vaultPath);
|
|
16
|
+
}
|
|
17
|
+
setVaultPath(vaultPath) {
|
|
18
|
+
this.vaultPath = path.resolve(vaultPath);
|
|
19
|
+
}
|
|
20
|
+
setSignature(provider, model) {
|
|
21
|
+
if (this.provider !== provider || this.model !== model) {
|
|
22
|
+
this.provider = provider;
|
|
23
|
+
this.model = model;
|
|
24
|
+
this.dirty = true;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
getSignature() {
|
|
28
|
+
return { provider: this.provider, model: this.model };
|
|
29
|
+
}
|
|
30
|
+
isCompatible(provider, model) {
|
|
31
|
+
if (this.provider === "none" || !this.model) {
|
|
32
|
+
return this.vectors.size === 0;
|
|
33
|
+
}
|
|
34
|
+
return this.provider === provider && this.model === model;
|
|
35
|
+
}
|
|
36
|
+
load() {
|
|
37
|
+
this.vectors.clear();
|
|
38
|
+
const cachePath = this.getCachePath();
|
|
39
|
+
if (!fs.existsSync(cachePath)) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
const raw = JSON.parse(fs.readFileSync(cachePath, "utf-8"));
|
|
44
|
+
if ("version" in raw && "vectors" in raw) {
|
|
45
|
+
this.provider = typeof raw.provider === "string" ? raw.provider : "none";
|
|
46
|
+
this.model = typeof raw.model === "string" ? raw.model : "";
|
|
47
|
+
for (const [docId, value] of Object.entries(raw.vectors)) {
|
|
48
|
+
if (Array.isArray(value)) {
|
|
49
|
+
this.vectors.set(docId, {
|
|
50
|
+
hash: "",
|
|
51
|
+
embedding: new Float32Array(value)
|
|
52
|
+
});
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (!value || !Array.isArray(value.embedding)) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
this.vectors.set(docId, {
|
|
59
|
+
hash: typeof value.hash === "string" ? value.hash : "",
|
|
60
|
+
embedding: new Float32Array(value.embedding)
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
} else {
|
|
64
|
+
this.provider = "none";
|
|
65
|
+
this.model = "";
|
|
66
|
+
for (const [docId, embedding] of Object.entries(raw)) {
|
|
67
|
+
if (Array.isArray(embedding)) {
|
|
68
|
+
this.vectors.set(docId, {
|
|
69
|
+
hash: "",
|
|
70
|
+
embedding: new Float32Array(embedding)
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
this.dirty = false;
|
|
76
|
+
} catch {
|
|
77
|
+
this.provider = "none";
|
|
78
|
+
this.model = "";
|
|
79
|
+
this.vectors.clear();
|
|
80
|
+
this.dirty = false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
save() {
|
|
84
|
+
if (!this.dirty) return;
|
|
85
|
+
const cacheDir = path.dirname(this.getCachePath());
|
|
86
|
+
fs.mkdirSync(cacheDir, { recursive: true });
|
|
87
|
+
const vectors = {};
|
|
88
|
+
for (const [docId, entry] of this.vectors.entries()) {
|
|
89
|
+
vectors[docId] = {
|
|
90
|
+
hash: entry.hash,
|
|
91
|
+
embedding: Array.from(entry.embedding)
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
const payload = {
|
|
95
|
+
version: 2,
|
|
96
|
+
provider: this.provider,
|
|
97
|
+
model: this.model,
|
|
98
|
+
vectors
|
|
99
|
+
};
|
|
100
|
+
fs.writeFileSync(this.getCachePath(), JSON.stringify(payload));
|
|
101
|
+
const legacyBinPath = path.join(cacheDir, LEGACY_BIN_FILE);
|
|
102
|
+
if (!fs.existsSync(legacyBinPath)) {
|
|
103
|
+
fs.writeFileSync(legacyBinPath, "");
|
|
104
|
+
}
|
|
105
|
+
this.dirty = false;
|
|
106
|
+
}
|
|
107
|
+
get(docId) {
|
|
108
|
+
return this.vectors.get(docId)?.embedding;
|
|
109
|
+
}
|
|
110
|
+
getHash(docId) {
|
|
111
|
+
return this.vectors.get(docId)?.hash;
|
|
112
|
+
}
|
|
113
|
+
set(docId, hash, embedding) {
|
|
114
|
+
this.vectors.set(docId, { hash, embedding });
|
|
115
|
+
this.dirty = true;
|
|
116
|
+
}
|
|
117
|
+
has(docId) {
|
|
118
|
+
return this.vectors.has(docId);
|
|
119
|
+
}
|
|
120
|
+
delete(docId) {
|
|
121
|
+
if (this.vectors.delete(docId)) {
|
|
122
|
+
this.dirty = true;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
prune(validDocIds) {
|
|
126
|
+
let removedAny = false;
|
|
127
|
+
for (const key of this.vectors.keys()) {
|
|
128
|
+
if (!validDocIds.has(key)) {
|
|
129
|
+
this.vectors.delete(key);
|
|
130
|
+
removedAny = true;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (removedAny) {
|
|
134
|
+
this.dirty = true;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
entries() {
|
|
138
|
+
const pairs = Array.from(this.vectors.entries()).map(([id, entry]) => [id, entry.embedding]);
|
|
139
|
+
return pairs[Symbol.iterator]();
|
|
140
|
+
}
|
|
141
|
+
get size() {
|
|
142
|
+
return this.vectors.size;
|
|
143
|
+
}
|
|
144
|
+
clear() {
|
|
145
|
+
if (this.vectors.size === 0) return;
|
|
146
|
+
this.vectors.clear();
|
|
147
|
+
this.dirty = true;
|
|
148
|
+
}
|
|
149
|
+
getCachePath() {
|
|
150
|
+
return path.join(this.vaultPath, CACHE_DIR, CACHE_FILE);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
function computeEmbeddingHash(text) {
|
|
154
|
+
return crypto.createHash("sha1").update(text).digest("hex");
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// src/lib/hosted-embeddings.ts
|
|
158
|
+
var DEFAULT_OPENAI_MODEL = "text-embedding-3-small";
|
|
159
|
+
var DEFAULT_GEMINI_MODEL = "text-embedding-004";
|
|
160
|
+
var DEFAULT_OLLAMA_MODEL = "nomic-embed-text";
|
|
161
|
+
function normalizeBaseUrl(url) {
|
|
162
|
+
return url.replace(/\/+$/, "");
|
|
163
|
+
}
|
|
164
|
+
function toFloat32(values) {
|
|
165
|
+
if (!Array.isArray(values)) {
|
|
166
|
+
throw new Error("Embedding response did not contain a numeric vector.");
|
|
167
|
+
}
|
|
168
|
+
return new Float32Array(values.map((value) => Number(value)));
|
|
169
|
+
}
|
|
170
|
+
function resolveApiKey(provider, configuredApiKey) {
|
|
171
|
+
if (configuredApiKey?.trim()) return configuredApiKey.trim();
|
|
172
|
+
if (provider === "openai") return process.env.OPENAI_API_KEY?.trim();
|
|
173
|
+
if (provider === "gemini") return process.env.GEMINI_API_KEY?.trim() || process.env.GOOGLE_API_KEY?.trim();
|
|
174
|
+
return void 0;
|
|
175
|
+
}
|
|
176
|
+
function resolveEmbeddingConfig(searchConfig) {
|
|
177
|
+
const provider = searchConfig?.embeddings?.provider ?? "none";
|
|
178
|
+
if (provider === "none") {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
if (provider === "openai") {
|
|
182
|
+
return {
|
|
183
|
+
provider,
|
|
184
|
+
model: searchConfig?.embeddings?.model?.trim() || DEFAULT_OPENAI_MODEL,
|
|
185
|
+
baseUrl: normalizeBaseUrl(searchConfig?.embeddings?.baseUrl?.trim() || "https://api.openai.com/v1"),
|
|
186
|
+
apiKey: resolveApiKey(provider, searchConfig?.embeddings?.apiKey)
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
if (provider === "gemini") {
|
|
190
|
+
return {
|
|
191
|
+
provider,
|
|
192
|
+
model: searchConfig?.embeddings?.model?.trim() || DEFAULT_GEMINI_MODEL,
|
|
193
|
+
baseUrl: normalizeBaseUrl(searchConfig?.embeddings?.baseUrl?.trim() || "https://generativelanguage.googleapis.com/v1beta"),
|
|
194
|
+
apiKey: resolveApiKey(provider, searchConfig?.embeddings?.apiKey)
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
return {
|
|
198
|
+
provider,
|
|
199
|
+
model: searchConfig?.embeddings?.model?.trim() || DEFAULT_OLLAMA_MODEL,
|
|
200
|
+
baseUrl: normalizeBaseUrl(searchConfig?.embeddings?.baseUrl?.trim() || "http://127.0.0.1:11434")
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
async function openAiEmbed(text, config) {
|
|
204
|
+
if (!config.apiKey) {
|
|
205
|
+
throw new Error("OpenAI embeddings require an API key (search.embeddings.apiKey or OPENAI_API_KEY).");
|
|
206
|
+
}
|
|
207
|
+
const response = await fetch(`${config.baseUrl}/embeddings`, {
|
|
208
|
+
method: "POST",
|
|
209
|
+
headers: {
|
|
210
|
+
"Content-Type": "application/json",
|
|
211
|
+
Authorization: `Bearer ${config.apiKey}`
|
|
212
|
+
},
|
|
213
|
+
body: JSON.stringify({
|
|
214
|
+
model: config.model,
|
|
215
|
+
input: text
|
|
216
|
+
}),
|
|
217
|
+
signal: AbortSignal.timeout(2e4)
|
|
218
|
+
});
|
|
219
|
+
if (!response.ok) {
|
|
220
|
+
throw new Error(`OpenAI embedding request failed with status ${response.status}.`);
|
|
221
|
+
}
|
|
222
|
+
const payload = await response.json();
|
|
223
|
+
return toFloat32(payload.data?.[0]?.embedding);
|
|
224
|
+
}
|
|
225
|
+
function geminiModelPath(model) {
|
|
226
|
+
return model.startsWith("models/") ? model : `models/${model}`;
|
|
227
|
+
}
|
|
228
|
+
async function geminiEmbed(text, config, isQuery) {
|
|
229
|
+
if (!config.apiKey) {
|
|
230
|
+
throw new Error("Gemini embeddings require an API key (search.embeddings.apiKey, GEMINI_API_KEY, or GOOGLE_API_KEY).");
|
|
231
|
+
}
|
|
232
|
+
const response = await fetch(`${config.baseUrl}/${geminiModelPath(config.model)}:embedContent`, {
|
|
233
|
+
method: "POST",
|
|
234
|
+
headers: {
|
|
235
|
+
"Content-Type": "application/json",
|
|
236
|
+
"x-goog-api-key": config.apiKey
|
|
237
|
+
},
|
|
238
|
+
body: JSON.stringify({
|
|
239
|
+
content: {
|
|
240
|
+
parts: [{ text }]
|
|
241
|
+
},
|
|
242
|
+
taskType: isQuery ? "RETRIEVAL_QUERY" : "RETRIEVAL_DOCUMENT"
|
|
243
|
+
}),
|
|
244
|
+
signal: AbortSignal.timeout(2e4)
|
|
245
|
+
});
|
|
246
|
+
if (!response.ok) {
|
|
247
|
+
throw new Error(`Gemini embedding request failed with status ${response.status}.`);
|
|
248
|
+
}
|
|
249
|
+
const payload = await response.json();
|
|
250
|
+
const values = payload.embedding?.values ?? payload.embeddings?.[0]?.values;
|
|
251
|
+
return toFloat32(values);
|
|
252
|
+
}
|
|
253
|
+
async function ollamaEmbed(text, config) {
|
|
254
|
+
const primary = await fetch(`${config.baseUrl}/api/embed`, {
|
|
255
|
+
method: "POST",
|
|
256
|
+
headers: { "Content-Type": "application/json" },
|
|
257
|
+
body: JSON.stringify({
|
|
258
|
+
model: config.model,
|
|
259
|
+
input: text
|
|
260
|
+
}),
|
|
261
|
+
signal: AbortSignal.timeout(2e4)
|
|
262
|
+
});
|
|
263
|
+
if (primary.ok) {
|
|
264
|
+
const payload2 = await primary.json();
|
|
265
|
+
return toFloat32(payload2.embeddings?.[0]);
|
|
266
|
+
}
|
|
267
|
+
const fallback = await fetch(`${config.baseUrl}/api/embeddings`, {
|
|
268
|
+
method: "POST",
|
|
269
|
+
headers: { "Content-Type": "application/json" },
|
|
270
|
+
body: JSON.stringify({
|
|
271
|
+
model: config.model,
|
|
272
|
+
prompt: text
|
|
273
|
+
}),
|
|
274
|
+
signal: AbortSignal.timeout(2e4)
|
|
275
|
+
});
|
|
276
|
+
if (!fallback.ok) {
|
|
277
|
+
throw new Error(`Ollama embedding request failed with status ${fallback.status}.`);
|
|
278
|
+
}
|
|
279
|
+
const payload = await fallback.json();
|
|
280
|
+
return toFloat32(payload.embedding);
|
|
281
|
+
}
|
|
282
|
+
async function embedText(text, config, options = {}) {
|
|
283
|
+
const normalized = text.trim();
|
|
284
|
+
if (!normalized) {
|
|
285
|
+
throw new Error("Cannot embed empty text.");
|
|
286
|
+
}
|
|
287
|
+
const truncated = normalized.slice(0, 12e3);
|
|
288
|
+
if (config.provider === "openai") {
|
|
289
|
+
return openAiEmbed(truncated, config);
|
|
290
|
+
}
|
|
291
|
+
if (config.provider === "gemini") {
|
|
292
|
+
return geminiEmbed(truncated, config, options.isQuery ?? false);
|
|
293
|
+
}
|
|
294
|
+
return ollamaEmbed(truncated, config);
|
|
295
|
+
}
|
|
296
|
+
function cosineSimilarity(a, b) {
|
|
297
|
+
if (a.length !== b.length || a.length === 0) {
|
|
298
|
+
return 0;
|
|
299
|
+
}
|
|
300
|
+
let dot = 0;
|
|
301
|
+
let normA = 0;
|
|
302
|
+
let normB = 0;
|
|
303
|
+
for (let index = 0; index < a.length; index += 1) {
|
|
304
|
+
const av = a[index];
|
|
305
|
+
const bv = b[index];
|
|
306
|
+
dot += av * bv;
|
|
307
|
+
normA += av * av;
|
|
308
|
+
normB += bv * bv;
|
|
309
|
+
}
|
|
310
|
+
if (normA === 0 || normB === 0) {
|
|
311
|
+
return 0;
|
|
312
|
+
}
|
|
313
|
+
return dot / (Math.sqrt(normA) * Math.sqrt(normB));
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
export {
|
|
317
|
+
EmbeddingStore,
|
|
318
|
+
computeEmbeddingHash,
|
|
319
|
+
resolveEmbeddingConfig,
|
|
320
|
+
embedText,
|
|
321
|
+
cosineSimilarity
|
|
322
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {
|
|
2
|
+
addInboxItem
|
|
3
|
+
} from "./chunk-2PKBIKDH.js";
|
|
4
|
+
import {
|
|
5
|
+
resolveVaultPath
|
|
6
|
+
} from "./chunk-GJO3CFUN.js";
|
|
7
|
+
|
|
8
|
+
// src/commands/inbox.ts
|
|
9
|
+
import * as fs from "fs";
|
|
10
|
+
function resolveInboxContent(options) {
|
|
11
|
+
const inline = options.content?.trim();
|
|
12
|
+
if (inline) {
|
|
13
|
+
return inline;
|
|
14
|
+
}
|
|
15
|
+
if (options.stdin) {
|
|
16
|
+
const reader = options.readStdin ?? (() => fs.readFileSync(0, "utf-8"));
|
|
17
|
+
const stdinContent = reader().trim();
|
|
18
|
+
if (stdinContent) {
|
|
19
|
+
return stdinContent;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
throw new Error("Inbox content is required. Provide <content> or pipe stdin.");
|
|
23
|
+
}
|
|
24
|
+
async function inboxAddCommand(options) {
|
|
25
|
+
const vaultPath = resolveVaultPath({ explicitPath: options.vaultPath });
|
|
26
|
+
const content = resolveInboxContent(options);
|
|
27
|
+
const result = addInboxItem(vaultPath, content, {
|
|
28
|
+
title: options.title,
|
|
29
|
+
source: options.source
|
|
30
|
+
});
|
|
31
|
+
console.log(`\u2713 Added inbox capture: ${result.id}`);
|
|
32
|
+
console.log(` Path: ${result.path}`);
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
function registerInboxCommand(program) {
|
|
36
|
+
const inbox = program.command("inbox").description("Manage raw captures in the vault inbox");
|
|
37
|
+
inbox.command("add [content]").description("Add content to inbox (or pipe stdin)").option("-t, --title <title>", "Optional capture title").option("--source <source>", "Source label (email, transcript, note, export, etc.)").option("--stdin", "Read content from stdin").option("-v, --vault <path>", "Vault path").action(async (content, rawOptions) => {
|
|
38
|
+
await inboxAddCommand({
|
|
39
|
+
vaultPath: rawOptions.vault,
|
|
40
|
+
content,
|
|
41
|
+
title: rawOptions.title,
|
|
42
|
+
source: rawOptions.source,
|
|
43
|
+
stdin: rawOptions.stdin || !process.stdin.isTTY
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export {
|
|
49
|
+
inboxAddCommand,
|
|
50
|
+
registerInboxCommand
|
|
51
|
+
};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runReflection
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-TWMI3SNN.js";
|
|
4
4
|
import {
|
|
5
5
|
Observer
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-7SWP5FKU.js";
|
|
7
7
|
import {
|
|
8
8
|
resolveVaultPath
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-GJO3CFUN.js";
|
|
10
10
|
|
|
11
11
|
// src/commands/replay.ts
|
|
12
12
|
import * as fs from "fs";
|