claudemesh-cli 1.0.0-alpha.31 → 1.0.0-alpha.33
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/dist/entrypoints/cli.js +69 -31
- package/dist/entrypoints/cli.js.map +6 -6
- package/dist/entrypoints/mcp.js +753 -30
- package/dist/entrypoints/mcp.js.map +26 -5
- package/package.json +2 -2
package/dist/entrypoints/mcp.js
CHANGED
|
@@ -3465,6 +3465,693 @@ var init_exit_codes = __esm(() => {
|
|
|
3465
3465
|
};
|
|
3466
3466
|
});
|
|
3467
3467
|
|
|
3468
|
+
// src/constants/timings.ts
|
|
3469
|
+
var TIMINGS;
|
|
3470
|
+
var init_timings = __esm(() => {
|
|
3471
|
+
TIMINGS = {
|
|
3472
|
+
DEVICE_CODE_POLL_MS: 1500,
|
|
3473
|
+
DEVICE_CODE_TIMEOUT_MS: 5 * 60 * 1000,
|
|
3474
|
+
WS_RECONNECT_BASE_MS: 1000,
|
|
3475
|
+
WS_RECONNECT_MAX_MS: 30000,
|
|
3476
|
+
UPDATE_CHECK_INTERVAL_MS: 24 * 60 * 60 * 1000,
|
|
3477
|
+
TELEGRAM_CONNECT_TIMEOUT_MS: 5 * 60 * 1000,
|
|
3478
|
+
TELEGRAM_POLL_INTERVAL_MS: 2000,
|
|
3479
|
+
API_TIMEOUT_MS: 15000,
|
|
3480
|
+
API_RETRY_COUNT: 2
|
|
3481
|
+
};
|
|
3482
|
+
});
|
|
3483
|
+
|
|
3484
|
+
// src/constants/urls.ts
|
|
3485
|
+
var exports_urls = {};
|
|
3486
|
+
__export(exports_urls, {
|
|
3487
|
+
env: () => env,
|
|
3488
|
+
VERSION: () => VERSION,
|
|
3489
|
+
URLS: () => URLS
|
|
3490
|
+
});
|
|
3491
|
+
var URLS, VERSION = "1.0.0-alpha.33", env;
|
|
3492
|
+
var init_urls = __esm(() => {
|
|
3493
|
+
URLS = {
|
|
3494
|
+
BROKER: process.env.CLAUDEMESH_BROKER_URL ?? "wss://ic.claudemesh.com/ws",
|
|
3495
|
+
API_BASE: process.env.CLAUDEMESH_API_URL ?? "https://claudemesh.com",
|
|
3496
|
+
DASHBOARD: "https://claudemesh.com/dashboard",
|
|
3497
|
+
NPM_REGISTRY: "https://registry.npmjs.org/claudemesh-cli"
|
|
3498
|
+
};
|
|
3499
|
+
env = {
|
|
3500
|
+
CLAUDEMESH_BROKER_URL: URLS.BROKER,
|
|
3501
|
+
CLAUDEMESH_CONFIG_DIR: process.env.CLAUDEMESH_CONFIG_DIR || undefined,
|
|
3502
|
+
CLAUDEMESH_DEBUG: process.env.CLAUDEMESH_DEBUG === "1" || process.env.CLAUDEMESH_DEBUG === "true"
|
|
3503
|
+
};
|
|
3504
|
+
});
|
|
3505
|
+
|
|
3506
|
+
// src/services/logger/logger.ts
|
|
3507
|
+
function timestamp() {
|
|
3508
|
+
return new Date().toISOString();
|
|
3509
|
+
}
|
|
3510
|
+
function log(msg, ...args) {
|
|
3511
|
+
if (!isQuiet)
|
|
3512
|
+
console.log(msg, ...args);
|
|
3513
|
+
}
|
|
3514
|
+
function debug(msg, ...args) {
|
|
3515
|
+
if (isDebug)
|
|
3516
|
+
console.error(`[${timestamp()}] DEBUG ${msg}`, ...args);
|
|
3517
|
+
}
|
|
3518
|
+
function warn(msg, ...args) {
|
|
3519
|
+
console.error(`⚠ ${msg}`, ...args);
|
|
3520
|
+
}
|
|
3521
|
+
var isDebug, isQuiet;
|
|
3522
|
+
var init_logger = __esm(() => {
|
|
3523
|
+
isDebug = process.env.CLAUDEMESH_DEBUG === "1" || process.env.CLAUDEMESH_DEBUG === "true";
|
|
3524
|
+
isQuiet = process.argv.includes("-q") || process.argv.includes("--quiet");
|
|
3525
|
+
});
|
|
3526
|
+
|
|
3527
|
+
// src/services/logger/facade.ts
|
|
3528
|
+
var init_facade4 = __esm(() => {
|
|
3529
|
+
init_logger();
|
|
3530
|
+
});
|
|
3531
|
+
|
|
3532
|
+
// src/services/api/errors.ts
|
|
3533
|
+
var ApiError, NetworkError;
|
|
3534
|
+
var init_errors2 = __esm(() => {
|
|
3535
|
+
ApiError = class ApiError extends Error {
|
|
3536
|
+
status;
|
|
3537
|
+
statusText;
|
|
3538
|
+
body;
|
|
3539
|
+
constructor(status, statusText, body) {
|
|
3540
|
+
super(`API error ${status}: ${statusText}`);
|
|
3541
|
+
this.status = status;
|
|
3542
|
+
this.statusText = statusText;
|
|
3543
|
+
this.body = body;
|
|
3544
|
+
this.name = "ApiError";
|
|
3545
|
+
}
|
|
3546
|
+
get isUnauthorized() {
|
|
3547
|
+
return this.status === 401;
|
|
3548
|
+
}
|
|
3549
|
+
get isNotFound() {
|
|
3550
|
+
return this.status === 404;
|
|
3551
|
+
}
|
|
3552
|
+
get isConflict() {
|
|
3553
|
+
return this.status === 409;
|
|
3554
|
+
}
|
|
3555
|
+
get isRateLimited() {
|
|
3556
|
+
return this.status === 429;
|
|
3557
|
+
}
|
|
3558
|
+
};
|
|
3559
|
+
NetworkError = class NetworkError extends Error {
|
|
3560
|
+
url;
|
|
3561
|
+
constructor(url, cause) {
|
|
3562
|
+
super(`Network error reaching ${url}`);
|
|
3563
|
+
this.url = url;
|
|
3564
|
+
this.name = "NetworkError";
|
|
3565
|
+
this.cause = cause;
|
|
3566
|
+
}
|
|
3567
|
+
};
|
|
3568
|
+
});
|
|
3569
|
+
|
|
3570
|
+
// src/services/api/client.ts
|
|
3571
|
+
async function request(opts) {
|
|
3572
|
+
const base = opts.baseUrl ?? URLS.API_BASE;
|
|
3573
|
+
const url = `${base}${opts.path}`;
|
|
3574
|
+
const method = opts.method ?? "GET";
|
|
3575
|
+
const controller = new AbortController;
|
|
3576
|
+
const timeout = setTimeout(() => controller.abort(), opts.timeoutMs ?? TIMINGS.API_TIMEOUT_MS);
|
|
3577
|
+
const headers = {
|
|
3578
|
+
"Content-Type": "application/json",
|
|
3579
|
+
Accept: "application/json",
|
|
3580
|
+
"User-Agent": "claudemesh-cli/1.0"
|
|
3581
|
+
};
|
|
3582
|
+
if (opts.token)
|
|
3583
|
+
headers.Authorization = `Bearer ${opts.token}`;
|
|
3584
|
+
debug(`${method} ${url}`);
|
|
3585
|
+
try {
|
|
3586
|
+
const res = await fetch(url, {
|
|
3587
|
+
method,
|
|
3588
|
+
headers,
|
|
3589
|
+
body: opts.body ? JSON.stringify(opts.body) : undefined,
|
|
3590
|
+
signal: controller.signal
|
|
3591
|
+
});
|
|
3592
|
+
if (!res.ok) {
|
|
3593
|
+
let body;
|
|
3594
|
+
try {
|
|
3595
|
+
body = await res.json();
|
|
3596
|
+
} catch {
|
|
3597
|
+
body = await res.text();
|
|
3598
|
+
}
|
|
3599
|
+
throw new ApiError(res.status, res.statusText, body);
|
|
3600
|
+
}
|
|
3601
|
+
const text = await res.text();
|
|
3602
|
+
if (!text)
|
|
3603
|
+
return;
|
|
3604
|
+
return JSON.parse(text);
|
|
3605
|
+
} catch (err) {
|
|
3606
|
+
if (err instanceof ApiError)
|
|
3607
|
+
throw err;
|
|
3608
|
+
throw new NetworkError(url, err);
|
|
3609
|
+
} finally {
|
|
3610
|
+
clearTimeout(timeout);
|
|
3611
|
+
}
|
|
3612
|
+
}
|
|
3613
|
+
async function get(path, token) {
|
|
3614
|
+
return request({ path, token });
|
|
3615
|
+
}
|
|
3616
|
+
async function post(path, body, token) {
|
|
3617
|
+
return request({ path, method: "POST", body, token });
|
|
3618
|
+
}
|
|
3619
|
+
var init_client = __esm(() => {
|
|
3620
|
+
init_urls();
|
|
3621
|
+
init_timings();
|
|
3622
|
+
init_facade4();
|
|
3623
|
+
init_errors2();
|
|
3624
|
+
});
|
|
3625
|
+
|
|
3626
|
+
// src/services/api/my.ts
|
|
3627
|
+
var exports_my = {};
|
|
3628
|
+
__export(exports_my, {
|
|
3629
|
+
revokeSession: () => revokeSession,
|
|
3630
|
+
renameMesh: () => renameMesh,
|
|
3631
|
+
getProfile: () => getProfile,
|
|
3632
|
+
getMeshes: () => getMeshes,
|
|
3633
|
+
createMesh: () => createMesh,
|
|
3634
|
+
createInvite: () => createInvite,
|
|
3635
|
+
cliSync: () => cliSync
|
|
3636
|
+
});
|
|
3637
|
+
async function getProfile(token) {
|
|
3638
|
+
return get("/api/my/profile", token);
|
|
3639
|
+
}
|
|
3640
|
+
async function getMeshes(token) {
|
|
3641
|
+
return get("/api/my/meshes", token);
|
|
3642
|
+
}
|
|
3643
|
+
async function createMesh(token, body) {
|
|
3644
|
+
return post("/api/my/meshes", body, token);
|
|
3645
|
+
}
|
|
3646
|
+
async function renameMesh(token, slug, newName) {
|
|
3647
|
+
return request({
|
|
3648
|
+
path: `/api/my/meshes/${slug}`,
|
|
3649
|
+
method: "PATCH",
|
|
3650
|
+
body: { name: newName },
|
|
3651
|
+
token
|
|
3652
|
+
});
|
|
3653
|
+
}
|
|
3654
|
+
async function createInvite(token, meshSlug, body) {
|
|
3655
|
+
return post(`/api/my/meshes/${meshSlug}/invites`, body, token);
|
|
3656
|
+
}
|
|
3657
|
+
async function revokeSession(token) {
|
|
3658
|
+
const BROKER_HTTP = (await Promise.resolve().then(() => (init_urls(), exports_urls))).URLS.BROKER.replace("wss://", "https://").replace("ws://", "http://").replace("/ws", "");
|
|
3659
|
+
return request({
|
|
3660
|
+
path: "/cli/session/revoke",
|
|
3661
|
+
method: "POST",
|
|
3662
|
+
body: { token },
|
|
3663
|
+
baseUrl: BROKER_HTTP
|
|
3664
|
+
});
|
|
3665
|
+
}
|
|
3666
|
+
async function cliSync(token) {
|
|
3667
|
+
return post("/cli-sync", undefined, token);
|
|
3668
|
+
}
|
|
3669
|
+
var init_my = __esm(() => {
|
|
3670
|
+
init_client();
|
|
3671
|
+
});
|
|
3672
|
+
|
|
3673
|
+
// src/services/api/public.ts
|
|
3674
|
+
var exports_public = {};
|
|
3675
|
+
__export(exports_public, {
|
|
3676
|
+
requestDeviceCode: () => requestDeviceCode,
|
|
3677
|
+
pollDeviceCode: () => pollDeviceCode,
|
|
3678
|
+
claimInvite: () => claimInvite
|
|
3679
|
+
});
|
|
3680
|
+
async function claimInvite(code, body) {
|
|
3681
|
+
return post(`/api/public/invites/${code}/claim`, body);
|
|
3682
|
+
}
|
|
3683
|
+
async function requestDeviceCode(deviceInfo) {
|
|
3684
|
+
return request({
|
|
3685
|
+
path: "/cli/device-code",
|
|
3686
|
+
method: "POST",
|
|
3687
|
+
body: deviceInfo,
|
|
3688
|
+
baseUrl: BROKER_HTTP
|
|
3689
|
+
});
|
|
3690
|
+
}
|
|
3691
|
+
async function pollDeviceCode(deviceCode) {
|
|
3692
|
+
return request({
|
|
3693
|
+
path: `/cli/device-code/${deviceCode}`,
|
|
3694
|
+
baseUrl: BROKER_HTTP
|
|
3695
|
+
});
|
|
3696
|
+
}
|
|
3697
|
+
var BROKER_HTTP;
|
|
3698
|
+
var init_public = __esm(() => {
|
|
3699
|
+
init_client();
|
|
3700
|
+
init_urls();
|
|
3701
|
+
BROKER_HTTP = URLS.BROKER.replace("wss://", "https://").replace("ws://", "http://").replace("/ws", "");
|
|
3702
|
+
});
|
|
3703
|
+
|
|
3704
|
+
// src/services/api/facade.ts
|
|
3705
|
+
var init_facade5 = __esm(() => {
|
|
3706
|
+
init_client();
|
|
3707
|
+
init_errors2();
|
|
3708
|
+
init_my();
|
|
3709
|
+
init_public();
|
|
3710
|
+
});
|
|
3711
|
+
|
|
3712
|
+
// src/services/device/info.ts
|
|
3713
|
+
import { hostname as hostname2, platform as platform2, arch, release } from "node:os";
|
|
3714
|
+
function getDeviceInfo() {
|
|
3715
|
+
return {
|
|
3716
|
+
hostname: hostname2(),
|
|
3717
|
+
platform: platform2(),
|
|
3718
|
+
arch: arch(),
|
|
3719
|
+
osRelease: release(),
|
|
3720
|
+
nodeVersion: process.version
|
|
3721
|
+
};
|
|
3722
|
+
}
|
|
3723
|
+
var init_info = () => {};
|
|
3724
|
+
|
|
3725
|
+
// src/services/device/facade.ts
|
|
3726
|
+
var init_facade6 = __esm(() => {
|
|
3727
|
+
init_info();
|
|
3728
|
+
});
|
|
3729
|
+
|
|
3730
|
+
// src/services/spawn/claude.ts
|
|
3731
|
+
import { spawnSync } from "node:child_process";
|
|
3732
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
3733
|
+
function findClaudeBinary() {
|
|
3734
|
+
const candidates = [
|
|
3735
|
+
process.env.CLAUDE_BIN,
|
|
3736
|
+
"/usr/local/bin/claude",
|
|
3737
|
+
`${process.env.HOME}/.local/bin/claude`,
|
|
3738
|
+
`${process.env.HOME}/.npm/bin/claude`
|
|
3739
|
+
].filter(Boolean);
|
|
3740
|
+
for (const bin of candidates) {
|
|
3741
|
+
if (existsSync2(bin))
|
|
3742
|
+
return bin;
|
|
3743
|
+
}
|
|
3744
|
+
const which = spawnSync("which", ["claude"], { encoding: "utf-8" });
|
|
3745
|
+
if (which.status === 0 && which.stdout.trim())
|
|
3746
|
+
return which.stdout.trim();
|
|
3747
|
+
return null;
|
|
3748
|
+
}
|
|
3749
|
+
function spawnClaude(opts) {
|
|
3750
|
+
const bin = findClaudeBinary();
|
|
3751
|
+
if (!bin)
|
|
3752
|
+
throw new Error("Claude binary not found. Install with: npm i -g @anthropic-ai/claude-code");
|
|
3753
|
+
return spawnSync(bin, opts.args, {
|
|
3754
|
+
stdio: "inherit",
|
|
3755
|
+
env: { ...process.env, ...opts.env },
|
|
3756
|
+
cwd: opts.cwd
|
|
3757
|
+
});
|
|
3758
|
+
}
|
|
3759
|
+
var init_claude = () => {};
|
|
3760
|
+
|
|
3761
|
+
// src/services/spawn/browser.ts
|
|
3762
|
+
import { execFile } from "node:child_process";
|
|
3763
|
+
import { platform as platform3 } from "node:os";
|
|
3764
|
+
function openBrowser(url) {
|
|
3765
|
+
return new Promise((resolve, reject) => {
|
|
3766
|
+
const os = platform3();
|
|
3767
|
+
let bin;
|
|
3768
|
+
let args;
|
|
3769
|
+
if (os === "darwin") {
|
|
3770
|
+
bin = "open";
|
|
3771
|
+
args = [url];
|
|
3772
|
+
} else if (os === "win32") {
|
|
3773
|
+
bin = "cmd";
|
|
3774
|
+
args = ["/c", "start", "", url];
|
|
3775
|
+
} else {
|
|
3776
|
+
bin = "xdg-open";
|
|
3777
|
+
args = [url];
|
|
3778
|
+
}
|
|
3779
|
+
execFile(bin, args, (err) => {
|
|
3780
|
+
if (err)
|
|
3781
|
+
reject(err);
|
|
3782
|
+
else
|
|
3783
|
+
resolve();
|
|
3784
|
+
});
|
|
3785
|
+
});
|
|
3786
|
+
}
|
|
3787
|
+
var init_browser = () => {};
|
|
3788
|
+
|
|
3789
|
+
// src/services/spawn/facade.ts
|
|
3790
|
+
var exports_facade3 = {};
|
|
3791
|
+
__export(exports_facade3, {
|
|
3792
|
+
spawnClaude: () => spawnClaude,
|
|
3793
|
+
openBrowser: () => openBrowser,
|
|
3794
|
+
findClaudeBinary: () => findClaudeBinary
|
|
3795
|
+
});
|
|
3796
|
+
var init_facade7 = __esm(() => {
|
|
3797
|
+
init_claude();
|
|
3798
|
+
init_browser();
|
|
3799
|
+
});
|
|
3800
|
+
|
|
3801
|
+
// src/services/auth/token-store.ts
|
|
3802
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, unlinkSync, existsSync as existsSync3, openSync as openSync2, closeSync as closeSync2 } from "node:fs";
|
|
3803
|
+
function getStoredToken() {
|
|
3804
|
+
if (!existsSync3(PATHS.AUTH_FILE))
|
|
3805
|
+
return null;
|
|
3806
|
+
try {
|
|
3807
|
+
const raw = readFileSync2(PATHS.AUTH_FILE, "utf-8");
|
|
3808
|
+
return JSON.parse(raw);
|
|
3809
|
+
} catch {
|
|
3810
|
+
return null;
|
|
3811
|
+
}
|
|
3812
|
+
}
|
|
3813
|
+
function storeToken(auth) {
|
|
3814
|
+
ensureConfigDir();
|
|
3815
|
+
const data = { ...auth, stored_at: new Date().toISOString() };
|
|
3816
|
+
const content = JSON.stringify(data, null, 2) + `
|
|
3817
|
+
`;
|
|
3818
|
+
const fd = openSync2(PATHS.AUTH_FILE, "w", 384);
|
|
3819
|
+
try {
|
|
3820
|
+
writeFileSync2(fd, content, "utf-8");
|
|
3821
|
+
} finally {
|
|
3822
|
+
closeSync2(fd);
|
|
3823
|
+
}
|
|
3824
|
+
}
|
|
3825
|
+
function clearToken() {
|
|
3826
|
+
try {
|
|
3827
|
+
unlinkSync(PATHS.AUTH_FILE);
|
|
3828
|
+
} catch {}
|
|
3829
|
+
}
|
|
3830
|
+
var init_token_store = __esm(() => {
|
|
3831
|
+
init_paths();
|
|
3832
|
+
init_facade();
|
|
3833
|
+
});
|
|
3834
|
+
|
|
3835
|
+
// src/services/auth/errors.ts
|
|
3836
|
+
var AuthError, DeviceCodeExpired, NotSignedIn;
|
|
3837
|
+
var init_errors3 = __esm(() => {
|
|
3838
|
+
AuthError = class AuthError extends Error {
|
|
3839
|
+
constructor(message) {
|
|
3840
|
+
super(message);
|
|
3841
|
+
this.name = "AuthError";
|
|
3842
|
+
}
|
|
3843
|
+
};
|
|
3844
|
+
DeviceCodeExpired = class DeviceCodeExpired extends AuthError {
|
|
3845
|
+
constructor() {
|
|
3846
|
+
super("Device code expired. Run `claudemesh login` again.");
|
|
3847
|
+
}
|
|
3848
|
+
};
|
|
3849
|
+
NotSignedIn = class NotSignedIn extends AuthError {
|
|
3850
|
+
constructor() {
|
|
3851
|
+
super("Not signed in. Run `claudemesh login` first.");
|
|
3852
|
+
}
|
|
3853
|
+
};
|
|
3854
|
+
});
|
|
3855
|
+
|
|
3856
|
+
// src/services/auth/device-code.ts
|
|
3857
|
+
import { createInterface as createInterface2 } from "node:readline";
|
|
3858
|
+
function parseJwtUser(token) {
|
|
3859
|
+
try {
|
|
3860
|
+
const parts = token.split(".");
|
|
3861
|
+
if (parts[1]) {
|
|
3862
|
+
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
|
|
3863
|
+
if (payload.exp && payload.exp < Date.now() / 1000)
|
|
3864
|
+
throw new Error("expired");
|
|
3865
|
+
return {
|
|
3866
|
+
id: payload.sub ?? "",
|
|
3867
|
+
display_name: payload.name ?? payload.email ?? "",
|
|
3868
|
+
email: payload.email ?? ""
|
|
3869
|
+
};
|
|
3870
|
+
}
|
|
3871
|
+
} catch {}
|
|
3872
|
+
throw new Error("Invalid token");
|
|
3873
|
+
}
|
|
3874
|
+
async function loginWithDeviceCode() {
|
|
3875
|
+
const device = getDeviceInfo();
|
|
3876
|
+
const { device_code, user_code, session_id, verification_url, token_url } = await exports_public.requestDeviceCode({
|
|
3877
|
+
hostname: device.hostname,
|
|
3878
|
+
platform: device.platform,
|
|
3879
|
+
arch: device.arch
|
|
3880
|
+
});
|
|
3881
|
+
const browserUrl = `${verification_url}?session=${session_id}`;
|
|
3882
|
+
const isTTY2 = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
3883
|
+
const orange2 = (s) => isTTY2 ? `\x1B[38;5;208m${s}\x1B[0m` : s;
|
|
3884
|
+
const bold2 = (s) => isTTY2 ? `\x1B[1m${s}\x1B[0m` : s;
|
|
3885
|
+
const dim2 = (s) => isTTY2 ? `\x1B[2m${s}\x1B[0m` : s;
|
|
3886
|
+
log("");
|
|
3887
|
+
log(" " + orange2("claudemesh") + " — sign in to connect your terminal");
|
|
3888
|
+
log("");
|
|
3889
|
+
log(" ┌──────────────────────────────────┐");
|
|
3890
|
+
log(" │ │");
|
|
3891
|
+
log(" │ Your code: " + bold2(user_code) + " │");
|
|
3892
|
+
log(" │ │");
|
|
3893
|
+
log(" └──────────────────────────────────┘");
|
|
3894
|
+
log("");
|
|
3895
|
+
log(" " + dim2("Confirm this code matches your browser."));
|
|
3896
|
+
log("");
|
|
3897
|
+
log(" " + dim2("If the browser didn't open, visit:"));
|
|
3898
|
+
log(" " + browserUrl);
|
|
3899
|
+
log("");
|
|
3900
|
+
log(" " + dim2("Can't use a browser? Generate a token at:"));
|
|
3901
|
+
log(" " + (token_url || verification_url.replace("/cli-auth", "/token")));
|
|
3902
|
+
log(" " + dim2("Then paste it below."));
|
|
3903
|
+
log("");
|
|
3904
|
+
log(" Waiting… " + dim2("(paste token or Ctrl-C to cancel)"));
|
|
3905
|
+
try {
|
|
3906
|
+
await openBrowser(browserUrl);
|
|
3907
|
+
} catch {
|
|
3908
|
+
warn(" Could not open browser automatically.");
|
|
3909
|
+
}
|
|
3910
|
+
return new Promise((resolve, reject) => {
|
|
3911
|
+
let done = false;
|
|
3912
|
+
const rl = createInterface2({ input: process.stdin, output: process.stdout });
|
|
3913
|
+
rl.on("line", (line) => {
|
|
3914
|
+
if (done)
|
|
3915
|
+
return;
|
|
3916
|
+
const trimmed = line.trim();
|
|
3917
|
+
if (trimmed.split(".").length === 3 && trimmed.length > 50) {
|
|
3918
|
+
done = true;
|
|
3919
|
+
rl.close();
|
|
3920
|
+
try {
|
|
3921
|
+
const user = parseJwtUser(trimmed);
|
|
3922
|
+
storeToken({ session_token: trimmed, user, token_source: "manual" });
|
|
3923
|
+
resolve({ user, session_token: trimmed });
|
|
3924
|
+
} catch (e) {
|
|
3925
|
+
reject(new Error("Invalid or expired token. Generate a new one."));
|
|
3926
|
+
}
|
|
3927
|
+
}
|
|
3928
|
+
});
|
|
3929
|
+
const startTime = Date.now();
|
|
3930
|
+
const poll = async () => {
|
|
3931
|
+
while (!done && Date.now() - startTime < TIMINGS.DEVICE_CODE_TIMEOUT_MS) {
|
|
3932
|
+
await new Promise((r) => setTimeout(r, TIMINGS.DEVICE_CODE_POLL_MS));
|
|
3933
|
+
if (done)
|
|
3934
|
+
return;
|
|
3935
|
+
try {
|
|
3936
|
+
const result = await exports_public.pollDeviceCode(device_code);
|
|
3937
|
+
if (result.status === "approved" && result.session_token && result.user) {
|
|
3938
|
+
if (done)
|
|
3939
|
+
return;
|
|
3940
|
+
done = true;
|
|
3941
|
+
rl.close();
|
|
3942
|
+
storeToken({ session_token: result.session_token, user: result.user, token_source: "device-code" });
|
|
3943
|
+
resolve({ user: result.user, session_token: result.session_token });
|
|
3944
|
+
return;
|
|
3945
|
+
}
|
|
3946
|
+
if (result.status === "expired") {
|
|
3947
|
+
if (done)
|
|
3948
|
+
return;
|
|
3949
|
+
done = true;
|
|
3950
|
+
rl.close();
|
|
3951
|
+
reject(new DeviceCodeExpired);
|
|
3952
|
+
return;
|
|
3953
|
+
}
|
|
3954
|
+
} catch {}
|
|
3955
|
+
}
|
|
3956
|
+
if (!done) {
|
|
3957
|
+
done = true;
|
|
3958
|
+
rl.close();
|
|
3959
|
+
reject(new DeviceCodeExpired);
|
|
3960
|
+
}
|
|
3961
|
+
};
|
|
3962
|
+
poll();
|
|
3963
|
+
});
|
|
3964
|
+
}
|
|
3965
|
+
var init_device_code = __esm(() => {
|
|
3966
|
+
init_timings();
|
|
3967
|
+
init_facade5();
|
|
3968
|
+
init_facade6();
|
|
3969
|
+
init_facade7();
|
|
3970
|
+
init_facade4();
|
|
3971
|
+
init_token_store();
|
|
3972
|
+
init_errors3();
|
|
3973
|
+
});
|
|
3974
|
+
|
|
3975
|
+
// src/services/auth/client.ts
|
|
3976
|
+
function requireToken() {
|
|
3977
|
+
const auth = getStoredToken();
|
|
3978
|
+
if (!auth)
|
|
3979
|
+
throw new NotSignedIn;
|
|
3980
|
+
return auth.session_token;
|
|
3981
|
+
}
|
|
3982
|
+
async function whoAmI() {
|
|
3983
|
+
const auth = getStoredToken();
|
|
3984
|
+
if (!auth)
|
|
3985
|
+
return { signed_in: false };
|
|
3986
|
+
try {
|
|
3987
|
+
const profile = await exports_my.getProfile(auth.session_token);
|
|
3988
|
+
const meshes = await exports_my.getMeshes(auth.session_token);
|
|
3989
|
+
const owned = meshes.filter((m) => m.role === "owner").length;
|
|
3990
|
+
return {
|
|
3991
|
+
signed_in: true,
|
|
3992
|
+
user: profile,
|
|
3993
|
+
token_source: auth.token_source,
|
|
3994
|
+
meshes: { owned, guest: meshes.length - owned }
|
|
3995
|
+
};
|
|
3996
|
+
} catch (err) {
|
|
3997
|
+
if (err instanceof ApiError && err.isUnauthorized) {
|
|
3998
|
+
clearToken();
|
|
3999
|
+
return { signed_in: false };
|
|
4000
|
+
}
|
|
4001
|
+
throw err;
|
|
4002
|
+
}
|
|
4003
|
+
}
|
|
4004
|
+
async function logout() {
|
|
4005
|
+
const token = requireToken();
|
|
4006
|
+
let revoked = false;
|
|
4007
|
+
try {
|
|
4008
|
+
await exports_my.revokeSession(token);
|
|
4009
|
+
revoked = true;
|
|
4010
|
+
} catch {}
|
|
4011
|
+
clearToken();
|
|
4012
|
+
return { revoked };
|
|
4013
|
+
}
|
|
4014
|
+
async function register(callbackPort) {
|
|
4015
|
+
const { openBrowser: openBrowser2 } = await Promise.resolve().then(() => (init_facade7(), exports_facade3));
|
|
4016
|
+
const url = `https://claudemesh.com/register?source=cli&callback=http://localhost:${callbackPort}`;
|
|
4017
|
+
await openBrowser2(url);
|
|
4018
|
+
}
|
|
4019
|
+
var init_client2 = __esm(() => {
|
|
4020
|
+
init_facade5();
|
|
4021
|
+
init_facade5();
|
|
4022
|
+
init_token_store();
|
|
4023
|
+
init_errors3();
|
|
4024
|
+
});
|
|
4025
|
+
|
|
4026
|
+
// src/services/auth/dashboard-sync.ts
|
|
4027
|
+
async function syncWithBroker(syncToken, peerPubkey, displayName, brokerBaseUrl) {
|
|
4028
|
+
const base = brokerBaseUrl ?? deriveHttpUrl(URLS.BROKER);
|
|
4029
|
+
const res = await fetch(`${base}/cli-sync`, {
|
|
4030
|
+
method: "POST",
|
|
4031
|
+
headers: { "Content-Type": "application/json" },
|
|
4032
|
+
body: JSON.stringify({
|
|
4033
|
+
sync_token: syncToken,
|
|
4034
|
+
peer_pubkey: peerPubkey,
|
|
4035
|
+
display_name: displayName
|
|
4036
|
+
})
|
|
4037
|
+
});
|
|
4038
|
+
if (!res.ok) {
|
|
4039
|
+
const body2 = await res.text();
|
|
4040
|
+
let msg;
|
|
4041
|
+
try {
|
|
4042
|
+
msg = JSON.parse(body2).error ?? body2;
|
|
4043
|
+
} catch {
|
|
4044
|
+
msg = body2;
|
|
4045
|
+
}
|
|
4046
|
+
throw new Error(`Broker sync failed (${res.status}): ${msg}`);
|
|
4047
|
+
}
|
|
4048
|
+
const body = await res.json();
|
|
4049
|
+
if (!body.ok)
|
|
4050
|
+
throw new Error(`Broker sync failed: ${body.error ?? "unknown error"}`);
|
|
4051
|
+
return { account_id: body.account_id, meshes: body.meshes };
|
|
4052
|
+
}
|
|
4053
|
+
function deriveHttpUrl(wssUrl) {
|
|
4054
|
+
const url = new URL(wssUrl);
|
|
4055
|
+
url.protocol = url.protocol === "wss:" ? "https:" : "http:";
|
|
4056
|
+
url.pathname = url.pathname.replace(/\/ws\/?$/, "");
|
|
4057
|
+
return url.toString().replace(/\/$/, "");
|
|
4058
|
+
}
|
|
4059
|
+
var init_dashboard_sync = __esm(() => {
|
|
4060
|
+
init_urls();
|
|
4061
|
+
});
|
|
4062
|
+
|
|
4063
|
+
// src/services/auth/callback-listener.ts
|
|
4064
|
+
import { createServer } from "node:http";
|
|
4065
|
+
function startCallbackListener() {
|
|
4066
|
+
return new Promise((resolveStart) => {
|
|
4067
|
+
let resolveToken;
|
|
4068
|
+
let resolved = false;
|
|
4069
|
+
const tokenPromise = new Promise((r) => {
|
|
4070
|
+
resolveToken = r;
|
|
4071
|
+
});
|
|
4072
|
+
const server = createServer((req, res) => {
|
|
4073
|
+
const url = new URL(req.url, "http://localhost");
|
|
4074
|
+
if (req.method === "OPTIONS") {
|
|
4075
|
+
res.writeHead(204, {
|
|
4076
|
+
"Access-Control-Allow-Origin": "https://claudemesh.com",
|
|
4077
|
+
"Access-Control-Allow-Methods": "GET",
|
|
4078
|
+
"Access-Control-Allow-Headers": "Content-Type"
|
|
4079
|
+
});
|
|
4080
|
+
res.end();
|
|
4081
|
+
return;
|
|
4082
|
+
}
|
|
4083
|
+
if (url.pathname === "/ping") {
|
|
4084
|
+
res.writeHead(200, {
|
|
4085
|
+
"Content-Type": "text/plain",
|
|
4086
|
+
"Access-Control-Allow-Origin": "https://claudemesh.com"
|
|
4087
|
+
});
|
|
4088
|
+
res.end("ok");
|
|
4089
|
+
return;
|
|
4090
|
+
}
|
|
4091
|
+
if (url.pathname === "/callback") {
|
|
4092
|
+
const token = url.searchParams.get("token");
|
|
4093
|
+
if (token && !resolved) {
|
|
4094
|
+
resolved = true;
|
|
4095
|
+
res.writeHead(200, {
|
|
4096
|
+
"Content-Type": "text/html",
|
|
4097
|
+
"Access-Control-Allow-Origin": "https://claudemesh.com"
|
|
4098
|
+
});
|
|
4099
|
+
res.end("<html><body><h2>Done! You can close this tab.</h2></body></html>");
|
|
4100
|
+
resolveToken(token);
|
|
4101
|
+
setTimeout(() => server.close(), 500);
|
|
4102
|
+
} else {
|
|
4103
|
+
res.writeHead(400, { "Content-Type": "text/plain" });
|
|
4104
|
+
res.end("Missing token");
|
|
4105
|
+
}
|
|
4106
|
+
return;
|
|
4107
|
+
}
|
|
4108
|
+
res.writeHead(404);
|
|
4109
|
+
res.end();
|
|
4110
|
+
});
|
|
4111
|
+
server.listen(0, "127.0.0.1", () => {
|
|
4112
|
+
const addr = server.address();
|
|
4113
|
+
resolveStart({
|
|
4114
|
+
port: addr.port,
|
|
4115
|
+
token: tokenPromise,
|
|
4116
|
+
close: () => server.close()
|
|
4117
|
+
});
|
|
4118
|
+
});
|
|
4119
|
+
});
|
|
4120
|
+
}
|
|
4121
|
+
var init_callback_listener = () => {};
|
|
4122
|
+
|
|
4123
|
+
// src/services/auth/facade.ts
|
|
4124
|
+
var exports_facade4 = {};
|
|
4125
|
+
__export(exports_facade4, {
|
|
4126
|
+
whoAmI: () => whoAmI,
|
|
4127
|
+
syncWithBroker: () => syncWithBroker,
|
|
4128
|
+
storeToken: () => storeToken,
|
|
4129
|
+
startCallbackListener: () => startCallbackListener,
|
|
4130
|
+
register: () => register,
|
|
4131
|
+
logout: () => logout,
|
|
4132
|
+
loginWithDeviceCode: () => loginWithDeviceCode,
|
|
4133
|
+
getStoredToken: () => getStoredToken,
|
|
4134
|
+
generatePairingCode: () => generatePairingCode,
|
|
4135
|
+
clearToken: () => clearToken,
|
|
4136
|
+
NotSignedIn: () => NotSignedIn,
|
|
4137
|
+
DeviceCodeExpired: () => DeviceCodeExpired,
|
|
4138
|
+
AuthError: () => AuthError
|
|
4139
|
+
});
|
|
4140
|
+
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
4141
|
+
function generatePairingCode() {
|
|
4142
|
+
const bytes = randomBytes3(4);
|
|
4143
|
+
return Array.from(bytes, (b) => CHARS[b % CHARS.length]).join("");
|
|
4144
|
+
}
|
|
4145
|
+
var CHARS = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz23456789";
|
|
4146
|
+
var init_facade8 = __esm(() => {
|
|
4147
|
+
init_device_code();
|
|
4148
|
+
init_client2();
|
|
4149
|
+
init_dashboard_sync();
|
|
4150
|
+
init_token_store();
|
|
4151
|
+
init_callback_listener();
|
|
4152
|
+
init_errors3();
|
|
4153
|
+
});
|
|
4154
|
+
|
|
3468
4155
|
// src/commands/grants.ts
|
|
3469
4156
|
var exports_grants = {};
|
|
3470
4157
|
__export(exports_grants, {
|
|
@@ -3474,23 +4161,47 @@ __export(exports_grants, {
|
|
|
3474
4161
|
runBlock: () => runBlock,
|
|
3475
4162
|
isAllowed: () => isAllowed
|
|
3476
4163
|
});
|
|
3477
|
-
import { existsSync as
|
|
4164
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
3478
4165
|
import { homedir as homedir2 } from "node:os";
|
|
3479
4166
|
import { join as join2 } from "node:path";
|
|
4167
|
+
async function syncToBroker(meshSlug, grants) {
|
|
4168
|
+
const auth = getStoredToken();
|
|
4169
|
+
if (!auth)
|
|
4170
|
+
return;
|
|
4171
|
+
let userId = "";
|
|
4172
|
+
try {
|
|
4173
|
+
const payload = JSON.parse(Buffer.from(auth.session_token.split(".")[1], "base64url").toString());
|
|
4174
|
+
userId = payload.sub ?? "";
|
|
4175
|
+
} catch {
|
|
4176
|
+
return;
|
|
4177
|
+
}
|
|
4178
|
+
if (!userId)
|
|
4179
|
+
return;
|
|
4180
|
+
try {
|
|
4181
|
+
await request({
|
|
4182
|
+
path: `/cli/mesh/${meshSlug}/grants`,
|
|
4183
|
+
method: "POST",
|
|
4184
|
+
body: { user_id: userId, grants },
|
|
4185
|
+
baseUrl: BROKER_HTTP2
|
|
4186
|
+
});
|
|
4187
|
+
} catch (e) {
|
|
4188
|
+
render.warn(`broker grant sync failed — client filter still active: ${e instanceof Error ? e.message : e}`);
|
|
4189
|
+
}
|
|
4190
|
+
}
|
|
3480
4191
|
function readGrants() {
|
|
3481
|
-
if (!
|
|
4192
|
+
if (!existsSync4(GRANT_FILE))
|
|
3482
4193
|
return {};
|
|
3483
4194
|
try {
|
|
3484
|
-
return JSON.parse(
|
|
4195
|
+
return JSON.parse(readFileSync3(GRANT_FILE, "utf-8"));
|
|
3485
4196
|
} catch {
|
|
3486
4197
|
return {};
|
|
3487
4198
|
}
|
|
3488
4199
|
}
|
|
3489
4200
|
function writeGrants(g) {
|
|
3490
4201
|
const dir = join2(homedir2(), ".claudemesh");
|
|
3491
|
-
if (!
|
|
4202
|
+
if (!existsSync4(dir))
|
|
3492
4203
|
mkdirSync2(dir, { recursive: true });
|
|
3493
|
-
|
|
4204
|
+
writeFileSync3(GRANT_FILE, JSON.stringify(g, null, 2), { mode: 384 });
|
|
3494
4205
|
}
|
|
3495
4206
|
function resolveCaps(input) {
|
|
3496
4207
|
if (input.includes("all"))
|
|
@@ -3538,6 +4249,7 @@ async function runGrant(peer, caps, opts = {}) {
|
|
|
3538
4249
|
meshGrants[resolved.pubkey] = merged;
|
|
3539
4250
|
store[mesh] = meshGrants;
|
|
3540
4251
|
writeGrants(store);
|
|
4252
|
+
await syncToBroker(mesh, { [resolved.pubkey]: merged });
|
|
3541
4253
|
render.ok(`Granted ${wanted.join(", ")} to ${resolved.displayName} on ${mesh}.`);
|
|
3542
4254
|
render.kv([["now", merged.join(", ")]]);
|
|
3543
4255
|
return EXIT.SUCCESS;
|
|
@@ -3565,6 +4277,7 @@ async function runRevoke(peer, caps, opts = {}) {
|
|
|
3565
4277
|
meshGrants[resolved.pubkey] = after;
|
|
3566
4278
|
store[mesh] = meshGrants;
|
|
3567
4279
|
writeGrants(store);
|
|
4280
|
+
await syncToBroker(mesh, { [resolved.pubkey]: after });
|
|
3568
4281
|
render.ok(`Revoked ${wanted.join(", ")} from ${resolved.displayName} on ${mesh}.`);
|
|
3569
4282
|
render.kv([["now", after.length ? after.join(", ") : "(none)"]]);
|
|
3570
4283
|
return EXIT.SUCCESS;
|
|
@@ -3589,6 +4302,7 @@ async function runBlock(peer, opts = {}) {
|
|
|
3589
4302
|
meshGrants[resolved.pubkey] = [];
|
|
3590
4303
|
store[mesh] = meshGrants;
|
|
3591
4304
|
writeGrants(store);
|
|
4305
|
+
await syncToBroker(mesh, { [resolved.pubkey]: [] });
|
|
3592
4306
|
render.ok(`Blocked ${resolved.displayName} on ${mesh} (all capabilities revoked).`);
|
|
3593
4307
|
render.hint(`Undo with: claudemesh grant ${resolved.displayName} all --mesh ${mesh}`);
|
|
3594
4308
|
return EXIT.SUCCESS;
|
|
@@ -3628,12 +4342,16 @@ function isAllowed(meshSlug, peerPubkey, cap) {
|
|
|
3628
4342
|
return DEFAULT_CAPS.includes(cap);
|
|
3629
4343
|
return entry.includes(cap);
|
|
3630
4344
|
}
|
|
3631
|
-
var ALL_CAPS, DEFAULT_CAPS, GRANT_FILE;
|
|
4345
|
+
var BROKER_HTTP2, ALL_CAPS, DEFAULT_CAPS, GRANT_FILE;
|
|
3632
4346
|
var init_grants = __esm(() => {
|
|
3633
4347
|
init_facade();
|
|
3634
4348
|
init_connect();
|
|
3635
4349
|
init_render();
|
|
3636
4350
|
init_exit_codes();
|
|
4351
|
+
init_facade8();
|
|
4352
|
+
init_facade5();
|
|
4353
|
+
init_urls();
|
|
4354
|
+
BROKER_HTTP2 = URLS.BROKER.replace("wss://", "https://").replace("ws://", "http://").replace("/ws", "");
|
|
3637
4355
|
ALL_CAPS = ["read", "dm", "broadcast", "state-read", "state-write", "file-read"];
|
|
3638
4356
|
DEFAULT_CAPS = ["read", "dm", "broadcast", "state-read"];
|
|
3639
4357
|
GRANT_FILE = join2(homedir2(), ".claudemesh", "grants.json");
|
|
@@ -3703,8 +4421,10 @@ async function resolveClient(to) {
|
|
|
3703
4421
|
};
|
|
3704
4422
|
}
|
|
3705
4423
|
const nameLower = target.toLowerCase();
|
|
4424
|
+
const candidates = [];
|
|
3706
4425
|
for (const c of targetClients) {
|
|
3707
4426
|
const peers = await c.listPeers();
|
|
4427
|
+
candidates.push({ mesh: c.meshSlug, peers });
|
|
3708
4428
|
const match = peers.find((p) => p.displayName.toLowerCase() === nameLower);
|
|
3709
4429
|
if (match)
|
|
3710
4430
|
return { client: c, targetSpec: match.pubkey };
|
|
@@ -3715,13 +4435,11 @@ async function resolveClient(to) {
|
|
|
3715
4435
|
return { client: c, targetSpec: partials[0].pubkey };
|
|
3716
4436
|
}
|
|
3717
4437
|
}
|
|
3718
|
-
|
|
3719
|
-
return { client: targetClients[0], targetSpec: target };
|
|
3720
|
-
}
|
|
4438
|
+
const known = candidates.flatMap((c) => c.peers.map((p) => `${c.mesh}/${p.displayName}`));
|
|
3721
4439
|
return {
|
|
3722
4440
|
client: null,
|
|
3723
4441
|
targetSpec: target,
|
|
3724
|
-
error: `peer "${target}" not found
|
|
4442
|
+
error: `peer "${target}" not found. ` + (known.length ? `Known peers: ${known.slice(0, 10).join(", ")}${known.length > 10 ? ", …" : ""}` : "No connected peers on your mesh(es). Use pubkey hex, @group, or * for broadcast.")
|
|
3725
4443
|
};
|
|
3726
4444
|
}
|
|
3727
4445
|
async function resolvePeerName(client, pubkey) {
|
|
@@ -4039,9 +4757,9 @@ ${manifest.allowed_tools.map((t) => ` - ${t}`).join(`
|
|
|
4039
4757
|
const results = [];
|
|
4040
4758
|
const seen = new Set;
|
|
4041
4759
|
for (const target of targets) {
|
|
4042
|
-
const { client, targetSpec, error } = await resolveClient(target);
|
|
4760
|
+
const { client, targetSpec, error: error2 } = await resolveClient(target);
|
|
4043
4761
|
if (!client) {
|
|
4044
|
-
results.push(`✗ ${target}: ${
|
|
4762
|
+
results.push(`✗ ${target}: ${error2 ?? "no client resolved"}`);
|
|
4045
4763
|
continue;
|
|
4046
4764
|
}
|
|
4047
4765
|
if (seen.has(targetSpec))
|
|
@@ -4077,6 +4795,9 @@ ${manifest.allowed_tools.map((t) => ` - ${t}`).join(`
|
|
|
4077
4795
|
sections.push(`${header}
|
|
4078
4796
|
No peers connected.`);
|
|
4079
4797
|
} else {
|
|
4798
|
+
const pubkeyCounts = new Map;
|
|
4799
|
+
for (const p of peers)
|
|
4800
|
+
pubkeyCounts.set(p.pubkey, (pubkeyCounts.get(p.pubkey) ?? 0) + 1);
|
|
4080
4801
|
const peerLines = peers.map((p) => {
|
|
4081
4802
|
const summary = p.summary ? ` — "${p.summary}"` : "";
|
|
4082
4803
|
const groupsStr = p.groups?.length ? ` [${p.groups.map((g) => `@${g.name}${g.role ? ":" + g.role : ""}`).join(", ")}]` : "";
|
|
@@ -4094,7 +4815,9 @@ No peers connected.`);
|
|
|
4094
4815
|
const profileAvatar = p.profile?.avatar ? `${p.profile.avatar} ` : "";
|
|
4095
4816
|
const profileTitle = p.profile?.title ? ` (${p.profile.title})` : "";
|
|
4096
4817
|
const hiddenTag = p.visible === false ? " [hidden]" : "";
|
|
4097
|
-
|
|
4818
|
+
const sameKeyCount = pubkeyCounts.get(p.pubkey) ?? 1;
|
|
4819
|
+
const sameKeyTag = sameKeyCount > 1 ? ` [shares key with ${sameKeyCount - 1} other session(s)]` : "";
|
|
4820
|
+
return `- ${profileAvatar}**${p.displayName}**${profileTitle} [${p.status}]${localityTag}${hiddenTag}${sameKeyTag}${groupsStr}${metaStr} (${p.pubkey.slice(0, 12)}…)${cwdStr}${summary}`;
|
|
4098
4821
|
});
|
|
4099
4822
|
sections.push(`${header}
|
|
4100
4823
|
${peerLines.join(`
|
|
@@ -4102,13 +4825,13 @@ ${peerLines.join(`
|
|
|
4102
4825
|
}
|
|
4103
4826
|
}
|
|
4104
4827
|
try {
|
|
4105
|
-
const { writeFileSync:
|
|
4828
|
+
const { writeFileSync: writeFileSync4, mkdirSync: mkdirSync3, existsSync: existsSync5 } = await import("node:fs");
|
|
4106
4829
|
const { join: joinPath } = await import("node:path");
|
|
4107
4830
|
const { homedir: homedir3 } = await import("node:os");
|
|
4108
4831
|
const dir = joinPath(homedir3(), ".claudemesh");
|
|
4109
|
-
if (!
|
|
4832
|
+
if (!existsSync5(dir))
|
|
4110
4833
|
mkdirSync3(dir, { recursive: true });
|
|
4111
|
-
|
|
4834
|
+
writeFileSync4(joinPath(dir, "peer-cache.json"), JSON.stringify(statusCache));
|
|
4112
4835
|
} catch {}
|
|
4113
4836
|
return text(sections.join(`
|
|
4114
4837
|
|
|
@@ -4350,15 +5073,15 @@ ${lines.join(`
|
|
|
4350
5073
|
const { path: filePath, name: fileName, tags, to: fileTo } = args ?? {};
|
|
4351
5074
|
if (!filePath)
|
|
4352
5075
|
return text("share_file: `path` required", true);
|
|
4353
|
-
const { existsSync:
|
|
4354
|
-
if (!
|
|
5076
|
+
const { existsSync: existsSync5 } = await import("node:fs");
|
|
5077
|
+
if (!existsSync5(filePath))
|
|
4355
5078
|
return text(`share_file: file not found: ${filePath}`, true);
|
|
4356
5079
|
const client = allClients()[0];
|
|
4357
5080
|
if (!client)
|
|
4358
5081
|
return text("share_file: not connected", true);
|
|
4359
5082
|
if (fileTo) {
|
|
4360
5083
|
const { encryptFile: encryptFile2, sealKeyForPeer: sealKeyForPeer2 } = await Promise.resolve().then(() => (init_file_crypto(), exports_file_crypto));
|
|
4361
|
-
const { readFileSync:
|
|
5084
|
+
const { readFileSync: readFileSync4, writeFileSync: writeFileSync4, mkdtempSync, unlinkSync: unlinkSync2, rmdirSync } = await import("node:fs");
|
|
4362
5085
|
const { tmpdir } = await import("node:os");
|
|
4363
5086
|
const { join: join3, basename } = await import("node:path");
|
|
4364
5087
|
const peers = await client.listPeers();
|
|
@@ -4366,7 +5089,7 @@ ${lines.join(`
|
|
|
4366
5089
|
if (!targetPeer) {
|
|
4367
5090
|
return text(`share_file: peer not found: ${fileTo}`, true);
|
|
4368
5091
|
}
|
|
4369
|
-
const plaintext =
|
|
5092
|
+
const plaintext = readFileSync4(filePath);
|
|
4370
5093
|
const { ciphertext, nonce, key } = await encryptFile2(new Uint8Array(plaintext));
|
|
4371
5094
|
const sealedForTarget = await sealKeyForPeer2(key, targetPeer.pubkey);
|
|
4372
5095
|
const myPubkey = client.getSessionPubkey();
|
|
@@ -4385,7 +5108,7 @@ ${lines.join(`
|
|
|
4385
5108
|
const baseName = basename(rawName).replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 255);
|
|
4386
5109
|
const tmpDir = mkdtempSync(join3(tmpdir(), "cm-"));
|
|
4387
5110
|
const tmpPath = join3(tmpDir, baseName);
|
|
4388
|
-
|
|
5111
|
+
writeFileSync4(tmpPath, combined);
|
|
4389
5112
|
try {
|
|
4390
5113
|
const fileId = await client.uploadFile(tmpPath, client.meshId, client.meshSlug, {
|
|
4391
5114
|
name: baseName,
|
|
@@ -4400,7 +5123,7 @@ ${lines.join(`
|
|
|
4400
5123
|
return text(`share_file: upload failed — ${e instanceof Error ? e.message : String(e)}`, true);
|
|
4401
5124
|
} finally {
|
|
4402
5125
|
try {
|
|
4403
|
-
|
|
5126
|
+
unlinkSync2(tmpPath);
|
|
4404
5127
|
} catch {}
|
|
4405
5128
|
try {
|
|
4406
5129
|
rmdirSync(tmpDir);
|
|
@@ -4460,10 +5183,10 @@ ${lines.join(`
|
|
|
4460
5183
|
const plaintext = await decryptFile2(ciphertext, nonce, kf);
|
|
4461
5184
|
if (!plaintext)
|
|
4462
5185
|
return text(genericErr, true);
|
|
4463
|
-
const { writeFileSync:
|
|
5186
|
+
const { writeFileSync: writeFileSync5, mkdirSync: mkdirSync4 } = await import("node:fs");
|
|
4464
5187
|
const { dirname: dirname2 } = await import("node:path");
|
|
4465
5188
|
mkdirSync4(dirname2(save_to), { recursive: true });
|
|
4466
|
-
|
|
5189
|
+
writeFileSync5(save_to, plaintext);
|
|
4467
5190
|
return text(`Downloaded and decrypted: ${result.name} → ${save_to}`);
|
|
4468
5191
|
}
|
|
4469
5192
|
let res = await fetch(result.url, { signal: AbortSignal.timeout(1e4) }).catch(() => null);
|
|
@@ -4473,10 +5196,10 @@ ${lines.join(`
|
|
|
4473
5196
|
}
|
|
4474
5197
|
if (!res.ok)
|
|
4475
5198
|
return text(`get_file: download failed (${res.status})`, true);
|
|
4476
|
-
const { writeFileSync:
|
|
5199
|
+
const { writeFileSync: writeFileSync4, mkdirSync: mkdirSync3 } = await import("node:fs");
|
|
4477
5200
|
const { dirname } = await import("node:path");
|
|
4478
5201
|
mkdirSync3(dirname(save_to), { recursive: true });
|
|
4479
|
-
|
|
5202
|
+
writeFileSync4(save_to, Buffer.from(await res.arrayBuffer()));
|
|
4480
5203
|
return text(`Downloaded: ${result.name} → ${save_to}`);
|
|
4481
5204
|
}
|
|
4482
5205
|
case "list_files": {
|
|
@@ -5234,10 +5957,10 @@ ${lines.join(`
|
|
|
5234
5957
|
const entryType = vType ?? "env";
|
|
5235
5958
|
let plaintextBytes;
|
|
5236
5959
|
if (entryType === "file") {
|
|
5237
|
-
const { existsSync:
|
|
5238
|
-
if (!
|
|
5960
|
+
const { existsSync: existsSync5, readFileSync: readFileSync4 } = await import("node:fs");
|
|
5961
|
+
if (!existsSync5(value))
|
|
5239
5962
|
return text(`vault_set: file not found: ${value}`, true);
|
|
5240
|
-
plaintextBytes = new Uint8Array(
|
|
5963
|
+
plaintextBytes = new Uint8Array(readFileSync4(value));
|
|
5241
5964
|
} else {
|
|
5242
5965
|
plaintextBytes = new TextEncoder().encode(value);
|
|
5243
5966
|
}
|
|
@@ -5804,4 +6527,4 @@ startMcpServer().catch((err) => {
|
|
|
5804
6527
|
process.exit(1);
|
|
5805
6528
|
});
|
|
5806
6529
|
|
|
5807
|
-
//# debugId=
|
|
6530
|
+
//# debugId=176161E2F9EDE48B64756E2164756E21
|