rovloom 0.4.0 → 0.5.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.
Files changed (29) hide show
  1. package/README.md +13 -41
  2. package/dist/src/admin/index.js +1 -1
  3. package/dist/src/{chunk-1fyfrgte.js → chunk-0ake7e4r.js} +4 -4
  4. package/dist/src/{chunk-qfyefed3.js → chunk-1bf0wmgk.js} +1 -1
  5. package/dist/src/chunk-5j0gj6w2.js +7 -0
  6. package/dist/src/{chunk-dtj9y82v.js → chunk-5n8csngz.js} +119 -34
  7. package/dist/src/{chunk-v1httsp6.js → chunk-64ftwe9b.js} +2 -2
  8. package/dist/src/{chunk-76wgt2g5.js → chunk-9y36gntb.js} +6 -5
  9. package/dist/src/{chunk-ydmabg5t.js → chunk-9yg6x3gt.js} +5 -5
  10. package/dist/src/{chunk-keg92d31.js → chunk-abd4envz.js} +13 -11
  11. package/dist/src/{chunk-6hxy1fcg.js → chunk-bspzg8er.js} +2 -2
  12. package/dist/src/{chunk-t3pn1435.js → chunk-e7x51y0t.js} +2 -2
  13. package/dist/src/{chunk-qab3m6nh.js → chunk-ebm3kvnq.js} +18 -5
  14. package/dist/src/{chunk-ymsx7hhd.js → chunk-erdq0rn8.js} +8 -8
  15. package/dist/src/{chunk-wdr3sdsm.js → chunk-fnakrk0a.js} +42 -11
  16. package/dist/src/{chunk-bjdqj43d.js → chunk-hpzr94hm.js} +23 -6
  17. package/dist/src/{chunk-fd9n51mc.js → chunk-n073xnr1.js} +51 -22
  18. package/dist/src/{chunk-xmkgq3nh.js → chunk-r0nfthsf.js} +2 -2
  19. package/dist/src/{chunk-z1vhdr3c.js → chunk-rwpynx2j.js} +10 -10
  20. package/dist/src/{chunk-8x6ygvhh.js → chunk-sj24fpz3.js} +4 -4
  21. package/dist/src/{chunk-5vx1b9z8.js → chunk-xhq21g24.js} +3 -3
  22. package/dist/src/{chunk-4af38z2b.js → chunk-ybte82d3.js} +1 -1
  23. package/dist/src/{chunk-khmgp03q.js → chunk-ympzv86c.js} +65 -13
  24. package/dist/src/{chunk-se5daacy.js → chunk-z7kkfrgz.js} +1 -1
  25. package/dist/src/cli/index.js +12 -12
  26. package/dist/src/cli/main.js +9 -9
  27. package/dist/src/mcp/index.js +2 -2
  28. package/dist/src/webui/index.js +13 -3
  29. package/package.json +1 -1
@@ -1,14 +1,14 @@
1
1
  // @bun
2
2
  import {
3
3
  resolveRoleConfigPath2
4
- } from "./chunk-qfyefed3.js";
4
+ } from "./chunk-1bf0wmgk.js";
5
5
  import {
6
6
  CliError2,
7
7
  parseConfig2,
8
8
  configDocument2,
9
9
  configTemplate2,
10
10
  readConfig2
11
- } from "./chunk-bjdqj43d.js";
11
+ } from "./chunk-hpzr94hm.js";
12
12
  import {
13
13
  ensurePrivateDirectory
14
14
  } from "./chunk-0y5542k8.js";
@@ -19,7 +19,7 @@ import {
19
19
  } from "./chunk-7crhmqn2.js";
20
20
  import {
21
21
  PRODUCT_VERSION2
22
- } from "./chunk-xmkgq3nh.js";
22
+ } from "./chunk-r0nfthsf.js";
23
23
  import {
24
24
  canonicalLoopbackHost
25
25
  } from "./chunk-6n9s7nfe.js";
@@ -539,13 +539,14 @@ function createHttpFacade2(options) {
539
539
  return denied(503);
540
540
  }
541
541
  const host = request.headers.get("host");
542
- const loopback = url.origin === origin.origin && host === origin.host;
542
+ const lanOrigin = options.lan === true && host !== null && Buffer.byteLength(host) <= 2048 && url.protocol === "http:" && host.toLowerCase() !== origin.host.toLowerCase() && host.toLowerCase() !== publicUrl?.host.toLowerCase() ? "http://" + host.toLowerCase() : undefined;
543
+ const loopback = url.origin === origin.origin && host !== null && host.toLowerCase() === origin.host.toLowerCase();
543
544
  const proxied = publicUrl !== undefined && host === publicUrl.host && url.host === publicUrl.host;
