agent-embassy 1.0.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 (145) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/CONTRIBUTING.md +122 -0
  3. package/LICENSE +21 -0
  4. package/README.md +185 -0
  5. package/README.zh-CN.md +185 -0
  6. package/SECURITY.md +224 -0
  7. package/assets/live-dashboard/app.css +1610 -0
  8. package/assets/mark-seal.svg +7 -0
  9. package/assets/mark.svg +7 -0
  10. package/assets/social-preview.png +0 -0
  11. package/assets/vendor/react/LICENSE +21 -0
  12. package/assets/vendor/react/react-dom.production.min.js +267 -0
  13. package/assets/vendor/react/react.production.min.js +31 -0
  14. package/dist/src/errors.d.ts +5 -0
  15. package/dist/src/errors.js +11 -0
  16. package/dist/src/errors.js.map +1 -0
  17. package/dist/src/gateway/claude-compatibility-scratch.d.ts +18 -0
  18. package/dist/src/gateway/claude-compatibility-scratch.js +158 -0
  19. package/dist/src/gateway/claude-compatibility-scratch.js.map +1 -0
  20. package/dist/src/gateway/claude-helper-client.d.ts +43 -0
  21. package/dist/src/gateway/claude-helper-client.js +212 -0
  22. package/dist/src/gateway/claude-helper-client.js.map +1 -0
  23. package/dist/src/gateway/claude-helper-protocol.d.ts +172 -0
  24. package/dist/src/gateway/claude-helper-protocol.js +373 -0
  25. package/dist/src/gateway/claude-helper-protocol.js.map +1 -0
  26. package/dist/src/gateway/claude-helper-supervisor.d.ts +74 -0
  27. package/dist/src/gateway/claude-helper-supervisor.js +497 -0
  28. package/dist/src/gateway/claude-helper-supervisor.js.map +1 -0
  29. package/dist/src/gateway/claude-helper.d.ts +1 -0
  30. package/dist/src/gateway/claude-helper.js +269 -0
  31. package/dist/src/gateway/claude-helper.js.map +1 -0
  32. package/dist/src/gateway/claude-peer.d.ts +273 -0
  33. package/dist/src/gateway/claude-peer.js +2359 -0
  34. package/dist/src/gateway/claude-peer.js.map +1 -0
  35. package/dist/src/gateway/claude-runtime.d.ts +40 -0
  36. package/dist/src/gateway/claude-runtime.js +302 -0
  37. package/dist/src/gateway/claude-runtime.js.map +1 -0
  38. package/dist/src/gateway/cli-copy.d.ts +8 -0
  39. package/dist/src/gateway/cli-copy.en.d.ts +13 -0
  40. package/dist/src/gateway/cli-copy.en.js +43 -0
  41. package/dist/src/gateway/cli-copy.en.js.map +1 -0
  42. package/dist/src/gateway/cli-copy.js +19 -0
  43. package/dist/src/gateway/cli-copy.js.map +1 -0
  44. package/dist/src/gateway/cli-copy.zh-CN.d.ts +13 -0
  45. package/dist/src/gateway/cli-copy.zh-CN.js +43 -0
  46. package/dist/src/gateway/cli-copy.zh-CN.js.map +1 -0
  47. package/dist/src/gateway/cli.d.ts +44 -0
  48. package/dist/src/gateway/cli.js +969 -0
  49. package/dist/src/gateway/cli.js.map +1 -0
  50. package/dist/src/gateway/codex-app-server.d.ts +310 -0
  51. package/dist/src/gateway/codex-app-server.js +1746 -0
  52. package/dist/src/gateway/codex-app-server.js.map +1 -0
  53. package/dist/src/gateway/codex-local-transport.d.ts +81 -0
  54. package/dist/src/gateway/codex-local-transport.js +617 -0
  55. package/dist/src/gateway/codex-local-transport.js.map +1 -0
  56. package/dist/src/gateway/codex-registration-generation.d.ts +5 -0
  57. package/dist/src/gateway/codex-registration-generation.js +19 -0
  58. package/dist/src/gateway/codex-registration-generation.js.map +1 -0
  59. package/dist/src/gateway/codex-registration-succession.d.ts +209 -0
  60. package/dist/src/gateway/codex-registration-succession.js +588 -0
  61. package/dist/src/gateway/codex-registration-succession.js.map +1 -0
  62. package/dist/src/gateway/compatibility.d.ts +70 -0
  63. package/dist/src/gateway/compatibility.js +252 -0
  64. package/dist/src/gateway/compatibility.js.map +1 -0
  65. package/dist/src/gateway/config.d.ts +24 -0
  66. package/dist/src/gateway/config.js +130 -0
  67. package/dist/src/gateway/config.js.map +1 -0
  68. package/dist/src/gateway/control.d.ts +308 -0
  69. package/dist/src/gateway/control.js +1573 -0
  70. package/dist/src/gateway/control.js.map +1 -0
  71. package/dist/src/gateway/dashboard-copy.d.ts +7 -0
  72. package/dist/src/gateway/dashboard-copy.en.d.ts +506 -0
  73. package/dist/src/gateway/dashboard-copy.en.js +507 -0
  74. package/dist/src/gateway/dashboard-copy.en.js.map +1 -0
  75. package/dist/src/gateway/dashboard-copy.js +516 -0
  76. package/dist/src/gateway/dashboard-copy.js.map +1 -0
  77. package/dist/src/gateway/dashboard-copy.zh-CN.d.ts +506 -0
  78. package/dist/src/gateway/dashboard-copy.zh-CN.js +507 -0
  79. package/dist/src/gateway/dashboard-copy.zh-CN.js.map +1 -0
  80. package/dist/src/gateway/dashboard-model.d.ts +207 -0
  81. package/dist/src/gateway/dashboard-model.js +720 -0
  82. package/dist/src/gateway/dashboard-model.js.map +1 -0
  83. package/dist/src/gateway/dashboard.d.ts +26 -0
  84. package/dist/src/gateway/dashboard.js +941 -0
  85. package/dist/src/gateway/dashboard.js.map +1 -0
  86. package/dist/src/gateway/delivery-machine.d.ts +235 -0
  87. package/dist/src/gateway/delivery-machine.js +540 -0
  88. package/dist/src/gateway/delivery-machine.js.map +1 -0
  89. package/dist/src/gateway/instance-lease.d.ts +21 -0
  90. package/dist/src/gateway/instance-lease.js +549 -0
  91. package/dist/src/gateway/instance-lease.js.map +1 -0
  92. package/dist/src/gateway/live-dashboard-app/app.js +2914 -0
  93. package/dist/src/gateway/live-dashboard-assets.d.ts +10 -0
  94. package/dist/src/gateway/live-dashboard-assets.js +73 -0
  95. package/dist/src/gateway/live-dashboard-assets.js.map +1 -0
  96. package/dist/src/gateway/live-dashboard-bootstrap.d.ts +36 -0
  97. package/dist/src/gateway/live-dashboard-bootstrap.js +176 -0
  98. package/dist/src/gateway/live-dashboard-bootstrap.js.map +1 -0
  99. package/dist/src/gateway/live-dashboard-command.d.ts +54 -0
  100. package/dist/src/gateway/live-dashboard-command.js +324 -0
  101. package/dist/src/gateway/live-dashboard-command.js.map +1 -0
  102. package/dist/src/gateway/live-dashboard-http.d.ts +41 -0
  103. package/dist/src/gateway/live-dashboard-http.js +445 -0
  104. package/dist/src/gateway/live-dashboard-http.js.map +1 -0
  105. package/dist/src/gateway/live-dashboard-protocol.d.ts +38 -0
  106. package/dist/src/gateway/live-dashboard-protocol.js +156 -0
  107. package/dist/src/gateway/live-dashboard-protocol.js.map +1 -0
  108. package/dist/src/gateway/live-dashboard-server.d.ts +33 -0
  109. package/dist/src/gateway/live-dashboard-server.js +130 -0
  110. package/dist/src/gateway/live-dashboard-server.js.map +1 -0
  111. package/dist/src/gateway/live-dashboard-stream.d.ts +46 -0
  112. package/dist/src/gateway/live-dashboard-stream.js +233 -0
  113. package/dist/src/gateway/live-dashboard-stream.js.map +1 -0
  114. package/dist/src/gateway/live-dashboard.d.ts +31 -0
  115. package/dist/src/gateway/live-dashboard.js +190 -0
  116. package/dist/src/gateway/live-dashboard.js.map +1 -0
  117. package/dist/src/gateway/locale.d.ts +4 -0
  118. package/dist/src/gateway/locale.js +10 -0
  119. package/dist/src/gateway/locale.js.map +1 -0
  120. package/dist/src/gateway/progress-watch-machine.d.ts +97 -0
  121. package/dist/src/gateway/progress-watch-machine.js +172 -0
  122. package/dist/src/gateway/progress-watch-machine.js.map +1 -0
  123. package/dist/src/gateway/providers.d.ts +287 -0
  124. package/dist/src/gateway/providers.js +2451 -0
  125. package/dist/src/gateway/providers.js.map +1 -0
  126. package/dist/src/gateway/server.d.ts +57 -0
  127. package/dist/src/gateway/server.js +264 -0
  128. package/dist/src/gateway/server.js.map +1 -0
  129. package/dist/src/gateway/service.d.ts +449 -0
  130. package/dist/src/gateway/service.js +4831 -0
  131. package/dist/src/gateway/service.js.map +1 -0
  132. package/dist/src/gateway/store.d.ts +340 -0
  133. package/dist/src/gateway/store.js +4047 -0
  134. package/dist/src/gateway/store.js.map +1 -0
  135. package/dist/src/gateway/types.d.ts +514 -0
  136. package/dist/src/gateway/types.js +414 -0
  137. package/dist/src/gateway/types.js.map +1 -0
  138. package/dist/src/mutex.d.ts +4 -0
  139. package/dist/src/mutex.js +23 -0
  140. package/dist/src/mutex.js.map +1 -0
  141. package/docs/DESIGN.md +134 -0
  142. package/docs/GATEWAY-ARCHITECTURE.md +858 -0
  143. package/package.json +80 -0
  144. package/skills/embassy-peer/SKILL.md +198 -0
  145. package/skills/embassy-peer/agents/openai.yaml +4 -0
