openfused 0.3.6 → 0.3.9

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
@@ -1,6 +1,6 @@
1
1
  # OpenFused
2
2
 
3
- Decentralized context mesh for AI agents. Encrypted messaging, peer sync, agent registry. The protocol is files.
3
+ The file protocol for AI agent context. Encrypted, signed, peer-to-peer.
4
4
 
5
5
  ## What is this?
6
6
 
package/dist/cli.js CHANGED
@@ -6,13 +6,13 @@ import { watchInbox, watchContext, watchSync } from "./watch.js";
6
6
  import { syncAll, syncOne, deliverOne } from "./sync.js";
7
7
  import * as registry from "./registry.js";
8
8
  import { fingerprint } from "./crypto.js";
9
- import { resolve } from "node:path";
9
+ import { resolve, join } from "node:path";
10
10
  import { readFile } from "node:fs/promises";
11
- const VERSION = "0.3.6";
11
+ const VERSION = "0.3.9";
12
12
  const program = new Command();
13
13
  program
14
14
  .name("openfuse")
15
- .description("Decentralized context mesh for AI agents. The protocol is files.")
15
+ .description("The file protocol for AI agent context. Encrypted, signed, peer-to-peer.")
16
16
  .version(VERSION);
17
17
  // --- init ---
18
18
  program
@@ -399,19 +399,25 @@ key
399
399
  console.log(`Key already in keyring (fingerprint: ${fp})`);
400
400
  return;
401
401
  }
402
+ const autoTrust = config.autoTrust ?? false;
402
403
  config.keyring.push({
403
404
  name,
404
405
  address: opts.address ?? "",
405
406
  signingKey,
406
407
  encryptionKey: opts.encryptionKey,
407
408
  fingerprint: fp,
408
- trusted: false,
409
+ trusted: autoTrust,
409
410
  added: new Date().toISOString(),
410
411
  });
411
412
  await store.writeConfig(config);
412
413
  console.log(`Imported key for: ${name}`);
413
414
  console.log(` Fingerprint: ${fp}`);
414
- console.log(`\nKey is NOT trusted yet. Run: openfuse key trust ${name}`);
415
+ if (autoTrust) {
416
+ console.log(` Auto-trusted (workspace mode)`);
417
+ }
418
+ else {
419
+ console.log(`\nKey is NOT trusted yet. Run: openfuse key trust ${name}`);
420
+ }
415
421
  });
416
422
  key
417
423
  .command("trust <name>")
@@ -554,13 +560,46 @@ program
554
560
  console.log(`Imported key for ${manifest.name} from registry [untrusted]`);
555
561
  console.log(` Run \`openfuse key trust ${manifest.name}\` to trust`);
556
562
  }
557
- await store.sendInbox(name, message);
558
- console.log(`Message queued in outbox for ${name}. Run \`openfuse sync\` to deliver.`);
563
+ const filename = await store.sendInbox(name, message);
564
+ // Try direct HTTP delivery if endpoint is http(s)
565
+ if (manifest.endpoint.startsWith("http")) {
566
+ try {
567
+ const body = await readFile(join(store.root, "outbox", filename), "utf-8");
568
+ const r = await fetch(`${manifest.endpoint.replace(/\/$/, "")}/inbox`, {
569
+ method: "POST",
570
+ headers: { "Content-Type": "application/json" },
571
+ body,
572
+ });
573
+ if (r.ok) {
574
+ // Archive to .sent/
575
+ const { mkdir, rename } = await import("node:fs/promises");
576
+ const sentDir = join(store.root, "outbox", ".sent");
577
+ await mkdir(sentDir, { recursive: true });
578
+ await rename(join(store.root, "outbox", filename), join(sentDir, filename));
579
+ console.log(`Delivered to ${name}.`);
580
+ }
581
+ else {
582
+ console.log(`Queued for ${name}. Endpoint returned ${r.status}. Will deliver on next sync.`);
583
+ }
584
+ }
585
+ catch {
586
+ console.log(`Queued for ${name}. Will deliver on next sync.`);
587
+ }
588
+ }
589
+ else {
590
+ console.log(`Queued for ${name}. Run \`openfuse sync\` to deliver.`);
591
+ }
559
592
  }
560
593
  catch {
561
594
  // Not in registry — send as a peer message
562
- await store.sendInbox(name, message);
563
- console.log(`Message sent to ${name}'s outbox.`);
595
+ const filename = await store.sendInbox(name, message);
596
+ const delivered = await deliverOne(store, name, filename);
597
+ if (delivered) {
598
+ console.log(`Delivered to ${name}.`);
599
+ }
600
+ else {
601
+ console.log(`Queued for ${name}. Run \`openfuse sync\` to deliver.`);
602
+ }
564
603
  }
565
604
  });
566
605
  program.parse();
package/dist/mcp.js CHANGED
@@ -23,7 +23,7 @@ const storeDir = process.env.OPENFUSE_DIR || process.argv[3] || ".";
23
23
  const store = new ContextStore(resolve(storeDir));
24
24
  const server = new McpServer({
25
25
  name: "openfuse",
26
- version: "0.3.6",
26
+ version: "0.3.9",
27
27
  });
28
28
  // --- Context ---