544
- if (!loopback && !proxied || url.pathname !== "/mcp" || url.search || url.hash) {
545
+ if (!loopback && !proxied && lanOrigin === undefined || url.pathname !== "/mcp" || url.search || url.hash) {
545
546
  return denied(403);
546
547
  }
547
548
  const requestOrigin = request.headers.get("origin");
548
- if (requestOrigin !== null && !allowedOrigins.has(requestOrigin)) {
549
+ if (requestOrigin !== null && !allowedOrigins.has(requestOrigin) && requestOrigin !== lanOrigin) {
549
550
  return denied(403);
550
551
  }
551
552
  if (!["GET", "POST", "DELETE"].includes(request.method)) {
@@ -763,4 +764,4 @@ function startHttpFacade2(options) {
763
764
 
764
765
  export { createMcpFacade2, HTTP_BODY_BYTES2, createHttpFacade2, startHttpFacade2 };
765
766
 
766
- //# debugId=70BAA7C73CB4FDA064756E2164756E21
767
+ //# debugId=7CD2FDC41059ADFA64756E2164756E21
@@ -3,11 +3,11 @@ import {
3
3
  writeAdminFiles2,
4
4
  managementSourceExists2,
5
5
  handleAdminCommand2
6
- } from "./chunk-wdr3sdsm.js";
7
- import"./chunk-qab3m6nh.js";
8
- import"./chunk-qfyefed3.js";
9
- import"./chunk-se5daacy.js";
10
- import"./chunk-bjdqj43d.js";
6
+ } from "./chunk-fnakrk0a.js";
7
+ import"./chunk-ebm3kvnq.js";
8
+ import"./chunk-1bf0wmgk.js";
9
+ import"./chunk-z7kkfrgz.js";
10
+ import"./chunk-hpzr94hm.js";
11
11
  import"./chunk-3nnahj0j.js";
12
12
  import"./chunk-0y5542k8.js";
13
13
  import"./chunk-g7pnjzkk.js";
@@ -1,13 +1,13 @@
1
1
  // @bun
2
2
  import {
3
3
  readRuntimeConfig2
4
- } from "./chunk-6hxy1fcg.js";
4
+ } from "./chunk-bspzg8er.js";
5
5
  import {
6
6
  readOrCreateRoleConfig
7
- } from "./chunk-v1httsp6.js";
7
+ } from "./chunk-64ftwe9b.js";
8
8
  import {
9
9
  resolveRoleConfigPath2
10
- } from "./chunk-qfyefed3.js";
10
+ } from "./chunk-1bf0wmgk.js";
11
11
  import {
12
12
  CLI_ERROR_CODES,
13
13
  CliError2,
@@ -15,10 +15,10 @@ import {
15
15
  configDocument2,
16
16
  configTemplate2,
17
17
  readConfig2
18
- } from "./chunk-bjdqj43d.js";
18
+ } from "./chunk-hpzr94hm.js";
19
19
  import {
20
20
  PRODUCT_VERSION2
21
- } from "./chunk-xmkgq3nh.js";
21
+ } from "./chunk-r0nfthsf.js";
22
22
  import {
23
23
  isWildcardHostname
24
24
  } from "./chunk-6n9s7nfe.js";
@@ -85,6 +85,7 @@ var HELP2 = `Rovloom ${PRODUCT_VERSION2}
85
85
  rovloom admin --help
86
86
 
87
87
  gateway / connector \u542F\u52A8\u5BF9\u5E94\u89D2\u8272\u3002\u9996\u6B21\u8FD0\u884C\u65F6\u5728\u771F\u5B9E\u672C\u5730\u7EC8\u7AEF\u5B8C\u6210\u4E00\u6B21\u6027\u914D\u5BF9\u4E0E\u539F\u751F\u5B89\u88C5\u6279\u51C6\uFF1B
88
+ \u5728\u7EC8\u7AEF\u62D2\u7EDD\u914D\u5BF9\u63D0\u793A\u65F6\uFF0CGateway \u4FDD\u6301\u672A\u914D\u5BF9\u8FD0\u884C\uFF0C\u53EF\u5148\u8FD0\u884C rovloom admin create \u518D\u4ECE\u7BA1\u7406\u9875\u5B8C\u6210\u9996\u53F0\u914D\u5BF9\uFF1B
88
89
  --add-device \u5728\u5DF2\u5B8C\u6210\u7684\u5F15\u5BFC\u4E4B\u4E0A\u518D\u914D\u5BF9\u4E00\u53F0 Connector\uFF08\u6CBF\u7528\u540C\u4E00 MCP \u51ED\u636E\uFF0C\u6388\u6743\u968F\u4E4B\u6269\u5927\u5230\u65B0\u8BBE\u5907\uFF09\uFF1B
89
90
  --repair-device / --repair \u91CD\u65B0\u914D\u5BF9\u5DF2\u914D\u5BF9\u7684\u540C\u4E00\u8BBE\u5907\uFF08\u51ED\u636E\u4E22\u5931\u6216\u6CC4\u6F0F\uFF09\uFF0C\u4FDD\u7559\u539F\u751F\u8BBE\u7F6E\u4E0E MCP \u6388\u6743\u3002
90
91
  --claim \u8BA9\u672A\u914D\u5BF9\u7684 Connector \u5411\u8FD0\u884C\u4E2D\u7684 Gateway \u5728\u7EBF\u8BA4\u9886\u7BA1\u7406\u5458\u521B\u5EFA\u7684\u914D\u5BF9\u7533\u8BF7\uFF08\u7BA1\u7406\u9875\u6838\u5BF9\u7801\u6279\u51C6\uFF0CGateway \u4E0D\u505C\u673A\uFF09\u3002
@@ -211,19 +212,19 @@ async function runCli2(args, io, runtime = {}, environment) {
211
212
  throw new CliError2("invalid_arguments");
212
213
  }
213
214
  if (args[0] === "admin") {
214
- const { handleAdminCommand } = await import("./chunk-ydmabg5t.js");
215
+ const { handleAdminCommand } = await import("./chunk-9yg6x3gt.js");
215
216
  return await handleAdminCommand(args, io, environment);
216
217
  }
217
218
  if (args[0] === "doctor" || args[0] === "storage") {
218
- const { handleStorageCommand } = await import("./chunk-1fyfrgte.js");
219
+ const { handleStorageCommand } = await import("./chunk-0ake7e4r.js");
219
220
  return await handleStorageCommand(args, io, environment);
220
221
  }
221
222
  if (args[0] === "token") {
222
- const { handleTokenCommand } = await import("./chunk-8x6ygvhh.js");
223
+ const { handleTokenCommand } = await import("./chunk-sj24fpz3.js");
223
224
  return await handleTokenCommand(args, io, environment);
224
225
  }
225
226
  if (args[0] === "config" && args[1] === "init") {
226
- const { initializeRoleConfig } = await import("./chunk-5vx1b9z8.js");
227
+ const { initializeRoleConfig } = await import("./chunk-xhq21g24.js");
227
228
  initializeRoleConfig(args, environment);
228
229
  io.stderr.write(`config_ready
