@lifeaitools/clauth 0.1.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/cli/index.js ADDED
@@ -0,0 +1,403 @@
1
+ #!/usr/bin/env node
2
+ // cli/index.js — clauth entry point
3
+
4
+ import { Command } from "commander";
5
+ import chalk from "chalk";
6
+ import ora from "ora";
7
+ import inquirer from "inquirer";
8
+ import Conf from "conf";
9
+ import { getMachineHash, deriveToken, deriveSeedHash } from "./fingerprint.js";
10
+ import * as api from "./api.js";
11
+ import os from "os";
12
+
13
+ const config = new Conf({ projectName: "clauth" });
14
+ const VERSION = "0.1.0";
15
+
16
+ // ============================================================
17
+ // Password prompt helper
18
+ // ============================================================
19
+ async function promptPassword(message = "clauth password") {
20
+ const { pw } = await inquirer.prompt([{
21
+ type: "password",
22
+ name: "pw",
23
+ message,
24
+ mask: "*",
25
+ validate: v => v.length >= 8 || "Password must be at least 8 characters"
26
+ }]);
27
+ return pw;
28
+ }
29
+
30
+ // ============================================================
31
+ // Auth helper — get pw + derive token
32
+ // ============================================================
33
+ async function getAuth(pw) {
34
+ const password = pw || await promptPassword();
35
+ const machineHash = getMachineHash();
36
+ const { token, timestamp } = deriveToken(password, machineHash);
37
+ return { password, machineHash, token, timestamp };
38
+ }
39
+
40
+ // ============================================================
41
+ // Program
42
+ // ============================================================
43
+ const program = new Command();
44
+
45
+ program
46
+ .name("clauth")
47
+ .version(VERSION)
48
+ .description(chalk.cyan("šŸ” clauth") + " — Hardware-bound credential vault for LIFEAI infrastructure");
49
+
50
+ // ──────────────────────────────────────────────
51
+ // clauth install (Supabase provisioning + skill install + test)
52
+ // ──────────────────────────────────────────────
53
+ import { runInstall } from './commands/install.js';
54
+
55
+ program
56
+ .command('install')
57
+ .description('Provision Supabase, deploy Edge Function, install Claude skill')
58
+ .action(async () => {
59
+ await runInstall();
60
+ });
61
+
62
+ // ──────────────────────────────────────────────
63
+ // clauth setup
64
+ // ──────────────────────────────────────────────
65
+ program
66
+ .command("setup")
67
+ .description("Register this machine with the vault (run after clauth install)")
68
+ .option("--admin-token <token>", "Bootstrap token (from clauth install output)")
69
+ .option("--label <label>", "Human label for this machine")
70
+ .action(async (opts) => {
71
+ console.log(chalk.cyan("\nšŸ” clauth setup\n"));
72
+
73
+ // URL + anon key already saved by clauth install — fail fast if missing
74
+ const savedUrl = config.get("supabase_url");
75
+ const savedAnon = config.get("supabase_anon_key");
76
+ if (!savedUrl || !savedAnon) {
77
+ console.log(chalk.yellow(" Supabase config not found. Run clauth install first.\n"));
78
+ process.exit(1);
79
+ }
80
+ console.log(chalk.gray(` Project: ${savedUrl}\n`));
81
+
82
+ const answers = await inquirer.prompt([
83
+ { type: "input", name: "label", message: "Machine label:", default: opts.label || os.hostname() },
84
+ { type: "password", name: "pw", message: "Set password:", mask: "*" },
85
+ { type: "password", name: "adminTk", message: "Bootstrap token:", mask: "*",
86
+ default: opts.adminToken || "" },
87
+ ]);
88
+
89
+ const spinner = ora("Registering machine with vault...").start();
90
+ try {
91
+ const machineHash = getMachineHash();
92
+ const seedHash = deriveSeedHash(machineHash, answers.pw);
93
+ const result = await api.registerMachine(machineHash, seedHash, answers.label, answers.adminTk);
94
+ if (result.error) throw new Error(result.error);
95
+ spinner.succeed(chalk.green(`Machine registered: ${machineHash.slice(0,12)}...`));
96
+ console.log(chalk.green("\nāœ“ clauth is ready.\n"));
97
+ console.log(chalk.cyan(" clauth test — verify connection"));
98
+ console.log(chalk.cyan(" clauth status — see all services\n"));
99
+ } catch (err) {
100
+ spinner.fail(chalk.red(`Setup failed: ${err.message}`));
101
+ process.exit(1);
102
+ }
103
+ });
104
+
105
+ // ──────────────────────────────────────────────
106
+ // clauth status
107
+ // ──────────────────────────────────────────────
108
+ program
109
+ .command("status")
110
+ .description("Show all services and their state")
111
+ .option("-p, --pw <password>", "Password (or will prompt)")
112
+ .action(async (opts) => {
113
+ const auth = await getAuth(opts.pw);
114
+ const spinner = ora("Fetching service status...").start();
115
+ try {
116
+ const result = await api.status(auth.password, auth.machineHash, auth.token, auth.timestamp);
117
+ spinner.stop();
118
+ if (result.error) { console.log(chalk.red(`Error: ${result.error}`)); return; }
119
+
120
+ console.log(chalk.cyan("\nšŸ” clauth service status\n"));
121
+ console.log(
122
+ chalk.bold(
123
+ " " + "SERVICE".padEnd(20) + "TYPE".padEnd(12) + "STATUS".padEnd(12) +
124
+ "KEY STORED".padEnd(12) + "LAST RETRIEVED"
125
+ )
126
+ );
127
+ console.log(" " + "─".repeat(72));
128
+
129
+ for (const s of result.services || []) {
130
+ const status = s.enabled
131
+ ? chalk.green("ACTIVE".padEnd(12))
132
+ : s.vault_key
133
+ ? chalk.yellow("SUSPENDED".padEnd(12))
134
+ : chalk.gray("NO KEY".padEnd(12));
135
+ const hasKey = s.vault_key ? chalk.green("āœ“".padEnd(12)) : chalk.gray("—".padEnd(12));
136
+ const lastGet = s.last_retrieved
137
+ ? new Date(s.last_retrieved).toLocaleDateString()
138
+ : chalk.gray("never");
139
+
140
+ console.log(` ${s.name.padEnd(20)}${s.key_type.padEnd(12)}${status}${hasKey}${lastGet}`);
141
+ }
142
+ console.log();
143
+ } catch (err) {
144
+ spinner.fail(chalk.red(err.message));
145
+ }
146
+ });
147
+
148
+ // ──────────────────────────────────────────────
149
+ // clauth write pw <new_password>
150
+ // clauth write params
151
+ // clauth write key <service> <value>
152
+ // ──────────────────────────────────────────────
153
+ const writeCmd = program.command("write").description("Write credentials or update auth parameters");
154
+
155
+ writeCmd
156
+ .command("pw [newpw]")
157
+ .description("Set or update clauth master password")
158
+ .action(async (newpw) => {
159
+ console.log(chalk.cyan("\nšŸ” clauth write pw\n"));
160
+ const current = await promptPassword("Current password (to verify)");
161
+ const pw = newpw || (await inquirer.prompt([
162
+ { type: "password", name: "p", message: "New password:", mask: "*" },
163
+ { type: "password", name: "c", message: "Confirm new password:", mask: "*" }
164
+ ]).then(a => { if (a.p !== a.c) { console.log(chalk.red("Passwords don't match")); process.exit(1); } return a.p; }));
165
+
166
+ // Re-register machine with new seed hash
167
+ const machineHash = getMachineHash();
168
+ const newSeedHash = deriveSeedHash(machineHash, pw);
169
+ const { token, timestamp } = deriveToken(current, machineHash);
170
+ const adminToken = await inquirer.prompt([{
171
+ type: "password", name: "t", message: "Admin bootstrap token (required for re-registration):", mask: "*"
172
+ }]).then(a => a.t);
173
+
174
+ const spinner = ora("Updating password and re-registering machine...").start();
175
+ try {
176
+ const result = await api.registerMachine(machineHash, newSeedHash, null, adminToken);
177
+ if (result.error) throw new Error(result.error);
178
+ spinner.succeed(chalk.green("Password updated and machine re-registered."));
179
+ } catch (err) {
180
+ spinner.fail(chalk.red(err.message));
181
+ }
182
+ });
183
+
184
+ writeCmd
185
+ .command("params")
186
+ .description("Re-read hardware fingerprint (use after hardware change)")
187
+ .action(async () => {
188
+ const spinner = ora("Reading hardware fingerprint...").start();
189
+ try {
190
+ const hash = getMachineHash();
191
+ spinner.succeed(chalk.green(`Machine hash: ${hash.slice(0,16)}...`));
192
+ console.log(chalk.gray("Full hash: " + hash));
193
+ } catch (err) {
194
+ spinner.fail(chalk.red(err.message));
195
+ }
196
+ });
197
+
198
+ writeCmd
199
+ .command("key <service> [value]")
200
+ .description("Write a credential into vault for a service")
201
+ .option("-p, --pw <password>", "Password")
202
+ .action(async (service, value, opts) => {
203
+ const auth = await getAuth(opts.pw);
204
+ let val = value;
205
+ if (!val) {
206
+ const { v } = await inquirer.prompt([{ type: "password", name: "v", message: `Value for ${service}:`, mask: "*" }]);
207
+ val = v;
208
+ }
209
+ const spinner = ora(`Writing key for ${service}...`).start();
210
+ try {
211
+ const result = await api.write(auth.password, auth.machineHash, auth.token, auth.timestamp, service, val);
212
+ if (result.error) throw new Error(result.error);
213
+ spinner.succeed(chalk.green(`Key stored in vault: auth.${service}`));
214
+ } catch (err) {
215
+ spinner.fail(chalk.red(err.message));
216
+ }
217
+ });
218
+
219
+ // ──────────────────────────────────────────────
220
+ // clauth enable <service|all>
221
+ // clauth disable <service|all>
222
+ // ──────────────────────────────────────────────
223
+ program
224
+ .command("enable <service>")
225
+ .description("Enable a service (or 'all')")
226
+ .option("-p, --pw <password>")
227
+ .action(async (service, opts) => {
228
+ const auth = await getAuth(opts.pw);
229
+ const spinner = ora(`Enabling ${service}...`).start();
230
+ try {
231
+ const result = await api.enable(auth.password, auth.machineHash, auth.token, auth.timestamp, service, true);
232
+ if (result.error) throw new Error(result.error);
233
+ spinner.succeed(chalk.green(`Enabled: ${service}`));
234
+ } catch (err) { spinner.fail(chalk.red(err.message)); }
235
+ });
236
+
237
+ program
238
+ .command("disable <service>")
239
+ .description("Disable a service (or 'all')")
240
+ .option("-p, --pw <password>")
241
+ .action(async (service, opts) => {
242
+ const auth = await getAuth(opts.pw);
243
+ const spinner = ora(`Disabling ${service}...`).start();
244
+ try {
245
+ const result = await api.enable(auth.password, auth.machineHash, auth.token, auth.timestamp, service, false);
246
+ if (result.error) throw new Error(result.error);
247
+ spinner.succeed(chalk.yellow(`Disabled: ${service}`));
248
+ } catch (err) { spinner.fail(chalk.red(err.message)); }
249
+ });
250
+
251
+ // ──────────────────────────────────────────────
252
+ // clauth add service <name>
253
+ // clauth remove service <name>
254
+ // clauth list services
255
+ // ──────────────────────────────────────────────
256
+ const addCmd = program.command("add").description("Add resources to the registry");
257
+
258
+ addCmd
259
+ .command("service <name>")
260
+ .description("Register a new service slot")
261
+ .option("--type <type>", "Key type: token | keypair | connstring | oauth")
262
+ .option("--label <label>", "Human-readable label")
263
+ .option("--description <desc>", "Description")
264
+ .option("-p, --pw <password>")
265
+ .action(async (name, opts) => {
266
+ const auth = await getAuth(opts.pw);
267
+ const answers = await inquirer.prompt([
268
+ { type: "input", name: "label", message: "Label:", default: opts.label || name },
269
+ { type: "list", name: "key_type", message: "Key type:", choices: ["token","keypair","connstring","oauth"], default: opts.type || "token" },
270
+ { type: "input", name: "desc", message: "Description (optional):", default: opts.description || "" }
271
+ ]);
272
+ const spinner = ora(`Adding service: ${name}...`).start();
273
+ try {
274
+ const result = await api.addService(
275
+ auth.password, auth.machineHash, auth.token, auth.timestamp,
276
+ name, answers.label, answers.key_type, answers.desc
277
+ );
278
+ if (result.error) throw new Error(result.error);
279
+ spinner.succeed(chalk.green(`Service added: ${name} (${answers.key_type})`));
280
+ console.log(chalk.gray(` Next: clauth write key ${name}`));
281
+ } catch (err) { spinner.fail(chalk.red(err.message)); }
282
+ });
283
+
284
+ const removeCmd = program.command("remove").description("Remove resources from the registry");
285
+
286
+ removeCmd
287
+ .command("service <name>")
288
+ .description("Remove a service and its key from vault")
289
+ .option("-p, --pw <password>")
290
+ .action(async (name, opts) => {
291
+ const { confirm } = await inquirer.prompt([{
292
+ type: "input", name: "confirm",
293
+ message: chalk.red(`Type "CONFIRM REMOVE ${name.toUpperCase()}" to proceed:`)
294
+ }]);
295
+ const auth = await getAuth(opts.pw);
296
+ const spinner = ora(`Removing ${name}...`).start();
297
+ try {
298
+ const result = await api.removeService(auth.password, auth.machineHash, auth.token, auth.timestamp, name, confirm);
299
+ if (result.error) throw new Error(result.error);
300
+ spinner.succeed(chalk.yellow(`Removed: ${name}`));
301
+ } catch (err) { spinner.fail(chalk.red(err.message)); }
302
+ });
303
+
304
+ program
305
+ .command("list")
306
+ .description("List all registered services")
307
+ .option("-p, --pw <password>")
308
+ .action(async (opts) => {
309
+ const auth = await getAuth(opts.pw);
310
+ const result = await api.status(auth.password, auth.machineHash, auth.token, auth.timestamp);
311
+ if (result.error) { console.log(chalk.red(result.error)); return; }
312
+ console.log(chalk.cyan("\n Registered services:\n"));
313
+ for (const s of result.services || []) {
314
+ console.log(` ${chalk.bold(s.name.padEnd(20))} ${chalk.gray(s.key_type.padEnd(12))} ${chalk.gray(s.description || "")}`);
315
+ }
316
+ console.log();
317
+ });
318
+
319
+ // ──────────────────────────────────────────────
320
+ // clauth test <service|all>
321
+ // ──────────────────────────────────────────────
322
+ program
323
+ .command("test [service]")
324
+ .description("Test HMAC handshake — no key returned")
325
+ .option("-p, --pw <password>")
326
+ .action(async (service, opts) => {
327
+ const auth = await getAuth(opts.pw);
328
+ const spinner = ora("Testing auth handshake...").start();
329
+ try {
330
+ const result = await api.test(auth.password, auth.machineHash, auth.token, auth.timestamp);
331
+ if (result.error) throw new Error(`${result.error}: ${result.reason}`);
332
+ spinner.succeed(chalk.green("PASS — HMAC validated"));
333
+ console.log(chalk.gray(` Machine: ${auth.machineHash.slice(0,16)}...`));
334
+ console.log(chalk.gray(` Window: ${new Date(result.timestamp).toISOString()}`));
335
+ } catch (err) {
336
+ spinner.fail(chalk.red("FAIL — " + err.message));
337
+ }
338
+ });
339
+
340
+ // ──────────────────────────────────────────────
341
+ // clauth get <service>
342
+ // ──────────────────────────────────────────────
343
+ program
344
+ .command("get <service>")
345
+ .description("Retrieve a key from vault")
346
+ .option("-p, --pw <password>")
347
+ .option("--json", "Output raw JSON")
348
+ .action(async (service, opts) => {
349
+ const auth = await getAuth(opts.pw);
350
+ const spinner = ora(`Retrieving ${service}...`).start();
351
+ try {
352
+ const result = await api.retrieve(auth.password, auth.machineHash, auth.token, auth.timestamp, service);
353
+ spinner.stop();
354
+ if (result.error) { console.log(chalk.red(`Error: ${result.error}`)); return; }
355
+ if (opts.json) {
356
+ console.log(JSON.stringify(result, null, 2));
357
+ } else {
358
+ console.log(chalk.cyan(`\nšŸ”‘ ${service} (${result.key_type})\n`));
359
+ const val = typeof result.value === "string" ? result.value : JSON.stringify(result.value, null, 2);
360
+ console.log(val);
361
+ console.log();
362
+ }
363
+ } catch (err) {
364
+ spinner.fail(chalk.red(err.message));
365
+ }
366
+ });
367
+
368
+ // ──────────────────────────────────────────────
369
+ // clauth revoke <service|all>
370
+ // ──────────────────────────────────────────────
371
+ program
372
+ .command("revoke <service>")
373
+ .description("Delete key from vault (destructive)")
374
+ .option("-p, --pw <password>")
375
+ .action(async (service, opts) => {
376
+ const phrase = service === "all" ? "CONFIRM REVOKE ALL" : `CONFIRM REVOKE ${service.toUpperCase()}`;
377
+ const { confirm } = await inquirer.prompt([{
378
+ type: "input", name: "confirm",
379
+ message: chalk.red(`Type "${phrase}" to proceed:`)
380
+ }]);
381
+ const auth = await getAuth(opts.pw);
382
+ const spinner = ora(`Revoking ${service}...`).start();
383
+ try {
384
+ const result = await api.revoke(auth.password, auth.machineHash, auth.token, auth.timestamp, service, confirm);
385
+ if (result.error) throw new Error(result.error);
386
+ spinner.succeed(chalk.yellow(`Revoked: ${service}`));
387
+ } catch (err) { spinner.fail(chalk.red(err.message)); }
388
+ });
389
+
390
+ // ──────────────────────────────────────────────
391
+ // clauth --help override banner
392
+ // ──────────────────────────────────────────────
393
+ program.addHelpText("beforeAll", chalk.cyan(`
394
+ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•— ā–ˆā–ˆā•—ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā•— ā–ˆā–ˆā•—
395
+ ā–ˆā–ˆā•”ā•ā•ā•ā•ā•ā–ˆā–ˆā•‘ ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•—ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā•šā•ā•ā–ˆā–ˆā•”ā•ā•ā•ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘
396
+ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•‘
397
+ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•‘
398
+ ā•šā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā•šā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•”ā• ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘
399
+ ā•šā•ā•ā•ā•ā•ā•ā•šā•ā•ā•ā•ā•ā•ā•ā•šā•ā• ā•šā•ā• ā•šā•ā•ā•ā•ā•ā• ā•šā•ā• ā•šā•ā• ā•šā•ā•
400
+ v${VERSION} — LIFEAI Credential Vault
401
+ `));
402
+
403
+ program.parse(process.argv);
package/install.ps1 ADDED
@@ -0,0 +1,44 @@
1
+ # clauth installer — Windows
2
+ # One-liner: iex ((New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/LIFEAI/clauth/main/install.ps1'))
3
+
4
+ $ErrorActionPreference = "Stop"
5
+ $REPO = "https://github.com/LIFEAI/clauth.git"
6
+ $DIR = "$env:USERPROFILE\.clauth"
7
+
8
+ # Check git
9
+ try { git --version | Out-Null } catch {
10
+ Write-Host ""
11
+ Write-Host " x git is required." -ForegroundColor Red
12
+ Write-Host " Install from https://git-scm.com then re-run this script."
13
+ Write-Host ""
14
+ exit 1
15
+ }
16
+
17
+ # Check Node
18
+ try { node --version | Out-Null } catch {
19
+ Write-Host ""
20
+ Write-Host " x Node.js v18+ is required." -ForegroundColor Red
21
+ Write-Host " Install from https://nodejs.org then re-run this script."
22
+ Write-Host ""
23
+ exit 1
24
+ }
25
+
26
+ # Clone or update
27
+ if (Test-Path "$DIR\.git") {
28
+ Write-Host " Updating clauth..."
29
+ Set-Location $DIR; git pull --quiet
30
+ } else {
31
+ Write-Host " Cloning clauth..."
32
+ git clone --quiet $REPO $DIR
33
+ }
34
+
35
+ # Run compiled bootstrap binary
36
+ $bootstrap = "$DIR\scripts\bin\bootstrap-win.exe"
37
+ if (-not (Test-Path $bootstrap)) {
38
+ Write-Host " x Bootstrap binary not found at $bootstrap" -ForegroundColor Red
39
+ exit 1
40
+ }
41
+
42
+ Set-Location $DIR
43
+ & $bootstrap
44
+ exit $LASTEXITCODE
package/install.sh ADDED
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env bash
2
+ # clauth installer
3
+ set -e
4
+
5
+ REPO="https://github.com/LIFEAI/clauth.git"
6
+ DIR="$HOME/.clauth"
7
+
8
+ # Check git
9
+ if ! command -v git &>/dev/null; then
10
+ echo ""; echo " x git is required."
11
+ echo " Install git from https://git-scm.com then re-run this script."; echo ""
12
+ exit 1
13
+ fi
14
+
15
+ # Check Node
16
+ if ! command -v node &>/dev/null; then
17
+ echo ""; echo " x Node.js v18+ is required."
18
+ echo " Install from https://nodejs.org then re-run this script."; echo ""
19
+ exit 1
20
+ fi
21
+
22
+ # Clone or update
23
+ if [ -d "$DIR/.git" ]; then
24
+ echo " Updating clauth..."; cd "$DIR" && git pull --quiet
25
+ else
26
+ echo " Cloning clauth..."; git clone --quiet "$REPO" "$DIR"
27
+ fi
28
+
29
+ # Run compiled bootstrap
30
+ UNAME=$(uname -s | tr '[:upper:]' '[:lower:]')
31
+ if [[ "$UNAME" == *"darwin"* ]]; then
32
+ BOOTSTRAP="$DIR/scripts/bin/bootstrap-macos"
33
+ else
34
+ BOOTSTRAP="$DIR/scripts/bin/bootstrap-linux"
35
+ fi
36
+
37
+ chmod +x "$BOOTSTRAP"
38
+ cd "$DIR" && "$BOOTSTRAP"
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@lifeaitools/clauth",
3
+ "version": "0.1.0",
4
+ "description": "Hardware-bound credential vault for the LIFEAI infrastructure stack",
5
+ "type": "module",
6
+ "bin": {
7
+ "clauth": "./cli/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "bash scripts/build.sh"
11
+ },
12
+ "dependencies": {
13
+ "chalk": "^5.3.0",
14
+ "commander": "^12.1.0",
15
+ "conf": "^13.0.0",
16
+ "inquirer": "^10.1.0",
17
+ "node-fetch": "^3.3.2",
18
+ "ora": "^8.1.0"
19
+ },
20
+ "engines": {
21
+ "node": ">=18.0.0"
22
+ },
23
+ "keywords": [
24
+ "lifeai",
25
+ "credentials",
26
+ "vault",
27
+ "cli",
28
+ "prt"
29
+ ],
30
+ "author": "Dave Ladouceur <dave@life.ai>",
31
+ "license": "MIT",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "https://github.com/LIFEAI/clauth.git"
35
+ },
36
+ "devDependencies": {
37
+ "javascript-obfuscator": "^5.3.0"
38
+ },
39
+ "files": [
40
+ "cli/",
41
+ "scripts/bin/",
42
+ "scripts/bootstrap.cjs",
43
+ "scripts/build.sh",
44
+ "supabase/",
45
+ ".clauth-skill/",
46
+ "install.sh",
47
+ "install.ps1",
48
+ "README.md"
49
+ ],
50
+ "publishConfig": {
51
+ "access": "public"
52
+ },
53
+ "homepage": "https://github.com/LIFEAI/clauth"
54
+ }
Binary file
Binary file
Binary file
@@ -0,0 +1,43 @@
1
+ // bootstrap.cjs — CommonJS, compiled to binary by pkg
2
+ // Installs npm deps, links clauth, chains to: clauth install
3
+ 'use strict';
4
+ const { execSync, spawnSync } = require('child_process');
5
+ const { join } = require('path');
6
+ const ROOT = join(__dirname, '..');
7
+
8
+ function run(cmd, opts) {
9
+ return spawnSync(cmd, Object.assign({ shell: true, stdio: 'inherit', cwd: ROOT }, opts || {}));
10
+ }
11
+ function check(cmd) {
12
+ try { execSync(cmd + ' --version', { stdio: 'pipe' }); return true; } catch { return false; }
13
+ }
14
+
15
+ console.log('\n Installing clauth runtime...\n');
16
+
17
+ if (!check('git')) {
18
+ console.error(' x git not found. Install from https://git-scm.com');
19
+ process.exit(1);
20
+ }
21
+ var nodeVer = parseInt(process.version.slice(1));
22
+ if (nodeVer < 18) {
23
+ console.error(' x Node.js v18+ required (found ' + process.version + ')');
24
+ console.error(' Install from https://nodejs.org');
25
+ process.exit(1);
26
+ }
27
+
28
+ console.log(' -> Installing dependencies...');
29
+ var inst = run('npm install --no-fund --no-audit', { stdio: ['ignore','ignore','pipe'] });
30
+ if (inst.status !== 0) { console.error(' x npm install failed'); process.exit(1); }
31
+ console.log(' + Dependencies ready');
32
+
33
+ console.log(' -> Linking clauth command...');
34
+ var lnk = run('npm link', { stdio: ['ignore','ignore','pipe'] });
35
+ if (lnk.status !== 0) {
36
+ var slnk = run('sudo npm link', { stdio: 'inherit' });
37
+ if (slnk.status !== 0) console.warn(' ! Could not link globally — add ' + ROOT + '/node_modules/.bin to PATH');
38
+ }
39
+ console.log(' + clauth linked');
40
+
41
+ console.log('\n -> Launching clauth install...\n');
42
+ var r = run('clauth install');
43
+ process.exit(r.status || 0);
@@ -0,0 +1,45 @@
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"