openfused 0.3.13 → 0.3.15
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 +5 -5
- package/dist/cli.js +12 -1
- package/dist/mcp.js +2 -1
- package/dist/sync.js +21 -3
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -67,11 +67,11 @@ history/ — archived [DONE] context
|
|
|
67
67
|
openfuse context
|
|
68
68
|
openfuse context --append "## Update\nFinished the research phase."
|
|
69
69
|
|
|
70
|
-
# Mark work as done, then compact to history/
|
|
70
|
+
# Mark work as done, then compact to history/ (TS CLI only)
|
|
71
71
|
# (edit CONTEXT.md, add [DONE] to the header, then:)
|
|
72
72
|
openfuse compact
|
|
73
73
|
|
|
74
|
-
# Add validity windows to time-sensitive context
|
|
74
|
+
# Add validity windows to time-sensitive context (TS CLI only)
|
|
75
75
|
# <!-- validity: 6h --> for task state, 1d for sprint, 3d for architecture
|
|
76
76
|
openfuse validate # scan for stale entries
|
|
77
77
|
openfuse compact --prune-stale # archive expired validity windows
|
|
@@ -181,7 +181,7 @@ Pull peer context, pull their outbox for your mail, push your outbox. Two transp
|
|
|
181
181
|
|
|
182
182
|
```bash
|
|
183
183
|
# LAN — rsync over SSH (uses your ~/.ssh/config for host aliases)
|
|
184
|
-
openfuse peer add ssh://
|
|
184
|
+
openfuse peer add ssh://your-server:/home/agent/store --name wisp
|
|
185
185
|
|
|
186
186
|
# WAN — HTTP against the OpenFused daemon
|
|
187
187
|
openfuse peer add https://wisp.openfused.dev --name wisp
|
|
@@ -193,7 +193,7 @@ openfuse sync
|
|
|
193
193
|
openfuse watch
|
|
194
194
|
|
|
195
195
|
# Watch + reverse SSH tunnel (NAT traversal)
|
|
196
|
-
openfuse watch --tunnel
|
|
196
|
+
openfuse watch --tunnel your-server
|
|
197
197
|
```
|
|
198
198
|
|
|
199
199
|
Sync does three things:
|
|
@@ -276,7 +276,7 @@ Public mode endpoints:
|
|
|
276
276
|
openfuse watch -d ./store # sync every 60s
|
|
277
277
|
openfuse watch -d ./store --sync-interval 30 # sync every 30s
|
|
278
278
|
openfuse watch -d ./store --sync-interval 0 # local watch only
|
|
279
|
-
openfuse watch -d ./store --tunnel
|
|
279
|
+
openfuse watch -d ./store --tunnel your-server # + reverse SSH tunnel
|
|
280
280
|
```
|
|
281
281
|
|
|
282
282
|
## Reachability
|
package/dist/cli.js
CHANGED
|
@@ -9,7 +9,18 @@ import { fingerprint } from "./crypto.js";
|
|
|
9
9
|
import { resolve, join } from "node:path";
|
|
10
10
|
import { readFile } from "node:fs/promises";
|
|
11
11
|
import { parseValiditySections, buildValidityReport } from "./validity.js";
|
|
12
|
-
|
|
12
|
+
import { createRequire } from "node:module";
|
|
13
|
+
const VERSION = createRequire(import.meta.url)("../package.json").version;
|
|
14
|
+
// Enable proxy support: Node.js built-in fetch doesn't respect HTTP_PROXY env vars.
|
|
15
|
+
// Setting a global EnvHttpProxyAgent makes all fetch() calls proxy-aware —
|
|
16
|
+
// essential for corporate networks, containers, and tunneled environments.
|
|
17
|
+
if (process.env.https_proxy || process.env.HTTPS_PROXY || process.env.http_proxy || process.env.HTTP_PROXY) {
|
|
18
|
+
try {
|
|
19
|
+
const { EnvHttpProxyAgent, setGlobalDispatcher } = await import("undici");
|
|
20
|
+
setGlobalDispatcher(new EnvHttpProxyAgent());
|
|
21
|
+
}
|
|
22
|
+
catch { }
|
|
23
|
+
}
|
|
13
24
|
const program = new Command();
|
|
14
25
|
program
|
|
15
26
|
.name("openfuse")
|
package/dist/mcp.js
CHANGED
|
@@ -10,6 +10,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
10
10
|
import { z } from "zod";
|
|
11
11
|
import { ContextStore, validateName } from "./store.js";
|
|
12
12
|
import { resolve } from "node:path";
|
|
13
|
+
import { createRequire } from "node:module";
|
|
13
14
|
// LLMs will pass whatever filenames users ask for — including "../../etc/shadow".
|
|
14
15
|
// This is the trust boundary between the AI and the filesystem.
|
|
15
16
|
function sanitizeFilename(name) {
|
|
@@ -23,7 +24,7 @@ const storeDir = process.env.OPENFUSE_DIR || process.argv[3] || ".";
|
|
|
23
24
|
const store = new ContextStore(resolve(storeDir));
|
|
24
25
|
const server = new McpServer({
|
|
25
26
|
name: "openfuse",
|
|
26
|
-
version: "
|
|
27
|
+
version: createRequire(import.meta.url)("../package.json").version,
|
|
27
28
|
});
|
|
28
29
|
// --- Context ---
|
|
29
30
|
server.tool("context_read", "Read the agent's CONTEXT.md (working memory)", async () => {
|
package/dist/sync.js
CHANGED
|
@@ -203,15 +203,33 @@ async function syncHttp(store, peer, baseUrl, peerDir) {
|
|
|
203
203
|
for (const msg of messages) {
|
|
204
204
|
const ts = (msg.timestamp || new Date().toISOString()).replace(/[:.]/g, "-");
|
|
205
205
|
const from = msg.from || "unknown";
|
|
206
|
-
// SECURITY: sanitize remote-controlled values before constructing local filenames.
|
|
207
|
-
// Without this, a malicious "from" like "../../.keys/x" could write outside inbox/.
|
|
208
206
|
const safeFrom = from.replace(/[^a-zA-Z0-9\-_]/g, "");
|
|
209
207
|
const safeTs = ts.replace(/[^a-zA-Z0-9\-_]/g, "");
|
|
210
208
|
const fname = `${safeTs}_from-${safeFrom}_to-${myName}.json`;
|
|
209
|
+
const outboxFile = msg._outboxFile; // filename on sender's outbox
|
|
211
210
|
const dest = join(inboxDir, fname);
|
|
212
211
|
if (!existsSync(dest)) {
|
|
213
|
-
|
|
212
|
+
// Strip the _outboxFile metadata before saving
|
|
213
|
+
const { _outboxFile, ...cleanMsg } = msg;
|
|
214
|
+
await writeFile(dest, JSON.stringify(cleanMsg, null, 2));
|
|
214
215
|
pulled.push(`outbox→${fname}`);
|
|
216
|
+
// ACK: tell sender to move this message to .sent/
|
|
217
|
+
if (outboxFile) {
|
|
218
|
+
try {
|
|
219
|
+
const ackTs = new Date().toISOString();
|
|
220
|
+
const ackChallenge = `ACK:${myName}:${outboxFile}:${ackTs}`;
|
|
221
|
+
const ackSig = await signChallenge(store.root, ackChallenge);
|
|
222
|
+
await fetch(`${baseUrl}/outbox/${myName}/${outboxFile}`, {
|
|
223
|
+
method: "DELETE",
|
|
224
|
+
headers: {
|
|
225
|
+
"X-OpenFuse-PublicKey": ackSig.publicKey,
|
|
226
|
+
"X-OpenFuse-Signature": ackSig.signature,
|
|
227
|
+
"X-OpenFuse-Timestamp": ackTs,
|
|
228
|
+
},
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
catch { } // best-effort ACK
|
|
232
|
+
}
|
|
215
233
|
}
|
|
216
234
|
}
|
|
217
235
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openfused",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.15",
|
|
4
4
|
"description": "The file protocol for AI agent context. Encrypted, signed, peer-to-peer.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"chokidar": "^5.0.0",
|
|
30
30
|
"commander": "^14.0.0",
|
|
31
31
|
"nanoid": "^5.1.7",
|
|
32
|
+
"undici": "^7.24.5",
|
|
32
33
|
"zod": "^4.3.6"
|
|
33
34
|
},
|
|
34
35
|
"devDependencies": {
|