229
230
  `);
@@ -313,13 +314,14 @@ async function runCli2(args, io, runtime = {}, environment) {
313
314
  io.stderr.write(WILDCARD_LISTEN_WARNING);
314
315
  }
315
316
  try {
316
- const { startHttpFacade } = await import("./chunk-4af38z2b.js");
317
+ const { startHttpFacade } = await import("./chunk-ybte82d3.js");
317
318
  const http = startHttpFacade({
318
319
  service: gateway.service,
319
320
  authentication: gateway.authentication,
320
321
  hostname: config.mcp_hostname,
321
322
  port: config.mcp_port,
322
323
  ...config.mcp_public_url ? { publicUrl: config.mcp_public_url } : {},
324
+ ...config.mcp_lan ? { lan: true } : {},
323
325
  diagnostic: (code) => io.stderr.write(code + `
324
326
  `)
325
327
  });
@@ -374,4 +376,4 @@ Gateway \u5DF2\u542F\u52A8\uFF1B\u4F7F\u7528 Agent \u524D\u4ECD\u9700\u5B8C\u621
374
376
 
375
377
  export { HELP2, parseCommand2, runCli2 };
376
378
 
377
- //# debugId=D32F2D6B4ECB1A3C64756E2164756E21
379
+ //# debugId=EDE27C0F1768E16864756E2164756E21
@@ -8,10 +8,10 @@ import {
8
8
  import {
9
9
  runtimeReference,
10
10
  readRuntimeJson
11
- } from "./chunk-se5daacy.js";
11
+ } from "./chunk-z7kkfrgz.js";
12
12
  import {
13
13
  CliError2
14
- } from "./chunk-bjdqj43d.js";
14
+ } from "./chunk-hpzr94hm.js";
15
15
 
16
16
  // src/cli/runtime-config.ts
17
17
  function providers(config) {
@@ -69,10 +69,10 @@ import {
69
69
  } from "./chunk-2tn0r64b.js";
70
70
  import {
71
71
  readRuntimeFile
72
- } from "./chunk-se5daacy.js";
72
+ } from "./chunk-z7kkfrgz.js";
73
73
  import {
74
74
  CliError2
75
- } from "./chunk-bjdqj43d.js";
75
+ } from "./chunk-hpzr94hm.js";
76
76
  import"./chunk-vwcntax3.js";
77
77
  import"./chunk-gbsbwssz.js";
78
78
  import"./chunk-3nnahj0j.js";
@@ -6,12 +6,15 @@ import {
6
6
  boundedJson2,
7
7
  validatePolicies2
8
8
  } from "./chunk-qt9m2kg2.js";
9
+ import {
10
+ DEFAULT_PAIRING_POLICY_REF
11
+ } from "./chunk-5j0gj6w2.js";
9
12
  import {
10
13
  readRuntimeJson
11
- } from "./chunk-se5daacy.js";
14
+ } from "./chunk-z7kkfrgz.js";
12
15
  import {
13
16
  CliError2
14
- } from "./chunk-bjdqj43d.js";
17
+ } from "./chunk-hpzr94hm.js";
15
18
  import {
16
19
  privatePath,
17
20
  readPrivateBytes
@@ -255,7 +258,13 @@ var DEFAULT_ADMIN_TTL_DAYS = 30;
255
258
  var DAY2 = 86400000;
256
259
  var PRINCIPAL2 = /^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$/;
257
260
  function emptyManagement(port) {
258
- return { schema_version: 1, kind: "management-session-source", port, sessions: [], pairing_policy_refs: [] };
261
+ return {
262
+ schema_version: 1,
263
+ kind: "management-session-source",
264
+ port,
265
+ sessions: [],
266
+ pairing_policy_refs: [DEFAULT_PAIRING_POLICY_REF]
267
+ };
259
268
  }
260
269
  function isAdminPlaceholder(entry) {
261
270
  return entry.principal.policy.revision === ADMIN_POLICY_REVISION && entry.principal.policy.grants.length === 0;
@@ -309,7 +318,11 @@ function issueAdmin(callers, management, principal, now, days) {
309
318
  placeholder
310
319
  ]
311
320
  },
312
- management: { ...management, sessions: [...others, session] },
321
+ management: {
322
+ ...management,
323
+ sessions: [...others, session],
324
+ pairing_policy_refs: management.pairing_policy_refs.length ? management.pairing_policy_refs : [DEFAULT_PAIRING_POLICY_REF]
325
+ },
313
326
  secret,
314
327
  expires_at
315
328
  };
@@ -340,4 +353,4 @@ function summarizeAdmins(management, now) {
340
353
 
341
354
  export { setupFileStamp, writeSetupFile, readSetupJson, writeSetupJson, REGISTRY_MAX_BYTES, parseRegistry, createCaller, setDiscardPermission, renewCaller, rotateCaller, revokeCaller, summarize, DEFAULT_ADMIN_TTL_DAYS, emptyManagement, isAdminPlaceholder, issueAdmin, revokeAdmin, summarizeAdmins };
342
355
 
343
- //# debugId=AF7C6D3D6A23BCC764756E2164756E21
356
+ //# debugId=3023B85F5DE2326664756E2164756E21
@@ -21,7 +21,7 @@ import {
21
21
  observedHerdrSource
22
22
  } from "./chunk-9tt13dm0.js";
23
23
  import"./chunk-g7pnjzkk.js";
24
- import"./chunk-wdr3sdsm.js";
24
+ import"./chunk-fnakrk0a.js";
25
25
  import"./chunk-mqyq5jh6.js";
26
26
  import"./chunk-zj48jvfe.js";
27
27
  import {
@@ -30,7 +30,7 @@ import {
30
30
  setupReference,
31
31
  setupSessionsFor,
32
32
  GatewaySetup
33
- } from "./chunk-fd9n51mc.js";
33
+ } from "./chunk-n073xnr1.js";
34
34
  import {
35
35
  compileHerdrSchemas2
36
36
  } from "./chunk-5h82060k.js";
@@ -72,17 +72,17 @@ import {
72
72
  writeSetupFile,
73
73
  readSetupJson,
74
74
  writeSetupJson
75
- } from "./chunk-qab3m6nh.js";
75
+ } from "./chunk-ebm3kvnq.js";
76
76
  import {
77
77
  readRuntimeConfig2
78
- } from "./chunk-6hxy1fcg.js";
78
+ } from "./chunk-bspzg8er.js";
79
79
  import {
80
80
  privateDirectory
81
- } from "./chunk-v1httsp6.js";
82
- import"./chunk-qfyefed3.js";
81
+ } from "./chunk-64ftwe9b.js";
82
+ import"./chunk-1bf0wmgk.js";
83
83
  import {
84
84
  runtimeReference
85
- } from "./chunk-se5daacy.js";
85
+ } from "./chunk-z7kkfrgz.js";
86
86
  import {
87
87
  herdrMode,
88
88
  luvusMode,
@@ -92,7 +92,7 @@ import {
92
92
  parseConfig2,
93
93
  configDocument2,
94
94
  readConfig2
95
- } from "./chunk-bjdqj43d.js";
95
+ } from "./chunk-hpzr94hm.js";
96
96
  import {
97
97
  createFileCredentialSink2,
98
98
  loadCredential2
@@ -15,19 +15,22 @@ import {
15
15
  issueAdmin,
16
16
  revokeAdmin,
17
17
  summarizeAdmins
18
- } from "./chunk-qab3m6nh.js";
18
+ } from "./chunk-ebm3kvnq.js";
19
19
  import {
20
20
  resolveRoleConfigPath2
21
- } from "./chunk-qfyefed3.js";
21
+ } from "./chunk-1bf0wmgk.js";
22
22
  import {
23
23
  runtimeReference,
24
24
  readRuntimeJson
25
- } from "./chunk-se5daacy.js";
25
+ } from "./chunk-z7kkfrgz.js";
26
26
  import {
27
27
  CLI_ERROR_CODES,
28
28
  CliError2,
29
29
  readConfig2
30
- } from "./chunk-bjdqj43d.js";
30
+ } from "./chunk-hpzr94hm.js";
31
+ import {
32
+ canonicalLoopbackHost
33
+ } from "./chunk-6n9s7nfe.js";
31
34
 
32
35
  // src/cli/admin-command.ts
33
36
  var ADMIN_HELP = `\u7528\u6CD5\uFF1A
