@lifeaitools/clauth 1.30.6 ā 1.30.7
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/.clauth-skill/SKILL.md +17 -75
- package/README.md +10 -70
- package/cli/api.js +11 -110
- package/cli/commands/scrub.js +109 -205
- package/cli/commands/serve.js +850 -3059
- package/cli/fingerprint.js +10 -0
- package/cli/index.js +58 -22
- package/cli/studio-debug.js +8 -679
- package/cli/supervisor-registry.js +440 -0
- package/cli/supervisor-registry.test.js +173 -0
- package/package.json +3 -10
- package/scripts/bin/bootstrap-linux +0 -0
- package/scripts/bin/bootstrap-macos +0 -0
- package/scripts/bin/bootstrap-win.exe +0 -0
- package/scripts/postinstall.js +0 -25
- package/cli/api.classify.test.js +0 -75
- package/cli/commands/agent-cron.js +0 -396
- package/cli/commands/agent-pool.js +0 -1962
- package/cli/commands/scrub.test.js +0 -115
- package/cli/enrollment-script.js +0 -82
- package/cli/webdav-service.js +0 -339
package/cli/fingerprint.js
CHANGED
|
@@ -32,6 +32,16 @@ function writeCache(primary, secondary) {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
function getMachineId() {
|
|
35
|
+
// Containers do not have a durable /etc/machine-id. Coolify supplies this
|
|
36
|
+
// value as a private runtime secret so a redeploy remains the same enrolled
|
|
37
|
+
// clauth machine. Accept the lowercase-dash form used by Coolify too.
|
|
38
|
+
const containerMachineId = process.env.CLAUTH_MACHINE_ID || process.env["clauth-machine-id"];
|
|
39
|
+
if (containerMachineId) {
|
|
40
|
+
const value = containerMachineId.trim();
|
|
41
|
+
if (!value) throw new Error("CLAUTH_MACHINE_ID must not be empty");
|
|
42
|
+
return { primary: value, secondary: value, platform: os.platform() };
|
|
43
|
+
}
|
|
44
|
+
|
|
35
45
|
// Fast path: use cached IDs if available (avoids WMI/PowerShell on every restart)
|
|
36
46
|
const cached = readCache();
|
|
37
47
|
if (cached) return { ...cached, platform: os.platform() };
|
package/cli/index.js
CHANGED
|
@@ -13,11 +13,53 @@ import { writeCredentialWithRecovery } from "./recovery.js";
|
|
|
13
13
|
import os from "os";
|
|
14
14
|
import fs from "fs";
|
|
15
15
|
import path from "path";
|
|
16
|
-
import { writeEnrollmentScript } from "./enrollment-script.js";
|
|
17
16
|
|
|
18
17
|
const config = new Conf(getConfOptions());
|
|
19
18
|
const VERSION = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version;
|
|
20
19
|
|
|
20
|
+
function shellSingleQuote(value) {
|
|
21
|
+
return `'${String(value ?? "").replace(/'/g, "''")}'`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function enrollmentScriptName(label) {
|
|
25
|
+
const slug = String(label || "new-computer")
|
|
26
|
+
.toLowerCase()
|
|
27
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
28
|
+
.replace(/^-+|-+$/g, "")
|
|
29
|
+
.slice(0, 40) || "new-computer";
|
|
30
|
+
return `clauth-enroll-${slug}.ps1`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function writeEnrollmentScript({ supabaseUrl, anonKey, enrollmentCode, label }) {
|
|
34
|
+
const appDir = process.platform === "win32"
|
|
35
|
+
? path.join(process.env.APPDATA || path.join(os.homedir(), "AppData", "Roaming"), "clauth")
|
|
36
|
+
: path.join(os.homedir(), ".config", "clauth");
|
|
37
|
+
fs.mkdirSync(appDir, { recursive: true });
|
|
38
|
+
const scriptPath = path.join(appDir, enrollmentScriptName(label));
|
|
39
|
+
const script = [
|
|
40
|
+
"$ErrorActionPreference = 'Stop'",
|
|
41
|
+
"$label = $env:COMPUTERNAME",
|
|
42
|
+
"if (-not $label) { $label = [System.Net.Dns]::GetHostName() }",
|
|
43
|
+
"Write-Host 'Installing clauth...'",
|
|
44
|
+
"npm install -g @lifeaitools/clauth@latest",
|
|
45
|
+
"Write-Host 'Enrolling this computer with clauth...'",
|
|
46
|
+
[
|
|
47
|
+
"clauth setup",
|
|
48
|
+
`--supabase-url ${shellSingleQuote(supabaseUrl)}`,
|
|
49
|
+
`--anon-key ${shellSingleQuote(anonKey)}`,
|
|
50
|
+
`--enrollment-code ${shellSingleQuote(enrollmentCode)}`,
|
|
51
|
+
"--label \"$label\"",
|
|
52
|
+
].join(" "),
|
|
53
|
+
"Write-Host 'Installing clauth startup service...'",
|
|
54
|
+
"clauth serve install",
|
|
55
|
+
"Write-Host 'clauth enrollment complete.'",
|
|
56
|
+
"$self = $PSCommandPath",
|
|
57
|
+
"Start-Process powershell.exe -WindowStyle Hidden -ArgumentList @('-NoProfile','-Command',\"Start-Sleep -Seconds 2; Remove-Item -LiteralPath '$self' -Force -ErrorAction SilentlyContinue\")",
|
|
58
|
+
].join("\r\n");
|
|
59
|
+
fs.writeFileSync(scriptPath, `${script}\r\n`, "utf8");
|
|
60
|
+
return scriptPath;
|
|
61
|
+
}
|
|
62
|
+
|
|
21
63
|
// ============================================================
|
|
22
64
|
// Password prompt helper
|
|
23
65
|
// ============================================================
|
|
@@ -119,7 +161,7 @@ async function searchServices(auth, query, opts = {}) {
|
|
|
119
161
|
.map(([field]) => field);
|
|
120
162
|
|
|
121
163
|
let addressHints = [];
|
|
122
|
-
if (opts.addresses
|
|
164
|
+
if (opts.addresses !== false && ADDRESS_KEY_TYPES.has(String(s.key_type || "").toLowerCase()) && s.vault_key) {
|
|
123
165
|
const secret = await api.retrieve(auth.password, auth.machineHash, auth.token, auth.timestamp, s.name);
|
|
124
166
|
if (!secret.error) {
|
|
125
167
|
addressHints = collectAddressHints(secret.value, s.key_type);
|
|
@@ -349,7 +391,6 @@ program
|
|
|
349
391
|
.option("--label <label>", "Suggested label for the new computer")
|
|
350
392
|
.option("--ttl-minutes <minutes>", "Enrollment lifetime, 5 to 1440 minutes", "60")
|
|
351
393
|
.option("--install-id <id>", "Override install id; default is current machine's install id")
|
|
352
|
-
.option("--target <target>", "Enrollment target: windows or linux", "windows")
|
|
353
394
|
.option("-p, --pw <password>", "Password (or will prompt)")
|
|
354
395
|
.action(async (opts) => {
|
|
355
396
|
console.log(chalk.cyan("\nš clauth enroll\n"));
|
|
@@ -373,7 +414,6 @@ program
|
|
|
373
414
|
anonKey,
|
|
374
415
|
enrollmentCode: result.enrollment_code,
|
|
375
416
|
label: opts.label,
|
|
376
|
-
target: opts.target,
|
|
377
417
|
});
|
|
378
418
|
spinner.succeed(chalk.green(`Enrollment created for install_id=${result.install_id}`));
|
|
379
419
|
console.log("");
|
|
@@ -635,15 +675,15 @@ program
|
|
|
635
675
|
|
|
636
676
|
program
|
|
637
677
|
.command("search <query>")
|
|
638
|
-
.description("Search services by name, label, project, description, or
|
|
678
|
+
.description("Search services by name, label, project, description, type, or redacted address hints")
|
|
639
679
|
.option("-p, --pw <password>")
|
|
640
680
|
.option("--project <name>", "Filter by project scope")
|
|
641
|
-
.option("--addresses", "
|
|
681
|
+
.option("--no-addresses", "Skip address-bearing secret metadata scans")
|
|
642
682
|
.action(async (query, opts) => {
|
|
643
683
|
const auth = await getAuth(opts.pw);
|
|
644
684
|
const spinner = ora("Searching services...").start();
|
|
645
685
|
try {
|
|
646
|
-
const rows = await searchServices(auth, query, { project: opts.project, addresses: opts.addresses
|
|
686
|
+
const rows = await searchServices(auth, query, { project: opts.project, addresses: opts.addresses });
|
|
647
687
|
spinner.stop();
|
|
648
688
|
console.log(chalk.cyan(`\n Search results for "${query}":\n`));
|
|
649
689
|
if (!rows.length) {
|
|
@@ -746,13 +786,9 @@ program
|
|
|
746
786
|
.addHelpText("after", `
|
|
747
787
|
Examples:
|
|
748
788
|
clauth scrub Scrub the most recent (active) transcript
|
|
749
|
-
clauth scrub <file> Scrub a specific file
|
|
750
|
-
clauth scrub all Scrub every transcript
|
|
789
|
+
clauth scrub <file> Scrub a specific .jsonl file
|
|
790
|
+
clauth scrub all Scrub every transcript in ~/.claude/projects/
|
|
751
791
|
clauth scrub all --force Rescrub all files (ignore markers)
|
|
752
|
-
clauth scrub session Scrub ONLY the ending session (transcript + sidecars); reads SessionEnd hook JSON on stdin
|
|
753
|
-
|
|
754
|
-
Redacts: built-in token patterns, your ~/.clauth/scrub-patterns.json,
|
|
755
|
-
and this machine's live vault values (best-effort via the daemon).
|
|
756
792
|
`)
|
|
757
793
|
.action(async (target, opts) => {
|
|
758
794
|
await runScrub(target, opts);
|
|
@@ -1000,16 +1036,14 @@ program.addHelpText("beforeAll", chalk.cyan(`
|
|
|
1000
1036
|
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
1001
1037
|
program
|
|
1002
1038
|
.command("serve [action]")
|
|
1003
|
-
.description("Manage localhost HTTP vault daemon (start|stop|restart|ping|install|uninstall)")
|
|
1039
|
+
.description("Manage localhost HTTP vault daemon and supervisor (start|stop|restart|ping|supervisor|install|uninstall)")
|
|
1004
1040
|
.option("--port <n>", "Port (default: 52437)")
|
|
1005
1041
|
.option("-p, --pw <password>", "clauth password (optional ā omit to start locked, unlock in browser)")
|
|
1006
1042
|
.option("--services <list>", "Comma-separated service whitelist (default: all)")
|
|
1007
1043
|
.option("--tunnel <hostname>", "Fixed tunnel hostname (e.g. clauth.prtrust.fund) ā uses named Cloudflare Tunnel instead of random URL")
|
|
1008
1044
|
.option("--staged", "Start on staging port (52438) for blue-green verification before make-live")
|
|
1009
1045
|
.option("--isolated", "Run on a non-live port without touching live PID files, browser, or boot-key credentials")
|
|
1010
|
-
.option("--from-boot-key", "Internal: password came from boot.key auto-unlock (degrade gracefully on verify failure)")
|
|
1011
|
-
.option("--pw-env", "Internal: read the daemon password from CLAUTH_BOOT_PASSWORD")
|
|
1012
|
-
.option("--pw-stdin", "Internal: read the installer password from standard input")
|
|
1046
|
+
.option("--from-boot-key", "Internal: password came from boot.key auto-unlock (degrade gracefully on verify failure)")
|
|
1013
1047
|
.option("--action <action>", "Internal: action override for daemon child")
|
|
1014
1048
|
.addHelpText("after", `
|
|
1015
1049
|
Actions:
|
|
@@ -1018,8 +1052,9 @@ Actions:
|
|
|
1018
1052
|
restart Stop + start
|
|
1019
1053
|
ping Check if the daemon is running
|
|
1020
1054
|
foreground Run in foreground (Ctrl+C to stop) ā default if no action given
|
|
1021
|
-
mcp Run as MCP stdio server for Claude Code (JSON-RPC over stdin/stdout)
|
|
1022
|
-
|
|
1055
|
+
mcp Run as MCP stdio server for Claude Code (JSON-RPC over stdin/stdout)
|
|
1056
|
+
supervisor Run localhost-only supervisor control plane on port 52439
|
|
1057
|
+
install Store password securely + register auto-start service (cross-platform)
|
|
1023
1058
|
Windows: DPAPI + HKCU\\Run | macOS: Keychain + LaunchAgent | Linux: libsecret/openssl + systemd
|
|
1024
1059
|
uninstall Remove auto-start service + delete stored password
|
|
1025
1060
|
upgrade Blue-green upgrade: start new version on staging port, verify, then make live
|
|
@@ -1035,9 +1070,10 @@ Examples:
|
|
|
1035
1070
|
clauth serve ping Check status
|
|
1036
1071
|
clauth serve restart Restart (stays locked until browser unlock)
|
|
1037
1072
|
clauth serve start --services github,vercel
|
|
1038
|
-
clauth serve mcp Start MCP server for Claude Code
|
|
1039
|
-
clauth serve mcp -p mypass Start MCP server pre-unlocked
|
|
1040
|
-
clauth serve
|
|
1073
|
+
clauth serve mcp Start MCP server for Claude Code
|
|
1074
|
+
clauth serve mcp -p mypass Start MCP server pre-unlocked
|
|
1075
|
+
clauth serve supervisor Start supervisor API on http://127.0.0.1:52439
|
|
1076
|
+
clauth serve foreground --port 53137 --isolated
|
|
1041
1077
|
Start isolated passwordless server for route tests
|
|
1042
1078
|
clauth serve install Set up auto-start on login (DPAPI/Keychain/libsecret)
|
|
1043
1079
|
clauth serve install --tunnel host Auto-start with Cloudflare Tunnel
|