@lifeaitools/clauth 1.30.26 → 1.31.1

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 (39) hide show
  1. package/.clauth-skill/SKILL.md +0 -31
  2. package/.clauth-skill/references/keys-guide.md +270 -270
  3. package/.clauth-skill/references/operator-guide.md +0 -27
  4. package/README.md +2 -48
  5. package/cli/api.js +238 -238
  6. package/cli/commands/agent-pool.js +51 -15
  7. package/cli/commands/install.js +396 -396
  8. package/cli/commands/login.js +135 -0
  9. package/cli/commands/login.test.js +73 -0
  10. package/cli/commands/serve.js +16 -846
  11. package/cli/commands/uninstall.js +164 -164
  12. package/cli/commands/watchdog.js +1 -1
  13. package/cli/index.js +29 -20
  14. package/cli/supervisor-registry.js +1 -6
  15. package/cli/watchdog-registry.js +2 -30
  16. package/cli/watchdog-registry.test.js +5 -28
  17. package/cli/webdav-service.js +339 -339
  18. package/install.ps1 +102 -102
  19. package/install.sh +49 -49
  20. package/package.json +4 -6
  21. package/scripts/bin/bootstrap-linux +0 -0
  22. package/scripts/bin/bootstrap-macos +0 -0
  23. package/scripts/bin/bootstrap-win.exe +0 -0
  24. package/scripts/bootstrap.cjs +121 -121
  25. package/scripts/build.mjs +66 -0
  26. package/scripts/build.sh +5 -45
  27. package/scripts/postinstall.js +189 -189
  28. package/supabase/functions/auth-vault/index.ts +350 -350
  29. package/supabase/migrations/001_clauth_schema.sql +94 -94
  30. package/supabase/migrations/002_vault_helpers.sql +90 -90
  31. package/supabase/migrations/20260317_lockout.sql +26 -26
  32. package/cli/commands/ops-install.js +0 -211
  33. package/cli/commands/ops.js +0 -69
  34. package/cli/ops/coolify-adapter.js +0 -80
  35. package/cli/ops/deployment-adapter.js +0 -63
  36. package/cli/ops/job-store.js +0 -116
  37. package/cli/ops/operation-policy.js +0 -51
  38. package/cli/ops/pm2-adapter.js +0 -128
  39. package/cli/ops/serialized-executor.js +0 -9
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Regenerate bootstrap binaries from source on every supported host.
3
+ * npm's own Node process is authoritative; a separately found Git Bash on
4
+ * Windows may not expose node on PATH.
5
+ */
6
+ import { chmodSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
7
+ import { spawnSync } from "node:child_process";
8
+ import { createRequire } from "node:module";
9
+ import { dirname, join } from "node:path";
10
+ import { fileURLToPath } from "node:url";
11
+
12
+ const require = createRequire(import.meta.url);
13
+ const root = dirname(dirname(fileURLToPath(import.meta.url)));
14
+ const scripts = join(root, "scripts");
15
+ const bin = join(scripts, "bin");
16
+ const tmp = join(bin, "tmp");
17
+ const obfuscated = join(scripts, "bootstrap.ob.cjs");
18
+
19
+ try {
20
+ process.stdout.write("→ Obfuscating bootstrap.cjs...\n");
21
+ const obfuscator = require("javascript-obfuscator");
22
+ const source = readFileSync(join(scripts, "bootstrap.cjs"), "utf8");
23
+ const output = obfuscator.obfuscate(source, {
24
+ compact: true,
25
+ controlFlowFlattening: true,
26
+ controlFlowFlatteningThreshold: 0.75,
27
+ deadCodeInjection: true,
28
+ deadCodeInjectionThreshold: 0.4,
29
+ identifierNamesGenerator: "hexadecimal",
30
+ rotateStringArray: true,
31
+ shuffleStringArray: true,
32
+ splitStrings: true,
33
+ splitStringsChunkLength: 8,
34
+ stringArray: true,
35
+ stringArrayEncoding: ["base64"],
36
+ stringArrayThreshold: 0.85,
37
+ transformObjectKeys: true,
38
+ target: "node",
39
+ });
40
+ writeFileSync(obfuscated, output.getObfuscatedCode());
41
+ process.stdout.write(" ✓ Obfuscated\n→ Compiling binaries...\n");
42
+ mkdirSync(tmp, { recursive: true });
43
+ const compile = spawnSync(
44
+ process.platform === "win32" ? "npx.cmd" : "npx",
45
+ ["pkg", obfuscated, "--targets", "node18-win-x64,node18-linux-x64,node18-macos-x64", "--out-path", tmp],
46
+ // Windows `.cmd` shims require cmd.exe; inputs are constant paths/targets.
47
+ { cwd: root, encoding: "utf8", shell: process.platform === "win32", windowsHide: true },
48
+ );
49
+ const outputLog = `${compile.stdout ?? ""}${compile.stderr ?? ""}`.split(/\r?\n/).filter((line) => line && !line.includes("Warning")).join("\n");
50
+ if (outputLog) process.stdout.write(`${outputLog}\n`);
51
+ if (compile.error || compile.status !== 0) throw compile.error ?? new Error(`pkg exited ${compile.status ?? "unknown"}`);
52
+ for (const [from, to] of [["bootstrap.ob-linux", "bootstrap-linux"], ["bootstrap.ob-macos", "bootstrap-macos"], ["bootstrap.ob-win.exe", "bootstrap-win.exe"]]) {
53
+ const sourcePath = join(tmp, from);
54
+ if (!existsSync(sourcePath)) throw new Error(`pkg did not produce ${from}`);
55
+ renameSync(sourcePath, join(bin, to));
56
+ }
57
+ for (const filename of ["bootstrap-linux", "bootstrap-macos"]) chmodSync(join(bin, filename), 0o755);
58
+ rmSync(tmp, { recursive: true, force: true });
59
+ rmSync(obfuscated, { force: true });
60
+ process.stdout.write(`${readdirSync(bin).join("\n")}\n✓ Build complete\n`);
61
+ } catch (error) {
62
+ rmSync(tmp, { recursive: true, force: true });
63
+ rmSync(obfuscated, { force: true });
64
+ process.stderr.write(`Build failed: ${error instanceof Error ? error.message : String(error)}\n`);
65
+ process.exitCode = 1;
66
+ }
package/scripts/build.sh CHANGED
@@ -1,45 +1,5 @@
1
- #!/usr/bin/env bash
2
- # scripts/build.sh regenerate bootstrap binaries from source
3
- # Run: npm run build
4
- set -e
5
- cd "$(dirname "$0")/.."
6
-
7
- echo "→ Obfuscating bootstrap.cjs..."
8
- node -e "
9
- const J = require('javascript-obfuscator');
10
- const fs = require('fs');
11
- const src = fs.readFileSync('scripts/bootstrap.cjs', 'utf8');
12
- const out = J.obfuscate(src, {
13
- compact: true,
14
- controlFlowFlattening: true, controlFlowFlatteningThreshold: 0.75,
15
- deadCodeInjection: true, deadCodeInjectionThreshold: 0.4,
16
- identifierNamesGenerator: 'hexadecimal',
17
- rotateStringArray: true, shuffleStringArray: true,
18
- splitStrings: true, splitStringsChunkLength: 8,
19
- stringArray: true, stringArrayEncoding: ['base64'],
20
- stringArrayThreshold: 0.85,
21
- transformObjectKeys: true, target: 'node'
22
- });
23
- fs.writeFileSync('scripts/bootstrap.ob.cjs', out.getObfuscatedCode());
24
- console.log(' ✓ Obfuscated');
25
- "
26
-
27
- echo "→ Compiling binaries..."
28
- mkdir -p scripts/bin
29
- npx pkg scripts/bootstrap.ob.cjs \
30
- --targets node18-win-x64,node18-linux-x64,node18-macos-x64 \
31
- --out-path scripts/bin/tmp/ \
32
- 2>&1 | grep -v "^$" | grep -v "Warning" || true
33
-
34
- # Rename to clean names
35
- mv -f scripts/bin/tmp/bootstrap.ob-linux scripts/bin/bootstrap-linux 2>/dev/null || true
36
- mv -f scripts/bin/tmp/bootstrap.ob-macos scripts/bin/bootstrap-macos 2>/dev/null || true
37
- mv -f scripts/bin/tmp/bootstrap.ob-win.exe scripts/bin/bootstrap-win.exe 2>/dev/null || true
38
- rm -rf scripts/bin/tmp
39
- chmod +x scripts/bin/bootstrap-linux scripts/bin/bootstrap-macos 2>/dev/null || true
40
-
41
- # Clean intermediate
42
- rm -f scripts/bootstrap.ob.cjs
43
-
44
- ls -lh scripts/bin/
45
- echo "✓ Build complete"
1
+ #!/usr/bin/env bash
2
+ # Compatibility shim for callers that still invoke this path directly.
3
+ # npm runs the Node implementation on every platform.
4
+ set -e
5
+ exec "${npm_node_execpath:-node}" "$(dirname "$0")/build.mjs" "$@"
@@ -1,189 +1,189 @@
1
- #!/usr/bin/env node
2
- // scripts/postinstall.js
3
- // Runs after npm install -g @lifeaitools/clauth
4
- // On Windows: writes watchdog.ps1 to %APPDATA%\clauth\ and registers
5
- // the Task Scheduler job via UAC elevation.
6
-
7
- import fs from "fs";
8
- import path from "path";
9
- import os from "os";
10
- import { fileURLToPath } from "url";
11
- import { spawnSync } from "child_process";
12
-
13
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
14
- const APPDATA = process.env.APPDATA || path.join(os.homedir(), "AppData", "Roaming");
15
- const CLAUTH_DIR = path.join(APPDATA, "clauth");
16
- const DEST_PS1 = path.join(CLAUTH_DIR, "watchdog.ps1");
17
- const SOURCE_PS1 = path.join(__dirname, "..", "cli", "assets", "watchdog.ps1");
18
- const PS_EXE = "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe";
19
- const TASK_NAME = "ClautWatchdog";
20
-
21
- const CONFIG_DIR = os.platform() === "win32"
22
- ? path.join(APPDATA, "clauth-nodejs", "Config")
23
- : path.join(os.homedir(), ".config", "clauth-nodejs");
24
-
25
- let version = "1.0.0";
26
- try {
27
- const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "package.json"), "utf8"));
28
- version = pkg.version;
29
- } catch {}
30
-
31
- // ----------------------------------------------------------------
32
- // Watchdog helpers (Windows only)
33
- // ----------------------------------------------------------------
34
-
35
- function writeWatchdogScript() {
36
- try {
37
- fs.mkdirSync(CLAUTH_DIR, { recursive: true });
38
- fs.copyFileSync(SOURCE_PS1, DEST_PS1);
39
- return true;
40
- } catch (err) {
41
- console.log(` ! Could not write watchdog script: ${err.message}`);
42
- return false;
43
- }
44
- }
45
-
46
- function isWatchdogRegistered() {
47
- try {
48
- const r = spawnSync(PS_EXE, [
49
- "-NoProfile", "-Command",
50
- `(Get-ScheduledTask -TaskName '${TASK_NAME}' -ErrorAction SilentlyContinue) -ne $null`,
51
- ], { encoding: "utf8", stdio: ["pipe","pipe","pipe"], timeout: 5000 });
52
- return (r.stdout || "").trim().toLowerCase() === "true";
53
- } catch { return false; }
54
- }
55
-
56
- function registerWatchdog() {
57
- const escaped = DEST_PS1.replace(/'/g, "''");
58
- const psCmd = [
59
- `$a = New-ScheduledTaskAction -Execute 'powershell.exe'`,
60
- ` -Argument '-NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File \\"${escaped}\\"';`,
61
- `$t = New-ScheduledTaskTrigger -AtLogOn;`,
62
- `$s = New-ScheduledTaskSettingsSet -ExecutionTimeLimit 0 -RestartCount 3`,
63
- ` -RestartInterval (New-TimeSpan -Minutes 1) -MultipleInstances IgnoreNew;`,
64
- `Unregister-ScheduledTask -TaskName '${TASK_NAME}' -Confirm:$false -ErrorAction SilentlyContinue;`,
65
- `Register-ScheduledTask -TaskName '${TASK_NAME}' -Action $a -Trigger $t`,
66
- ` -Settings $s -RunLevel Highest -Description 'clauth daemon watchdog';`,
67
- ].join(" ");
68
-
69
- // Try direct first (works if already running as Administrator)
70
- const direct = spawnSync(PS_EXE, [
71
- "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", psCmd,
72
- ], { encoding: "utf8", stdio: ["pipe","pipe","pipe"], timeout: 10000 });
73
-
74
- if (direct.status === 0) return "ok";
75
-
76
- // Trigger UAC elevation — opens the Windows approval dialog
77
- const inner = psCmd.replace(/"/g, '\\"');
78
- const elevated = spawnSync(PS_EXE, [
79
- "-NoProfile", "-Command",
80
- `Start-Process '${PS_EXE}' -Verb RunAs -Wait -ArgumentList '-NoProfile -ExecutionPolicy Bypass -Command "${inner}"'`,
81
- ], { stdio: "inherit", encoding: "utf8", timeout: 60000 });
82
-
83
- return elevated.status === 0 ? "ok" : "denied";
84
- }
85
-
86
- function startWatchdog() {
87
- spawnSync(PS_EXE, [
88
- "-NoProfile", "-Command",
89
- `Start-ScheduledTask -TaskName '${TASK_NAME}' -ErrorAction SilentlyContinue`,
90
- ], { stdio: "pipe", timeout: 5000 });
91
- }
92
-
93
- function installCodevelopTerminalProfiles() {
94
- const cli = path.join(__dirname, "..", "cli", "index.js");
95
- const result = spawnSync(process.execPath, [
96
- cli,
97
- "codevelop",
98
- "install-terminal",
99
- "--repo",
100
- "C:\\Dev\\regen-root",
101
- ], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: 10000 });
102
-
103
- if (result.status === 0) {
104
- console.log(" ✓ Co-development Windows Terminal profiles installed");
105
- } else {
106
- const msg = (result.stderr || result.stdout || "").trim();
107
- console.log(` ! Co-development terminal profile install skipped${msg ? `: ${msg}` : ""}`);
108
- console.log(" Install later with: clauth codevelop install-terminal --repo C:\\Dev\\regen-root");
109
- }
110
- }
111
-
112
- // ----------------------------------------------------------------
113
- // Main
114
- // ----------------------------------------------------------------
115
-
116
- async function main() {
117
- const configPath = path.join(CONFIG_DIR, "config.json");
118
- const isUpgrade = fs.existsSync(configPath);
119
-
120
- if (isUpgrade) {
121
- console.log(`\n \u2713 clauth upgraded to v${version}`);
122
- console.log(` \u2713 Config preserved at ${CONFIG_DIR}`);
123
- try {
124
- const controller = new AbortController();
125
- const to = setTimeout(() => controller.abort(), 2000);
126
- const res = await fetch("http://127.0.0.1:52437/ping", { signal: controller.signal });
127
- clearTimeout(to);
128
- if (res.ok) console.log(" \u21BB Daemon running \u2014 restart: clauth serve restart");
129
- } catch {
130
- console.log(" \u25CB Daemon not running");
131
- }
132
- } else {
133
- console.log(`\n Welcome to clauth v${version}!`);
134
- console.log(" Run 'clauth install' to set up your vault");
135
- }
136
-
137
- // Windows: register watchdog on fresh install; refresh script on upgrade
138
- if (os.platform() === "win32") {
139
- const registered = isWatchdogRegistered();
140
- if (!registered) {
141
- console.log("\n Setting up auto-restart watchdog...");
142
- console.log(" Windows will ask for administrator approval \u2014 please click Yes.\n");
143
- if (writeWatchdogScript()) {
144
- const result = registerWatchdog();
145
- if (result === "ok") {
146
- startWatchdog();
147
- console.log(" \u2713 Watchdog registered and started (Task: ClautWatchdog)");
148
- console.log(` \u2713 Script: ${DEST_PS1}`);
149
- } else {
150
- console.log(" ! Watchdog registration skipped (approval denied).");
151
- console.log(" Install later with: clauth watchdog install");
152
- }
153
- }
154
- } else {
155
- writeWatchdogScript(); // refresh script on upgrade
156
- console.log(" \u2713 Watchdog script updated");
157
- }
158
- installCodevelopTerminalProfiles();
159
- }
160
-
161
- // Windows: install dependencies via winget if not already present
162
- if (os.platform() === "win32") {
163
- const deps = [
164
- { cmd: "rclone", args: ["version"], wingetId: "Rclone.Rclone", label: "rclone (WebDAV bridge)" },
165
- { cmd: "pwsh", args: ["--version"], wingetId: "Microsoft.PowerShell", label: "PowerShell 7 (fs_exec shell)" },
166
- ];
167
- for (const dep of deps) {
168
- const check = spawnSync(dep.cmd, dep.args, { stdio: "pipe", timeout: 5000, windowsHide: true });
169
- if (check.status === 0) {
170
- console.log(` ✓ ${dep.label} already installed`);
171
- } else {
172
- console.log(` Installing ${dep.label}...`);
173
- const r = spawnSync("winget", [
174
- "install", "--id", dep.wingetId,
175
- "--silent", "--accept-package-agreements", "--accept-source-agreements",
176
- ], { stdio: "inherit", timeout: 120000 });
177
- if (r.status === 0) {
178
- console.log(` ✓ ${dep.label} installed`);
179
- } else {
180
- console.log(` ! ${dep.label} install skipped — install manually: winget install ${dep.wingetId}`);
181
- }
182
- }
183
- }
184
- }
185
-
186
- console.log(" Run 'clauth doctor' to verify installation\n");
187
- }
188
-
189
- main().catch(() => {});
1
+ #!/usr/bin/env node
2
+ // scripts/postinstall.js
3
+ // Runs after npm install -g @lifeaitools/clauth
4
+ // On Windows: writes watchdog.ps1 to %APPDATA%\clauth\ and registers
5
+ // the Task Scheduler job via UAC elevation.
6
+
7
+ import fs from "fs";
8
+ import path from "path";
9
+ import os from "os";
10
+ import { fileURLToPath } from "url";
11
+ import { spawnSync } from "child_process";
12
+
13
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
14
+ const APPDATA = process.env.APPDATA || path.join(os.homedir(), "AppData", "Roaming");
15
+ const CLAUTH_DIR = path.join(APPDATA, "clauth");
16
+ const DEST_PS1 = path.join(CLAUTH_DIR, "watchdog.ps1");
17
+ const SOURCE_PS1 = path.join(__dirname, "..", "cli", "assets", "watchdog.ps1");
18
+ const PS_EXE = "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe";
19
+ const TASK_NAME = "ClautWatchdog";
20
+
21
+ const CONFIG_DIR = os.platform() === "win32"
22
+ ? path.join(APPDATA, "clauth-nodejs", "Config")
23
+ : path.join(os.homedir(), ".config", "clauth-nodejs");
24
+
25
+ let version = "1.0.0";
26
+ try {
27
+ const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "package.json"), "utf8"));
28
+ version = pkg.version;
29
+ } catch {}
30
+
31
+ // ----------------------------------------------------------------
32
+ // Watchdog helpers (Windows only)
33
+ // ----------------------------------------------------------------
34
+
35
+ function writeWatchdogScript() {
36
+ try {
37
+ fs.mkdirSync(CLAUTH_DIR, { recursive: true });
38
+ fs.copyFileSync(SOURCE_PS1, DEST_PS1);
39
+ return true;
40
+ } catch (err) {
41
+ console.log(` ! Could not write watchdog script: ${err.message}`);
42
+ return false;
43
+ }
44
+ }
45
+
46
+ function isWatchdogRegistered() {
47
+ try {
48
+ const r = spawnSync(PS_EXE, [
49
+ "-NoProfile", "-Command",
50
+ `(Get-ScheduledTask -TaskName '${TASK_NAME}' -ErrorAction SilentlyContinue) -ne $null`,
51
+ ], { encoding: "utf8", stdio: ["pipe","pipe","pipe"], timeout: 5000 });
52
+ return (r.stdout || "").trim().toLowerCase() === "true";
53
+ } catch { return false; }
54
+ }
55
+
56
+ function registerWatchdog() {
57
+ const escaped = DEST_PS1.replace(/'/g, "''");
58
+ const psCmd = [
59
+ `$a = New-ScheduledTaskAction -Execute 'powershell.exe'`,
60
+ ` -Argument '-NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File \\"${escaped}\\"';`,
61
+ `$t = New-ScheduledTaskTrigger -AtLogOn;`,
62
+ `$s = New-ScheduledTaskSettingsSet -ExecutionTimeLimit 0 -RestartCount 3`,
63
+ ` -RestartInterval (New-TimeSpan -Minutes 1) -MultipleInstances IgnoreNew;`,
64
+ `Unregister-ScheduledTask -TaskName '${TASK_NAME}' -Confirm:$false -ErrorAction SilentlyContinue;`,
65
+ `Register-ScheduledTask -TaskName '${TASK_NAME}' -Action $a -Trigger $t`,
66
+ ` -Settings $s -RunLevel Highest -Description 'clauth daemon watchdog';`,
67
+ ].join(" ");
68
+
69
+ // Try direct first (works if already running as Administrator)
70
+ const direct = spawnSync(PS_EXE, [
71
+ "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", psCmd,
72
+ ], { encoding: "utf8", stdio: ["pipe","pipe","pipe"], timeout: 10000 });
73
+
74
+ if (direct.status === 0) return "ok";
75
+
76
+ // Trigger UAC elevation — opens the Windows approval dialog
77
+ const inner = psCmd.replace(/"/g, '\\"');
78
+ const elevated = spawnSync(PS_EXE, [
79
+ "-NoProfile", "-Command",
80
+ `Start-Process '${PS_EXE}' -Verb RunAs -Wait -ArgumentList '-NoProfile -ExecutionPolicy Bypass -Command "${inner}"'`,
81
+ ], { stdio: "inherit", encoding: "utf8", timeout: 60000 });
82
+
83
+ return elevated.status === 0 ? "ok" : "denied";
84
+ }
85
+
86
+ function startWatchdog() {
87
+ spawnSync(PS_EXE, [
88
+ "-NoProfile", "-Command",
89
+ `Start-ScheduledTask -TaskName '${TASK_NAME}' -ErrorAction SilentlyContinue`,
90
+ ], { stdio: "pipe", timeout: 5000 });
91
+ }
92
+
93
+ function installCodevelopTerminalProfiles() {
94
+ const cli = path.join(__dirname, "..", "cli", "index.js");
95
+ const result = spawnSync(process.execPath, [
96
+ cli,
97
+ "codevelop",
98
+ "install-terminal",
99
+ "--repo",
100
+ "C:\\Dev\\regen-root",
101
+ ], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: 10000 });
102
+
103
+ if (result.status === 0) {
104
+ console.log(" ✓ Co-development Windows Terminal profiles installed");
105
+ } else {
106
+ const msg = (result.stderr || result.stdout || "").trim();
107
+ console.log(` ! Co-development terminal profile install skipped${msg ? `: ${msg}` : ""}`);
108
+ console.log(" Install later with: clauth codevelop install-terminal --repo C:\\Dev\\regen-root");
109
+ }
110
+ }
111
+
112
+ // ----------------------------------------------------------------
113
+ // Main
114
+ // ----------------------------------------------------------------
115
+
116
+ async function main() {
117
+ const configPath = path.join(CONFIG_DIR, "config.json");
118
+ const isUpgrade = fs.existsSync(configPath);
119
+
120
+ if (isUpgrade) {
121
+ console.log(`\n \u2713 clauth upgraded to v${version}`);
122
+ console.log(` \u2713 Config preserved at ${CONFIG_DIR}`);
123
+ try {
124
+ const controller = new AbortController();
125
+ const to = setTimeout(() => controller.abort(), 2000);
126
+ const res = await fetch("http://127.0.0.1:52437/ping", { signal: controller.signal });
127
+ clearTimeout(to);
128
+ if (res.ok) console.log(" \u21BB Daemon running \u2014 restart: clauth serve restart");
129
+ } catch {
130
+ console.log(" \u25CB Daemon not running");
131
+ }
132
+ } else {
133
+ console.log(`\n Welcome to clauth v${version}!`);
134
+ console.log(" Run 'clauth install' to set up your vault");
135
+ }
136
+
137
+ // Windows: register watchdog on fresh install; refresh script on upgrade
138
+ if (os.platform() === "win32") {
139
+ const registered = isWatchdogRegistered();
140
+ if (!registered) {
141
+ console.log("\n Setting up auto-restart watchdog...");
142
+ console.log(" Windows will ask for administrator approval \u2014 please click Yes.\n");
143
+ if (writeWatchdogScript()) {
144
+ const result = registerWatchdog();
145
+ if (result === "ok") {
146
+ startWatchdog();
147
+ console.log(" \u2713 Watchdog registered and started (Task: ClautWatchdog)");
148
+ console.log(` \u2713 Script: ${DEST_PS1}`);
149
+ } else {
150
+ console.log(" ! Watchdog registration skipped (approval denied).");
151
+ console.log(" Install later with: clauth watchdog install");
152
+ }
153
+ }
154
+ } else {
155
+ writeWatchdogScript(); // refresh script on upgrade
156
+ console.log(" \u2713 Watchdog script updated");
157
+ }
158
+ installCodevelopTerminalProfiles();
159
+ }
160
+
161
+ // Windows: install dependencies via winget if not already present
162
+ if (os.platform() === "win32") {
163
+ const deps = [
164
+ { cmd: "rclone", args: ["version"], wingetId: "Rclone.Rclone", label: "rclone (WebDAV bridge)" },
165
+ { cmd: "pwsh", args: ["--version"], wingetId: "Microsoft.PowerShell", label: "PowerShell 7 (fs_exec shell)" },
166
+ ];
167
+ for (const dep of deps) {
168
+ const check = spawnSync(dep.cmd, dep.args, { stdio: "pipe", timeout: 5000, windowsHide: true });
169
+ if (check.status === 0) {
170
+ console.log(` ✓ ${dep.label} already installed`);
171
+ } else {
172
+ console.log(` Installing ${dep.label}...`);
173
+ const r = spawnSync("winget", [
174
+ "install", "--id", dep.wingetId,
175
+ "--silent", "--accept-package-agreements", "--accept-source-agreements",
176
+ ], { stdio: "inherit", timeout: 120000 });
177
+ if (r.status === 0) {
178
+ console.log(` ✓ ${dep.label} installed`);
179
+ } else {
180
+ console.log(` ! ${dep.label} install skipped — install manually: winget install ${dep.wingetId}`);
181
+ }
182
+ }
183
+ }
184
+ }
185
+
186
+ console.log(" Run 'clauth doctor' to verify installation\n");
187
+ }
188
+
189
+ main().catch(() => {});