@@ -39,7 +42,8 @@ var ADMIN_HELP = `\u7528\u6CD5\uFF1A
39
42
  \u53E3\u4EE4\u539F\u503C\u53EA\u5728 create \u65F6\u5199\u5230 stdout \u4E00\u6B21\uFF08Gateway \u53EA\u4FDD\u5B58 SHA-256 \u6458\u8981\uFF09\uFF1B\u5176\u4F59\u4FE1\u606F\u5199\u5230 stderr\u3002\u4E22\u5931\u53E3\u4EE4\u5C31\u518D create \u4E00\u6B21\uFF1A
40
43
  \u540C\u540D\u7BA1\u7406\u5458\u88AB\u91CD\u65B0\u7B7E\u53D1\uFF0C\u65E7\u53E3\u4EE4\u4E0E\u5DF2\u767B\u5F55\u7684\u6D4F\u89C8\u5668\u4F1A\u8BDD\u7ACB\u5373\u5931\u6548\u3002revoke \u5220\u9664\u7BA1\u7406\u5458\uFF0C\u540C\u6837\u7ACB\u5373\u751F\u6548\u3002\u4FEE\u6539\u65E0\u9700\u91CD\u542F Gateway\u3002
41
44
  \u7BA1\u7406\u5458\u4E0D\u80FD\u8C03\u7528 MCP\uFF0C\u4E5F\u4E0E MCP \u4EE4\u724C\u3001\u8BBE\u5907\u51ED\u636E\u4E92\u4E0D\u901A\u7528\uFF1B\u6709\u6548\u671F\u9ED8\u8BA4 ${DEFAULT_ADMIN_TTL_DAYS} \u5929\uFF081-365\uFF09\u3002
42
- \u9700\u8981\u5148\u5B8C\u6210 Gateway \u9996\u6B21\u914D\u5BF9\uFF08\u6B64\u65F6\u624D\u5B58\u5728 MCP \u8C03\u7528\u65B9\u6CE8\u518C\u8868\uFF09\u3002
45
+ \u53EF\u5728\u9996\u6B21\u914D\u5BF9\u524D\u521B\u5EFA\uFF1A\u5168\u65B0 Gateway \u4F1A\u81EA\u884C\u521D\u59CB\u5316\u7A7A\u7684 MCP \u8C03\u7528\u65B9\u6CE8\u518C\u8868\uFF0C\u968F\u540E\u5373\u53EF\u5728\u7BA1\u7406\u9875
46
+ \u5728\u7EBF\u914D\u5BF9\u9996\u53F0 Connector\uFF08\u65B0\u5EFA\u7533\u8BF7\uFF0C\u8BBE\u5907\u8FD0\u884C rovloom connector --claim\uFF09\u3002
43
47
  `;
