agent-embassy 1.2.0 → 1.3.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.
- package/CHANGELOG.md +24 -0
- package/CONTRIBUTING.md +25 -7
- package/README.md +20 -12
- package/README.zh-CN.md +14 -13
- package/SECURITY.md +55 -41
- package/dist/src/gateway/claude-helper-supervisor.js +0 -1
- package/dist/src/gateway/claude-helper-supervisor.js.map +1 -1
- package/dist/src/gateway/claude-runtime.d.ts +0 -2
- package/dist/src/gateway/claude-runtime.js +6 -17
- package/dist/src/gateway/claude-runtime.js.map +1 -1
- package/dist/src/gateway/cli-copy.d.ts +1 -1
- package/dist/src/gateway/cli-copy.en.d.ts +3 -1
- package/dist/src/gateway/cli-copy.en.js +5 -3
- package/dist/src/gateway/cli-copy.en.js.map +1 -1
- package/dist/src/gateway/cli-copy.js +2 -0
- package/dist/src/gateway/cli-copy.js.map +1 -1
- package/dist/src/gateway/cli-copy.zh-CN.d.ts +3 -1
- package/dist/src/gateway/cli-copy.zh-CN.js +5 -3
- package/dist/src/gateway/cli-copy.zh-CN.js.map +1 -1
- package/dist/src/gateway/cli.d.ts +2 -5
- package/dist/src/gateway/cli.js +30 -67
- package/dist/src/gateway/cli.js.map +1 -1
- package/dist/src/gateway/codex-app-server.d.ts +1 -7
- package/dist/src/gateway/codex-app-server.js +5 -52
- package/dist/src/gateway/codex-app-server.js.map +1 -1
- package/dist/src/gateway/codex-local-transport.d.ts +4 -10
- package/dist/src/gateway/codex-local-transport.js +13 -16
- package/dist/src/gateway/codex-local-transport.js.map +1 -1
- package/dist/src/gateway/compatibility.d.ts +0 -27
- package/dist/src/gateway/compatibility.js +1 -101
- package/dist/src/gateway/compatibility.js.map +1 -1
- package/dist/src/gateway/config.d.ts +0 -3
- package/dist/src/gateway/config.js +0 -10
- package/dist/src/gateway/config.js.map +1 -1
- package/dist/src/gateway/control.d.ts +1 -20
- package/dist/src/gateway/control.js +2 -33
- package/dist/src/gateway/control.js.map +1 -1
- package/dist/src/gateway/dashboard-copy.d.ts +1 -1
- package/dist/src/gateway/dashboard-copy.en.d.ts +6 -7
- package/dist/src/gateway/dashboard-copy.en.js +15 -16
- package/dist/src/gateway/dashboard-copy.en.js.map +1 -1
- package/dist/src/gateway/dashboard-copy.js +6 -7
- package/dist/src/gateway/dashboard-copy.js.map +1 -1
- package/dist/src/gateway/dashboard-copy.zh-CN.d.ts +6 -7
- package/dist/src/gateway/dashboard-copy.zh-CN.js +15 -16
- package/dist/src/gateway/dashboard-copy.zh-CN.js.map +1 -1
- package/dist/src/gateway/dashboard-model.d.ts +3 -7
- package/dist/src/gateway/dashboard-model.js +41 -16
- package/dist/src/gateway/dashboard-model.js.map +1 -1
- package/dist/src/gateway/dashboard.js +5 -7
- package/dist/src/gateway/dashboard.js.map +1 -1
- package/dist/src/gateway/live-dashboard-app/app.js +17 -45
- package/dist/src/gateway/live-dashboard-command.d.ts +5 -1
- package/dist/src/gateway/live-dashboard-command.js +8 -6
- package/dist/src/gateway/live-dashboard-command.js.map +1 -1
- package/dist/src/gateway/live-dashboard-http.d.ts +0 -4
- package/dist/src/gateway/live-dashboard-http.js +19 -93
- package/dist/src/gateway/live-dashboard-http.js.map +1 -1
- package/dist/src/gateway/live-dashboard-protocol.d.ts +1 -5
- package/dist/src/gateway/live-dashboard-protocol.js +0 -42
- package/dist/src/gateway/live-dashboard-protocol.js.map +1 -1
- package/dist/src/gateway/live-dashboard-server.d.ts +2 -2
- package/dist/src/gateway/live-dashboard-server.js +18 -4
- package/dist/src/gateway/live-dashboard-server.js.map +1 -1
- package/dist/src/gateway/live-dashboard.d.ts +3 -6
- package/dist/src/gateway/live-dashboard.js +6 -42
- package/dist/src/gateway/live-dashboard.js.map +1 -1
- package/dist/src/gateway/provenance-envelope.js +1 -1
- package/dist/src/gateway/provenance-envelope.js.map +1 -1
- package/dist/src/gateway/providers.d.ts +1 -21
- package/dist/src/gateway/providers.js +15 -261
- package/dist/src/gateway/providers.js.map +1 -1
- package/dist/src/gateway/server.js +0 -3
- package/dist/src/gateway/server.js.map +1 -1
- package/dist/src/gateway/service.d.ts +3 -15
- package/dist/src/gateway/service.js +76 -257
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/store.js +76 -18
- package/dist/src/gateway/store.js.map +1 -1
- package/dist/src/gateway/types.d.ts +0 -4
- package/dist/src/gateway/types.js.map +1 -1
- package/docs/GATEWAY-ARCHITECTURE.md +75 -63
- package/package.json +1 -1
- package/skills/embassy-peer/SKILL.md +25 -10
- package/dist/src/gateway/claude-compatibility-scratch.d.ts +0 -18
- package/dist/src/gateway/claude-compatibility-scratch.js +0 -158
- package/dist/src/gateway/claude-compatibility-scratch.js.map +0 -1
- package/dist/src/gateway/live-dashboard-bootstrap.d.ts +0 -36
- package/dist/src/gateway/live-dashboard-bootstrap.js +0 -176
- package/dist/src/gateway/live-dashboard-bootstrap.js.map +0 -1
- package/docs/DESIGN.md +0 -134
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
import { randomBytes, randomUUID } from "node:crypto";
|
|
2
|
-
import { spawn as nodeSpawn, } from "node:child_process";
|
|
3
|
-
import os from "node:os";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import { BridgeError } from "../errors.js";
|
|
6
|
-
const MAX_SCRATCH_OUTPUT_BYTES = 64 * 1024;
|
|
7
|
-
const SCRATCH_START_TIMEOUT_MS = 2_000;
|
|
8
|
-
const SCRATCH_CLOSE_TIMEOUT_MS = 2_000;
|
|
9
|
-
function waitForSpawn(child) {
|
|
10
|
-
return new Promise((resolve, reject) => {
|
|
11
|
-
const timer = setTimeout(() => {
|
|
12
|
-
cleanup();
|
|
13
|
-
reject(new Error("scratch spawn timeout"));
|
|
14
|
-
}, SCRATCH_START_TIMEOUT_MS);
|
|
15
|
-
timer.unref();
|
|
16
|
-
const cleanup = () => {
|
|
17
|
-
clearTimeout(timer);
|
|
18
|
-
child.off("spawn", onSpawn);
|
|
19
|
-
child.off("error", onError);
|
|
20
|
-
child.off("exit", onExit);
|
|
21
|
-
};
|
|
22
|
-
const onSpawn = () => {
|
|
23
|
-
cleanup();
|
|
24
|
-
resolve();
|
|
25
|
-
};
|
|
26
|
-
const onError = (error) => {
|
|
27
|
-
cleanup();
|
|
28
|
-
reject(error);
|
|
29
|
-
};
|
|
30
|
-
const onExit = () => {
|
|
31
|
-
cleanup();
|
|
32
|
-
reject(new Error("scratch exited before ready"));
|
|
33
|
-
};
|
|
34
|
-
child.once("spawn", onSpawn);
|
|
35
|
-
child.once("error", onError);
|
|
36
|
-
child.once("exit", onExit);
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
function waitForExit(child, timeoutMs) {
|
|
40
|
-
if (child.exitCode !== null || child.signalCode !== null) {
|
|
41
|
-
return Promise.resolve(true);
|
|
42
|
-
}
|
|
43
|
-
return new Promise((resolve) => {
|
|
44
|
-
const timer = setTimeout(() => {
|
|
45
|
-
cleanup();
|
|
46
|
-
resolve(false);
|
|
47
|
-
}, timeoutMs);
|
|
48
|
-
timer.unref();
|
|
49
|
-
const cleanup = () => {
|
|
50
|
-
clearTimeout(timer);
|
|
51
|
-
child.off("exit", onExit);
|
|
52
|
-
};
|
|
53
|
-
const onExit = () => {
|
|
54
|
-
cleanup();
|
|
55
|
-
resolve(true);
|
|
56
|
-
};
|
|
57
|
-
child.once("exit", onExit);
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
export async function startClaudeCompatibilityScratch(runtime, dependencies = {}) {
|
|
61
|
-
const user = (dependencies.userInfo ?? os.userInfo)();
|
|
62
|
-
if (!path.isAbsolute(user.homedir) ||
|
|
63
|
-
path.normalize(user.homedir) !== user.homedir ||
|
|
64
|
-
user.homedir.includes("\0") ||
|
|
65
|
-
!/^[A-Za-z0-9._-]{1,128}$/.test(user.username)) {
|
|
66
|
-
throw new BridgeError("CLAUDE_CERTIFICATION_USER_INVALID", "The bounded Claude certification scratch requires one canonical local user.");
|
|
67
|
-
}
|
|
68
|
-
const sessionId = randomUUID();
|
|
69
|
-
const name = `embassy-compat-${randomBytes(6).toString("hex")}`;
|
|
70
|
-
const args = [
|
|
71
|
-
"--print",
|
|
72
|
-
"--input-format",
|
|
73
|
-
"stream-json",
|
|
74
|
-
"--output-format",
|
|
75
|
-
"stream-json",
|
|
76
|
-
"--verbose",
|
|
77
|
-
"--session-id",
|
|
78
|
-
sessionId,
|
|
79
|
-
"--name",
|
|
80
|
-
name,
|
|
81
|
-
"--safe-mode",
|
|
82
|
-
"--tools",
|
|
83
|
-
"",
|
|
84
|
-
"--strict-mcp-config",
|
|
85
|
-
"--no-session-persistence",
|
|
86
|
-
"--permission-mode",
|
|
87
|
-
"dontAsk",
|
|
88
|
-
"--settings",
|
|
89
|
-
'{"crossSessionInbound":"accept"}',
|
|
90
|
-
];
|
|
91
|
-
const spawn = dependencies.spawn ??
|
|
92
|
-
((command, argv, options) => nodeSpawn(command, [...argv], options));
|
|
93
|
-
let child;
|
|
94
|
-
try {
|
|
95
|
-
child = spawn(runtime.claudeExecutable, args, {
|
|
96
|
-
cwd: user.homedir,
|
|
97
|
-
detached: false,
|
|
98
|
-
env: {
|
|
99
|
-
HOME: user.homedir,
|
|
100
|
-
USER: user.username,
|
|
101
|
-
LOGNAME: user.username,
|
|
102
|
-
SHELL: "/bin/zsh",
|
|
103
|
-
PATH: "/usr/bin:/bin:/usr/sbin:/sbin",
|
|
104
|
-
TMPDIR: os.tmpdir(),
|
|
105
|
-
},
|
|
106
|
-
shell: false,
|
|
107
|
-
stdio: "pipe",
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
catch {
|
|
111
|
-
throw new BridgeError("CLAUDE_CERTIFICATION_SCRATCH_UNAVAILABLE", "The bounded Claude certification scratch could not start.", true);
|
|
112
|
-
}
|
|
113
|
-
let outputBytes = 0;
|
|
114
|
-
let outputOverflow = false;
|
|
115
|
-
const observeOutput = (chunk) => {
|
|
116
|
-
outputBytes += Buffer.byteLength(chunk);
|
|
117
|
-
if (outputBytes > MAX_SCRATCH_OUTPUT_BYTES && !outputOverflow) {
|
|
118
|
-
outputOverflow = true;
|
|
119
|
-
child.kill("SIGTERM");
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
child.stdout.on("data", observeOutput);
|
|
123
|
-
child.stderr.on("data", observeOutput);
|
|
124
|
-
try {
|
|
125
|
-
await waitForSpawn(child);
|
|
126
|
-
}
|
|
127
|
-
catch {
|
|
128
|
-
child.kill("SIGKILL");
|
|
129
|
-
await waitForExit(child, SCRATCH_CLOSE_TIMEOUT_MS);
|
|
130
|
-
throw new BridgeError("CLAUDE_CERTIFICATION_SCRATCH_UNAVAILABLE", "The bounded Claude certification scratch did not become ready.", true);
|
|
131
|
-
}
|
|
132
|
-
let closeOperation;
|
|
133
|
-
return {
|
|
134
|
-
name,
|
|
135
|
-
sessionId,
|
|
136
|
-
assertRunning: () => {
|
|
137
|
-
if (outputOverflow ||
|
|
138
|
-
child.exitCode !== null ||
|
|
139
|
-
child.signalCode !== null) {
|
|
140
|
-
throw new BridgeError("CLAUDE_CERTIFICATION_SCRATCH_EXITED", "The bounded Claude certification scratch exited before settlement.", true);
|
|
141
|
-
}
|
|
142
|
-
},
|
|
143
|
-
close: () => {
|
|
144
|
-
closeOperation ??= (async () => {
|
|
145
|
-
child.stdin.end();
|
|
146
|
-
if (await waitForExit(child, SCRATCH_CLOSE_TIMEOUT_MS))
|
|
147
|
-
return;
|
|
148
|
-
child.kill("SIGTERM");
|
|
149
|
-
if (await waitForExit(child, SCRATCH_CLOSE_TIMEOUT_MS))
|
|
150
|
-
return;
|
|
151
|
-
child.kill("SIGKILL");
|
|
152
|
-
await waitForExit(child, SCRATCH_CLOSE_TIMEOUT_MS);
|
|
153
|
-
})();
|
|
154
|
-
return closeOperation;
|
|
155
|
-
},
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
//# sourceMappingURL=claude-compatibility-scratch.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"claude-compatibility-scratch.js","sourceRoot":"","sources":["../../../src/gateway/claude-compatibility-scratch.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,36 +0,0 @@
|
|
|
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>;
|
|
@@ -1,176 +0,0 @@
|
|
|
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("&", "&")
|
|
28
|
-
.replaceAll('"', """)
|
|
29
|
-
.replaceAll("<", "<")
|
|
30
|
-
.replaceAll(">", ">");
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"live-dashboard-bootstrap.js","sourceRoot":"","sources":["../../../src/gateway/live-dashboard-bootstrap.ts"],"names":[],"mappings":"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"}
|
package/docs/DESIGN.md
DELETED
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
# Embassy Design System — "Porcelain & Seal"
|
|
2
|
-
|
|
3
|
-
Canon for every user surface: marketing site, dashboard, README visuals, mark,
|
|
4
|
-
and social imagery. One token system; no surface invents its own values.
|
|
5
|
-
Agreed jointly (PM + engineering) 2026-08-08.
|
|
6
|
-
|
|
7
|
-
> **PM amendment — 2026-08-09 (the warm/arch era).** The visual identity
|
|
8
|
-
> moved on from this document's imagery on the operator's direction; the
|
|
9
|
-
> honesty rules below remain canon, the imagery sections are historical.
|
|
10
|
-
> What ships today: the **gate/archway mark** with an amber glow and pennant
|
|
11
|
-
> (`assets/embassy-logo/mark.svg`, badge and lockup alongside; the tent
|
|
12
|
-
> variants at `assets/mark.svg` / `assets/mark-seal.svg` remain as favicon
|
|
13
|
-
> until superseded); the **warm anime banner** — three chibi agent mascots
|
|
14
|
-
> exchanging envelopes before the glowing arch (`assets/social-preview.png`,
|
|
15
|
-
> brief in `docs/BANNER-BRIEF.md`); and the **live dashboard's Cohere-token
|
|
16
|
-
> chip system** (`assets/live-dashboard/app.css`) in place of the porcelain
|
|
17
|
-
> palette and seal/receipt iconography described below — state is carried by
|
|
18
|
-
> tinted chips (progress stone, positive green, qualified outline,
|
|
19
|
-
> indeterminate purple, warning coral, failure red, inert outline), with the
|
|
20
|
-
> same rules: progress is never green, `released` ≠ read, refusals are not
|
|
21
|
-
> failures, and the brand accent is never a state color. A successor canon
|
|
22
|
-
> document for the warm era is owed; until then, treat BANNER-BRIEF.md plus
|
|
23
|
-
> the shipped dashboard tokens as the working truth for imagery and color.
|
|
24
|
-
|
|
25
|
-
## Idea
|
|
26
|
-
|
|
27
|
-
Embassy's brand is the **receipt** — the seal that records a message
|
|
28
|
-
crossing a boundary and how delivery settled. (A settlement record, not
|
|
29
|
-
cryptographic proof: today `delivered` can mean the receiving App Server
|
|
30
|
-
accepted the turn, not that the model consumed or completed it. Copy on any
|
|
31
|
-
surface must never claim more than this.) The visual world is a light, unhurried diplomatic
|
|
32
|
-
register: porcelain paper, near-black ink, hairline rules, and exactly one
|
|
33
|
-
decisive color — seal red. Abstract, artistic, calm. No buildings, no flags,
|
|
34
|
-
no vendor colors, no circuit-board "AI" imagery.
|
|
35
|
-
|
|
36
|
-
## Tokens
|
|
37
|
-
|
|
38
|
-
### Color
|
|
39
|
-
|
|
40
|
-
| Token | Value | Use |
|
|
41
|
-
| --- | --- | --- |
|
|
42
|
-
| `--porcelain` | `#f8f4ec` | Page ground |
|
|
43
|
-
| `--porcelain-raise` | `#fffdf8` | Cards, panels |
|
|
44
|
-
| `--ink` | `#231f1a` | Primary text |
|
|
45
|
-
| `--ink-soft` | `#6d6558` | Secondary text |
|
|
46
|
-
| `--rule` | `#e4dccd` | Hairlines, borders |
|
|
47
|
-
| `--seal` | `#b3382c` | Brand + one primary action per view — the cinnabar seal. **Never a state color.** |
|
|
48
|
-
| `--jade` | `#557f68` | Healthy / delivered / positive states |
|
|
49
|
-
| `--ochre` | `#a8842f` | Waiting / queued / in-progress states |
|
|
50
|
-
| `--codeblock` | `#262019` | Terminal code blocks only — the one deliberate dark exception |
|
|
51
|
-
|
|
52
|
-
Rules: cinnabar never decorates and never signals any state — it is the brand
|
|
53
|
-
and the single most important action on screen. **There is no second red.**
|
|
54
|
-
Failure is carried by SHAPE (the broken seal) rendered in `--ink`, never by a
|
|
55
|
-
red that would compete with the brand at small sizes. Jade and ochre are
|
|
56
|
-
semantic only and never used decoratively. Dark-mode variants are NOT provided in v1 —
|
|
57
|
-
the light porcelain world is the committed identity (paint every ground
|
|
58
|
-
explicitly; never inherit host backgrounds).
|
|
59
|
-
|
|
60
|
-
### Type
|
|
61
|
-
|
|
62
|
-
| Role | Stack | Treatment |
|
|
63
|
-
| --- | --- | --- |
|
|
64
|
-
| Display | `"Iowan Old Style", "Palatino Nova", Palatino, Georgia, serif` | Large, tight-tracked (−0.01em), `text-wrap: balance` |
|
|
65
|
-
| Body | `-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, sans-serif` | 16–17px / 1.65, max width 65ch |
|
|
66
|
-
| Utility | `ui-monospace, "SF Mono", Menlo, Consolas, monospace` | Commands, receipts, timestamps, stats; `font-variant-numeric: tabular-nums` |
|
|
67
|
-
| Label | Body stack | 11–12px, uppercase, letter-spacing 0.14em, `--ink-soft` (or `--seal` for the active section) |
|
|
68
|
-
|
|
69
|
-
### Space & structure
|
|
70
|
-
|
|
71
|
-
- Base unit 8px; section rhythm 72–96px on the site, 24–32px on the dashboard.
|
|
72
|
-
- Hairline rules (`1px solid --rule`) separate; whitespace groups. Prefer
|
|
73
|
-
asymmetric editorial layouts over centered symmetry on the site.
|
|
74
|
-
- Cards: `--porcelain-raise`, 1px `--rule` border, radius 10px, no shadows
|
|
75
|
-
heavier than `0 1px 2px rgb(35 31 26 / 4%)`.
|
|
76
|
-
- Wide content (tables, code) scrolls in its own container; the page never
|
|
77
|
-
scrolls horizontally.
|
|
78
|
-
|
|
79
|
-
## The mark
|
|
80
|
-
|
|
81
|
-
An abstract seal: a circle holding two facing arcs that shelter a sealed
|
|
82
|
-
center point — the parentheses of a meeting. **No diagonal strokes anywhere**
|
|
83
|
-
(diagonals collapse into an error X at small sizes), **never radial from the
|
|
84
|
-
hub** (reads as a clock), **nothing detached below center** (reads as a
|
|
85
|
-
face). Two parties, one meeting point. At 20px and below, drop the outer
|
|
86
|
-
ring. Sources:
|
|
87
|
-
|
|
88
|
-
- `assets/mark.svg` — ink line version on light grounds.
|
|
89
|
-
- `assets/mark-seal.svg` — solid seal-red disc with porcelain chevrons; used
|
|
90
|
-
for favicon and small sizes (legible at 16px).
|
|
91
|
-
|
|
92
|
-
Receipt iconography derives from the mark: **delivered** = intact seal
|
|
93
|
-
(jade), **queued** = half-drawn seal (ochre), **expired/failed** = broken
|
|
94
|
-
seal (ink — shape carries the failure; no red competes with the brand). The
|
|
95
|
-
brand cinnabar seal itself never marks a state. No other icon family is
|
|
96
|
-
used.
|
|
97
|
-
|
|
98
|
-
## Site first viewport
|
|
99
|
-
|
|
100
|
-
Not an illustration with a title: a compact, authentic message exchange —
|
|
101
|
-
two named agents, the seal at center, a delivered receipt — showing the
|
|
102
|
-
product doing its one thing. Then accreditation/how-it-works, protocol
|
|
103
|
-
truth, real dashboard proof, quickstart/security.
|
|
104
|
-
|
|
105
|
-
## Dashboard information architecture
|
|
106
|
-
|
|
107
|
-
1. **Exchange board** — Claude selection ↔ queue/pouch ↔ Codex registration;
|
|
108
|
-
broker readiness and the next action inline.
|
|
109
|
-
2. **Needs attention** — ordered, actionable, hidden when empty.
|
|
110
|
-
3. **In transit** — queue count, oldest wait, and explicit stall state from the
|
|
111
|
-
bounded public snapshot.
|
|
112
|
-
4. **Activity ledger** — receipt lifecycle; details on demand.
|
|
113
|
-
5. **Sessions & routes** — secondary.
|
|
114
|
-
6. **Compatibility & diagnostics** — collapsed by default.
|
|
115
|
-
|
|
116
|
-
Every alert pairs the state with the exact next command. Raw data lives
|
|
117
|
-
behind the questions, never in front of them. Review lenses: a new user must
|
|
118
|
-
understand purpose / readiness / queue / next action within 10 seconds; a
|
|
119
|
-
protocol expert must verify discovery ≠ selection ≠ registration,
|
|
120
|
-
accepted ≠ delivered, progress ≠ failure, no private data, no overclaims,
|
|
121
|
-
and correct ambiguity/restart/version semantics.
|
|
122
|
-
|
|
123
|
-
## Localization
|
|
124
|
-
|
|
125
|
-
Runtime dashboards, CLI guidance, and native gateway notices render from
|
|
126
|
-
closed, parity-tested `en` / `zh-CN` catalogs. Commands, JSON keys, enums,
|
|
127
|
-
aliases, protocol tags, and safe codes stay English. English remains canonical
|
|
128
|
-
for security meaning. The marketing site and README ship parallel locale
|
|
129
|
-
artifacts rather than changing the runtime protocol.
|
|
130
|
-
|
|
131
|
-
## Review gate
|
|
132
|
-
|
|
133
|
-
Every batch built under this system passes two adversarial reviews — a
|
|
134
|
-
new-user lens and an AI-expert lens — before it ships.
|