clauderipple 0.9.5 → 0.11.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 +118 -0
- package/README.es.md +45 -0
- package/README.ja.md +17 -0
- package/README.ko.md +31 -0
- package/README.md +70 -0
- package/README.pt-BR.md +45 -0
- package/README.zh-CN.md +17 -0
- package/dist/app/assets/icon.icns +0 -0
- package/dist/app/assets/icon.ico +0 -0
- package/dist/app/assets/icon.png +0 -0
- package/dist/app/assets/trayDirectTemplate.png +0 -0
- package/dist/app/assets/trayDirectTemplate@2x.png +0 -0
- package/dist/app/assets/trayDownTemplate.png +0 -0
- package/dist/app/assets/trayDownTemplate@2x.png +0 -0
- package/dist/app/assets/trayTemplate.png +0 -0
- package/dist/app/assets/trayTemplate@2x.png +0 -0
- package/dist/app/assets/trayWarnTemplate.png +0 -0
- package/dist/app/assets/trayWarnTemplate@2x.png +0 -0
- package/dist/app/assets/trayWin.png +0 -0
- package/dist/app/assets/trayWin@2x.png +0 -0
- package/dist/app/assets/trayWinDirect.png +0 -0
- package/dist/app/assets/trayWinDirect@2x.png +0 -0
- package/dist/app/assets/trayWinDown.png +0 -0
- package/dist/app/assets/trayWinDown@2x.png +0 -0
- package/dist/app/assets/trayWinWarn.png +0 -0
- package/dist/app/assets/trayWinWarn@2x.png +0 -0
- package/dist/app/dist/claude-desktop.js +67 -0
- package/dist/app/dist/main.js +423 -110
- package/dist/app/dist/preload.js +21 -0
- package/dist/app/dist/protocol.js +121 -0
- package/dist/app/dist/status-model.js +87 -0
- package/dist/app/dist/window.js +133 -0
- package/dist/app/package.json +1 -1
- package/dist/cli/src/awake-setup.js +314 -0
- package/dist/cli/src/bundle.js +9 -5
- package/dist/cli/src/direct.js +159 -0
- package/dist/cli/src/doctor.js +205 -0
- package/dist/cli/src/hooks/agent-title.js +7 -4
- package/dist/cli/src/index.js +227 -31
- package/dist/cli/src/launchd.js +29 -20
- package/dist/cli/src/launcher.js +215 -0
- package/dist/cli/src/power.js +182 -0
- package/dist/cli/src/registration.js +157 -0
- package/dist/cli/src/remote.js +263 -0
- package/dist/cli/src/schtasks.js +50 -40
- package/dist/cli/src/settings.js +26 -1
- package/dist/cli/src/tray.js +5 -2
- package/dist/mod/hooks/i18n.ts +473 -227
- package/dist/mod/hooks/judge.ts +35 -17
- package/dist/mod/hooks/modes.ts +56 -1
- package/dist/mod/hooks/register.tsx +237 -32
- package/dist/mod/hooks/session.ts +102 -1
- package/dist/mod/hooks/settings.js +7 -3
- package/dist/mod/hooks/settings.ts +9 -4
- package/dist/mod/hooks/stats.ts +25 -1
- package/dist/mod/hooks/ui/agents.tsx +903 -79
- package/dist/mod/hooks/ui/alerts.tsx +20 -17
- package/dist/mod/hooks/ui/art.ts +33 -7
- package/dist/mod/hooks/ui/band.tsx +262 -81
- package/dist/mod/hooks/ui/flat.ts +265 -0
- package/dist/mod/hooks/ui/kit.tsx +70 -55
- package/dist/mod/hooks/ui/look.ts +129 -0
- package/dist/mod/hooks/ui/settings.tsx +71 -46
- package/dist/mod/hooks/ui/setup.tsx +15 -13
- package/dist/mod/hooks/ui/theme.ts +3 -0
- package/dist/mod/hooks/ui/tools.ts +124 -0
- package/dist/mod/hooks/ui/view.ts +120 -4
- package/dist/mod/hooks/workers.ts +33 -6
- package/dist/mod/tests/register.test.tsx +155 -11
- package/dist/mod/tests/ui.test.tsx +408 -27
- package/dist/mod/types/index.d.ts +66 -2
- package/dist/remote/package.json +28 -0
- package/dist/remote/src/away.js +85 -0
- package/dist/remote/src/bridge-client.js +336 -0
- package/dist/remote/src/composer-menu.js +11 -0
- package/dist/remote/src/config.js +102 -0
- package/dist/remote/src/desktop.js +1018 -0
- package/dist/remote/src/e2ee.js +126 -0
- package/dist/remote/src/e2ee.ts +126 -0
- package/dist/remote/src/eventlog.js +298 -0
- package/dist/remote/src/expo-push.js +127 -0
- package/dist/remote/src/folders.js +79 -0
- package/dist/remote/src/fsutil.js +39 -0
- package/dist/remote/src/handoff.js +38 -0
- package/dist/remote/src/host-service.js +168 -0
- package/dist/remote/src/images.js +215 -0
- package/dist/remote/src/local-control.js +138 -0
- package/dist/remote/src/main.js +264 -0
- package/dist/remote/src/permissions.js +124 -0
- package/dist/remote/src/power.js +76 -0
- package/dist/remote/src/processes.js +24 -0
- package/dist/remote/src/protocol.js +32 -0
- package/dist/remote/src/protocol.ts +284 -0
- package/dist/remote/src/push-content.js +32 -0
- package/dist/remote/src/push.js +134 -0
- package/dist/remote/src/receipts.js +111 -0
- package/dist/remote/src/relay.js +438 -0
- package/dist/remote/src/router.js +208 -0
- package/dist/remote/src/sdk-launcher.js +18 -0
- package/dist/remote/src/server.js +706 -0
- package/dist/remote/src/service.js +157 -0
- package/dist/remote/src/sessions.js +1800 -0
- package/dist/remote/src/sidebar-storage.js +211 -0
- package/dist/remote/src/sidebar.js +173 -0
- package/dist/remote/src/tool-details.js +205 -0
- package/dist/remote/src/tool-details.ts +153 -0
- package/dist/remote/src/worktree.js +99 -0
- package/dist/remote/web/app.ts +746 -0
- package/dist/remote/web/conn.ts +193 -0
- package/dist/remote/web/demo.ts +134 -0
- package/dist/remote/web/dom.ts +124 -0
- package/dist/remote/web/esc.ts +4 -0
- package/dist/remote/web/i18n.ts +374 -0
- package/dist/remote/web/icon.svg +1 -0
- package/dist/remote/web/index.html +24 -0
- package/dist/remote/web/manifest.webmanifest +10 -0
- package/dist/remote/web/mascot.ts +60 -0
- package/dist/remote/web/md.ts +78 -0
- package/dist/remote/web/notify.ts +55 -0
- package/dist/remote/web/pushstate.ts +27 -0
- package/dist/remote/web/secure.ts +109 -0
- package/dist/remote/web/sidebar.ts +106 -0
- package/dist/remote/web/style.css +311 -0
- package/dist/remote/web/sw.ts +48 -0
- package/dist/remote/web/timeline.ts +224 -0
- package/dist/remote/web/views.ts +323 -0
- package/dist/router/src/admin.js +331 -5
- package/dist/router/src/awake-win.js +590 -0
- package/dist/router/src/awake.js +432 -0
- package/dist/router/src/config.js +94 -0
- package/dist/router/src/health.js +86 -3
- package/dist/router/src/hold.js +107 -0
- package/dist/router/src/index.js +108 -6
- package/dist/router/src/ingress/server.js +26 -4
- package/dist/router/src/ingress/translate.js +6 -2
- package/dist/router/src/phone.js +82 -0
- package/dist/router/src/power.js +107 -0
- package/dist/router/src/providers/anthropic-usage.js +33 -1
- package/dist/router/src/providers/google/antigravity.js +73 -10
- package/dist/router/src/providers/google/index.js +191 -14
- package/dist/router/src/providers/google/prompt-refusal.js +29 -0
- package/dist/router/src/providers/google/thoughtSignatures.js +13 -0
- package/dist/router/src/providers/google/transport.js +1 -1
- package/dist/router/src/providers/google/usage.js +302 -0
- package/dist/router/src/providers/grok/index.js +18 -0
- package/dist/router/src/providers/grok/usage.js +77 -0
- package/dist/router/src/providers/openai/translate.js +13 -2
- package/dist/router/src/providers/opencode-usage.js +116 -0
- package/dist/router/src/providers/retry.js +4 -1
- package/dist/router/src/proxy.js +371 -261
- package/dist/router/src/remote-host.js +320 -0
- package/dist/router/src/remote-tunnel.js +320 -0
- package/dist/router/src/requestlog.js +48 -39
- package/dist/router/src/tether-win.js +211 -0
- package/dist/router/src/tether.js +712 -0
- package/dist/router/src/usage-history.js +227 -0
- package/dist/router/src/version.js +1 -1
- package/dist/ui/app.js +1083 -59
- package/dist/ui/i18n.js +670 -69
- package/dist/ui/index.html +33 -6
- package/dist/ui/style.css +177 -0
- package/docs/ARCHITECTURE.md +402 -14
- package/package.json +8 -2
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// Running the host day to day: its own launchd agent (spec: `com.clauderipple.host`, KeepAlive,
|
|
2
|
+
// ProcessType Interactive; not inside the router, which must not restart to ship host changes).
|
|
3
|
+
import { execFileSync } from "node:child_process";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import os from "node:os";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { claudeBinary } from "../../cli/src/claude-auth.js";
|
|
8
|
+
export const LABEL = "com.clauderipple.host";
|
|
9
|
+
// ---- where things are --------------------------------------------------------------------------
|
|
10
|
+
/** The user's own CLI when there is one: it is the version the router's measurements and the ripple mod are kept current with. */
|
|
11
|
+
export function findClaude(configured, exists = fs.existsSync, opts = {}) {
|
|
12
|
+
if (configured)
|
|
13
|
+
return configured;
|
|
14
|
+
const platform = opts.platform ?? process.platform;
|
|
15
|
+
const p = platform === "win32" ? path.win32 : path.posix;
|
|
16
|
+
const home = opts.home ?? os.homedir();
|
|
17
|
+
const names = platform === "win32" ? ["claude.exe", "claude.cmd", "claude.bat"] : ["claude"];
|
|
18
|
+
const dirs = [p.join(home, ".local", "bin"), ...(platform === "win32" ? [p.join(process.env.APPDATA ?? p.join(home, "AppData", "Roaming"), "npm")] : ["/opt/homebrew/bin", "/usr/local/bin"]),
|
|
19
|
+
...(opts.pathValue ?? process.env.PATH ?? process.env.Path ?? "").split(platform === "win32" ? ";" : ":")];
|
|
20
|
+
for (const dir of dirs.filter(Boolean))
|
|
21
|
+
for (const name of names) {
|
|
22
|
+
const candidate = p.join(dir, name);
|
|
23
|
+
if (exists(candidate))
|
|
24
|
+
return candidate;
|
|
25
|
+
}
|
|
26
|
+
// Shared discovery also covers both AppData roots and Desktop's version/hash cache layout.
|
|
27
|
+
return platform === process.platform && exists === fs.existsSync ? claudeBinary() ?? undefined : undefined;
|
|
28
|
+
}
|
|
29
|
+
const xml = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
30
|
+
export function plist(spec) {
|
|
31
|
+
const program = [spec.node, "--disable-warning=ExperimentalWarning", spec.script, ...spec.args];
|
|
32
|
+
const env = Object.entries(spec.env).map(([k, v]) => `\t\t<key>${xml(k)}</key>\n\t\t<string>${xml(v)}</string>`).join("\n");
|
|
33
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
34
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
35
|
+
<plist version="1.0">
|
|
36
|
+
<dict>
|
|
37
|
+
\t<key>Label</key>
|
|
38
|
+
\t<string>${LABEL}</string>
|
|
39
|
+
\t<key>ProgramArguments</key>
|
|
40
|
+
\t<array>
|
|
41
|
+
${program.map((a) => `\t\t<string>${xml(a)}</string>`).join("\n")}
|
|
42
|
+
\t</array>
|
|
43
|
+
\t<key>WorkingDirectory</key>
|
|
44
|
+
\t<string>${xml(spec.workingDir)}</string>
|
|
45
|
+
\t<key>EnvironmentVariables</key>
|
|
46
|
+
\t<dict>
|
|
47
|
+
${env}
|
|
48
|
+
\t</dict>
|
|
49
|
+
\t<key>RunAtLoad</key>
|
|
50
|
+
\t<true/>
|
|
51
|
+
\t<key>KeepAlive</key>
|
|
52
|
+
\t<true/>
|
|
53
|
+
\t<key>ThrottleInterval</key>
|
|
54
|
+
\t<integer>10</integer>
|
|
55
|
+
\t<key>ProcessType</key>
|
|
56
|
+
\t<string>Interactive</string>
|
|
57
|
+
\t<key>StandardOutPath</key>
|
|
58
|
+
\t<string>${xml(spec.log)}</string>
|
|
59
|
+
\t<key>StandardErrorPath</key>
|
|
60
|
+
\t<string>${xml(spec.log)}</string>
|
|
61
|
+
</dict>
|
|
62
|
+
</plist>
|
|
63
|
+
`;
|
|
64
|
+
}
|
|
65
|
+
/** PATH for the agent: launchd starts it with almost nothing, and the SDK spawns `claude`, which spawns git, rg, node… */
|
|
66
|
+
export function agentPath(claudePath, nodePath) {
|
|
67
|
+
if (process.platform !== "darwin")
|
|
68
|
+
return [...new Set([...(claudePath ? [path.dirname(claudePath)] : []), path.dirname(nodePath), ...((process.env.PATH ?? process.env.Path ?? "").split(path.delimiter))])].join(path.delimiter);
|
|
69
|
+
const dirs = [
|
|
70
|
+
...(claudePath ? [path.dirname(claudePath)] : []),
|
|
71
|
+
path.dirname(nodePath),
|
|
72
|
+
"/opt/homebrew/bin", "/usr/local/bin", "/usr/bin", "/bin", "/usr/sbin", "/sbin",
|
|
73
|
+
];
|
|
74
|
+
return Array.from(new Set(dirs)).join(":");
|
|
75
|
+
}
|
|
76
|
+
export function paths(home = os.homedir()) {
|
|
77
|
+
return { home, plist: path.join(home, "Library", "LaunchAgents", `${LABEL}.plist`), log: path.join(home, ".clauderipple", "logs", "host.log") };
|
|
78
|
+
}
|
|
79
|
+
export function specFor(opts) {
|
|
80
|
+
const node = opts.node ?? process.execPath;
|
|
81
|
+
const p = paths(opts.home);
|
|
82
|
+
return {
|
|
83
|
+
node,
|
|
84
|
+
script: opts.script,
|
|
85
|
+
// installCmd already persists the selected bind in host.json. Repeating it here would
|
|
86
|
+
// overwrite a dashboard change every time launchd restarts the host.
|
|
87
|
+
args: [],
|
|
88
|
+
// The checkout, so relative paths in logs read naturally; modules resolve from the script itself.
|
|
89
|
+
workingDir: path.resolve(path.dirname(opts.script), "..", "..", ".."),
|
|
90
|
+
log: p.log,
|
|
91
|
+
env: {
|
|
92
|
+
PATH: agentPath(opts.claudePath, node),
|
|
93
|
+
HOME: p.home,
|
|
94
|
+
...(process.platform === "win32" ? { USERPROFILE: p.home } : {}),
|
|
95
|
+
CLAUDERIPPLE_HOME: process.env.CLAUDERIPPLE_HOME ?? path.join(p.home, ".clauderipple"),
|
|
96
|
+
...(opts.remoteHome ? { RIPPLE_REMOTE_HOME: opts.remoteHome } : {}),
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
const runSync = (cmd, args) => {
|
|
101
|
+
try {
|
|
102
|
+
return { status: 0, out: execFileSync(cmd, args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }) };
|
|
103
|
+
}
|
|
104
|
+
catch (e) {
|
|
105
|
+
const err = e;
|
|
106
|
+
return { status: err.status ?? 1, out: `${err.stdout ?? ""}${err.stderr ?? ""}` };
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
const domain = () => `gui/${process.getuid?.() ?? 501}`;
|
|
110
|
+
export function install(spec, run = runSync, p = paths()) {
|
|
111
|
+
const done = [];
|
|
112
|
+
fs.mkdirSync(path.dirname(p.plist), { recursive: true });
|
|
113
|
+
fs.mkdirSync(path.dirname(spec.log), { recursive: true, mode: 0o700 });
|
|
114
|
+
// A loaded agent keeps its old plist until it is booted out; replace it, do not stack a second one.
|
|
115
|
+
if (run("/bin/launchctl", ["print", `${domain()}/${LABEL}`]).status === 0) {
|
|
116
|
+
run("/bin/launchctl", ["bootout", `${domain()}/${LABEL}`]);
|
|
117
|
+
done.push("stopped the running agent");
|
|
118
|
+
}
|
|
119
|
+
fs.writeFileSync(p.plist, plist(spec), { mode: 0o644 });
|
|
120
|
+
done.push(`wrote ${p.plist}`);
|
|
121
|
+
// Right after a bootout, launchd may still be tearing the old agent down and answers
|
|
122
|
+
// "Bootstrap failed: 5: Input/output error"; the host then stayed down. Give it a few seconds.
|
|
123
|
+
let r = run("/bin/launchctl", ["bootstrap", domain(), p.plist]);
|
|
124
|
+
for (let tries = 1; r.status === 5 && tries < 10; tries++) {
|
|
125
|
+
run("/bin/sleep", ["0.5"]);
|
|
126
|
+
r = run("/bin/launchctl", ["bootstrap", domain(), p.plist]);
|
|
127
|
+
}
|
|
128
|
+
if (r.status !== 0)
|
|
129
|
+
throw new Error(`launchctl bootstrap failed (${r.status}): ${r.out.trim()}`);
|
|
130
|
+
done.push(`loaded ${LABEL}; logs in ${spec.log}`);
|
|
131
|
+
return done;
|
|
132
|
+
}
|
|
133
|
+
export function uninstall(run = runSync, p = paths()) {
|
|
134
|
+
const done = [];
|
|
135
|
+
if (run("/bin/launchctl", ["print", `${domain()}/${LABEL}`]).status === 0) {
|
|
136
|
+
const r = run("/bin/launchctl", ["bootout", `${domain()}/${LABEL}`]);
|
|
137
|
+
done.push(r.status === 0 ? `stopped ${LABEL}` : `launchctl bootout said (${r.status}): ${r.out.trim()}`);
|
|
138
|
+
}
|
|
139
|
+
else
|
|
140
|
+
done.push(`${LABEL} was not loaded`);
|
|
141
|
+
if (fs.existsSync(p.plist)) {
|
|
142
|
+
fs.rmSync(p.plist);
|
|
143
|
+
done.push(`removed ${p.plist}`);
|
|
144
|
+
}
|
|
145
|
+
return done;
|
|
146
|
+
}
|
|
147
|
+
/** `launchctl print` is not a stable interface; only the two lines a person needs are read, and the raw state is shown as is. */
|
|
148
|
+
export function parseLaunchctlPrint(out) {
|
|
149
|
+
const m = (re) => re.exec(out)?.[1]?.trim() ?? null;
|
|
150
|
+
const pid = m(/^\s*pid = (\d+)/m);
|
|
151
|
+
return { state: m(/^\s*state = (.+)$/m), pid: pid ? Number(pid) : null, lastExit: m(/^\s*last exit code = (.+)$/m) };
|
|
152
|
+
}
|
|
153
|
+
export function agentStatus(run = runSync, p = paths()) {
|
|
154
|
+
const r = run("/bin/launchctl", ["print", `${domain()}/${LABEL}`]);
|
|
155
|
+
const parsed = r.status === 0 ? parseLaunchctlPrint(r.out) : { state: null, pid: null, lastExit: null };
|
|
156
|
+
return { installed: fs.existsSync(p.plist), loaded: r.status === 0, ...parsed };
|
|
157
|
+
}
|