44
48
  function parse(args) {
45
49
  const sub = args[1];
@@ -87,16 +91,43 @@ function loadManagement(path, port) {
87
91
  }
88
92
  return { file: value, exists: true };
89
93
  }
94
+ function callerResource(config) {
95
+ const hostname = canonicalLoopbackHost(config.mcp_hostname);
96
+ return new URL("http://" + hostname + ":" + config.mcp_port + "/mcp").href;
97
+ }
98
+ function emptyCallerRegistry(resource) {
99
+ return {
100
+ schema_version: 1,
101
+ kind: "mcp-caller-source",
102
+ resource,
103
+ local_policy: { revision: "rovloom_unpaired", grants: [] },
104
+ callers: []
105
+ };
106
+ }
107
+ function callersStamp(path) {
108
+ try {
109
+ return setupFileStamp(path);
110
+ } catch (error) {
111
+ if (error.code === "ENOENT") {
112
+ return;
113
+ }
114
+ throw error;
115
+ }
116
+ }
90
117
  function writeAdminFiles2(config, principal, at, days) {
91
118
  const callersPath = runtimeReference(config.state_dir, "mcp-callers");
92
119
  const managementPath = runtimeReference(config.state_dir, "management");
93
- const callersStamp = setupFileStamp(callersPath);
94
- const callers = parseRegistry(readRuntimeJson(callersPath, REGISTRY_MAX_BYTES));
120
+ const stamp = callersStamp(callersPath);
121
+ const callers = parseRegistry(readSetupJson(callersPath, REGISTRY_MAX_BYTES) ?? emptyCallerRegistry(callerResource(config)));
95
122
  const { file, exists } = loadManagement(managementPath, config.management_port);
96
- const stamp = exists ? setupFileStamp(managementPath) : undefined;
123
+ const managementStamp = exists ? setupFileStamp(managementPath) : undefined;
97
124
  const issued = issueAdmin(callers, file, principal, at, days);
98
- writeSetupFile(callersPath, boundedJson2(issued.callers, REGISTRY_MAX_BYTES), true, callersStamp);
99
- writeSetupFile(managementPath, boundedJson2(issued.management, 65536), exists, stamp);
125
+ if (stamp === undefined) {
126
+ writeSetupFile(callersPath, boundedJson2(issued.callers, REGISTRY_MAX_BYTES), false);
127
+ } else {
128
+ writeSetupFile(callersPath, boundedJson2(issued.callers, REGISTRY_MAX_BYTES), true, stamp);
129
+ }
130
+ writeSetupFile(managementPath, boundedJson2(issued.management, 65536), exists, managementStamp);
100
131
  return { secret: issued.secret, expires_at: issued.expires_at };
101
132
  }
