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 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://alice.local:/home/agent/context --name wisp
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 alice.local
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 alice.local # + reverse SSH 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
- const VERSION = "0.3.13";
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: "0.3.13",
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
- await writeFile(dest, JSON.stringify(msg, null, 2));
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.13",
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": {