@@ -0,0 +1,10 @@
1
+ import { type DashboardLocale } from "./dashboard-copy.js";
2
+ export type LiveDashboardAssets = Readonly<{
3
+ shellHtml: string;
4
+ clientJavaScript: string;
5
+ styleSheet: string;
6
+ appJavaScript: string;
7
+ vendorReactJavaScript: string;
8
+ vendorReactDomJavaScript: string;
9
+ }>;
10
+ export declare function renderLiveDashboardAssets(locale: DashboardLocale): LiveDashboardAssets;
@@ -0,0 +1,73 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { BridgeError } from "../errors.js";
3
+ import { assertDashboardLocale, getDashboardCopy, } from "./dashboard-copy.js";
4
+ const APP_JAVASCRIPT_CANDIDATES = [
5
+ "./live-dashboard-app/app.js",
6
+ "../../dist/src/gateway/live-dashboard-app/app.js",
7
+ ];
8
+ const VENDOR_REACT_CANDIDATES = [
9
+ "../../../assets/vendor/react/react.production.min.js",
10
+ "../../assets/vendor/react/react.production.min.js",
11
+ ];
12
+ const VENDOR_REACT_DOM_CANDIDATES = [
13
+ "../../../assets/vendor/react/react-dom.production.min.js",
14
+ "../../assets/vendor/react/react-dom.production.min.js",
15
+ ];
16
+ const STYLE_SHEET_CANDIDATES = [
17
+ "../../../assets/live-dashboard/app.css",
18
+ "../../assets/live-dashboard/app.css",
19
+ ];
20
+ function readBundledAsset(candidates) {
21
+ for (const rel of candidates) {
22
+ try {
23
+ return readFileSync(new URL(rel, import.meta.url), "utf8");
24
+ }
25
+ catch {
26
+ // Try the next candidate location.
27
+ }
28
+ }
29
+ throw new BridgeError("LIVE_DASHBOARD_ASSET_MISSING", `A bundled live dashboard asset is missing; looked for: ${candidates.join(", ")} (relative to ${import.meta.url}).`);
30
+ }
31
+ function escapeHtml(value) {
32
+ return value
33
+ .replaceAll("&", "&amp;")
34
+ .replaceAll('"', "&quot;")
35
+ .replaceAll("<", "&lt;")
36
+ .replaceAll(">", "&gt;");
37
+ }
38
+ function shell(locale) {
39
+ const copy = getDashboardCopy(locale);
40
+ return `<!doctype html>
41
+ <html lang="${locale}"><head><meta charset="utf-8">
42
+ <meta name="viewport" content="width=device-width,initial-scale=1">
43
+ <meta name="referrer" content="no-referrer">
44
+ <title>${escapeHtml(copy["live.title"])}</title>
45
+ <link rel="stylesheet" href="app.css">
46
+ <script defer src="react.js"></script>
47
+ <script defer src="react-dom.js"></script>
48
+ <script defer src="client.js"></script>
49
+ <script defer src="app.js"></script>
50
+ </head><body><div id="root" aria-live="off"></div>
51
+ <noscript>${escapeHtml(copy["live.noscript"])}</noscript></body></html>`;
52
+ }
53
+ function client(locale) {
54
+ const copies = {
55
+ en: getDashboardCopy("en"),
56
+ "zh-CN": getDashboardCopy("zh-CN"),
57
+ };
58
+ return `"use strict";
59
+ window.EMBASSY_BOOT=Object.freeze({locale:${JSON.stringify(locale)},copy:Object.freeze({en:Object.freeze(${JSON.stringify(copies.en)}),"zh-CN":Object.freeze(${JSON.stringify(copies["zh-CN"])})})});
60
+ `;
61
+ }
62
+ export function renderLiveDashboardAssets(locale) {
63
+ assertDashboardLocale(locale);
64
+ return {
65
+ shellHtml: shell(locale),
66
+ clientJavaScript: client(locale),
67
+ styleSheet: readBundledAsset(STYLE_SHEET_CANDIDATES),
68
+ appJavaScript: readBundledAsset(APP_JAVASCRIPT_CANDIDATES),
69
+ vendorReactJavaScript: readBundledAsset(VENDOR_REACT_CANDIDATES),
70
+ vendorReactDomJavaScript: readBundledAsset(VENDOR_REACT_DOM_CANDIDATES),
71
+ };
72
+ }
73
+ //# sourceMappingURL=live-dashboard-assets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live-dashboard-assets.js","sourceRoot":"","sources":["../../../src/gateway/live-dashboard-assets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EACL,qBAAqB,EACrB,gBAAgB,GAEjB,MAAM,qBAAqB,CAAC;AAW7B,MAAM,yBAAyB,GAAsB;IACnD,6BAA6B;IAC7B,kDAAkD;CACnD,CAAC;AAEF,MAAM,uBAAuB,GAAsB;IACjD,sDAAsD;IACtD,mDAAmD;CACpD,CAAC;AAEF,MAAM,2BAA2B,GAAsB;IACrD,0DAA0D;IAC1D,uDAAuD;CACxD,CAAC;AAEF,MAAM,sBAAsB,GAAsB;IAChD,wCAAwC;IACxC,qCAAqC;CACtC,CAAC;AAEF,SAAS,gBAAgB,CAAC,UAA6B;IACrD,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,OAAO,YAAY,CAAC,IAAI,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;QAC7D,CAAC;QAAC,MAAM,CAAC;YACP,mCAAmC;QACrC,CAAC;IACH,CAAC;IACD,MAAM,IAAI,WAAW,CACnB,8BAA8B,EAC9B,0DAA0D,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CACpH,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,KAAK;SACT,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC;SACxB,UAAU,CAAC,GAAG,EAAE,QAAQ,CAAC;SACzB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC;SACvB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AAC7B,CAAC;AAED,SAAS,KAAK,CAAC,MAAuB;IACpC,MAAM,IAAI,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACtC,OAAO;cACK,MAAM;;;SAGX,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;;;;;;;YAO3B,UAAU,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,2BAA2B,CAAC;AACzE,CAAC;AAED,SAAS,MAAM,CAAC,MAAuB;IACrC,MAAM,MAAM,GAAG;QACb,EAAE,EAAE,gBAAgB,CAAC,IAAI,CAAC;QAC1B,OAAO,EAAE,gBAAgB,CAAC,OAAO,CAAC;KACnC,CAAC;IACF,OAAO;4CACmC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,yCAAyC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,2BAA2B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;CAC7L,CAAC;AACF,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,MAAuB;IAEvB,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAC9B,OAAO;QACL,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC;QACxB,gBAAgB,EAAE,MAAM,CAAC,MAAM,CAAC;QAChC,UAAU,EAAE,gBAAgB,CAAC,sBAAsB,CAAC;QACpD,aAAa,EAAE,gBAAgB,CAAC,yBAAyB,CAAC;QAC1D,qBAAqB,EAAE,gBAAgB,CAAC,uBAAuB,CAAC;QAChE,wBAAwB,EAAE,gBAAgB,CAAC,2BAA2B,CAAC;KACxE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,36 @@
1
+ import { type FileHandle } from "node:fs/promises";
2
+ import { type DashboardLocale } from "./dashboard-copy.js";
3
+ export type LiveDashboardRandomBytes = (size: number) => Uint8Array;
4
+ export type LiveDashboardFileStat = Readonly<{
5
+ dev: number;
6
+ ino: number;
7
+ mode: number;
8
+ isDirectory(): boolean;
9
+ isFile(): boolean;
10
+ isSymbolicLink(): boolean;
11
+ }>;
12
+ export type LiveDashboardFileHandle = Pick<FileHandle, "writeFile" | "sync" | "stat" | "close">;
13
+ export type LiveDashboardFileSystem = Readonly<{
14
+ lstat(pathname: string): Promise<LiveDashboardFileStat>;
15
+ mkdir(pathname: string, options: {
16
+ mode: number;
17
+ }): Promise<void>;
18
+ open(pathname: string, flags: "wx", mode: number): Promise<LiveDashboardFileHandle>;
19
+ readdir(pathname: string): Promise<string[]>;
20
+ realpath(pathname: string): Promise<string>;
21
+ unlink(pathname: string): Promise<void>;
22
+ rmdir(pathname: string): Promise<void>;
23
+ }>;
24
+ export declare const defaultLiveDashboardFileSystem: LiveDashboardFileSystem;
25
+ export type LiveDashboardBootstrapArtifacts = Readonly<{
26
+ bootstrapPath: string;
27
+ capability: string;
28
+ close(): Promise<void>;
29
+ }>;
30
+ export declare function createLiveDashboardBootstrap(options: Readonly<{
31
+ privateStateRoot: string;
32
+ bootstrapTargetWithoutFragment: string;
33
+ lang: DashboardLocale;
34
+ fileSystem?: LiveDashboardFileSystem;
35
+ random?: LiveDashboardRandomBytes;
36
+ }>): Promise<LiveDashboardBootstrapArtifacts>;
@@ -0,0 +1,176 @@
1
+ import { randomBytes } from "node:crypto";
2
+ import { lstat, mkdir, open, readdir, realpath, rmdir, unlink, } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { assertDashboardLocale, getDashboardCopy, } from "./dashboard-copy.js";
5
+ export const defaultLiveDashboardFileSystem = {
6
+ lstat,
7
+ mkdir: async (pathname, options) => {
8
+ await mkdir(pathname, options);
9
+ },
10
+ open,
11
+ readdir,
12
+ realpath,
13
+ unlink,
14
+ rmdir,
15
+ };
16
+ function identity(stat) {
17
+ return { device: stat.dev, inode: stat.ino };
18
+ }
19
+ function sameIdentity(stat, expected) {
20
+ return stat.dev === expected.device && stat.ino === expected.inode;
21
+ }
22
+ function base64Url(bytes) {
23
+ return Buffer.from(bytes).toString("base64url");
24
+ }
25
+ function escapeHtml(value) {
26
+ return value
27
+ .replaceAll("&", "&amp;")
28
+ .replaceAll('"', "&quot;")
29
+ .replaceAll("<", "&lt;")
30
+ .replaceAll(">", "&gt;");
31
+ }
32
+ function bootstrapDocument(target, lang) {
33
+ const copy = getDashboardCopy(lang);
34
+ const escaped = escapeHtml(target);
35
+ return `<!doctype html>
36
+ <html lang="${lang}"><head><meta charset="utf-8"><meta name="referrer" content="no-referrer"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; navigate-to http://127.0.0.1:*"><meta http-equiv="refresh" content="0;url=${escaped}"><title>${escapeHtml(copy["live.bootstrap.title"])}</title></head><body><p><a rel="noreferrer" href="${escaped}">${escapeHtml(copy["live.bootstrap.open"])}</a></p></body></html>`;
37
+ }
38
+ export async function createLiveDashboardBootstrap(options) {
39
+ assertDashboardLocale(options.lang);
40
+ const fileSystem = options.fileSystem ?? defaultLiveDashboardFileSystem;
41
+ const random = options.random ?? randomBytes;
42
+ const targetMatch = /^http:\/\/127\.0\.0\.1:([1-9][0-9]{0,4})\/[A-Za-z0-9_-]{16,128}\/bootstrap$/u.exec(options.bootstrapTargetWithoutFragment);
43
+ if (targetMatch === null || Number(targetMatch[1]) > 65_535) {
44
+ throw new Error("LIVE_DASHBOARD_BOOTSTRAP_TARGET_INVALID");
45
+ }
46
+ const requestedRoot = path.resolve(options.privateStateRoot);
47
+ const rootPath = await fileSystem.realpath(requestedRoot);
48
+ const rootStat = await fileSystem.lstat(rootPath);
49
+ if (!rootStat.isDirectory() ||
50
+ rootStat.isSymbolicLink() ||
51
+ (rootStat.mode & 0o077) !== 0) {
52
+ throw new Error("LIVE_DASHBOARD_STATE_ROOT_NOT_PRIVATE");
53
+ }
54
+ let runDirectory = "";
55
+ let runIdentity;
56
+ for (let attempt = 0; attempt < 4; attempt += 1) {
57
+ const name = `live-${base64Url(random(16))}`;
58
+ if (!/^live-[A-Za-z0-9_-]{22}$/u.test(name)) {
59
+ throw new Error("LIVE_DASHBOARD_RANDOM_SOURCE_INVALID");
60
+ }
61
+ const candidate = path.join(rootPath, name);
62
+ try {
63
+ await fileSystem.mkdir(candidate, { mode: 0o700 });
64
+ const candidateStat = await fileSystem.lstat(candidate);
65
+ if (!candidateStat.isDirectory() ||
66
+ candidateStat.isSymbolicLink() ||
67
+ (candidateStat.mode & 0o077) !== 0) {
68
+ throw new Error("LIVE_DASHBOARD_RUN_DIRECTORY_NOT_PRIVATE");
69
+ }
70
+ runDirectory = candidate;
71
+ runIdentity = identity(candidateStat);
72
+ break;
73
+ }
74
+ catch (error) {
75
+ if (typeof error === "object" &&
76
+ error !== null &&
77
+ "code" in error &&
78
+ error.code === "EEXIST") {
79
+ continue;
80
+ }
81
+ throw error;
82
+ }
83
+ }
84
+ if (runIdentity === undefined) {
85
+ throw new Error("LIVE_DASHBOARD_RUN_DIRECTORY_COLLISION");
86
+ }
87
+ const capability = base64Url(random(32));
88
+ if (!/^[A-Za-z0-9_-]{43}$/u.test(capability)) {
89
+ throw new Error("LIVE_DASHBOARD_RANDOM_SOURCE_INVALID");
90
+ }
91
+ const target = `${options.bootstrapTargetWithoutFragment}#${capability}`;
92
+ const bootstrapPath = path.join(runDirectory, "bootstrap.html");
93
+ let handle;
94
+ let bootstrapIdentity;
95
+ try {
96
+ handle = await fileSystem.open(bootstrapPath, "wx", 0o600);
97
+ const openedStat = await handle.stat();
98
+ if (!openedStat.isFile() ||
99
+ openedStat.isSymbolicLink() ||
100
+ (openedStat.mode & 0o177) !== 0) {
101
+ throw new Error("LIVE_DASHBOARD_BOOTSTRAP_NOT_PRIVATE");
102
+ }
103
+ bootstrapIdentity = identity(openedStat);
104
+ await handle.writeFile(bootstrapDocument(target, options.lang), {
105
+ encoding: "utf8",
106
+ });
107
+ await handle.sync();
108
+ await handle.close();
109
+ handle = undefined;
110
+ const bootstrapStat = await fileSystem.lstat(bootstrapPath);
111
+ if (!bootstrapStat.isFile() ||
112
+ bootstrapStat.isSymbolicLink() ||
113
+ (bootstrapStat.mode & 0o177) !== 0) {
114
+ throw new Error("LIVE_DASHBOARD_BOOTSTRAP_NOT_PRIVATE");
115
+ }
116
+ if (!sameIdentity(bootstrapStat, bootstrapIdentity)) {
117
+ throw new Error("LIVE_DASHBOARD_BOOTSTRAP_REPLACED");
118
+ }
119
+ }
120
+ catch (error) {
121
+ await handle?.close().catch(() => undefined);
122
+ try {
123
+ const currentRun = await fileSystem.lstat(runDirectory);
124
+ if (sameIdentity(currentRun, runIdentity)) {
125
+ const entries = await fileSystem.readdir(runDirectory);
126
+ if (entries.length === 1 && entries[0] === "bootstrap.html") {
127
+ const currentBootstrap = await fileSystem.lstat(bootstrapPath);
128
+ if (bootstrapIdentity !== undefined &&
129
+ sameIdentity(currentBootstrap, bootstrapIdentity) &&
130
+ currentBootstrap.isFile() &&
131
+ !currentBootstrap.isSymbolicLink()) {
132
+ await fileSystem.unlink(bootstrapPath);
133
+ }
134
+ }
135
+ if ((await fileSystem.readdir(runDirectory)).length === 0) {
136
+ await fileSystem.rmdir(runDirectory);
137
+ }
138
+ }
139
+ }
140
+ catch {
141
+ // Never broaden cleanup after a startup error. A private empty artifact
142
+ // is preferable to deleting a path whose exact ownership changed.
143
+ }
144
+ throw error;
145
+ }
146
+ let closed = false;
147
+ return {
148
+ bootstrapPath,
149
+ capability,
150
+ close: async () => {
151
+ if (closed)
152
+ return;
153
+ const currentRun = await fileSystem.lstat(runDirectory);
154
+ if (!sameIdentity(currentRun, runIdentity) ||
155
+ !currentRun.isDirectory() ||
156
+ currentRun.isSymbolicLink()) {
157
+ throw new Error("LIVE_DASHBOARD_RUN_DIRECTORY_REPLACED");
158
+ }
159
+ const entries = await fileSystem.readdir(runDirectory);
160
+ if (entries.length !== 1 || entries[0] !== "bootstrap.html") {
161
+ throw new Error("LIVE_DASHBOARD_RUN_DIRECTORY_NOT_EXACT_OWNED");
162
+ }
163
+ const currentBootstrap = await fileSystem.lstat(bootstrapPath);
164
+ if (bootstrapIdentity === undefined ||
165
+ !sameIdentity(currentBootstrap, bootstrapIdentity) ||
166
+ !currentBootstrap.isFile() ||
167
+ currentBootstrap.isSymbolicLink()) {
168
+ throw new Error("LIVE_DASHBOARD_BOOTSTRAP_REPLACED");
169
+ }
170
+ await fileSystem.unlink(bootstrapPath);
171
+ await fileSystem.rmdir(runDirectory);
172
+ closed = true;
173
+ },
174
+ };
175
+ }
176
+ //# sourceMappingURL=live-dashboard-bootstrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live-dashboard-bootstrap.js","sourceRoot":"","sources":["../../../src/gateway/live-dashboard-bootstrap.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ import type { DashboardLocale } from "./dashboard-copy.js";
2
+ import { type GatewayConfig } from "./config.js";
3
+ import { type GatewayControlMethod, type GatewayControlResponse, type SendGatewayControlRequestOptions } from "./control.js";
4
+ import { type RunningLiveDashboard, type StartLiveDashboardOptions } from "./live-dashboard.js";
5
+ import type { LiveDashboardActionExecutor } from "./live-dashboard-http.js";
6
+ import type { LiveDashboardObserver } from "./live-dashboard-stream.js";
7
+ declare const OPEN_EXECUTABLE = "/usr/bin/open";
8
+ declare const OPEN_TIMEOUT_MS = 10000;
9
+ declare const OPEN_MAX_OUTPUT_BYTES: number;
10
+ type GatewaySignal = "SIGINT" | "SIGTERM";
11
+ export type LiveDashboardReadyResult = Readonly<{
12
+ status: "ready";
13
+ mode: "live";
14
+ locale: DashboardLocale;
15
+ }>;
16
+ export type LiveDashboardCommandOutcome = Readonly<{
17
+ status: "cancelled";
18
+ }>;
19
+ export type LiveDashboardCommandOptions = Readonly<{
20
+ env?: NodeJS.ProcessEnv;
21
+ locale: DashboardLocale;
22
+ signal?: AbortSignal;
23
+ onReady: (result: LiveDashboardReadyResult) => void | Promise<void>;
24
+ loadConfig?: (env: NodeJS.ProcessEnv) => GatewayConfig;
25
+ validateControlSocket: (stateDir: string, socketPath: string) => Promise<void>;
26
+ sendRequest?: GatewayControlSender;
27
+ }>;
28
+ type GatewayControlSender = <M extends GatewayControlMethod>(options: SendGatewayControlRequestOptions<M>) => Promise<GatewayControlResponse<M>>;
29
+ type OpenExecutor = (executable: typeof OPEN_EXECUTABLE, args: readonly [string], options: Readonly<{
30
+ cwd: "/";
31
+ env: Readonly<Record<string, string>>;
32
+ shell: false;
33
+ timeout: typeof OPEN_TIMEOUT_MS;
34
+ maxBuffer: typeof OPEN_MAX_OUTPUT_BYTES;
35
+ windowsHide: true;
36
+ signal: AbortSignal;
37
+ }>) => Promise<void>;
38
+ export type LiveDashboardCommandDependencies = Readonly<{
39
+ startDashboard?: (options: StartLiveDashboardOptions) => Promise<RunningLiveDashboard>;
40
+ executeOpen?: OpenExecutor;
41
+ addSignalListener?: (signal: GatewaySignal, listener: () => void) => void;
42
+ removeSignalListener?: (signal: GatewaySignal, listener: () => void) => void;
43
+ }>;
44
+ export declare function createGatewayLiveDashboardObserver(socketPath: string, sendRequest?: GatewayControlSender): LiveDashboardObserver;
45
+ export declare function createGatewayLiveDashboardActions(socketPath: string, sendRequest?: GatewayControlSender): LiveDashboardActionExecutor;
46
+ /**
47
+ * Run the opt-in live dashboard in the foreground until interrupted.
48
+ *
49
+ * The controller remains the only source of state. This command exposes one
50
+ * observer plus three closed, authenticated actions; it has no provider API
51
+ * or generic control-plane escape hatch.
52
+ */
53
+ export declare function runLiveDashboardCommand(options: LiveDashboardCommandOptions, dependencies?: LiveDashboardCommandDependencies): Promise<LiveDashboardCommandOutcome>;
54
+ export {};