102
133
  function managementSourceExists2(config) {
@@ -157,4 +188,4 @@ login at http://127.0.0.1:` + config.management_port + '/ with user "' + princip
157
188
 
158
189
  export { writeAdminFiles2, managementSourceExists2, handleAdminCommand2 };
159
190
 
160
- //# debugId=DF62A5BEF1087BFE64756E2164756E21
191
+ //# debugId=B65D75D1FF47247C64756E2164756E21
@@ -5,6 +5,9 @@ import {
5
5
  import {
6
6
  parseNativeJson2
7
7
  } from "./chunk-7crhmqn2.js";
8
+ import {
9
+ isWildcardHostname
10
+ } from "./chunk-6n9s7nfe.js";
8
11
  import {
9
12
  binDirectories
10
13
  } from "./chunk-3nnahj0j.js";
@@ -107,10 +110,14 @@ function parseConfig2(value, platform = process.platform) {
107
110
  if (!hosts.includes(row.hostname)) {
108
111
  return fail();
109
112
  }
113
+ if (row.lan !== undefined && row.lan !== true) {
114
+ return fail();
115
+ }
110
116
  return {
111
117
  hostname: row.hostname,
112
118
  port: port(row.port),
113
- public_url: row.public_url
119
+ public_url: row.public_url,
120
+ ...row.lan === true ? { lan: true } : {}
114
121
  };
115
122
  };
116
123
  if (input.schema_version !== 1 || !["gateway", "connector"].includes(input.role)) {
@@ -122,12 +129,15 @@ function parseConfig2(value, platform = process.platform) {
122
129
  }
123
130
  if (input.role === "gateway") {
124
131
  exact(input, ["schema_version", "role", "data", "mcp", "devices", "management"]);
125
- const mcp = listener(input.mcp, ["public_url"]);
132
+ const mcp = listener(input.mcp, ["public_url", "lan"]);
126
133
  if (mcp.public_url !== undefined && !publicMcpUrl(mcp.public_url)) {
127
134
  return fail();
128
135
  }
136
+ if (mcp.lan !== undefined && (mcp.lan !== true || !isWildcardHostname(mcp.hostname))) {
137
+ return fail();
138
+ }
129
139
  const devices = listener(input.devices);
130
- const management = exact(input.management, ["enabled", "port"], ["hostname"]);
140
+ const management = exact(input.management, ["enabled", "port"], ["hostname", "lan"]);
131
141
  if (typeof management.enabled !== "boolean") {
132
142
  return fail();
133
143
  }
@@ -136,6 +146,9 @@ function parseConfig2(value, platform = process.platform) {
136
146
  }
137
147
  const managementHostname = management.hostname ?? "127.0.0.1";
138
148
  const managementPort = port(management.port);
149
+ if (management.lan !== undefined && (management.lan !== true || managementHostname !== "0.0.0.0")) {
150
+ return fail();
151
+ }
139
152
  if (new Set([mcp.port, devices.port, ...management.enabled ? [managementPort] : []]).size !== (management.enabled ? 3 : 2)) {
140
153
  return fail();
141
154
  }
@@ -147,11 +160,13 @@ function parseConfig2(value, platform = process.platform) {
147
160
  mcp_hostname: mcp.hostname,
148
161
  mcp_port: mcp.port,
149
162
  ...mcp.public_url !== undefined ? { mcp_public_url: mcp.public_url } : {},
163
+ ...mcp.lan === true ? { mcp_lan: true } : {},
150
164
  device_hostname: devices.hostname,
151
165
  device_port: devices.port,
152
166
  management_enabled: management.enabled,
153
167
  management_hostname: managementHostname,
154
168
  management_port: managementPort,
169
+ ...management.lan === true ? { management_lan: true } : {},
155
170
  authentication_ref: "mcp-callers"
156
171
  });
157
172
  }
@@ -219,13 +234,15 @@ function configDocument2(config) {
219
234
  mcp: {
220
235
  hostname: config.mcp_hostname,
221
236
  port: config.mcp_port,
222
- ...config.mcp_public_url !== undefined ? { public_url: config.mcp_public_url } : {}
237
+ ...config.mcp_public_url !== undefined ? { public_url: config.mcp_public_url } : {},
238
+ ...config.mcp_lan === true ? { lan: true } : {}
223
239
  },
224
240
  devices: { hostname: config.device_hostname, port: config.device_port },
225
241
  management: {
226
242
  enabled: config.management_enabled,
227
243
  ...config.management_hostname !== "127.0.0.1" ? { hostname: config.management_hostname } : {},
228
- port: config.management_port
244
+ port: config.management_port,
245
+ ...config.management_lan === true ? { lan: true } : {}
229
246
  }
230
247
  } : {
231
248
  ...common,
@@ -286,4 +303,4 @@ function readConfig2(path) {
286
303
 
287
304
  export { herdrMode, luvusMode, selectedNativeProviders, CLI_ERROR_CODES, CliError2, CliCancelled, parseConfig2, configDocument2, configTemplate2, readConfig2 };
288
305
 
289
- //# debugId=8E2FBD65A09D61EC64756E2164756E21
306
+ //# debugId=75790FE78402A30364756E2164756E21
@@ -33,27 +33,28 @@ import {
33
33
  import {
34
34
  writeAdminFiles2,
35
35
  managementSourceExists2
36
- } from "./chunk-wdr3sdsm.js";
36
+ } from "./chunk-fnakrk0a.js";
37
37
  import {
38
38
  setupFileStamp,
39
39
  writeSetupFile,
40
40
  readSetupJson,
41
41
  writeSetupJson,
42
42
  REGISTRY_MAX_BYTES,
43
- parseRegistry
44
- } from "./chunk-qab3m6nh.js";
43
+ parseRegistry,
44
+ isAdminPlaceholder
45
+ } from "./chunk-ebm3kvnq.js";
45
46
  import {
46
47
  readRuntimeConfig2
47
- } from "./chunk-6hxy1fcg.js";
48
+ } from "./chunk-bspzg8er.js";
48
49
  import {
49
50
  runtimeReference,
50
51
  readRuntimeFile,
51
52
  readRuntimeJson
52
- } from "./chunk-se5daacy.js";
53
+ } from "./chunk-z7kkfrgz.js";
53
54
  import {
54
55
  luvusMode,
55
56
  CliError2
56
- } from "./chunk-bjdqj43d.js";
57
+ } from "./chunk-hpzr94hm.js";
57
58
  import {
58
59
  canonicalLoopbackHost
59
60
  } from "./chunk-6n9s7nfe.js";
