rovloom 0.5.0 → 0.6.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.
Files changed (64) hide show
  1. package/README.md +9 -1
  2. package/dist/src/admin/index.js +1 -1
  3. package/dist/src/{chunk-emcefrc1.js → chunk-0e9gg4sg.js} +3 -4
  4. package/dist/src/chunk-1xer1ent.js +102 -0
  5. package/dist/src/{chunk-863tk45b.js → chunk-41fny9qm.js} +5 -5
  6. package/dist/src/{chunk-zjzrcc59.js → chunk-59h200cr.js} +139 -7
  7. package/dist/src/chunk-5w5srj3b.js +93 -0
  8. package/dist/src/{chunk-d4ejrtjq.js → chunk-6n6b1xpy.js} +1 -1
  9. package/dist/src/{chunk-ympzv86c.js → chunk-6w4g9fw8.js} +16 -4
  10. package/dist/src/{chunk-smpevv7n.js → chunk-73aq2qkz.js} +9 -16
  11. package/dist/src/{chunk-0ake7e4r.js → chunk-8c9yc0ge.js} +9 -17
  12. package/dist/src/{chunk-57ayxqnb.js → chunk-8fy8w7ds.js} +2 -23
  13. package/dist/src/{chunk-64ftwe9b.js → chunk-8ykrqhxh.js} +8 -2
  14. package/dist/src/{chunk-2tn0r64b.js → chunk-9h9x79bx.js} +5 -5
  15. package/dist/src/{chunk-nyn75b8v.js → chunk-av31bx1e.js} +31 -2
  16. package/dist/src/{chunk-0xgpxdgc.js → chunk-bbdtsg4b.js} +7 -5
  17. package/dist/src/{chunk-q5pgbwb3.js → chunk-e7jgpxkf.js} +2 -2
  18. package/dist/src/{chunk-zj48jvfe.js → chunk-efty77sb.js} +3 -40
  19. package/dist/src/{chunk-abd4envz.js → chunk-enj7s8cv.js} +71 -78
  20. package/dist/src/{chunk-4etdq0cp.js → chunk-ftpy8xx3.js} +313 -28
  21. package/dist/src/{chunk-zdxww7ms.js → chunk-h3xyq7zk.js} +1 -1
  22. package/dist/src/{chunk-ttsrctxg.js → chunk-hxmq28pg.js} +9 -7
  23. package/dist/src/{chunk-r0nfthsf.js → chunk-j59ac0xs.js} +2 -2
  24. package/dist/src/{chunk-5s2emvww.js → chunk-j6svdqr8.js} +10 -302
  25. package/dist/src/{chunk-9y36gntb.js → chunk-jkzfck98.js} +10 -5
  26. package/dist/src/{chunk-sj24fpz3.js → chunk-m76cmkfy.js} +28 -30
  27. package/dist/src/{chunk-5n8csngz.js → chunk-m96mbzcw.js} +816 -305
  28. package/dist/src/{chunk-xhq21g24.js → chunk-m9c1pnv9.js} +3 -3
  29. package/dist/src/{chunk-fnakrk0a.js → chunk-n3z3jaxy.js} +39 -36
  30. package/dist/src/{chunk-e7x51y0t.js → chunk-ndj0ay2p.js} +19 -18
  31. package/dist/src/chunk-pgs9jp6t.js +320 -0
  32. package/dist/src/chunk-pksaqt9a.js +25 -0
  33. package/dist/src/{chunk-ebm3kvnq.js → chunk-pnep7yhj.js} +31 -100
  34. package/dist/src/chunk-qn5xae7g.js +66 -0
  35. package/dist/src/{chunk-0pewfj89.js → chunk-qp8tgms2.js} +1 -1
  36. package/dist/src/{chunk-7k9g0x5e.js → chunk-rmgw8h27.js} +10 -8
  37. package/dist/src/{chunk-gbsbwssz.js → chunk-sf4ztxba.js} +3 -3
  38. package/dist/src/{chunk-7q96e161.js → chunk-shez7hkc.js} +6 -12
  39. package/dist/src/chunk-sqz614bh.js +30 -0
  40. package/dist/src/{chunk-09f9q26d.js → chunk-vdwzb63d.js} +2 -2
  41. package/dist/src/chunk-xtvgm6kf.js +48 -0
  42. package/dist/src/chunk-y8zm75jt.js +157 -0
  43. package/dist/src/chunk-yasqw2vj.js +756 -0
  44. package/dist/src/{chunk-ybte82d3.js → chunk-z0qmfqvd.js} +4 -3
  45. package/dist/src/chunk-zm705snh.js +53 -0
  46. package/dist/src/cli/index.js +39 -30
  47. package/dist/src/cli/main.js +14 -9
  48. package/dist/src/connector/herdr/installation.js +4 -4
  49. package/dist/src/connector/herdr/provider.js +9 -9
  50. package/dist/src/connector/herdr/runtime.js +7 -7
  51. package/dist/src/connector/luvus/index.js +7 -6
  52. package/dist/src/mcp/index.js +16 -14
  53. package/dist/src/runtime/index.js +16 -15
  54. package/dist/src/service/index.js +3 -4
  55. package/dist/src/store.js +4 -4
  56. package/dist/src/transport/index.js +9 -9
  57. package/dist/src/webui/index.js +975 -834
  58. package/package.json +1 -1
  59. package/dist/src/chunk-5j0gj6w2.js +0 -7
  60. package/dist/src/chunk-9yg6x3gt.js +0 -24
  61. package/dist/src/chunk-erdq0rn8.js +0 -1300
  62. package/dist/src/chunk-n073xnr1.js +0 -1117
  63. package/dist/src/chunk-rwpynx2j.js +0 -51
  64. package/dist/src/chunk-vwcntax3.js +0 -228
