claude-simple 0.2.20 → 0.2.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/bin/edge-ctl.js +103 -29
- package/dist/{app.0.2.20.min.js → app.0.2.22.min.js} +97 -98
- package/dist/index.html +2 -2
- package/dist/{style.0.2.20.min.css → style.0.2.22.min.css} +9 -0
- package/package.json +2 -1
- package/public/chat.js +8 -1
- package/public/index.html +4 -2
- package/public/math.js +72 -0
- package/public/mermaid.js +52 -0
- package/public/shell/templates.js +0 -1
- package/public/style.css +9 -0
- package/public/sw.js +5 -3
- package/public/vendor/fonts/KaTeX_AMS-Regular.ttf +0 -0
- package/public/vendor/fonts/KaTeX_AMS-Regular.woff +0 -0
- package/public/vendor/fonts/KaTeX_AMS-Regular.woff2 +0 -0
- package/public/vendor/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
- package/public/vendor/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
- package/public/vendor/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
- package/public/vendor/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
- package/public/vendor/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
- package/public/vendor/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
- package/public/vendor/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
- package/public/vendor/fonts/KaTeX_Fraktur-Bold.woff +0 -0
- package/public/vendor/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
- package/public/vendor/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
- package/public/vendor/fonts/KaTeX_Fraktur-Regular.woff +0 -0
- package/public/vendor/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
- package/public/vendor/fonts/KaTeX_Main-Bold.ttf +0 -0
- package/public/vendor/fonts/KaTeX_Main-Bold.woff +0 -0
- package/public/vendor/fonts/KaTeX_Main-Bold.woff2 +0 -0
- package/public/vendor/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
- package/public/vendor/fonts/KaTeX_Main-BoldItalic.woff +0 -0
- package/public/vendor/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
- package/public/vendor/fonts/KaTeX_Main-Italic.ttf +0 -0
- package/public/vendor/fonts/KaTeX_Main-Italic.woff +0 -0
- package/public/vendor/fonts/KaTeX_Main-Italic.woff2 +0 -0
- package/public/vendor/fonts/KaTeX_Main-Regular.ttf +0 -0
- package/public/vendor/fonts/KaTeX_Main-Regular.woff +0 -0
- package/public/vendor/fonts/KaTeX_Main-Regular.woff2 +0 -0
- package/public/vendor/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
- package/public/vendor/fonts/KaTeX_Math-BoldItalic.woff +0 -0
- package/public/vendor/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
- package/public/vendor/fonts/KaTeX_Math-Italic.ttf +0 -0
- package/public/vendor/fonts/KaTeX_Math-Italic.woff +0 -0
- package/public/vendor/fonts/KaTeX_Math-Italic.woff2 +0 -0
- package/public/vendor/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
- package/public/vendor/fonts/KaTeX_SansSerif-Bold.woff +0 -0
- package/public/vendor/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
- package/public/vendor/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
- package/public/vendor/fonts/KaTeX_SansSerif-Italic.woff +0 -0
- package/public/vendor/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
- package/public/vendor/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
- package/public/vendor/fonts/KaTeX_SansSerif-Regular.woff +0 -0
- package/public/vendor/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
- package/public/vendor/fonts/KaTeX_Script-Regular.ttf +0 -0
- package/public/vendor/fonts/KaTeX_Script-Regular.woff +0 -0
- package/public/vendor/fonts/KaTeX_Script-Regular.woff2 +0 -0
- package/public/vendor/fonts/KaTeX_Size1-Regular.ttf +0 -0
- package/public/vendor/fonts/KaTeX_Size1-Regular.woff +0 -0
- package/public/vendor/fonts/KaTeX_Size1-Regular.woff2 +0 -0
- package/public/vendor/fonts/KaTeX_Size2-Regular.ttf +0 -0
- package/public/vendor/fonts/KaTeX_Size2-Regular.woff +0 -0
- package/public/vendor/fonts/KaTeX_Size2-Regular.woff2 +0 -0
- package/public/vendor/fonts/KaTeX_Size3-Regular.ttf +0 -0
- package/public/vendor/fonts/KaTeX_Size3-Regular.woff +0 -0
- package/public/vendor/fonts/KaTeX_Size3-Regular.woff2 +0 -0
- package/public/vendor/fonts/KaTeX_Size4-Regular.ttf +0 -0
- package/public/vendor/fonts/KaTeX_Size4-Regular.woff +0 -0
- package/public/vendor/fonts/KaTeX_Size4-Regular.woff2 +0 -0
- package/public/vendor/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
- package/public/vendor/fonts/KaTeX_Typewriter-Regular.woff +0 -0
- package/public/vendor/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
- package/public/vendor/katex.min.css +1 -0
- package/public/vendor/katex.min.js +1 -0
package/README.md
CHANGED
|
@@ -80,6 +80,12 @@ Edge-only env (when connecting to a hub):
|
|
|
80
80
|
| `MACHINE_ID` | Unique id for this host (default: hostname) |
|
|
81
81
|
| `LOCAL_PORT` | Local bind port (default `13000`, `127.0.0.1`) |
|
|
82
82
|
|
|
83
|
+
### macOS Edge:需要登录态的 CLI
|
|
84
|
+
|
|
85
|
+
如果 Edge 要运行 **AGY / Antigravity** 等把 OAuth token 放在 macOS Keychain 的 CLI,必须以当前登录用户的 **LaunchAgent**(`gui/<uid>`)运行,不能使用 system LaunchDaemon。`HOME`、PATH 和 `~/.gemini` 文件齐全仍不足以访问用户 Keychain。
|
|
86
|
+
|
|
87
|
+
`claude-edge migrate-user-agent` 可将旧的 macOS system Edge 迁移到用户会话。对只使用无用户凭据的后台 agent,system service 仍可选;默认建议使用用户 LaunchAgent。
|
|
88
|
+
|
|
83
89
|
## Features
|
|
84
90
|
|
|
85
91
|
### Chat
|
package/bin/edge-ctl.js
CHANGED
|
@@ -12,8 +12,13 @@ import os from 'os';
|
|
|
12
12
|
import path from 'path';
|
|
13
13
|
import { fileURLToPath } from 'url';
|
|
14
14
|
|
|
15
|
-
const
|
|
16
|
-
const
|
|
15
|
+
const DAEMON_LABEL = 'system/com.claude-simple.edge';
|
|
16
|
+
const DAEMON_PLIST = '/Library/LaunchDaemons/com.claude-simple.edge.plist';
|
|
17
|
+
const AGENT_NAME = 'com.claude-simple.edge';
|
|
18
|
+
const USER_ID = typeof process.getuid === 'function' ? process.getuid() : 0;
|
|
19
|
+
const AGENT_DOMAIN = `gui/${USER_ID}`;
|
|
20
|
+
const AGENT_LABEL = `${AGENT_DOMAIN}/${AGENT_NAME}`;
|
|
21
|
+
const AGENT_PLIST = path.join(os.homedir(), 'Library', 'LaunchAgents', `${AGENT_NAME}.plist`);
|
|
17
22
|
const SYSTEMD_UNIT = 'claude-simple-edge.service';
|
|
18
23
|
const MAC_OUT = path.join(os.homedir(), '.claude-simple-edge', 'edge.out.log');
|
|
19
24
|
const MAC_ERR = path.join(os.homedir(), '.claude-simple-edge', 'edge.err.log');
|
|
@@ -28,6 +33,7 @@ function usage(code = 0) {
|
|
|
28
33
|
logs Last 80 lines of stdout (or journal on Linux)
|
|
29
34
|
logs -f Follow logs
|
|
30
35
|
logs err Stderr only (launchd)
|
|
36
|
+
migrate-user-agent Move macOS Edge into the login session (required for Keychain-backed AGY auth)
|
|
31
37
|
|
|
32
38
|
Also installed as: claude-simple-edge, edge-daemon
|
|
33
39
|
`;
|
|
@@ -51,19 +57,79 @@ function hasCmd(cmd) {
|
|
|
51
57
|
|
|
52
58
|
function detectBackend() {
|
|
53
59
|
if (process.platform === 'darwin') {
|
|
54
|
-
|
|
55
|
-
|
|
60
|
+
// A user LaunchAgent can access the login Keychain. Prefer it over the
|
|
61
|
+
// legacy system LaunchDaemon, which intentionally cannot access it.
|
|
62
|
+
if (run('launchctl', ['print', AGENT_LABEL]).status === 0 || fs.existsSync(AGENT_PLIST)) return 'launchd-user';
|
|
63
|
+
if (fs.existsSync(DAEMON_PLIST)) return 'launchd';
|
|
64
|
+
const r = run('launchctl', ['print', DAEMON_LABEL]);
|
|
56
65
|
if (r.status === 0) return 'launchd';
|
|
57
66
|
}
|
|
58
67
|
if (hasCmd('systemctl')) {
|
|
59
68
|
const r = run('systemctl', ['cat', SYSTEMD_UNIT]);
|
|
60
69
|
if (r.status === 0) return 'systemd';
|
|
61
70
|
}
|
|
62
|
-
if (process.platform === 'darwin') return 'launchd';
|
|
71
|
+
if (process.platform === 'darwin') return 'launchd-user';
|
|
63
72
|
if (process.platform === 'linux') return 'systemd';
|
|
64
73
|
return null;
|
|
65
74
|
}
|
|
66
75
|
|
|
76
|
+
function macTarget(backend) {
|
|
77
|
+
return backend === 'launchd-user'
|
|
78
|
+
? { domain: AGENT_DOMAIN, label: AGENT_LABEL, plist: AGENT_PLIST, user: true }
|
|
79
|
+
: { domain: 'system', label: DAEMON_LABEL, plist: DAEMON_PLIST, user: false };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function plistEscape(value) {
|
|
83
|
+
return String(value).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function readDaemonEnvironment() {
|
|
87
|
+
const r = run('plutil', ['-extract', 'EnvironmentVariables', 'json', '-o', '-', DAEMON_PLIST]);
|
|
88
|
+
if (r.status !== 0) throw new Error(r.stderr || 'cannot read the existing Edge environment');
|
|
89
|
+
return JSON.parse(r.stdout);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function userAgentPlist(env) {
|
|
93
|
+
const client = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'client.js');
|
|
94
|
+
const pairs = Object.entries(env).sort(([a], [b]) => a.localeCompare(b)).map(([key, value]) =>
|
|
95
|
+
`\t\t<key>${plistEscape(key)}</key>\n\t\t<string>${plistEscape(value)}</string>`).join('\n');
|
|
96
|
+
return `<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0">\n<dict>\n\t<key>Label</key>\n\t<string>${AGENT_NAME}</string>\n\t<key>EnvironmentVariables</key>\n\t<dict>\n${pairs}\n\t</dict>\n\t<key>KeepAlive</key>\n\t<true/>\n\t<key>ProcessType</key>\n\t<string>Background</string>\n\t<key>ProgramArguments</key>\n\t<array>\n\t\t<string>${plistEscape(process.execPath)}</string>\n\t\t<string>${plistEscape(client)}</string>\n\t</array>\n\t<key>RunAtLoad</key>\n\t<true/>\n\t<key>StandardErrorPath</key>\n\t<string>${plistEscape(MAC_ERR)}</string>\n\t<key>StandardOutPath</key>\n\t<string>${plistEscape(MAC_OUT)}</string>\n\t<key>ThrottleInterval</key>\n\t<integer>3</integer>\n\t<key>WorkingDirectory</key>\n\t<string>${plistEscape(path.join(os.homedir(), '.claude-simple-edge'))}</string>\n</dict>\n</plist>\n`;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function cmdMigrateUserAgent() {
|
|
100
|
+
if (process.platform !== 'darwin') fail('user LaunchAgent migration is only needed on macOS');
|
|
101
|
+
let inherited;
|
|
102
|
+
try { inherited = readDaemonEnvironment(); }
|
|
103
|
+
catch (e) { fail(e.message); }
|
|
104
|
+
const home = os.homedir();
|
|
105
|
+
const prefix = [path.join(home, '.local', 'bin'), path.join(home, '.grok', 'bin'), process.env.PATH, inherited.PATH]
|
|
106
|
+
.filter(Boolean).join(':');
|
|
107
|
+
const env = {
|
|
108
|
+
...inherited,
|
|
109
|
+
HOME: home, USER: process.env.USER || os.userInfo().username, LOGNAME: process.env.LOGNAME || os.userInfo().username,
|
|
110
|
+
PATH: [...new Set(prefix.split(':').filter(Boolean))].join(':'),
|
|
111
|
+
};
|
|
112
|
+
const dir = path.dirname(AGENT_PLIST);
|
|
113
|
+
try {
|
|
114
|
+
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
115
|
+
const temp = `${AGENT_PLIST}.tmp-${process.pid}`;
|
|
116
|
+
fs.writeFileSync(temp, userAgentPlist(env), { mode: 0o600 });
|
|
117
|
+
// Stop the legacy daemon before the user agent claims the same loopback
|
|
118
|
+
// port. This calls the existing privileged edge command when available.
|
|
119
|
+
const stop = run(process.execPath, [fileURLToPath(import.meta.url), 'stop']);
|
|
120
|
+
if (stop.status !== 0) throw new Error('could not stop the legacy system Edge; run `claude-edge stop` once, then retry');
|
|
121
|
+
fs.renameSync(temp, AGENT_PLIST);
|
|
122
|
+
run('launchctl', ['bootout', AGENT_LABEL]); // harmless if it was not loaded
|
|
123
|
+
const boot = run('launchctl', ['bootstrap', AGENT_DOMAIN, AGENT_PLIST]);
|
|
124
|
+
if (boot.status !== 0) throw new Error(boot.stderr || 'could not bootstrap user Edge agent');
|
|
125
|
+
const start = run('launchctl', ['kickstart', '-k', AGENT_LABEL]);
|
|
126
|
+
if (start.status !== 0) throw new Error(start.stderr || 'could not start user Edge agent');
|
|
127
|
+
} catch (e) {
|
|
128
|
+
fail(`migration failed: ${e.message}`);
|
|
129
|
+
}
|
|
130
|
+
console.log(`migrated to user LaunchAgent: ${AGENT_LABEL}`);
|
|
131
|
+
}
|
|
132
|
+
|
|
67
133
|
function isRoot() {
|
|
68
134
|
return typeof process.getuid === 'function' && process.getuid() === 0;
|
|
69
135
|
}
|
|
@@ -125,25 +191,26 @@ function tailFile(file, n) {
|
|
|
125
191
|
}
|
|
126
192
|
|
|
127
193
|
function cmdStatus(backend) {
|
|
128
|
-
ensureRoot();
|
|
129
|
-
if (backend === 'launchd') {
|
|
130
|
-
const
|
|
194
|
+
if (backend === 'launchd') ensureRoot();
|
|
195
|
+
if (backend === 'launchd' || backend === 'launchd-user') {
|
|
196
|
+
const target = macTarget(backend);
|
|
197
|
+
const r = runRoot('launchctl', ['print', target.label]);
|
|
131
198
|
if (r.status !== 0) {
|
|
132
|
-
console.log(`service: ${
|
|
199
|
+
console.log(`service: ${target.label}`);
|
|
133
200
|
console.log('state: not-loaded');
|
|
134
|
-
console.log(`plist: ${
|
|
201
|
+
console.log(`plist: ${target.plist}`);
|
|
135
202
|
if (r.stderr) console.log(r.stderr.trim());
|
|
136
203
|
return;
|
|
137
204
|
}
|
|
138
205
|
const info = parseLaunchdPrint(r.stdout);
|
|
139
206
|
const machine = r.stdout.match(/MACHINE_ID => (\S+)/)?.[1] || process.env.MACHINE_ID || '-';
|
|
140
|
-
console.log(`service: ${
|
|
207
|
+
console.log(`service: ${target.label}`);
|
|
141
208
|
console.log(`machine: ${machine}`);
|
|
142
209
|
console.log(`state: ${info.state}`);
|
|
143
210
|
console.log(`pid: ${info.pid}`);
|
|
144
211
|
console.log(`runs: ${info.runs}`);
|
|
145
212
|
console.log(`listen: ${listenPort()}`);
|
|
146
|
-
console.log(`plist: ${
|
|
213
|
+
console.log(`plist: ${target.plist}`);
|
|
147
214
|
console.log(`stdout: ${MAC_OUT}`);
|
|
148
215
|
console.log(`stderr: ${MAC_ERR}`);
|
|
149
216
|
const last = tailFile(MAC_OUT, 8);
|
|
@@ -174,15 +241,16 @@ function cmdStatus(backend) {
|
|
|
174
241
|
}
|
|
175
242
|
|
|
176
243
|
function cmdStart(backend) {
|
|
177
|
-
ensureRoot();
|
|
178
|
-
if (backend === 'launchd') {
|
|
179
|
-
|
|
180
|
-
|
|
244
|
+
if (backend === 'launchd') ensureRoot();
|
|
245
|
+
if (backend === 'launchd' || backend === 'launchd-user') {
|
|
246
|
+
const target = macTarget(backend);
|
|
247
|
+
runRoot('launchctl', ['enable', target.label]);
|
|
248
|
+
const loaded = runRoot('launchctl', ['print', target.label]);
|
|
181
249
|
if (loaded.status !== 0) {
|
|
182
|
-
const b = runRoot('launchctl', ['bootstrap',
|
|
250
|
+
const b = runRoot('launchctl', ['bootstrap', target.domain, target.plist]);
|
|
183
251
|
if (b.status !== 0) fail('bootstrap failed', b.stderr || b.stdout);
|
|
184
252
|
}
|
|
185
|
-
const k = runRoot('launchctl', ['kickstart', '-k',
|
|
253
|
+
const k = runRoot('launchctl', ['kickstart', '-k', target.label]);
|
|
186
254
|
if (k.status !== 0) fail('start failed', k.stderr || k.stdout);
|
|
187
255
|
console.log('started');
|
|
188
256
|
return;
|
|
@@ -193,10 +261,11 @@ function cmdStart(backend) {
|
|
|
193
261
|
}
|
|
194
262
|
|
|
195
263
|
function cmdStop(backend) {
|
|
196
|
-
ensureRoot();
|
|
197
|
-
if (backend === 'launchd') {
|
|
198
|
-
|
|
199
|
-
runRoot('launchctl', ['
|
|
264
|
+
if (backend === 'launchd') ensureRoot();
|
|
265
|
+
if (backend === 'launchd' || backend === 'launchd-user') {
|
|
266
|
+
const target = macTarget(backend);
|
|
267
|
+
runRoot('launchctl', ['disable', target.label]);
|
|
268
|
+
runRoot('launchctl', ['bootout', target.label]);
|
|
200
269
|
console.log('stopped');
|
|
201
270
|
return;
|
|
202
271
|
}
|
|
@@ -206,15 +275,16 @@ function cmdStop(backend) {
|
|
|
206
275
|
}
|
|
207
276
|
|
|
208
277
|
function cmdRestart(backend) {
|
|
209
|
-
ensureRoot();
|
|
210
|
-
if (backend === 'launchd') {
|
|
211
|
-
|
|
212
|
-
|
|
278
|
+
if (backend === 'launchd') ensureRoot();
|
|
279
|
+
if (backend === 'launchd' || backend === 'launchd-user') {
|
|
280
|
+
const target = macTarget(backend);
|
|
281
|
+
runRoot('launchctl', ['enable', target.label]);
|
|
282
|
+
const loaded = runRoot('launchctl', ['print', target.label]);
|
|
213
283
|
if (loaded.status !== 0) {
|
|
214
|
-
const b = runRoot('launchctl', ['bootstrap',
|
|
284
|
+
const b = runRoot('launchctl', ['bootstrap', target.domain, target.plist]);
|
|
215
285
|
if (b.status !== 0) fail('bootstrap failed', b.stderr || b.stdout);
|
|
216
286
|
}
|
|
217
|
-
const k = runRoot('launchctl', ['kickstart', '-k',
|
|
287
|
+
const k = runRoot('launchctl', ['kickstart', '-k', target.label]);
|
|
218
288
|
if (k.status !== 0) fail('restart failed', k.stderr || k.stdout);
|
|
219
289
|
console.log('restarted');
|
|
220
290
|
return;
|
|
@@ -226,7 +296,7 @@ function cmdRestart(backend) {
|
|
|
226
296
|
|
|
227
297
|
function cmdLogs(backend, mode) {
|
|
228
298
|
if (backend === 'systemd') ensureRoot();
|
|
229
|
-
if (backend === 'launchd') {
|
|
299
|
+
if (backend === 'launchd' || backend === 'launchd-user') {
|
|
230
300
|
if (mode === '-f' || mode === '--follow') {
|
|
231
301
|
const child = spawn('tail', ['-n', '50', '-F', MAC_OUT, MAC_ERR], { stdio: 'inherit' });
|
|
232
302
|
child.on('exit', (c) => process.exit(c || 0));
|
|
@@ -261,6 +331,10 @@ const backend = detectBackend();
|
|
|
261
331
|
if (!backend) fail('no launchd/systemd edge service found');
|
|
262
332
|
|
|
263
333
|
switch (cmd) {
|
|
334
|
+
case 'migrate-user-agent':
|
|
335
|
+
case 'migrate':
|
|
336
|
+
cmdMigrateUserAgent();
|
|
337
|
+
break;
|
|
264
338
|
case 'status':
|
|
265
339
|
cmdStatus(backend);
|
|
266
340
|
break;
|