@@ -613,7 +614,7 @@ class SetupApproval {
613
614
  return { plan: previous };
614
615
  }
615
616
  if (!await this.terminal.confirm("Pair one Connector with this Gateway? / \u5141\u8BB8\u914D\u5BF9\u4E00\u4E2A Connector\uFF1F")) {
616
- throw new CliError2("configuration_required");
617
+ return { declined: true };
617
618
  }
618
619
  const now = Date.now();
619
620
  const attempt = randomUUID();
@@ -820,6 +821,34 @@ function unionGrants(existing, added) {
820
821
  }
821
822
  return merged;
822
823
  }
824
+ function publishFirstCallers(path, resource, authorization, caller) {
825
+ const previous = readSetupJson(path, REGISTRY_MAX_BYTES);
826
+ const created = {
827
+ schema_version: 1,
828
+ kind: "mcp-caller-source",
829
+ resource,
830
+ local_policy: authorization.policies.local,
831
+ callers: [caller]
832
+ };
833
+ if (previous === undefined) {
834
+ parseRegistry(JSON.parse(boundedJson2(created, REGISTRY_MAX_BYTES)));
835
+ writeSetupFile(path, boundedJson2(created, REGISTRY_MAX_BYTES), false);
836
+ return;
837
+ }
838
+ const registry = parseRegistry(previous, resource);
839
+ const kept = registry.callers.filter((entry) => isAdminPlaceholder(entry) || boundedJson2(entry, REGISTRY_MAX_BYTES) === boundedJson2(caller, REGISTRY_MAX_BYTES));
840
+ if (kept.length !== registry.callers.length) {
841
+ throw new CliError2("configuration_required");
842
+ }
843
+ const callers = [...kept];
844
+ if (!callers.some((entry) => boundedJson2(entry, REGISTRY_MAX_BYTES) === boundedJson2(caller, REGISTRY_MAX_BYTES))) {
845
+ callers.push(caller);
846
+ }
847
+ const merged = { ...created, callers };
848
+ parseRegistry(JSON.parse(boundedJson2(merged, REGISTRY_MAX_BYTES)), resource);
849
+ const stamp = setupFileStamp(path);
850
+ writeSetupFile(path, boundedJson2(merged, REGISTRY_MAX_BYTES), true, stamp);
851
+ }
823
852
 
824
853
  class GatewaySetup {
825
854
  config;
@@ -871,6 +900,14 @@ Stop that Connector, then run rovloom connector --repair on its machine and ente
871
900
  Connector endpoint: ` + gateway.transport.url.replace(/\/connector$/, "") + `
872
901
  `);
873
902
  const issued = await this.approval.issue();
903
+ if (issued.declined) {
904
+ const page = this.config.management_enabled ? "http://127.0.0.1:" + this.config.management_port + "/" : "";
905
+ this.terminal.show(`Gateway stays unpaired and running; no enrollment or credential is issued. / Gateway \u4FDD\u6301\u672A\u914D\u5BF9\u5E76\u7EE7\u7EED\u8FD0\u884C\uFF0C\u4E0D\u7B7E\u53D1\u51ED\u636E\u3002
906
+ ` + (page ? "Finish first pairing from the management page: create the administrator with `rovloom admin create`, sign in at " + page + ", create a pairing application, then run `rovloom connector --claim` on the device. / \u5728\u7BA1\u7406\u9875\u5B8C\u6210\u9996\u6B21\u914D\u5BF9\uFF1A\u5148\u7528 `rovloom admin create` \u521B\u5EFA\u7BA1\u7406\u5458\uFF0C\u767B\u5F55 " + page + " \u65B0\u5EFA\u914D\u5BF9\u7533\u8BF7\uFF0C\u518D\u5728\u8BBE\u5907\u4E0A\u8FD0\u884C `rovloom connector --claim`\u3002\n" : `Management is disabled; enable it or rerun to pair from this terminal. / \u7BA1\u7406\u9875\u672A\u542F\u7528\uFF1B\u8BF7\u542F\u7528\u540E\u91CD\u8BD5\u6216\u5728\u672C\u7EC8\u7AEF\u5B8C\u6210\u914D\u5BF9\u3002
907
+ `));
908
+ this.terminal.finishQuestions();
909
+ return;
910
+ }
874
911
  if (issued.code) {
875
912
  this.terminal.show(`One-time pairing code (5 minutes; keep private) / \u4E00\u6B21\u6027\u914D\u5BF9\u7801\uFF085\u5206\u949F\uFF0C\u8BF7\u4FDD\u5BC6\uFF09:
876
913
  ` + issued.code + `
@@ -978,19 +1015,11 @@ Run rovloom connector in another local terminal and enter the Gateway address an
978
1015
  value: entry.value
979
1016
  }));