29
29
  server.tool("context_read", "Read the agent's CONTEXT.md (working memory)", async () => {
@@ -1,5 +1,5 @@
1
1
  import { ContextStore } from "./store.js";
2
- export declare const DEFAULT_REGISTRY = "https://registry.openfused.dev";
2
+ export declare const DEFAULT_REGISTRY = "https://openfuse-registry.wzmcghee.workers.dev";
3
3
  export interface Manifest {
4
4
  name: string;
5
5
  endpoint: string;
package/dist/registry.js CHANGED
@@ -7,7 +7,8 @@
7
7
  // This is TOFU (Trust On First Use) done right: the registry distributes keys,
8
8
  // but never asserts trust. Trust is a local decision.
9
9
  import { signMessage, fingerprint } from "./crypto.js";
10
- export const DEFAULT_REGISTRY = "https://registry.openfused.dev";
10
+ // Custom domain pending propagation — use Worker URL as fallback
11
+ export const DEFAULT_REGISTRY = "https://openfuse-registry.wzmcghee.workers.dev";
11
12
  export function resolveRegistry(flag) {
12
13
  return flag || process.env.OPENFUSE_REGISTRY || DEFAULT_REGISTRY;
13
14
  }
@@ -44,13 +45,13 @@ export async function register(store, endpoint, registry) {
44
45
  // Discovery: try DNS TXT first (decentralized, no registry needed), fall back to Worker API.
45
46
  // DNS format: v=of1 e={endpoint} pk={pubkey} ek={agekey} fp={fingerprint}
46
47
  // Self-hosted: _openfuse.{name}.{their-domain} — user manages their own TXT records.
47
- // Our zone: _openfuse.{name}.openfused.dev — managed by the registry Worker on registration.
48
+ // Our zone: _openfuse.{name}.openfused.net — managed by the registry Worker on registration.
48
49
  export async function discover(name, registry) {
49
50
  // If name contains a dot, it's a domain — try DNS TXT directly
50
- // Otherwise try DNS at openfused.dev, then fall back to registry API
51
+ // Otherwise try DNS at openfused.net, then fall back to registry API
51
52
  const dnsNames = name.includes(".")
52
53
  ? [`_openfuse.${name}`]
53
- : [`_openfuse.${name}.openfused.dev`];
54
+ : [`_openfuse.${name}.openfused.net`];
54
55
  for (const dnsName of dnsNames) {
55
56
  const manifest = await discoverViaDns(dnsName, name);
56
57
  if (manifest)
package/dist/store.d.ts CHANGED
@@ -8,6 +8,7 @@ export interface MeshConfig {
8
8
  peers: PeerConfig[];
9
9
  keyring: KeyringEntry[];
10
10
  trustedKeys?: string[];
11
+ autoTrust?: boolean;
11
12
  }
12
13
  export interface PeerConfig {
13
14
  id: string;
package/dist/store.js CHANGED
@@ -71,12 +71,15 @@ export class ContextStore {
71
71
  await writeFile(destPath, content);
72
72
  }
73
73
  }
74
+ // Workspaces auto-trust: all imported keys are trusted by default.
75
+ // Safe because workspaces are private — you control who joins.
74
76
  const config = {
75
77
  id,
76
78
  name,
77
79
  created: new Date().toISOString(),
78
80
  peers: [],
79
81
  keyring: [],
82
+ autoTrust: true,
80
83
  };
81
84
  await this.writeConfig(config);
82
85
  }
@@ -193,7 +196,13 @@ export class ContextStore {
193
196
  const signed = deserializeSignedMessage(raw);
194
197
  if (signed) {
195
198
  const sigValid = verifyMessage(signed);
196
- const trusted = config.keyring.some((k) => k.trusted && k.signingKey.trim() === signed.publicKey.trim());
199
+ // autoTrust (workspace mode): any key in keyring is trusted, but key must still
200
+ // be present — prevents random internet keys from appearing verified in a workspace
201
+ // that's accidentally exposed to the network.
202
+ const inKeyring = config.keyring.some((k) => k.signingKey.trim() === signed.publicKey.trim());
203
+ const trusted = config.autoTrust
204
+ ? inKeyring
205
+ : config.keyring.some((k) => k.trusted && k.signingKey.trim() === signed.publicKey.trim());
197
206
  const verified = sigValid && trusted;
198
207
  let content;
199
208
  if (signed.encrypted) {
package/dist/sync.js CHANGED
@@ -35,6 +35,9 @@ function parseUrl(url) {
35
35
  if (/[;|`$]/.test(host)) {
36
36
  throw new Error("Invalid SSH URL: host contains shell metacharacters");
37
37
  }
38
+ if (/[;|`$&(){}]/.test(path)) {
39
+ throw new Error("Invalid SSH URL: path contains shell metacharacters");
40
+ }
38
41
  return { type: "ssh", host, path };
39
42
  }
40
43
  throw new Error(`Unknown URL scheme: ${url}. Use http:// or ssh://`);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "openfused",
3
- "version": "0.3.6",
4
- "description": "Decentralized context mesh for AI agents. Encrypted sync, signed messaging, MCP server. The protocol is files.",
3
+ "version": "0.3.9",
4
+ "description": "The file protocol for AI agent context. Encrypted, signed, peer-to-peer.",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "bin": {
@@ -47,7 +47,7 @@
47
47
  "ai",
48
48
  "agent",
49
49
  "context",
50
- "mesh",
50
+ "messaging",
51
51
  "fuse",
52
52
  "decentralized",
53
53
  "openclaw",