@lifeaitools/clauth 1.8.1 → 1.9.2
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 +32 -13
- package/cli/api.js +35 -17
- package/cli/commands/codevelop.js +283 -0
- package/cli/commands/install.js +10 -8
- package/cli/commands/serve.js +10733 -9219
- package/cli/index.js +145 -14
- package/package.json +1 -1
- package/scripts/bin/bootstrap-linux +0 -0
- package/scripts/bin/bootstrap-macos +0 -0
- package/scripts/bin/bootstrap-win.exe +0 -0
- package/supabase/functions/auth-vault/index.ts +98 -3
- package/supabase/migrations/001_clauth_schema.sql +12 -9
- package/supabase/migrations/003_machine_enrollments.sql +39 -0
package/README.md
CHANGED
|
@@ -27,19 +27,37 @@ At the end it prints a **bootstrap token** — save it for the next step.
|
|
|
27
27
|
|
|
28
28
|
---
|
|
29
29
|
|
|
30
|
-
## After Install — Register Your Machine
|
|
31
|
-
|
|
32
|
-
```bash
|
|
33
|
-
clauth setup
|
|
34
|
-
```
|
|
30
|
+
## After Install — Register Your Machine
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
clauth setup
|
|
34
|
+
```
|
|
35
35
|
|
|
36
36
|
Prompts for: machine label, password, bootstrap token (from `clauth install`).
|
|
37
37
|
|
|
38
|
-
Then verify:
|
|
39
|
-
```bash
|
|
40
|
-
clauth test # → PASS
|
|
41
|
-
clauth status # → 12 services, all NO KEY
|
|
42
|
-
```
|
|
38
|
+
Then verify:
|
|
39
|
+
```bash
|
|
40
|
+
clauth test # → PASS
|
|
41
|
+
clauth status # → 12 services, all NO KEY
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Add A New Computer
|
|
45
|
+
|
|
46
|
+
On an old computer where clauth is already registered:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
clauth enroll --label "Dave-New-Laptop"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
This creates a one-time enrollment code tied to the same `install_id` and writes
|
|
53
|
+
a one-time PowerShell setup script. Move that script to the new computer and run
|
|
54
|
+
it. The script installs clauth, enrolls the computer, installs startup, then
|
|
55
|
+
deletes itself. Setup defaults the machine label to the computer name and only
|
|
56
|
+
asks you to set the new computer's local clauth password.
|
|
57
|
+
|
|
58
|
+
The enrollment code does not copy repo credentials into the script. It lets the
|
|
59
|
+
new hardware-bound `machine_hash` join the shared Supabase Vault once. After the
|
|
60
|
+
code is redeemed, it cannot be used again.
|
|
43
61
|
|
|
44
62
|
---
|
|
45
63
|
|
|
@@ -70,9 +88,10 @@ clauth get github
|
|
|
70
88
|
## Command Reference
|
|
71
89
|
|
|
72
90
|
```
|
|
73
|
-
clauth install Provision Supabase + install Claude skill
|
|
74
|
-
clauth setup Register this machine with the vault
|
|
75
|
-
clauth
|
|
91
|
+
clauth install Provision Supabase + install Claude skill
|
|
92
|
+
clauth setup Register this machine with the vault
|
|
93
|
+
clauth enroll Create one-time code to add another computer
|
|
94
|
+
clauth status All services + state
|
|
76
95
|
clauth search <query> Find services by name, project, description, or redacted address
|
|
77
96
|
clauth test Verify connection
|
|
78
97
|
|
package/cli/api.js
CHANGED
|
@@ -102,20 +102,38 @@ export async function test(password, machineHash, token, timestamp) {
|
|
|
102
102
|
return authPost("test", password, machineHash, token, timestamp);
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
export async function changePassword(password, machineHash, token, timestamp, newSeedHash) {
|
|
106
|
-
return authPost("change-password", password, machineHash, token, timestamp, { new_hmac_seed_hash: newSeedHash });
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export async function
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
105
|
+
export async function changePassword(password, machineHash, token, timestamp, newSeedHash) {
|
|
106
|
+
return authPost("change-password", password, machineHash, token, timestamp, { new_hmac_seed_hash: newSeedHash });
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export async function createEnrollment(password, machineHash, token, timestamp, label, ttlMinutes, installId) {
|
|
110
|
+
const extra = {};
|
|
111
|
+
if (label) extra.label = label;
|
|
112
|
+
if (ttlMinutes) extra.ttl_minutes = ttlMinutes;
|
|
113
|
+
if (installId) extra.install_id = installId;
|
|
114
|
+
return authPost("create-enrollment", password, machineHash, token, timestamp, extra);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export async function registerMachine(machineHash, seedHash, label, adminToken, extras = {}) {
|
|
118
|
+
return post("register-machine", {
|
|
119
|
+
machine_hash: machineHash,
|
|
120
|
+
hmac_seed_hash: seedHash,
|
|
121
|
+
label,
|
|
122
|
+
admin_token: adminToken,
|
|
123
|
+
...extras
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export async function redeemEnrollment(machineHash, seedHash, label, enrollmentCode) {
|
|
128
|
+
return post("redeem-enrollment", {
|
|
129
|
+
machine_hash: machineHash,
|
|
130
|
+
hmac_seed_hash: seedHash,
|
|
131
|
+
label,
|
|
132
|
+
enrollment_code: enrollmentCode
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export default {
|
|
137
|
+
retrieve, write, enable, addService, updateService, removeService, revoke,
|
|
138
|
+
status, test, createEnrollment, registerMachine, redeemEnrollment, getBaseUrl, getAnonKey
|
|
139
|
+
};
|
|
@@ -45,6 +45,14 @@ function getRequestPath() {
|
|
|
45
45
|
return path.join(getClauthAppDir(), "codevelop-request.json");
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
function getAdhocStatePath() {
|
|
49
|
+
return path.join(getClauthAppDir(), "codevelop-channel-active.json");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function getAdhocChannelsPath() {
|
|
53
|
+
return path.join(getClauthAppDir(), "codevelop-channels.json");
|
|
54
|
+
}
|
|
55
|
+
|
|
48
56
|
function cmdValue(value) {
|
|
49
57
|
return String(value ?? "").replace(/%/g, "%%").replace(/"/g, "'");
|
|
50
58
|
}
|
|
@@ -430,6 +438,271 @@ function normalizeOptionalPeer(peer) {
|
|
|
430
438
|
return value;
|
|
431
439
|
}
|
|
432
440
|
|
|
441
|
+
function normalizeAdhocId(value, label) {
|
|
442
|
+
const text = String(value || "").trim().toLowerCase();
|
|
443
|
+
if (!text) throw new Error(`${label} is required`);
|
|
444
|
+
const normalized = text.replace(/[^a-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
445
|
+
if (!normalized) throw new Error(`${label} must contain letters, numbers, dots, underscores, or hyphens`);
|
|
446
|
+
if (normalized.length > 64) throw new Error(`${label} is too long; keep it under 64 characters`);
|
|
447
|
+
return normalized;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
function normalizeOptionalAdhocId(value) {
|
|
451
|
+
const text = String(value || "").trim();
|
|
452
|
+
return text ? normalizeAdhocId(text, "peer") : null;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
function getCodevelopBaseUrl(opts = {}) {
|
|
456
|
+
const port = Number(opts.port || DEFAULT_PORT);
|
|
457
|
+
if (RESERVED_PORTS.has(port)) throw new Error(`Refusing to use reserved clauth port ${port}`);
|
|
458
|
+
return opts.baseUrl || process.env.CODEVELOP_BASE_URL || `http://127.0.0.1:${port}`;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
async function ensureCodevelopReachable(opts = {}) {
|
|
462
|
+
const baseUrl = getCodevelopBaseUrl(opts);
|
|
463
|
+
if (await testPing(baseUrl)) return { baseUrl, startedClauthPid: null };
|
|
464
|
+
if (!asBool(opts.startIsolatedClauth)) {
|
|
465
|
+
throw new Error(`clauth is not reachable at ${baseUrl}. Re-run with --start-isolated-clauth.`);
|
|
466
|
+
}
|
|
467
|
+
const port = Number(opts.port || DEFAULT_PORT);
|
|
468
|
+
const startedClauthPid = startIsolatedClauth(port);
|
|
469
|
+
if (!(await waitForPing(baseUrl))) throw new Error(`isolated clauth did not become ready at ${baseUrl}`);
|
|
470
|
+
return { baseUrl, startedClauthPid };
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
function writeAdhocState(state) {
|
|
474
|
+
const appDir = getClauthAppDir();
|
|
475
|
+
fs.mkdirSync(appDir, { recursive: true });
|
|
476
|
+
fs.writeFileSync(getAdhocStatePath(), `${JSON.stringify({
|
|
477
|
+
...state,
|
|
478
|
+
updated_at: new Date().toISOString(),
|
|
479
|
+
}, null, 2)}\n`, "utf8");
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
function readAdhocState() {
|
|
483
|
+
const statePath = getAdhocStatePath();
|
|
484
|
+
if (!fs.existsSync(statePath)) return null;
|
|
485
|
+
return readJsonFile(statePath);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
function readAdhocChannels() {
|
|
489
|
+
const channelsPath = getAdhocChannelsPath();
|
|
490
|
+
if (!fs.existsSync(channelsPath)) return {};
|
|
491
|
+
const parsed = readJsonFile(channelsPath);
|
|
492
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
function writeAdhocChannels(channels) {
|
|
496
|
+
const appDir = getClauthAppDir();
|
|
497
|
+
fs.mkdirSync(appDir, { recursive: true });
|
|
498
|
+
fs.writeFileSync(getAdhocChannelsPath(), `${JSON.stringify(channels, null, 2)}\n`, "utf8");
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
async function getCodevelopStatus(baseUrl, sessionId) {
|
|
502
|
+
return requestJson("GET", `${baseUrl}/codevelop/${encodeURIComponent(sessionId)}/status`);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
async function findOrCreateAdhocChannel(opts = {}) {
|
|
506
|
+
const channel = normalizeAdhocId(opts.channel || opts.name || process.env.CODEVELOP_CHANNEL || "1", "channel");
|
|
507
|
+
const sessionName = `channel-${channel}`;
|
|
508
|
+
const { baseUrl, startedClauthPid } = await ensureCodevelopReachable(opts);
|
|
509
|
+
const channels = readAdhocChannels();
|
|
510
|
+
const existing = channels[channel];
|
|
511
|
+
if (existing?.session_id && existing?.base_url === baseUrl) {
|
|
512
|
+
try {
|
|
513
|
+
const session = await getCodevelopStatus(baseUrl, existing.session_id);
|
|
514
|
+
if (session.status !== "stopped") return { baseUrl, channel, session, created: false, startedClauthPid };
|
|
515
|
+
} catch {}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
const session = await requestJson("POST", `${baseUrl}/codevelop/start`, {
|
|
519
|
+
name: sessionName,
|
|
520
|
+
repo: opts.repo || DEFAULT_REPO,
|
|
521
|
+
metadata: {
|
|
522
|
+
mode: "adhoc-channel",
|
|
523
|
+
channel,
|
|
524
|
+
created_by: opts.peer || process.env.CODEVELOP_PEER || null,
|
|
525
|
+
},
|
|
526
|
+
});
|
|
527
|
+
channels[channel] = {
|
|
528
|
+
channel,
|
|
529
|
+
session_id: session.session_id,
|
|
530
|
+
base_url: baseUrl,
|
|
531
|
+
name: sessionName,
|
|
532
|
+
created_at: new Date().toISOString(),
|
|
533
|
+
updated_at: new Date().toISOString(),
|
|
534
|
+
};
|
|
535
|
+
writeAdhocChannels(channels);
|
|
536
|
+
return { baseUrl, channel, session, created: true, startedClauthPid };
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
async function loadAdhocContext(opts = {}) {
|
|
540
|
+
if (opts.session && opts.peer) {
|
|
541
|
+
return {
|
|
542
|
+
baseUrl: getCodevelopBaseUrl(opts),
|
|
543
|
+
channel: normalizeAdhocId(opts.channel || opts.name || "custom", "channel"),
|
|
544
|
+
sessionId: opts.session,
|
|
545
|
+
peer: normalizeAdhocId(opts.peer, "peer"),
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
const state = readAdhocState();
|
|
550
|
+
const channel = opts.channel || state?.channel || process.env.CODEVELOP_CHANNEL;
|
|
551
|
+
const peer = opts.peer || opts.from || state?.peer || process.env.CODEVELOP_PEER;
|
|
552
|
+
if (!channel || !peer) {
|
|
553
|
+
throw new Error("No active ad hoc channel. Run: clauth codevelop join --channel 1 --peer codex-1");
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
if (opts.channel || opts.peer || !state?.session_id) {
|
|
557
|
+
const joined = await joinAdhocChannel({ ...opts, channel, peer, silent: true });
|
|
558
|
+
return {
|
|
559
|
+
baseUrl: joined.baseUrl,
|
|
560
|
+
channel: joined.channel,
|
|
561
|
+
sessionId: joined.session_id,
|
|
562
|
+
peer: joined.peer,
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
return {
|
|
567
|
+
baseUrl: opts.baseUrl || state.base_url || getCodevelopBaseUrl(opts),
|
|
568
|
+
channel: normalizeAdhocId(channel, "channel"),
|
|
569
|
+
sessionId: state.session_id,
|
|
570
|
+
peer: normalizeAdhocId(peer, "peer"),
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
function formatAdhocMessage(message) {
|
|
575
|
+
const body = message.task || message.message || message.summary || "";
|
|
576
|
+
return `[${message.turn_id}] ${message.from} -> ${message.to} ${message.type || "message"}: ${body}`;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
async function joinAdhocChannel(opts = {}) {
|
|
580
|
+
const peer = normalizeAdhocId(opts.peer || opts.from || process.env.CODEVELOP_PEER, "peer");
|
|
581
|
+
const { baseUrl, channel, session, created, startedClauthPid } = await findOrCreateAdhocChannel(opts);
|
|
582
|
+
const sessionId = session.session_id;
|
|
583
|
+
const joined = await requestJson("POST", `${baseUrl}/codevelop/join`, {
|
|
584
|
+
session_id: sessionId,
|
|
585
|
+
peer_id: peer,
|
|
586
|
+
role: opts.role || "participant",
|
|
587
|
+
metadata: {
|
|
588
|
+
mode: "adhoc-channel",
|
|
589
|
+
channel,
|
|
590
|
+
cwd: process.cwd(),
|
|
591
|
+
},
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
writeAdhocState({
|
|
595
|
+
channel,
|
|
596
|
+
peer,
|
|
597
|
+
session_id: sessionId,
|
|
598
|
+
base_url: baseUrl,
|
|
599
|
+
state_path: getAdhocStatePath(),
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
if (!opts.silent) {
|
|
603
|
+
console.log(`CHANNEL=${channel}`);
|
|
604
|
+
console.log(`PEER=${peer}`);
|
|
605
|
+
console.log(`CODEVELOP_SESSION=${sessionId}`);
|
|
606
|
+
console.log(`BASE_URL=${baseUrl}`);
|
|
607
|
+
console.log(`CREATED=${created ? "yes" : "no"}`);
|
|
608
|
+
if (startedClauthPid) console.log(`CLAUTH_PID=${startedClauthPid}`);
|
|
609
|
+
console.log(`STATE=${getAdhocStatePath()}`);
|
|
610
|
+
console.log("");
|
|
611
|
+
console.log(`Send: clauth codevelop say --message "hello"`);
|
|
612
|
+
console.log(`Read: clauth codevelop read`);
|
|
613
|
+
console.log(`Watch: clauth codevelop watch`);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
return { ...joined, baseUrl, channel, peer, session_id: sessionId };
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
async function listAdhocPeers(opts = {}) {
|
|
620
|
+
const ctx = await loadAdhocContext(opts);
|
|
621
|
+
const status = await requestJson("GET", `${ctx.baseUrl}/codevelop/${encodeURIComponent(ctx.sessionId)}/status`);
|
|
622
|
+
console.log(`channel ${ctx.channel} (${ctx.sessionId})`);
|
|
623
|
+
for (const peer of Object.values(status.peers || {})) {
|
|
624
|
+
console.log(`${peer.peer_id}\trole=${peer.role || "participant"}\tqueued=${peer.queued}\tstreams=${peer.streams}\tlast_seen=${peer.last_seen_at || ""}`);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
async function sayAdhoc(opts = {}) {
|
|
629
|
+
const ctx = await loadAdhocContext(opts);
|
|
630
|
+
const message = opts.message || opts.task || opts.args?.join(" ") || "";
|
|
631
|
+
if (!String(message).trim()) throw new Error("--message is required for codevelop say");
|
|
632
|
+
|
|
633
|
+
const status = await requestJson("GET", `${ctx.baseUrl}/codevelop/${encodeURIComponent(ctx.sessionId)}/status`);
|
|
634
|
+
const explicitTo = normalizeOptionalAdhocId(opts.to);
|
|
635
|
+
const targets = explicitTo
|
|
636
|
+
? [explicitTo]
|
|
637
|
+
: Object.keys(status.peers || {}).filter(peer => peer !== ctx.peer && peer !== "system");
|
|
638
|
+
if (!targets.length) {
|
|
639
|
+
throw new Error(`No other peers are in channel ${ctx.channel}. Have the other pane run: clauth codevelop join --channel ${ctx.channel} --peer claude-1`);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
const sent = [];
|
|
643
|
+
for (const target of targets) {
|
|
644
|
+
const result = await requestJson("POST", `${ctx.baseUrl}/codevelop/send`, {
|
|
645
|
+
session_id: ctx.sessionId,
|
|
646
|
+
from: ctx.peer,
|
|
647
|
+
to: target,
|
|
648
|
+
type: "chat",
|
|
649
|
+
task: message,
|
|
650
|
+
message,
|
|
651
|
+
context: {
|
|
652
|
+
mode: "adhoc-channel",
|
|
653
|
+
channel: ctx.channel,
|
|
654
|
+
},
|
|
655
|
+
});
|
|
656
|
+
sent.push(result);
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
console.log(JSON.stringify({
|
|
660
|
+
channel: ctx.channel,
|
|
661
|
+
session_id: ctx.sessionId,
|
|
662
|
+
from: ctx.peer,
|
|
663
|
+
to: targets,
|
|
664
|
+
sent,
|
|
665
|
+
}, null, 2));
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
async function readAdhoc(opts = {}) {
|
|
669
|
+
const ctx = await loadAdhocContext(opts);
|
|
670
|
+
const inbox = await requestJson("POST", `${ctx.baseUrl}/codevelop/poll`, {
|
|
671
|
+
session_id: ctx.sessionId,
|
|
672
|
+
peer_id: ctx.peer,
|
|
673
|
+
});
|
|
674
|
+
if (asBool(opts.json)) {
|
|
675
|
+
console.log(JSON.stringify(inbox, null, 2));
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
if (!inbox.count) {
|
|
679
|
+
console.log(`channel ${ctx.channel}: no messages for ${ctx.peer}`);
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
682
|
+
for (const message of inbox.messages || []) console.log(formatAdhocMessage(message));
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
async function watchAdhoc(opts = {}) {
|
|
686
|
+
const ctx = await loadAdhocContext(opts);
|
|
687
|
+
const streamUrl = `${ctx.baseUrl}/codevelop/${encodeURIComponent(ctx.sessionId)}/${encodeURIComponent(ctx.peer)}/stream`;
|
|
688
|
+
const once = asBool(opts.once);
|
|
689
|
+
console.log(`Watching channel ${ctx.channel} as ${ctx.peer}`);
|
|
690
|
+
console.log(`stream ${streamUrl}`);
|
|
691
|
+
|
|
692
|
+
connectSse(streamUrl, {
|
|
693
|
+
onEvent: ({ event, data }) => {
|
|
694
|
+
if (event !== "message" && event !== "stop") return;
|
|
695
|
+
console.log(formatAdhocMessage(data || {}));
|
|
696
|
+
if (once) process.exit(0);
|
|
697
|
+
},
|
|
698
|
+
onError: err => {
|
|
699
|
+
console.error(`watch error: ${err.message}`);
|
|
700
|
+
process.exitCode = 1;
|
|
701
|
+
},
|
|
702
|
+
});
|
|
703
|
+
await new Promise(() => {});
|
|
704
|
+
}
|
|
705
|
+
|
|
433
706
|
function inferFromPeer({ from, to, peer } = {}) {
|
|
434
707
|
const explicit = normalizeOptionalPeer(from) || normalizeOptionalPeer(peer) || normalizeOptionalPeer(process.env.CODEVELOP_PEER);
|
|
435
708
|
if (explicit) return explicit;
|
|
@@ -884,6 +1157,11 @@ export async function runCodevelop(opts = {}) {
|
|
|
884
1157
|
return;
|
|
885
1158
|
}
|
|
886
1159
|
if (action === "start") return startCodevelop(opts);
|
|
1160
|
+
if (action === "join") return joinAdhocChannel(opts);
|
|
1161
|
+
if (action === "say") return sayAdhoc(opts);
|
|
1162
|
+
if (action === "read") return readAdhoc(opts);
|
|
1163
|
+
if (action === "watch") return watchAdhoc(opts);
|
|
1164
|
+
if (action === "who") return listAdhocPeers(opts);
|
|
887
1165
|
if (action === "launch-peer") return launchPeer(opts);
|
|
888
1166
|
if (action === "check-partner") return checkPartner(opts);
|
|
889
1167
|
if (action === "sync") return syncPartner(opts);
|
|
@@ -896,6 +1174,11 @@ export async function runCodevelop(opts = {}) {
|
|
|
896
1174
|
console.log(chalk.cyan("\nclauth codevelop\n"));
|
|
897
1175
|
console.log(" clauth codevelop install-terminal [--repo C:\\Dev\\regen-root]");
|
|
898
1176
|
console.log(" clauth codevelop start --port 53137 --start-isolated-clauth [--repo C:\\Dev\\regen-root]");
|
|
1177
|
+
console.log(" clauth codevelop join --channel 1 --peer codex-1 [--start-isolated-clauth]");
|
|
1178
|
+
console.log(" clauth codevelop say --message \"claude-1 look at this doc and report back\" [--to claude-1]");
|
|
1179
|
+
console.log(" clauth codevelop read");
|
|
1180
|
+
console.log(" clauth codevelop watch [--once]");
|
|
1181
|
+
console.log(" clauth codevelop who");
|
|
899
1182
|
console.log(" clauth codevelop ask --to claude|codex --task \"...\" --wait");
|
|
900
1183
|
console.log(" clauth codevelop reply --from claude|codex --turn turn-0001 --summary \"...\" --evidence \"...\"");
|
|
901
1184
|
console.log(" clauth codevelop inbox --peer claude|codex");
|
package/cli/commands/install.js
CHANGED
|
@@ -127,10 +127,11 @@ export async function runInstall(opts = {}) {
|
|
|
127
127
|
|
|
128
128
|
// Run migrations
|
|
129
129
|
const s4 = ora('Running database migrations...').start();
|
|
130
|
-
const migrations = [
|
|
131
|
-
{ name: '001_clauth_schema', file: 'supabase/migrations/001_clauth_schema.sql' },
|
|
132
|
-
{ name: '002_vault_helpers', file: 'supabase/migrations/002_vault_helpers.sql' },
|
|
133
|
-
|
|
130
|
+
const migrations = [
|
|
131
|
+
{ name: '001_clauth_schema', file: 'supabase/migrations/001_clauth_schema.sql' },
|
|
132
|
+
{ name: '002_vault_helpers', file: 'supabase/migrations/002_vault_helpers.sql' },
|
|
133
|
+
{ name: '003_machine_enrollments', file: 'supabase/migrations/003_machine_enrollments.sql' },
|
|
134
|
+
];
|
|
134
135
|
for (const m of migrations) {
|
|
135
136
|
const sql = readFileSync(join(ROOT, m.file), 'utf8');
|
|
136
137
|
try {
|
|
@@ -251,10 +252,11 @@ export async function runInstall(opts = {}) {
|
|
|
251
252
|
|
|
252
253
|
// ── Step 4: Run migrations ────────────────
|
|
253
254
|
const s4 = ora('Running database migrations...').start();
|
|
254
|
-
const migrations = [
|
|
255
|
-
{ name: '001_clauth_schema', file: 'supabase/migrations/001_clauth_schema.sql' },
|
|
256
|
-
{ name: '002_vault_helpers', file: 'supabase/migrations/002_vault_helpers.sql' },
|
|
257
|
-
|
|
255
|
+
const migrations = [
|
|
256
|
+
{ name: '001_clauth_schema', file: 'supabase/migrations/001_clauth_schema.sql' },
|
|
257
|
+
{ name: '002_vault_helpers', file: 'supabase/migrations/002_vault_helpers.sql' },
|
|
258
|
+
{ name: '003_machine_enrollments', file: 'supabase/migrations/003_machine_enrollments.sql' },
|
|
259
|
+
];
|
|
258
260
|
for (const m of migrations) {
|
|
259
261
|
const sql = readFileSync(join(ROOT, m.file), 'utf8');
|
|
260
262
|
try {
|