package/README.md CHANGED
@@ -45,9 +45,17 @@ always-on host runs the Gateway. Your AI client reaches the Gateway over MCP and
45
45
  workstation's real sessions.
46
46
 
47
47
  1. On the Gateway host: `rovloom gateway`.
48
- 2. On the workstation: `rovloom connector`, then enter the Gateway address and the one-time code.
48
+ 2. On the workstation: paste the join command the Gateway prints (`rovloom connector --join ws://…#code`).
49
49
  3. Add the Gateway's MCP URL and Bearer to your AI client and ask it to list the workstation's workspaces.
50
50
 
51
+ ## CLI language
52
+
53
+ CLI output (help, join messages, status hints) is English by default. Set `ROVLOOM_LANG=zh-CN`
54
+ to switch to Simplified Chinese; without it the CLI stays in English regardless of the system
55
+ locale (`LC_ALL`/`LANG` have no effect). Error and status codes (`config_valid`,
56
+ `pairing_required`, …) are stable identifiers and never change with the language. The management
57
+ page picks its language in the browser, independently of this setting.
58
+
51
59
  ## Install
52
60
 
53
61
  ```sh
@@ -8,7 +8,7 @@ import {
8
8
  StoreManagementWriteService2,
9
9
  createManagementHandler2,
10
10
  createManagementSessionAdapter2
11
- } from "../chunk-ympzv86c.js";
11
+ } from "../chunk-6w4g9fw8.js";
12
12
  import {
13
13
  sampleManagementTransport2,
14
14
  createManagementTransportProjection2
@@ -1,13 +1,12 @@
1
1
  // @bun
2
2
  import {
3
- SERVICE_HELP2,
4
3
  parseServiceCommand2,
5
4
  handleServiceCommand2
6
- } from "./chunk-7q96e161.js";
5
+ } from "./chunk-shez7hkc.js";
6
+ import"./chunk-pgs9jp6t.js";
7
7
  export {
8
- SERVICE_HELP2 as SERVICE_HELP,
9
8
  handleServiceCommand2 as handleServiceCommand,
10
9
  parseServiceCommand2 as parseServiceCommand
11
10
  };
12
11
 
13
- //# debugId=C3691EFE843F735764756E2164756E21
12
+ //# debugId=2172CFBA81B35CDA64756E2164756E21
@@ -0,0 +1,102 @@
1
+ // @bun
2
+ import {
3
+ boundedJson2
4
+ } from "./chunk-qt9m2kg2.js";
5
+ import {
6
+ readRuntimeJson
7
+ } from "./chunk-z7kkfrgz.js";
8
+ import {
9
+ CliError2
10
+ } from "./chunk-hpzr94hm.js";
11
+ import {
12
+ privatePath,
13
+ readPrivateBytes
14
+ } from "./chunk-0y5542k8.js";
15
+
16
+ // src/cli/setup-files.ts
17
+ import {
18
+ closeSync,
19
+ fsyncSync,
20
+ fchmodSync,
21
+ linkSync,
22
+ statSync,
23
+ openSync,
24
+ renameSync,
25
+ unlinkSync,
26
+ writeFileSync
27
+ } from "fs";
28
+ import { createHash, randomUUID } from "crypto";
29
+ import { dirname, join } from "path";
30
+ function setupFileStamp(path) {
31
+ const bytes = readPrivateBytes(path, 16777216);
32
+ try {
33
+ return createHash("sha256").update(bytes).digest("hex");
34
+ } finally {
35
+ bytes.fill(0);
36
+ }
37
+ }
38
+ function writeSetupFile(path, bytes, replace = false, expectedStamp) {
39
+ privatePath(path);
40
+ const previous = replace ? expectedStamp ?? setupFileStamp(path) : undefined;
41
+ if (replace && setupFileStamp(path) !== previous) {
42
+ throw new CliError2("config_changed");
43
+ }
44
+ const temporary = join(dirname(path), ".rovloom-setup-" + randomUUID() + ".tmp");
45
+ let fd;
46
+ let created = false;
47
+ try {
48
+ const mode = replace ? statSync(path).mode & 511 : 384;
49
+ fd = openSync(temporary, "wx", mode);
50
+ created = true;
51
+ if (replace && process.platform !== "win32") {
52
+ fchmodSync(fd, mode);
53
+ }
54
+ writeFileSync(fd, bytes);
55
+ fsyncSync(fd);
56
+ const complete = fd;
57
+ fd = undefined;
58
+ closeSync(complete);
59
+ if (replace) {
60
+ if (setupFileStamp(path) !== previous) {
61
+ throw new CliError2("config_changed");
62
+ }
63
+ renameSync(temporary, path);
64
+ } else {
65
+ linkSync(temporary, path);
66
+ unlinkSync(temporary);
67
+ }
68
+ created = false;
69
+ } catch (error) {
70
+ if (error instanceof CliError2) {
71
+ throw error;
72
+ }
73
+ throw new CliError2("config_unreadable");
74
+ } finally {
75
+ try {
76
+ if (fd !== undefined) {
77
+ closeSync(fd);
78
+ }
79
+ } finally {
80
+ if (created) {
81
+ unlinkSync(temporary);
82
+ }
83
+ }
84
+ }
85
+ }
86
+ function readSetupJson(path, maximum = 16384) {
87
+ try {
88
+ return readRuntimeJson(path, maximum);
89
+ } catch (error) {
90
+ if (error instanceof CliError2 && error.code === "backend_unavailable") {
91
+ return;
92
+ }
93
+ throw error;
94
+ }
95
+ }
96
+ function writeSetupJson(path, value, replace = false, maximum = 16384) {
97
+ writeSetupFile(path, boundedJson2(value, maximum), replace);
98
+ }
99
+
100
+ export { setupFileStamp, writeSetupFile, readSetupJson, writeSetupJson };
101
+
102
+ //# debugId=F153F55644C9BB1764756E2164756E21
@@ -10,9 +10,6 @@ import {
10
10
  import {
11
11
  compileHerdrSchemas2
12
12
  } from "./chunk-5h82060k.js";
13
- import {
14
- ConnectorCapacityError
15
- } from "./chunk-57ayxqnb.js";
16
13
  import {
17
14
  HerdrLocalError,
18
15
  readHerdrPeer,
@@ -23,7 +20,10 @@ import {
23
20
  measureHerdrInstallation,
24
21
  verifyHerdrInstallation,
25
22
  isHerdrInstanceBinding
26
- } from "./chunk-q5pgbwb3.js";
23
+ } from "./chunk-e7jgpxkf.js";
24
+ import {
25
+ ConnectorCapacityError
26
+ } from "./chunk-pksaqt9a.js";
27
27
 
28
28
  // src/connector/herdr/io.ts
29
29
  import { spawn } from "child_process";
@@ -430,4 +430,4 @@ function createHerdrHostServices2(installation, services) {
430
430
 
431
431
  export { isStoppedHerdrCommandCancellation, checkHerdrSignal, herdrDeadline, runHerdrCommand, withHerdrSocket, exchangeHerdr, HerdrInstallation2, createHerdrHostServices2 };
432
432
 
433
- //# debugId=CB0FB8FAF9DAAC5964756E2164756E21
433
+ //# debugId=C2DD57901BB8C75064756E2164756E21
@@ -25,16 +25,16 @@ import {
25
25
  decodeWireFrame2,
26
26
  discardFencedWireFrame2
27
27
  } from "./chunk-qt9m2kg2.js";
28
- import {
29
- LuvusAdapterError2,
30
- ConnectorCapacityError
31
- } from "./chunk-57ayxqnb.js";
32
28
  import {
33
29
  HerdrLocalError
34
- } from "./chunk-q5pgbwb3.js";
30
+ } from "./chunk-e7jgpxkf.js";
35
31
  import {
36
32
  createLuvusWireAdapter2
37
33
  } from "./chunk-hz8pm6hz.js";
34
+ import {
35
+ LuvusAdapterError2,
36
+ ConnectorCapacityError
37
+ } from "./chunk-pksaqt9a.js";
38
38
 
39
39
  // src/transport/gateway.ts
40
40
  import { randomUUID as randomUUID2 } from "crypto";
@@ -1795,6 +1795,138 @@ function createConnector2(options) {
1795
1795
  }
1796
1796
  };
1797
1797
  }
1798
+ // src/transport/pairing.ts
1799
+ class PairingAdmin2 {
1800
+ store;
1801
+ host;
1802
+ constructor(store, host) {
1803
+ this.store = store;
1804
+ this.host = host;
1805
+ }
1806
+ register(name) {
1807
+ if (this.host.authorize("register") !== undefined) {
1808
+ fail2("pairing_admin_forbidden");
1809
+ }
1810
+ return this.store.register(name);
1811
+ }
1812
+ issue(machine, ttlMs = 600000) {
1813
+ if (this.host.authorize("enroll", machine) !== undefined) {
1814
+ fail2("pairing_admin_forbidden");
1815
+ }
1816
+ return this.store.issueEnrollment(machine, ttlMs);
1817
+ }
1818
+ }
1819
+ // src/transport/custody.ts
1820
+ import { randomUUID as randomUUID4 } from "crypto";
1821
+ function createPairingDelivery2(options) {
1822
+ const timeout = options.timeout_ms ?? 5000;
1823
+ const concurrency = options.concurrency ?? 4;
1824
+ if (!Number.isSafeInteger(timeout) || timeout < 1 || timeout > 30000 || !Number.isSafeInteger(concurrency) || concurrency < 1 || concurrency > 64) {
1825
+ fail2("pairing_limit");
1826
+ }
1827
+ const pending = new Map;
1828
+ let closed = false;
1829
+ async function transfer(machine, operation, issue) {
1830
+ if (closed || pending.size >= concurrency) {
1831
+ fail2("pairing_unavailable");
1832
+ }
1833
+ id2(machine);
1834
+ const deliveryId = randomUUID4();
1835
+ let sink;
1836
+ try {
1837
+ sink = options.authorizeChannel({ machine_id: machine, delivery_id: deliveryId, operation });
1838
+ } catch {
1839
+ fail2("pairing_channel_forbidden");
1840
+ }
1841
+ if (!sink || typeof sink.deliver !== "function" || typeof sink.close !== "function") {
1842
+ fail2("pairing_channel_forbidden");
1843
+ }
1844
+ if (closed) {
1845
+ try {
1846
+ sink.close();
1847
+ } catch {}
1848
+ fail2("pairing_unavailable");
1849
+ }
1850
+ const controller = new AbortController;
1851
+ let rejectAbort;
1852
+ const aborted = new Promise((_, reject) => {
1853
+ rejectAbort = reject;
1854
+ });
1855
+ const closeSink = () => {
1856
+ controller.abort();
1857
+ try {
1858
+ sink.close();
1859
+ } catch {}
1860
+ };
1861
+ const abort = () => {
1862
+ closeSink();
1863
+ rejectAbort(new Error("pairing_delivery_unknown"));
1864
+ };
1865
+ const timer = setTimeout(abort, timeout);
1866
+ pending.set(deliveryId, { timer, abort });
1867
+ let installedDigest;
1868
+ let sending = false;
1869
+ try {
1870
+ const credential = issue();
1871
+ installedDigest = hash2(credential.credential);
1872
+ const generation = credential.recovery_generation;
1873
+ const revision = options.identities.credentialRevision(machine);
1874
+ sending = true;
1875
+ const delivered = Promise.resolve().then(() => sink.deliver(structuredClone(credential), controller.signal, { delivery_id: deliveryId, revision })).finally(() => {
1876
+ clearTimeout(timer);
1877
+ pending.delete(deliveryId);
1878
+ });
1879
+ const ack = await Promise.race([delivered, aborted]);
1880
+ if (!ack || ack.delivery_id !== deliveryId || ack.revision !== revision || ack.machine_id !== machine || ack.recovery_generation !== generation) {
1881
+ fail2("pairing_ack_mismatch");
1882
+ }
1883
+ if (closed || controller.signal.aborted) {
1884
+ fail2("pairing_delivery_unknown");
1885
+ }
1886
+ return { machine_id: machine, delivery_id: deliveryId, state: "delivered" };
1887
+ } catch {
1888
+ if (installedDigest !== undefined) {
1889
+ try {
1890
+ options.identities.rejectDelivery(machine, installedDigest);
1891
+ } catch {}
1892
+ }
1893
+ return fail2("pairing_delivery_unknown");
1894
+ } finally {
1895
+ clearTimeout(timer);
1896
+ closeSink();
1897
+ if (!sending) {
1898
+ pending.delete(deliveryId);
1899
+ }
1900
+ }
1901
+ }
1902
+ return {
1903
+ async redeem(request) {
1904
+ if (typeof request.enrollment !== "string" || !/^[A-Za-z0-9_-]{32,256}$/.test(request.enrollment)) {
1905
+ fail2("invalid_enrollment");
1906
+ }
1907
+ return transfer(request.registration_id, "enroll", () => {
1908
+ const device = options.backend.redeem(request.enrollment);
1909
+ if (device.machine_id !== request.registration_id) {
1910
+ fail2("pairing_target_mismatch");
1911
+ }
1912
+ return { ...device, recovery_generation: options.backend.generation() };
1913
+ });
1914
+ },
1915
+ status() {
1916
+ return { closed, pending: pending.size };
1917
+ },
1918
+ close() {
1919
+ if (closed) {
1920
+ return;
1921
+ }
1922
+ closed = true;
1923
+ for (const item of pending.values()) {
1924
+ clearTimeout(item.timer);
1925
+ item.abort();
1926
+ }
1927
+ }
1928
+ };
1929
+ }
1798
1930
  // src/transport/lifecycle.ts
1799
1931
  function createDeviceLifecycle2(store) {
1800
1932
  function authenticate(machine, generation, credential) {
@@ -1864,6 +1996,6 @@ function createDeviceLifecycleAdapter2(lifecycle, channels, services) {
1864
1996
  };
1865
1997
  return { backend, adapter: createLuvusWireAdapter2(backend) };
1866
1998
  }
1867
- export { closeSession, OFFER, providerHealth, ready, ReceiveWindow, ChannelRegistry2, createGateway2, createConnector2, createDeviceLifecycle2, createDeviceLifecycleAdapter2 };
1999
+ export { closeSession, OFFER, providerHealth, ready, ReceiveWindow, ChannelRegistry2, createGateway2, createConnector2, PairingAdmin2, createPairingDelivery2, createDeviceLifecycle2, createDeviceLifecycleAdapter2 };
1868
2000
 
1869
- //# debugId=4431B5C43A54FCC664756E2164756E21
2001
+ //# debugId=1F0ADD524CEDDA6964756E2164756E21
@@ -0,0 +1,93 @@
1
+ // @bun
2
+ import {
3
+ fail2,
4
+ object2,
5
+ fields2,
6
+ id2,
7
+ boundedJson2
8
+ } from "./chunk-qt9m2kg2.js";
9
+ import {
10
+ privatePath,
11
+ privateFile,
12
+ createPrivate,
13
+ syncParentDirectory
14
+ } from "./chunk-0y5542k8.js";
15
+
16
+ // src/transport/credentials.ts
17
+ import { constants, closeSync, fstatSync, openSync, readFileSync, renameSync, unlinkSync } from "fs";
18
+ import { randomUUID } from "crypto";
19
+ function validate(value) {
20
+ const v = object2(value);
21
+ fields2(v, ["machine_id", "recovery_generation", "credential"]);
22
+ id2(v.machine_id);
23
+ id2(v.recovery_generation);
24
+ if (typeof v.credential !== "string" || !/^[A-Za-z0-9_-]{32,256}$/.test(v.credential)) {
25
+ fail2("invalid_device_credential");
26
+ }
27
+ return v;
28
+ }
29
+ function saveCredential2(path, input, replace = false) {
30
+ privatePath(path);
31
+ const raw = boundedJson2(validate(input), 4096);
32
+ if (!replace) {
33
+ createPrivate(path, raw);
34
+ syncParentDirectory(path, true);
35
+ return;
36
+ }
37
+ privateFile(path);
38
+ const temporary = path + "." + randomUUID();
39
+ try {
40
+ createPrivate(temporary, raw);
41
+ renameSync(temporary, path);
42
+ syncParentDirectory(path, true);
43
+ } finally {
44
+ try {
45
+ unlinkSync(temporary);
46
+ } catch {}
47
+ }
48
+ }
49
+ function createFileCredentialSink2(path, expected, replace = false) {
50
+ privatePath(path);
51
+ id2(expected.machine_id);
52
+ id2(expected.recovery_generation);
53
+ let closed = false;
54
+ let used = false;
55
+ return {
56
+ async deliver(input, signal, context) {
57
+ if (closed || used || signal.aborted) {
58
+ fail2("credential_sink_closed");
59
+ }
60
+ if (input.machine_id !== expected.machine_id || input.recovery_generation !== expected.recovery_generation) {
61
+ fail2("credential_sink_mismatch");
62
+ }
63
+ used = true;
64
+ saveCredential2(path, input, replace);
65
+ return { ...context, machine_id: input.machine_id, recovery_generation: input.recovery_generation };
66
+ },
67
+ close() {
68
+ closed = true;
69
+ }
70
+ };
71
+ }
72
+ function loadCredential2(path) {
73
+ privatePath(path);
74
+ privateFile(path);
75
+ const fd = openSync(path, constants.O_RDONLY | constants.O_NOFOLLOW);
76
+ try {
77
+ const st = fstatSync(fd);
78
+ if (!st.isFile() || st.nlink !== 1 || process.platform !== "win32" && ((st.mode & 511) !== 384 || st.uid !== process.getuid?.()) || st.size > 4096) {
79
+ fail2("unsafe_storage_file");
80
+ }
81
+ try {
82
+ return validate(JSON.parse(readFileSync(fd, "utf8")));
83
+ } catch {
84
+ fail2("invalid_device_credential");
85
+ }
86
+ } finally {
87
+ closeSync(fd);
88
+ }
89
+ }
90
+
91
+ export { saveCredential2, createFileCredentialSink2, loadCredential2 };
92
+
93
+ //# debugId=CE63F3C4843F109E64756E2164756E21
@@ -14,7 +14,7 @@ import {
14
14
  } from "./chunk-qt9m2kg2.js";
15
15
  import {
16
16
  ConnectorCapacityError
17
- } from "./chunk-57ayxqnb.js";
17
+ } from "./chunk-pksaqt9a.js";
18
18
 
19
19
  // src/runtime/connector-attempts.ts
20
20
  var CONNECTOR_MAX_DEADLINE_MS2 = 10 * 60000;
@@ -931,7 +931,7 @@ function createManagementHandler2(options) {
931
931
  return failure2("invalid_arguments", 400);
932
932
  }
933
933
  const context = { ...identity, wait_signal: controller.signal };
934
- const reply = await options.service.execute(operation, args, context);
934
+ const reply = operation.startsWith("resources/") ? await options.resources.execute(operation.slice("resources/".length), args, identity, controller.signal) : await options.service.execute(operation, args, context);
935
935
  if (controller.signal.aborted) {
936
936
  return failure2("outcome_unconfirmed", 503);
937
937
  }
@@ -952,7 +952,7 @@ function createManagementHandler2(options) {
952
952
  } catch {
953
953
  return failure2("forbidden", 403);
954
954
  }
955
- if (!url.pathname.startsWith("/admin/v1/actions/")) {
955
+ if (!url.pathname.startsWith("/admin/v1/actions/") && !url.pathname.startsWith("/admin/v1/resources/")) {
956
956
  return reads.fetch(request);
957
957
  }
958
958
  let size = 0;
@@ -967,7 +967,19 @@ function createManagementHandler2(options) {
967
967
  if (request.method !== "POST") {
968
968
  return failure2("method_not_allowed", 405);
969
969
  }
970
- const operation = routes.get(url.pathname);
970
+ const resource = url.pathname.startsWith("/admin/v1/resources/") ? url.pathname.slice("/admin/v1/resources/".length) : null;
971
+ const operation = resource !== null && options.resources && [
972
+ "tokens_list",
973
+ "tokens_create",
974
+ "tokens_delete",
975
+ "tokens_rotate",
976
+ "pairing_codes_list",
977
+ "pairing_codes_create",
978
+ "pairing_codes_revoke",
979
+ "pairings_list",
980
+ "pairings_delete",
981
+ "devices_delete"
982
+ ].includes(resource) ? `resources/${resource}` : routes.get(url.pathname);
971
983
  if (!operation) {
972
984
  return failure2("not_found", 404);
973
985
  }
@@ -1184,4 +1196,4 @@ function createManagementSessionAdapter2(options) {
1184
1196
  }
1185
1197
  export { createManagementReadHandler2, startManagementReadListener2, startManagementListener2, loadManagementAssets2, ManagementServiceError2, StoreManagementWriteService2, createManagementHandler2, createManagementSessionAdapter2 };
1186
1198
 
1187
- //# debugId=5F343A955701396E64756E2164756E21
1199
+ //# debugId=77B098389207C26664756E2164756E21
@@ -2,6 +2,9 @@
2
2
  import {
3
3
  canonical2
4
4
  } from "./chunk-d71r315c.js";
5
+ import {
6
+ cliMessages2
7
+ } from "./chunk-pgs9jp6t.js";
5
8
 
6
9
  // src/mcp/schema.ts
7
10
  import { Ajv } from "ajv";
@@ -61,19 +64,9 @@ var schemas = {
61
64
  runtime_result_read: object({ result_id: id, cursor, max_bytes: { type: "integer", minimum: 1, maximum: MAX_RESULT_BYTES2 } }, ["result_id"]),
62
65
  runtime_response_discard: object({ call_id: id }, ["call_id"])
63
66
  };
64
- var descriptions = {
65
- machines_list: "\u5217\u51FA\u5F53\u524D caller \u53EF\u89C1\u7684\u8BBE\u5907\uFF1B\u5206\u9875\u548C\u8BA1\u6570\u987B\u7ECF\u8FC7\u5F53\u524D ACL\u3002",
66
- machines_get: "\u6309\u7A33\u5B9A ID \u6216\u7CBE\u786E\u540D\u79F0\u8BFB\u53D6\u53EF\u89C1\u8BBE\u5907\u3002",
67
- providers_list: "\u5217\u51FA\u6307\u5B9A\u8BBE\u5907\u4E0B\u5F53\u524D caller \u53EF\u89C1\u7684\u5DF2\u914D\u7F6E provider\uFF1B\u4E0D\u8FD4\u56DE\u672C\u673A\u914D\u7F6E\u3002",
68
- providers_get: "\u8BFB\u53D6\u663E\u5F0F provider \u7684 kind\u3001revision \u548C readiness\u3002",
69
- runtime_discover: "\u53D1\u73B0\u663E\u5F0F Target/revision \u7684\u6709\u6548\u80FD\u529B\u53CA\u6765\u6E90\uFF1B\u4E0D\u6388\u4E88\u6267\u884C\u6743\u9650\u3002",
70
- runtime_describe: "\u63CF\u8FF0\u663E\u5F0F Target/revision \u4E0B\u7CBE\u786E\u65B9\u6CD5\u7684\u539F\u751F\u53C2\u6570\u3001\u5206\u7C7B\u548C\u9650\u5236\u3002",
71
- runtime_call: "\u63D0\u4EA4\u4E00\u6B21\u663E\u5F0F Target/revision/\u5951\u7EA6\u7684\u539F\u751F\u8C03\u7528\u3002deadline \u662F\u7EDD\u5BF9\u6BEB\u79D2\u671F\u9650\uFF0Cwait_ms \u53EA\u63A7\u5236\u77ED\u7B49\uFF1B\u4E0D\u91CD\u8BD5\u6216\u7BA1\u7406 provider\u3002",
72
- runtime_call_get: "\u6309\u5F53\u524D\u5F52\u5C5E\u3001\u53CC\u7AEF\u7B56\u7565\u548C\u5185\u5BB9\u95E8\u7981\u8BFB\u53D6\u8C03\u7528\uFF1B\u77ED\u7B49\u5230\u671F\u4E0D\u6539\u53D8\u6267\u884C\u671F\u9650\u3002",
73
- runtime_call_cancel: "\u8BF7\u6C42\u505C\u6B62\u7B49\u5F85\u6216\u6865\u63A5\uFF1B\u4EC5\u62A5\u544A\u670D\u52A1\u53EF\u786E\u8BA4\u7A0B\u5EA6\uFF0C\u4E0D\u627F\u8BFA\u539F\u751F\u56DE\u6EDA\u3002",
74
- runtime_result_read: "\u6309\u5F53\u524D\u8BFB\u53D6\u6388\u6743\u548C\u671F\u9650\u8BFB\u53D6\u6709\u754C\u7ED3\u679C\u9875\uFF1Bcursor \u7531\u670D\u52A1\u7ED1\u5B9A caller \u548C\u539F\u7ED3\u679C\u3002",
75
- runtime_response_discard: "\u5904\u7406\u5B8C\u7ED3\u679C\u540E\u663E\u5F0F\u5220\u9664\u539F\u6587\u4E0E\u53E5\u67C4\u5E76\u91CA\u653E\u8BFB\u53D6\u5BB9\u91CF\uFF1B\u5FC5\u987B\u9A8C\u8BC1\u5F52\u5C5E\u3001\u5F53\u524D\u539F\u65B9\u6CD5\u7B56\u7565\u53CA\u72EC\u7ACB discard_response \u6743\u9650\u3002\u8BFB\u53D6\u5230 EOF \u4E0D\u4F1A\u81EA\u52A8\u5220\u9664\u7ED3\u679C\u3002"
76
- };
67
+ function toolDescription(name, language = "en") {
68
+ return cliMessages2(language)["mcp.tool." + name];
69
+ }
77
70
  var readOnly = new Set([
78
71
  "machines_list",
79
72
  "machines_get",
@@ -89,10 +82,10 @@ var validators = new Map(Object.entries(schemas).map(([name, schema]) => [name,
89
82
  function toolNames2() {
90
83
  return Object.keys(schemas);
91
84
  }
92
- function toolDefinition2(name) {
85
+ function toolDefinition2(name, language = "en") {
93
86
  return {
94
87
  name,
95
- description: descriptions[name],
88
+ description: toolDescription(name, language),
96
89
  inputSchema: structuredClone(schemas[name]),
97
90
  outputSchema: {
98
91
  type: "object",
@@ -178,4 +171,4 @@ class NativeRequestNotDispatchedError extends FacadeServiceError2 {
178
171
 
179
172
  export { MAX_MCP_BYTES2, MAX_RESULT_BYTES2, MAX_WAIT_MS2, TOOLS_PAGE_SIZE, toolNames2, toolDefinition2, isToolName, parseToolArguments2, SERVICE_ERROR_CODES, FacadeServiceError2, NativeRequestNotDispatchedError };
180
173
 
181
- //# debugId=08E91064C7F6137064756E2164756E21
174
+ //# debugId=E037D9DEF799B17A64756E2164756E21
@@ -14,8 +14,11 @@ import {
14
14
  assertUsage,
15
15
  GATEWAY_LOCK_FORMAT2,
16
16
  Store2
17
- } from "./chunk-nyn75b8v.js";
18
- import"./chunk-09f9q26d.js";
17
+ } from "./chunk-av31bx1e.js";
18
+ import"./chunk-vdwzb63d.js";
19
+ import {
20
+ cliMessages2
21
+ } from "./chunk-pgs9jp6t.js";
19
22
  import {
20
23
  readRuntimeConfig2
21
24
  } from "./chunk-bspzg8er.js";
@@ -33,8 +36,8 @@ import {
33
36
  import"./chunk-3nnahj0j.js";
34
37
  import {
35
38
  lockContent
36
- } from "./chunk-zdxww7ms.js";
37
- import"./chunk-0pewfj89.js";
39
+ } from "./chunk-h3xyq7zk.js";
40
+ import"./chunk-qp8tgms2.js";
38
41
  import {
39
42
  privatePath,
40
43
  databasePath,
@@ -131,17 +134,6 @@ function inspectStorage(input) {
131
134
  }
132
135
 
133
136
  // src/cli/storage-command.ts
134
- var STORAGE_HELP = `\u7528\u6CD5\uFF1A
135
- rovloom doctor --role gateway|connector [--config /absolute/config.json] [--json]
136
- rovloom storage check --role gateway [--config /absolute/config.json] [--json]
137
- rovloom storage backup --role gateway --output /path/to/gateway.backups/snapshot.db [--config /absolute/config.json] [--json]
138
- rovloom storage resume --role gateway [--config /absolute/config.json] [--json]
139
-
140
- Gateway \u547D\u4EE4\u987B\u5148\u505C\u6B62\u670D\u52A1\uFF1B\u6CBF\u7528\u540C\u4E00\u5199\u9501\uFF0C\u62D2\u7EDD\u6D3B\u52A8\u6216\u65E0\u6CD5\u5224\u5B9A\u7684\u6301\u6709\u8005\u3002
141
- check \u53EA\u8BFB\uFF1Bbackup \u4EC5\u4F7F\u7528\u771F\u5B9E\u72B6\u6001\u76EE\u5F55\u540C\u7EA7\u7684 <state>.backups \u666E\u901A\u76EE\u5F55\uFF0C\u5BFC\u51FA\u8131\u654F\u5FEB\u7167\uFF08\u4E0D\u542B\u539F\u6587\u53CA\u6709\u6548\u51ED\u636E\uFF09\uFF0C\u5B8C\u6574\u72B6\u6001\u9700\u53E6\u884C\u79BB\u7EBF\u5907\u4EFD\u3002
142
- resume \u662F\u672C\u673A\u64CD\u4F5C\u5458\u663E\u5F0F\u6279\u51C6\u7684\u89E3\u9664\u964D\u7EA7\uFF0C\u5B8C\u6574\u6027\u3001\u65F6\u949F\u6216\u9884\u7B97\u4E0D\u6B63\u5E38\u65F6\u4ECD\u62D2\u7EDD\u3002
143
- Connector doctor \u53EA\u68C0\u67E5\u914D\u7F6E\u53CA managed \u72B6\u6001\uFF0C\u4E0D\u542F\u52A8 native\uFF0C\u4E5F\u4E0D\u58F0\u660E native \u5C31\u7EEA\u3002
144
- `;
145
137
  function parse(args) {
146
138
  const action = args[0] === "doctor" ? "doctor" : args[1];
147
139
  if (!["doctor", "check", "backup", "resume"].includes(action ?? "")) {
@@ -201,7 +193,7 @@ async function handleStorageCommand(args, io, environment) {
201
193
  let json = args.includes("--json");
202
194
  try {
203
195
  if (args.length === 2 && args[1] === "--help") {
204
- io.stderr.write(STORAGE_HELP);
196
+ io.stderr.write(cliMessages2(io.language)["help.storage"]);
205
197
  return 0;
206
198
  }
207
199
  const flags = parse(args);
@@ -318,4 +310,4 @@ export {
318
310
  handleStorageCommand
319
311
  };
320
312
 
321
- //# debugId=007190958BDB411E64756E2164756E21
313
+ //# debugId=2C436BD5D6042D5D64756E2164756E21
@@ -3,27 +3,6 @@ import {
3
3
  fail2
4
4
  } from "./chunk-qt9m2kg2.js";
5
5
 
6
- // src/connector/luvus/types.ts
7
- class LuvusAdapterError2 extends Error {
8
- code;
9
- outcome;
10
- constructor(code, outcome = "not_dispatched") {
11
- super(code);
12
- this.code = code;
13
- this.outcome = outcome;
14
- this.name = "LuvusAdapterError";
15
- }
16
- }
17
-
18
- // src/connector/capacity.ts
19
- class ConnectorCapacityError extends LuvusAdapterError2 {
20
- capacity;
21
- constructor(resource, reclaimAt) {
22
- super(resource.startsWith("claim_") ? "claim_capacity" : "connector_attempt_capacity");
23
- this.capacity = Object.freeze({ resource, reclaim_at: reclaimAt });
24
- }
25
- }
26
-
27
6
  // src/connector/local/linux-peer.ts
28
7
  import { createRequire } from "module";
29
8
  import { Socket } from "net";
@@ -179,6 +158,6 @@ function assertTerminalExecutionAllowed(kind, request, enabled = false) {
179
158
  }
180
159
  }
181
160
 
182
- export { LuvusAdapterError2, ConnectorCapacityError, readLinuxPeer, pinTerminalExecution, terminalExecutionCatalog, assertTerminalExecutionAllowed };
161
+ export { readLinuxPeer, pinTerminalExecution, terminalExecutionCatalog, assertTerminalExecutionAllowed };
183
162
 
184
- //# debugId=D0819F737EC4D21B64756E2164756E21
163
+ //# debugId=190A991502F4F00A64756E2164756E21
@@ -41,7 +41,13 @@ function defaults(role, environment, initialization) {
41
41
  return { ...config, native: { ...config.native, provider: initialization.provider } };
42
42
  }
43
43
  if (config.role === "gateway" && initialization.container) {
44
- return { ...config, mcp_hostname: "0.0.0.0", device_hostname: "0.0.0.0", management_hostname: "0.0.0.0" };
44
+ return {
45
+ ...config,
46
+ mcp_hostname: "0.0.0.0",
47
+ device_hostname: "0.0.0.0",
48
+ management_hostname: "0.0.0.0",
49
+ management_lan: true
50
+ };
45
51
  }
46
52
  return config;
47
53
  }
@@ -98,4 +104,4 @@ function readOrCreateRoleConfig(role, path, environment, initialization = {}) {
98
104
 
99
105
  export { privateDirectory, readOrCreateRoleConfig };
100
106
 
101
- //# debugId=98F38BF75586543964756E2164756E21
107
+ //# debugId=2B2959D62D3C434064756E2164756E21