clawvault 3.1.0 → 3.2.1
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 +422 -141
- package/bin/clawvault.js +10 -2
- package/bin/command-registration.test.js +3 -1
- package/bin/command-runtime.js +9 -1
- package/bin/register-core-commands.js +23 -28
- package/bin/register-maintenance-commands.js +39 -3
- package/bin/register-query-commands.js +58 -29
- package/bin/register-tailscale-commands.js +106 -0
- 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 +451 -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-C7OK5WKP.js → chunk-2JQ3O2YL.js} +4 -4
- package/dist/{chunk-VR5NE7PZ.js → chunk-2RAZ4ZFE.js} +1 -1
- package/dist/{chunk-F2JEUD4J.js → chunk-4ITRXIVT.js} +5 -7
- package/dist/{chunk-GUKMRGM7.js → chunk-4OXMU5S2.js} +1 -1
- package/dist/chunk-5PJ4STIC.js +465 -0
- package/dist/{chunk-62YTUT6J.js → chunk-AZYOKJYC.js} +2 -2
- package/dist/chunk-BSJ6RIT7.js +447 -0
- package/dist/chunk-ECRZL5XR.js +50 -0
- package/dist/chunk-ERNE2FZ5.js +189 -0
- package/dist/{chunk-WAZ3NLWL.js → chunk-F55HGNU4.js} +0 -47
- package/dist/{chunk-VGLOTGAS.js → chunk-FAKNOB7Y.js} +2 -2
- package/dist/{chunk-QK3UCXWL.js → chunk-FHFUXL6G.js} +2 -2
- package/dist/chunk-GNJL4YGR.js +79 -0
- package/dist/chunk-HR4KN6S2.js +152 -0
- package/dist/{chunk-OZ7RIXTO.js → chunk-IIOU45CK.js} +1 -1
- package/dist/chunk-IJBFGPCS.js +33 -0
- package/dist/chunk-IVRIKYFE.js +520 -0
- package/dist/chunk-K7PNYS45.js +93 -0
- package/dist/chunk-MDIH26GC.js +183 -0
- package/dist/{chunk-LYHGEHXG.js → chunk-MFAWT5O5.js} +0 -1
- package/dist/{chunk-H34S76MB.js → chunk-MNPUYCHQ.js} +6 -6
- package/dist/chunk-NTOPJI7W.js +207 -0
- package/dist/{chunk-QBLMXKF2.js → chunk-OIWVQYQF.js} +1 -1
- package/dist/chunk-PG56HX5T.js +154 -0
- package/dist/{chunk-LNJA2UGL.js → chunk-PI4WMLMG.js} +7 -84
- package/dist/chunk-QMHPQYUV.js +363 -0
- package/dist/{chunk-H62BP7RI.js → chunk-QPDDIHXE.js} +209 -43
- 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-S5OJEGFG.js} +2 -2
- package/dist/chunk-SS4B7P7V.js +99 -0
- package/dist/chunk-TIGW564L.js +628 -0
- package/dist/chunk-U67V476Y.js +35 -0
- package/dist/{chunk-JY6FYXIT.js → chunk-UCQAOZHW.js} +6 -11
- package/dist/{chunk-ITPEXLHA.js → chunk-URXDAUVH.js} +24 -5
- package/dist/chunk-WIOLLGAD.js +190 -0
- package/dist/{chunk-3WRJEKN4.js → chunk-WJVWINEM.js} +72 -8
- package/dist/chunk-WMGIIABP.js +15 -0
- package/dist/{chunk-33UGEQRT.js → chunk-X3SPPUFG.js} +151 -64
- package/dist/{chunk-3NSBOUT3.js → chunk-Y3TIJEBP.js} +314 -79
- package/dist/chunk-Y6VJKXGL.js +373 -0
- package/dist/{chunk-LI4O6NVK.js → chunk-YDWHS4LJ.js} +49 -9
- package/dist/{chunk-U55BGUAU.js → chunk-YNIPYN4F.js} +5 -5
- package/dist/chunk-YXQCA6B7.js +226 -0
- package/dist/cli/index.js +26 -22
- 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 +7 -5
- package/dist/commands/doctor.d.ts +11 -7
- package/dist/commands/doctor.js +16 -14
- package/dist/commands/embed.js +5 -6
- package/dist/commands/entities.js +2 -2
- package/dist/commands/graph.js +3 -3
- package/dist/commands/inject.d.ts +1 -1
- package/dist/commands/inject.js +4 -5
- package/dist/commands/kanban.js +4 -4
- package/dist/commands/link.js +2 -2
- package/dist/commands/migrate-observations.js +4 -4
- package/dist/commands/observe.d.ts +0 -1
- package/dist/commands/observe.js +13 -12
- 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 -89
- 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 +18 -17
- package/dist/commands/status.d.ts +2 -0
- package/dist/commands/status.js +40 -30
- package/dist/commands/sync-bd.d.ts +10 -0
- package/dist/commands/sync-bd.js +10 -0
- package/dist/commands/tailscale.d.ts +52 -0
- package/dist/commands/tailscale.js +26 -0
- 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/index.d.ts +334 -191
- package/dist/index.js +432 -108
- package/dist/{inject-Bzi5E-By.d.ts → inject-DYUrDqQO.d.ts} +3 -3
- package/dist/ledger-B7g7jhqG.d.ts +44 -0
- package/dist/lib/auto-linker.js +1 -1
- package/dist/lib/canvas-layout.d.ts +115 -0
- package/dist/lib/canvas-layout.js +35 -0
- 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.d.ts +225 -0
- package/dist/lib/tailscale.js +50 -0
- package/dist/lib/task-utils.js +3 -3
- package/dist/lib/template-engine.js +1 -1
- package/dist/lib/webdav.d.ts +109 -0
- package/dist/lib/webdav.js +35 -0
- package/dist/plugin/index.d.ts +344 -28
- package/dist/plugin/index.js +3919 -227
- 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/{types-Y2_Um2Ls.d.ts → 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 +113 -0
- package/hooks/clawvault/handler.js +1559 -0
- package/hooks/clawvault/handler.test.js +510 -0
- package/hooks/clawvault/openclaw.plugin.json +72 -0
- package/openclaw.plugin.json +235 -30
- package/package.json +20 -20
- package/dist/chunk-3RG5ZIWI.js +0 -10
- package/dist/chunk-3ZIH425O.js +0 -871
- package/dist/chunk-6U6MK36V.js +0 -205
- package/dist/chunk-CMB7UL7C.js +0 -327
- package/dist/chunk-D2H45LON.js +0 -1074
- package/dist/chunk-E7MFQB6D.js +0 -163
- package/dist/chunk-GQSLDZTS.js +0 -560
- package/dist/chunk-MFM6K7PU.js +0 -374
- package/dist/chunk-MXSSG3QU.js +0 -42
- package/dist/chunk-OCGVIN3L.js +0 -88
- package/dist/chunk-PAH27GSN.js +0 -108
- package/dist/chunk-YCUNCH2I.js +0 -78
- package/dist/cli/index.cjs +0 -8584
- 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 -294
- package/dist/commands/compat.d.cts +0 -28
- package/dist/commands/context.cjs +0 -2990
- package/dist/commands/context.d.cts +0 -2
- package/dist/commands/doctor.cjs +0 -2986
- 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 -1278
- package/dist/commands/setup.d.cts +0 -99
- package/dist/commands/shell-init.cjs +0 -75
- package/dist/commands/shell-init.d.cts +0 -7
- package/dist/commands/sleep.cjs +0 -6029
- package/dist/commands/sleep.d.cts +0 -36
- package/dist/commands/status.cjs +0 -2737
- package/dist/commands/status.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 -2627
- package/dist/commands/wake.d.cts +0 -22
- package/dist/context-BUGaWpyL.d.cts +0 -46
- package/dist/index.cjs +0 -12373
- package/dist/index.d.cts +0 -854
- package/dist/inject-Bzi5E-By.d.cts +0 -137
- package/dist/lib/auto-linker.cjs +0 -176
- package/dist/lib/auto-linker.d.cts +0 -26
- 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/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/plugin/index.cjs +0 -1907
- package/dist/plugin/index.d.cts +0 -36
- 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.cts +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
|
@@ -0,0 +1,628 @@
|
|
|
1
|
+
import {
|
|
2
|
+
WEBDAV_PREFIX,
|
|
3
|
+
createWebDAVHandler
|
|
4
|
+
} from "./chunk-IVRIKYFE.js";
|
|
5
|
+
|
|
6
|
+
// src/lib/tailscale.ts
|
|
7
|
+
import { spawnSync, spawn } from "child_process";
|
|
8
|
+
import * as fs from "fs";
|
|
9
|
+
import * as path from "path";
|
|
10
|
+
import * as http from "http";
|
|
11
|
+
import * as https from "https";
|
|
12
|
+
import * as crypto from "crypto";
|
|
13
|
+
var DEFAULT_SERVE_PORT = 8384;
|
|
14
|
+
var CLAWVAULT_SERVE_PATH = "/.clawvault";
|
|
15
|
+
var MANIFEST_ENDPOINT = "/.clawvault/manifest";
|
|
16
|
+
var SYNC_ENDPOINT = "/.clawvault/sync";
|
|
17
|
+
var FILE_ENDPOINT = "/.clawvault/files";
|
|
18
|
+
function hasTailscale() {
|
|
19
|
+
const probe = spawnSync("tailscale", ["version"], {
|
|
20
|
+
stdio: "pipe",
|
|
21
|
+
encoding: "utf-8",
|
|
22
|
+
timeout: 5e3
|
|
23
|
+
});
|
|
24
|
+
return !probe.error && probe.status === 0;
|
|
25
|
+
}
|
|
26
|
+
function getTailscaleVersion() {
|
|
27
|
+
const result = spawnSync("tailscale", ["version"], {
|
|
28
|
+
stdio: "pipe",
|
|
29
|
+
encoding: "utf-8",
|
|
30
|
+
timeout: 5e3
|
|
31
|
+
});
|
|
32
|
+
if (result.error || result.status !== 0) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
const lines = result.stdout.trim().split("\n");
|
|
36
|
+
return lines[0] || null;
|
|
37
|
+
}
|
|
38
|
+
function getTailscaleStatus() {
|
|
39
|
+
const status = {
|
|
40
|
+
installed: false,
|
|
41
|
+
running: false,
|
|
42
|
+
connected: false,
|
|
43
|
+
peers: []
|
|
44
|
+
};
|
|
45
|
+
if (!hasTailscale()) {
|
|
46
|
+
status.error = "Tailscale CLI not found. Install from https://tailscale.com/download";
|
|
47
|
+
return status;
|
|
48
|
+
}
|
|
49
|
+
status.installed = true;
|
|
50
|
+
const result = spawnSync("tailscale", ["status", "--json"], {
|
|
51
|
+
stdio: "pipe",
|
|
52
|
+
encoding: "utf-8",
|
|
53
|
+
timeout: 1e4
|
|
54
|
+
});
|
|
55
|
+
if (result.error) {
|
|
56
|
+
status.error = `Failed to get Tailscale status: ${result.error.message}`;
|
|
57
|
+
return status;
|
|
58
|
+
}
|
|
59
|
+
if (result.status !== 0) {
|
|
60
|
+
status.error = result.stderr?.trim() || "Tailscale daemon not running";
|
|
61
|
+
return status;
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
const data = JSON.parse(result.stdout);
|
|
65
|
+
status.running = true;
|
|
66
|
+
status.backendState = data.BackendState;
|
|
67
|
+
status.connected = data.BackendState === "Running";
|
|
68
|
+
status.tailnetName = data.CurrentTailnet?.Name;
|
|
69
|
+
if (data.Self) {
|
|
70
|
+
status.selfIP = data.Self.TailscaleIPs?.[0];
|
|
71
|
+
status.selfHostname = data.Self.HostName;
|
|
72
|
+
status.selfDNSName = data.Self.DNSName;
|
|
73
|
+
}
|
|
74
|
+
if (data.Peer) {
|
|
75
|
+
for (const [_, peerData] of Object.entries(data.Peer)) {
|
|
76
|
+
const peer = {
|
|
77
|
+
hostname: peerData.HostName || "",
|
|
78
|
+
dnsName: peerData.DNSName || "",
|
|
79
|
+
tailscaleIPs: peerData.TailscaleIPs || [],
|
|
80
|
+
online: peerData.Online || false,
|
|
81
|
+
os: peerData.OS,
|
|
82
|
+
exitNode: peerData.ExitNode,
|
|
83
|
+
tags: peerData.Tags,
|
|
84
|
+
lastSeen: peerData.LastSeen
|
|
85
|
+
};
|
|
86
|
+
status.peers.push(peer);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
} catch (err) {
|
|
90
|
+
status.error = `Failed to parse Tailscale status: ${err}`;
|
|
91
|
+
}
|
|
92
|
+
return status;
|
|
93
|
+
}
|
|
94
|
+
function findPeer(hostname) {
|
|
95
|
+
const status = getTailscaleStatus();
|
|
96
|
+
if (!status.connected) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
const normalizedSearch = hostname.toLowerCase();
|
|
100
|
+
let peer = status.peers.find(
|
|
101
|
+
(p) => p.hostname.toLowerCase() === normalizedSearch
|
|
102
|
+
);
|
|
103
|
+
if (peer) return peer;
|
|
104
|
+
peer = status.peers.find(
|
|
105
|
+
(p) => p.dnsName.toLowerCase().startsWith(normalizedSearch)
|
|
106
|
+
);
|
|
107
|
+
if (peer) return peer;
|
|
108
|
+
peer = status.peers.find(
|
|
109
|
+
(p) => p.hostname.toLowerCase().includes(normalizedSearch)
|
|
110
|
+
);
|
|
111
|
+
return peer || null;
|
|
112
|
+
}
|
|
113
|
+
function getOnlinePeers() {
|
|
114
|
+
const status = getTailscaleStatus();
|
|
115
|
+
return status.peers.filter((p) => p.online);
|
|
116
|
+
}
|
|
117
|
+
function resolvePeerIP(hostname) {
|
|
118
|
+
const peer = findPeer(hostname);
|
|
119
|
+
return peer?.tailscaleIPs[0] || null;
|
|
120
|
+
}
|
|
121
|
+
function calculateChecksum(filePath) {
|
|
122
|
+
const content = fs.readFileSync(filePath);
|
|
123
|
+
return crypto.createHash("sha256").update(content).digest("hex");
|
|
124
|
+
}
|
|
125
|
+
function generateVaultManifest(vaultPath) {
|
|
126
|
+
const configPath = path.join(vaultPath, ".clawvault.json");
|
|
127
|
+
if (!fs.existsSync(configPath)) {
|
|
128
|
+
throw new Error(`Not a ClawVault: ${vaultPath}`);
|
|
129
|
+
}
|
|
130
|
+
const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
131
|
+
const files = [];
|
|
132
|
+
function walkDir(dir, relativePath = "") {
|
|
133
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
134
|
+
for (const entry of entries) {
|
|
135
|
+
const fullPath = path.join(dir, entry.name);
|
|
136
|
+
const relPath = path.join(relativePath, entry.name);
|
|
137
|
+
if (entry.name.startsWith(".") && entry.name !== ".clawvault.json") {
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (entry.name === "node_modules") {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (entry.isDirectory()) {
|
|
144
|
+
walkDir(fullPath, relPath);
|
|
145
|
+
} else if (entry.isFile() && (entry.name.endsWith(".md") || entry.name === ".clawvault.json")) {
|
|
146
|
+
const stats = fs.statSync(fullPath);
|
|
147
|
+
const category = relativePath.split(path.sep)[0] || "root";
|
|
148
|
+
files.push({
|
|
149
|
+
path: relPath,
|
|
150
|
+
size: stats.size,
|
|
151
|
+
modified: stats.mtime.toISOString(),
|
|
152
|
+
checksum: calculateChecksum(fullPath),
|
|
153
|
+
category
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
walkDir(vaultPath);
|
|
159
|
+
return {
|
|
160
|
+
name: config.name,
|
|
161
|
+
version: config.version || "1.0.0",
|
|
162
|
+
lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
163
|
+
files
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
function compareManifests(local, remote) {
|
|
167
|
+
const localFiles = new Map(local.files.map((f) => [f.path, f]));
|
|
168
|
+
const remoteFiles = new Map(remote.files.map((f) => [f.path, f]));
|
|
169
|
+
const toPush = [];
|
|
170
|
+
const toPull = [];
|
|
171
|
+
const conflicts = [];
|
|
172
|
+
const unchanged = [];
|
|
173
|
+
for (const [filePath, localFile] of localFiles) {
|
|
174
|
+
const remoteFile = remoteFiles.get(filePath);
|
|
175
|
+
if (!remoteFile) {
|
|
176
|
+
toPush.push(localFile);
|
|
177
|
+
} else if (localFile.checksum === remoteFile.checksum) {
|
|
178
|
+
unchanged.push(filePath);
|
|
179
|
+
} else {
|
|
180
|
+
const localTime = new Date(localFile.modified).getTime();
|
|
181
|
+
const remoteTime = new Date(remoteFile.modified).getTime();
|
|
182
|
+
if (localTime > remoteTime) {
|
|
183
|
+
toPush.push(localFile);
|
|
184
|
+
} else if (remoteTime > localTime) {
|
|
185
|
+
toPull.push(remoteFile);
|
|
186
|
+
} else {
|
|
187
|
+
conflicts.push({ path: filePath, local: localFile, remote: remoteFile });
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
for (const [filePath, remoteFile] of remoteFiles) {
|
|
192
|
+
if (!localFiles.has(filePath)) {
|
|
193
|
+
toPull.push(remoteFile);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return { toPush, toPull, conflicts, unchanged };
|
|
197
|
+
}
|
|
198
|
+
function serveVault(vaultPath, options = {}) {
|
|
199
|
+
const port = options.port || DEFAULT_SERVE_PORT;
|
|
200
|
+
const pathPrefix = options.pathPrefix || CLAWVAULT_SERVE_PATH;
|
|
201
|
+
if (!fs.existsSync(path.join(vaultPath, ".clawvault.json"))) {
|
|
202
|
+
throw new Error(`Not a ClawVault: ${vaultPath}`);
|
|
203
|
+
}
|
|
204
|
+
const webdavHandler = createWebDAVHandler({
|
|
205
|
+
rootPath: vaultPath,
|
|
206
|
+
prefix: WEBDAV_PREFIX,
|
|
207
|
+
auth: options.webdavAuth
|
|
208
|
+
});
|
|
209
|
+
const server = http.createServer(async (req, res) => {
|
|
210
|
+
const url = new URL(req.url || "/", `http://localhost:${port}`);
|
|
211
|
+
const pathname = url.pathname;
|
|
212
|
+
if (pathname.startsWith(WEBDAV_PREFIX)) {
|
|
213
|
+
try {
|
|
214
|
+
const handled = await webdavHandler(req, res);
|
|
215
|
+
if (handled) return;
|
|
216
|
+
} catch (err) {
|
|
217
|
+
res.writeHead(500, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
|
|
218
|
+
res.end(`WebDAV Error: ${err}`);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
223
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
224
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
225
|
+
if (req.method === "OPTIONS") {
|
|
226
|
+
res.writeHead(200);
|
|
227
|
+
res.end();
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
if (pathname === `${pathPrefix}/health`) {
|
|
231
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
232
|
+
res.end(JSON.stringify({ status: "ok", vault: path.basename(vaultPath) }));
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
if (pathname === `${pathPrefix}/manifest`) {
|
|
236
|
+
try {
|
|
237
|
+
const manifest = generateVaultManifest(vaultPath);
|
|
238
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
239
|
+
res.end(JSON.stringify(manifest));
|
|
240
|
+
} catch (err) {
|
|
241
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
242
|
+
res.end(JSON.stringify({ error: String(err) }));
|
|
243
|
+
}
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
if (pathname.startsWith(`${pathPrefix}/files/`)) {
|
|
247
|
+
const relativePath = decodeURIComponent(pathname.slice(`${pathPrefix}/files/`.length));
|
|
248
|
+
const filePath = path.join(vaultPath, relativePath);
|
|
249
|
+
const resolvedPath = path.resolve(filePath);
|
|
250
|
+
const resolvedVault = path.resolve(vaultPath);
|
|
251
|
+
if (!resolvedPath.startsWith(resolvedVault)) {
|
|
252
|
+
res.writeHead(403, { "Content-Type": "application/json" });
|
|
253
|
+
res.end(JSON.stringify({ error: "Access denied" }));
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
if (!fs.existsSync(filePath)) {
|
|
257
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
258
|
+
res.end(JSON.stringify({ error: "File not found" }));
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
try {
|
|
262
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
263
|
+
const stats = fs.statSync(filePath);
|
|
264
|
+
res.writeHead(200, {
|
|
265
|
+
"Content-Type": "text/markdown",
|
|
266
|
+
"Content-Length": Buffer.byteLength(content),
|
|
267
|
+
"Last-Modified": stats.mtime.toUTCString()
|
|
268
|
+
});
|
|
269
|
+
res.end(content);
|
|
270
|
+
} catch (err) {
|
|
271
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
272
|
+
res.end(JSON.stringify({ error: String(err) }));
|
|
273
|
+
}
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
if (pathname.startsWith(`${pathPrefix}/upload/`) && req.method === "POST") {
|
|
277
|
+
const relativePath = decodeURIComponent(pathname.slice(`${pathPrefix}/upload/`.length));
|
|
278
|
+
const filePath = path.join(vaultPath, relativePath);
|
|
279
|
+
const resolvedPath = path.resolve(filePath);
|
|
280
|
+
const resolvedVault = path.resolve(vaultPath);
|
|
281
|
+
if (!resolvedPath.startsWith(resolvedVault)) {
|
|
282
|
+
res.writeHead(403, { "Content-Type": "application/json" });
|
|
283
|
+
res.end(JSON.stringify({ error: "Access denied" }));
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
let body = "";
|
|
287
|
+
req.on("data", (chunk) => {
|
|
288
|
+
body += chunk;
|
|
289
|
+
});
|
|
290
|
+
req.on("end", () => {
|
|
291
|
+
try {
|
|
292
|
+
const dir = path.dirname(filePath);
|
|
293
|
+
if (!fs.existsSync(dir)) {
|
|
294
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
295
|
+
}
|
|
296
|
+
fs.writeFileSync(filePath, body, "utf-8");
|
|
297
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
298
|
+
res.end(JSON.stringify({ success: true, path: relativePath }));
|
|
299
|
+
} catch (err) {
|
|
300
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
301
|
+
res.end(JSON.stringify({ error: String(err) }));
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
if (pathname === pathPrefix || pathname === `${pathPrefix}/`) {
|
|
307
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
308
|
+
res.end(JSON.stringify({
|
|
309
|
+
service: "clawvault-sync",
|
|
310
|
+
version: "1.0.0",
|
|
311
|
+
vault: path.basename(vaultPath),
|
|
312
|
+
endpoints: {
|
|
313
|
+
health: `${pathPrefix}/health`,
|
|
314
|
+
manifest: `${pathPrefix}/manifest`,
|
|
315
|
+
files: `${pathPrefix}/files/<path>`,
|
|
316
|
+
upload: `${pathPrefix}/upload/<path>`,
|
|
317
|
+
webdav: `${WEBDAV_PREFIX}/`
|
|
318
|
+
}
|
|
319
|
+
}));
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
323
|
+
res.end(JSON.stringify({ error: "Not found" }));
|
|
324
|
+
});
|
|
325
|
+
server.listen(port, "0.0.0.0");
|
|
326
|
+
return {
|
|
327
|
+
server,
|
|
328
|
+
port,
|
|
329
|
+
stop: () => new Promise((resolve2, reject) => {
|
|
330
|
+
server.close((err) => {
|
|
331
|
+
if (err) reject(err);
|
|
332
|
+
else resolve2();
|
|
333
|
+
});
|
|
334
|
+
})
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
async function fetchRemoteManifest(host, port = DEFAULT_SERVE_PORT, useHttps = false) {
|
|
338
|
+
return new Promise((resolve2, reject) => {
|
|
339
|
+
const protocol = useHttps ? https : http;
|
|
340
|
+
const url = `${useHttps ? "https" : "http"}://${host}:${port}${CLAWVAULT_SERVE_PATH}/manifest`;
|
|
341
|
+
const req = protocol.get(url, { timeout: 1e4 }, (res) => {
|
|
342
|
+
let data = "";
|
|
343
|
+
res.on("data", (chunk) => {
|
|
344
|
+
data += chunk;
|
|
345
|
+
});
|
|
346
|
+
res.on("end", () => {
|
|
347
|
+
if (res.statusCode !== 200) {
|
|
348
|
+
reject(new Error(`Failed to fetch manifest: HTTP ${res.statusCode}`));
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
try {
|
|
352
|
+
resolve2(JSON.parse(data));
|
|
353
|
+
} catch (err) {
|
|
354
|
+
reject(new Error(`Invalid manifest response: ${err}`));
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
});
|
|
358
|
+
req.on("error", reject);
|
|
359
|
+
req.on("timeout", () => {
|
|
360
|
+
req.destroy();
|
|
361
|
+
reject(new Error("Request timed out"));
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
async function fetchRemoteFile(host, filePath, port = DEFAULT_SERVE_PORT, useHttps = false) {
|
|
366
|
+
return new Promise((resolve2, reject) => {
|
|
367
|
+
const protocol = useHttps ? https : http;
|
|
368
|
+
const encodedPath = encodeURIComponent(filePath).replace(/%2F/g, "/");
|
|
369
|
+
const url = `${useHttps ? "https" : "http"}://${host}:${port}${CLAWVAULT_SERVE_PATH}/files/${encodedPath}`;
|
|
370
|
+
const req = protocol.get(url, { timeout: 3e4 }, (res) => {
|
|
371
|
+
let data = "";
|
|
372
|
+
res.on("data", (chunk) => {
|
|
373
|
+
data += chunk;
|
|
374
|
+
});
|
|
375
|
+
res.on("end", () => {
|
|
376
|
+
if (res.statusCode !== 200) {
|
|
377
|
+
reject(new Error(`Failed to fetch file: HTTP ${res.statusCode}`));
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
resolve2(data);
|
|
381
|
+
});
|
|
382
|
+
});
|
|
383
|
+
req.on("error", reject);
|
|
384
|
+
req.on("timeout", () => {
|
|
385
|
+
req.destroy();
|
|
386
|
+
reject(new Error("Request timed out"));
|
|
387
|
+
});
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
async function pushFileToRemote(host, filePath, content, port = DEFAULT_SERVE_PORT, useHttps = false) {
|
|
391
|
+
return new Promise((resolve2, reject) => {
|
|
392
|
+
const protocol = useHttps ? https : http;
|
|
393
|
+
const encodedPath = encodeURIComponent(filePath).replace(/%2F/g, "/");
|
|
394
|
+
const url = new URL(`${useHttps ? "https" : "http"}://${host}:${port}${CLAWVAULT_SERVE_PATH}/upload/${encodedPath}`);
|
|
395
|
+
const options = {
|
|
396
|
+
hostname: url.hostname,
|
|
397
|
+
port: url.port,
|
|
398
|
+
path: url.pathname,
|
|
399
|
+
method: "POST",
|
|
400
|
+
headers: {
|
|
401
|
+
"Content-Type": "text/markdown",
|
|
402
|
+
"Content-Length": Buffer.byteLength(content)
|
|
403
|
+
},
|
|
404
|
+
timeout: 3e4
|
|
405
|
+
};
|
|
406
|
+
const req = protocol.request(options, (res) => {
|
|
407
|
+
let data = "";
|
|
408
|
+
res.on("data", (chunk) => {
|
|
409
|
+
data += chunk;
|
|
410
|
+
});
|
|
411
|
+
res.on("end", () => {
|
|
412
|
+
if (res.statusCode !== 200) {
|
|
413
|
+
reject(new Error(`Failed to push file: HTTP ${res.statusCode}`));
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
resolve2();
|
|
417
|
+
});
|
|
418
|
+
});
|
|
419
|
+
req.on("error", reject);
|
|
420
|
+
req.on("timeout", () => {
|
|
421
|
+
req.destroy();
|
|
422
|
+
reject(new Error("Request timed out"));
|
|
423
|
+
});
|
|
424
|
+
req.write(content);
|
|
425
|
+
req.end();
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
async function syncWithPeer(vaultPath, options) {
|
|
429
|
+
const startTime = Date.now();
|
|
430
|
+
const result = {
|
|
431
|
+
pushed: [],
|
|
432
|
+
pulled: [],
|
|
433
|
+
deleted: [],
|
|
434
|
+
unchanged: [],
|
|
435
|
+
errors: [],
|
|
436
|
+
stats: {
|
|
437
|
+
bytesTransferred: 0,
|
|
438
|
+
filesProcessed: 0,
|
|
439
|
+
duration: 0
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
const {
|
|
443
|
+
peer,
|
|
444
|
+
port = DEFAULT_SERVE_PORT,
|
|
445
|
+
direction = "bidirectional",
|
|
446
|
+
dryRun = false,
|
|
447
|
+
deleteOrphans = false,
|
|
448
|
+
categories,
|
|
449
|
+
https: useHttps = false
|
|
450
|
+
} = options;
|
|
451
|
+
let host = peer;
|
|
452
|
+
if (!peer.match(/^\d+\.\d+\.\d+\.\d+$/)) {
|
|
453
|
+
const resolvedIP = resolvePeerIP(peer);
|
|
454
|
+
if (!resolvedIP) {
|
|
455
|
+
result.errors.push(`Could not resolve peer: ${peer}`);
|
|
456
|
+
result.stats.duration = Date.now() - startTime;
|
|
457
|
+
return result;
|
|
458
|
+
}
|
|
459
|
+
host = resolvedIP;
|
|
460
|
+
}
|
|
461
|
+
try {
|
|
462
|
+
const localManifest = generateVaultManifest(vaultPath);
|
|
463
|
+
const remoteManifest = await fetchRemoteManifest(host, port, useHttps);
|
|
464
|
+
let { toPush, toPull, conflicts, unchanged } = compareManifests(localManifest, remoteManifest);
|
|
465
|
+
if (categories && categories.length > 0) {
|
|
466
|
+
const categorySet = new Set(categories);
|
|
467
|
+
toPush = toPush.filter((f) => categorySet.has(f.category));
|
|
468
|
+
toPull = toPull.filter((f) => categorySet.has(f.category));
|
|
469
|
+
}
|
|
470
|
+
result.unchanged = unchanged;
|
|
471
|
+
for (const conflict of conflicts) {
|
|
472
|
+
result.errors.push(`Conflict: ${conflict.path} (local and remote have same timestamp but different content)`);
|
|
473
|
+
}
|
|
474
|
+
if (direction === "push" || direction === "bidirectional") {
|
|
475
|
+
for (const file of toPush) {
|
|
476
|
+
try {
|
|
477
|
+
if (!dryRun) {
|
|
478
|
+
const content = fs.readFileSync(path.join(vaultPath, file.path), "utf-8");
|
|
479
|
+
await pushFileToRemote(host, file.path, content, port, useHttps);
|
|
480
|
+
result.stats.bytesTransferred += file.size;
|
|
481
|
+
}
|
|
482
|
+
result.pushed.push(file.path);
|
|
483
|
+
result.stats.filesProcessed++;
|
|
484
|
+
} catch (err) {
|
|
485
|
+
result.errors.push(`Failed to push ${file.path}: ${err}`);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
if (direction === "pull" || direction === "bidirectional") {
|
|
490
|
+
for (const file of toPull) {
|
|
491
|
+
try {
|
|
492
|
+
if (!dryRun) {
|
|
493
|
+
const content = await fetchRemoteFile(host, file.path, port, useHttps);
|
|
494
|
+
const filePath = path.join(vaultPath, file.path);
|
|
495
|
+
const dir = path.dirname(filePath);
|
|
496
|
+
if (!fs.existsSync(dir)) {
|
|
497
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
498
|
+
}
|
|
499
|
+
fs.writeFileSync(filePath, content, "utf-8");
|
|
500
|
+
result.stats.bytesTransferred += file.size;
|
|
501
|
+
}
|
|
502
|
+
result.pulled.push(file.path);
|
|
503
|
+
result.stats.filesProcessed++;
|
|
504
|
+
} catch (err) {
|
|
505
|
+
result.errors.push(`Failed to pull ${file.path}: ${err}`);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
if (deleteOrphans && direction === "pull") {
|
|
510
|
+
const remoteFiles = new Set(remoteManifest.files.map((f) => f.path));
|
|
511
|
+
for (const file of localManifest.files) {
|
|
512
|
+
if (!remoteFiles.has(file.path)) {
|
|
513
|
+
if (!categories || categories.includes(file.category)) {
|
|
514
|
+
try {
|
|
515
|
+
if (!dryRun) {
|
|
516
|
+
fs.unlinkSync(path.join(vaultPath, file.path));
|
|
517
|
+
}
|
|
518
|
+
result.deleted.push(file.path);
|
|
519
|
+
} catch (err) {
|
|
520
|
+
result.errors.push(`Failed to delete ${file.path}: ${err}`);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
} catch (err) {
|
|
527
|
+
result.errors.push(`Sync failed: ${err}`);
|
|
528
|
+
}
|
|
529
|
+
result.stats.duration = Date.now() - startTime;
|
|
530
|
+
return result;
|
|
531
|
+
}
|
|
532
|
+
function configureTailscaleServe(localPort, options = {}) {
|
|
533
|
+
if (!hasTailscale()) {
|
|
534
|
+
return null;
|
|
535
|
+
}
|
|
536
|
+
const args = ["serve"];
|
|
537
|
+
if (options.funnel) {
|
|
538
|
+
args.push("--bg");
|
|
539
|
+
args.push("funnel");
|
|
540
|
+
} else if (options.background) {
|
|
541
|
+
args.push("--bg");
|
|
542
|
+
}
|
|
543
|
+
args.push(`localhost:${localPort}`);
|
|
544
|
+
const proc = spawn("tailscale", args, {
|
|
545
|
+
stdio: "inherit",
|
|
546
|
+
detached: options.background
|
|
547
|
+
});
|
|
548
|
+
if (options.background) {
|
|
549
|
+
proc.unref();
|
|
550
|
+
}
|
|
551
|
+
return proc;
|
|
552
|
+
}
|
|
553
|
+
function stopTailscaleServe() {
|
|
554
|
+
if (!hasTailscale()) {
|
|
555
|
+
return false;
|
|
556
|
+
}
|
|
557
|
+
const result = spawnSync("tailscale", ["serve", "off"], {
|
|
558
|
+
stdio: "pipe",
|
|
559
|
+
encoding: "utf-8",
|
|
560
|
+
timeout: 5e3
|
|
561
|
+
});
|
|
562
|
+
return result.status === 0;
|
|
563
|
+
}
|
|
564
|
+
async function checkPeerClawVault(host, port = DEFAULT_SERVE_PORT) {
|
|
565
|
+
try {
|
|
566
|
+
const response = await new Promise((resolve2) => {
|
|
567
|
+
const req = http.get(
|
|
568
|
+
`http://${host}:${port}${CLAWVAULT_SERVE_PATH}/health`,
|
|
569
|
+
{ timeout: 5e3 },
|
|
570
|
+
(res) => {
|
|
571
|
+
resolve2(res.statusCode === 200);
|
|
572
|
+
}
|
|
573
|
+
);
|
|
574
|
+
req.on("error", () => resolve2(false));
|
|
575
|
+
req.on("timeout", () => {
|
|
576
|
+
req.destroy();
|
|
577
|
+
resolve2(false);
|
|
578
|
+
});
|
|
579
|
+
});
|
|
580
|
+
return response;
|
|
581
|
+
} catch {
|
|
582
|
+
return false;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
async function discoverClawVaultPeers(port = DEFAULT_SERVE_PORT) {
|
|
586
|
+
const status = getTailscaleStatus();
|
|
587
|
+
if (!status.connected) {
|
|
588
|
+
return [];
|
|
589
|
+
}
|
|
590
|
+
const clawvaultPeers = [];
|
|
591
|
+
const checkPromises = status.peers.filter((p) => p.online).map(async (peer) => {
|
|
592
|
+
const ip = peer.tailscaleIPs[0];
|
|
593
|
+
if (!ip) return;
|
|
594
|
+
const isServing = await checkPeerClawVault(ip, port);
|
|
595
|
+
if (isServing) {
|
|
596
|
+
peer.clawvaultServing = true;
|
|
597
|
+
peer.clawvaultPort = port;
|
|
598
|
+
clawvaultPeers.push(peer);
|
|
599
|
+
}
|
|
600
|
+
});
|
|
601
|
+
await Promise.all(checkPromises);
|
|
602
|
+
return clawvaultPeers;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
export {
|
|
606
|
+
DEFAULT_SERVE_PORT,
|
|
607
|
+
CLAWVAULT_SERVE_PATH,
|
|
608
|
+
MANIFEST_ENDPOINT,
|
|
609
|
+
SYNC_ENDPOINT,
|
|
610
|
+
FILE_ENDPOINT,
|
|
611
|
+
hasTailscale,
|
|
612
|
+
getTailscaleVersion,
|
|
613
|
+
getTailscaleStatus,
|
|
614
|
+
findPeer,
|
|
615
|
+
getOnlinePeers,
|
|
616
|
+
resolvePeerIP,
|
|
617
|
+
generateVaultManifest,
|
|
618
|
+
compareManifests,
|
|
619
|
+
serveVault,
|
|
620
|
+
fetchRemoteManifest,
|
|
621
|
+
fetchRemoteFile,
|
|
622
|
+
pushFileToRemote,
|
|
623
|
+
syncWithPeer,
|
|
624
|
+
configureTailscaleServe,
|
|
625
|
+
stopTailscaleServe,
|
|
626
|
+
checkPeerClawVault,
|
|
627
|
+
discoverClawVaultPeers
|
|
628
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
8
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
9
|
+
};
|
|
10
|
+
var __export = (target, all) => {
|
|
11
|
+
for (var name in all)
|
|
12
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
13
|
+
};
|
|
14
|
+
var __copyProps = (to, from, except, desc) => {
|
|
15
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
16
|
+
for (let key of __getOwnPropNames(from))
|
|
17
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
18
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
19
|
+
}
|
|
20
|
+
return to;
|
|
21
|
+
};
|
|
22
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
23
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
24
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
25
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
26
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
27
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
28
|
+
mod
|
|
29
|
+
));
|
|
30
|
+
|
|
31
|
+
export {
|
|
32
|
+
__commonJS,
|
|
33
|
+
__export,
|
|
34
|
+
__toESM
|
|
35
|
+
};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runReflection
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-MNPUYCHQ.js";
|
|
4
4
|
import {
|
|
5
5
|
Observer
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-Y3TIJEBP.js";
|
|
7
7
|
import {
|
|
8
8
|
resolveVaultPath
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-GNJL4YGR.js";
|
|
10
10
|
|
|
11
11
|
// src/commands/replay.ts
|
|
12
12
|
import * as fs from "fs";
|
|
@@ -135,8 +135,7 @@ function pushMessage(destination, conversationId, record) {
|
|
|
135
135
|
if (!text) {
|
|
136
136
|
return;
|
|
137
137
|
}
|
|
138
|
-
const
|
|
139
|
-
const role = rawRole ? rawRole.trim().toLowerCase() : void 0;
|
|
138
|
+
const role = typeof record.role === "string" ? record.role.trim().toLowerCase() : void 0;
|
|
140
139
|
destination.push({
|
|
141
140
|
source: "claude",
|
|
142
141
|
conversationId,
|
|
@@ -152,9 +151,8 @@ function normalizeClaudeExport(input) {
|
|
|
152
151
|
if (!item || typeof item !== "object") continue;
|
|
153
152
|
const record = item;
|
|
154
153
|
const conversationId = typeof record.id === "string" ? record.id : typeof record.uuid === "string" ? record.uuid : void 0;
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
for (const message of recordMessages) {
|
|
154
|
+
if (Array.isArray(record.messages)) {
|
|
155
|
+
for (const message of record.messages) {
|
|
158
156
|
if (!message || typeof message !== "object") continue;
|
|
159
157
|
pushMessage(messages, conversationId, message);
|
|
160
158
|
}
|
|
@@ -172,9 +170,6 @@ function normalizeClaudeExport(input) {
|
|
|
172
170
|
if (Array.isArray(root.messages)) {
|
|
173
171
|
return normalizeClaudeExport([{ id: root.id, messages: root.messages }]);
|
|
174
172
|
}
|
|
175
|
-
if (Array.isArray(root.chat_messages)) {
|
|
176
|
-
return normalizeClaudeExport([{ id: root.id, chat_messages: root.chat_messages }]);
|
|
177
|
-
}
|
|
178
173
|
}
|
|
179
174
|
return messages;
|
|
180
175
|
}
|