980
1017
  if (!additional) {
981
- publish(callersPath, {
982
- schema_version: 1,
983
- kind: "mcp-caller-source",
984
- resource,
985
- local_policy: authorization.policies.local,
986
- callers: [
987
- {
988
- principal: { id: authorization.principal_id, policy: authorization.policies.caller },
989
- token_sha256: createHash3("sha256").update(client.token).digest("hex"),
990
- issued_at: client.issued_at,
991
- expires_at: client.expires_at
992
- }
993
- ]
1018
+ publishFirstCallers(callersPath, resource, authorization, {
1019
+ principal: { id: authorization.principal_id, policy: authorization.policies.caller },
1020
+ token_sha256: createHash3("sha256").update(client.token).digest("hex"),
1021
+ issued_at: client.issued_at,
1022
+ expires_at: client.expires_at
994
1023
  });
995
1024
  publish(providersPath, { schema_version: 1, role: "gateway", providers: reviewedEntries }, 1048576);
996
1025
  } else {
@@ -1083,6 +1112,6 @@ function mergeSetupProviders(path, entries) {
1083
1112
  writeSetupFile(path, boundedJson2({ ...document, providers: merged }, 1048576), true, stamp);
1084
1113
  }
1085
1114
 
1086
- export { setupSessions, setupTarget, setupProviderKinds, selectedSetupPolicies, setupReference, setupSessionsFor, setupReply, requestJson, device, reviewSetupManifest, publishSetupSchemas, publish, GatewaySetup, mergeSetupCallers, mergeSetupProviders };
1115
+ export { setupSessions, setupTarget, setupProviderKinds, selectedSetupPolicies, setupReference, setupSessionsFor, setupReply, requestJson, device, reviewSetupManifest, publishSetupSchemas, publish, publishFirstCallers, GatewaySetup, mergeSetupCallers, mergeSetupProviders };
1087
1116
 
1088
- //# debugId=0617AAABC9378C6D64756E2164756E21
1117
+ //# debugId=3920190CFC3283A264756E2164756E21
@@ -1,8 +1,8 @@
1
1
  // @bun
2
2
  // src/mcp/version.ts
3
3
  var MCP_REVISION2 = "2025-11-25";
4
- var PRODUCT_VERSION2 = "0.4.0";
4
+ var PRODUCT_VERSION2 = "0.5.0";
5
5
 
6
6
  export { MCP_REVISION2, PRODUCT_VERSION2 };
7
7
 
8
- //# debugId=37FCDB7BED42DE7D64756E2164756E21
8
+ //# debugId=1479A7639E360A6A64756E2164756E21
@@ -1,19 +1,19 @@
1
1
  // @bun
2
2
  import {
3
3
  createProductionCliRuntime2
4
- } from "./chunk-dtj9y82v.js";
5
- import"./chunk-fd9n51mc.js";
6
- import"./chunk-wdr3sdsm.js";
7
- import"./chunk-qab3m6nh.js";
4
+ } from "./chunk-5n8csngz.js";
5
+ import"./chunk-n073xnr1.js";
6
+ import"./chunk-fnakrk0a.js";
7
+ import"./chunk-ebm3kvnq.js";
8
8
  import"./chunk-2tn0r64b.js";
9
- import"./chunk-khmgp03q.js";
9
+ import"./chunk-ympzv86c.js";
10
10
  import"./chunk-7k9g0x5e.js";
11
11
  import"./chunk-smpevv7n.js";
12
- import"./chunk-6hxy1fcg.js";
13
- import"./chunk-v1httsp6.js";
14
- import"./chunk-qfyefed3.js";
15
- import"./chunk-se5daacy.js";
16
- import"./chunk-bjdqj43d.js";
12
+ import"./chunk-bspzg8er.js";
13
+ import"./chunk-64ftwe9b.js";
14
+ import"./chunk-1bf0wmgk.js";
15
+ import"./chunk-z7kkfrgz.js";
16
+ import"./chunk-hpzr94hm.js";
17
17
  import"./chunk-4etdq0cp.js";
18
18
  import"./chunk-5s2emvww.js";
19
19
  import"./chunk-d4ejrtjq.js";
@@ -18,19 +18,19 @@ import {
18
18
  revokeCaller,
19
19
  summarize,
20
20
  isAdminPlaceholder
21
- } from "./chunk-qab3m6nh.js";
21
+ } from "./chunk-ebm3kvnq.js";
22
22
  import {
23
23
  resolveRoleConfigPath2
24
- } from "./chunk-qfyefed3.js";
24
+ } from "./chunk-1bf0wmgk.js";
25
25
  import {
26
26
  runtimeReference,
27
27
  readRuntimeJson
28
- } from "./chunk-se5daacy.js";
28
+ } from "./chunk-z7kkfrgz.js";
29
29
  import {
30
30
  CLI_ERROR_CODES,
31
31
  CliError2,
32
32
  readConfig2
33
- } from "./chunk-bjdqj43d.js";
33
+ } from "./chunk-hpzr94hm.js";
34
34
  import"./chunk-3nnahj0j.js";
35
35
  import"./chunk-0y5542k8.js";
36
36