claudemesh-cli 1.0.0-alpha.30 → 1.0.0-alpha.32
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 +112 -85
- package/dist/entrypoints/cli.js.map +8 -8
- package/dist/entrypoints/mcp.js +743 -25
- package/dist/entrypoints/mcp.js.map +25 -4
- 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.32", 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");
|
|
@@ -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))
|
|
@@ -4102,13 +4820,13 @@ ${peerLines.join(`
|
|
|
4102
4820
|
}
|
|
4103
4821
|
}
|
|
4104
4822
|
try {
|
|
4105
|
-
const { writeFileSync:
|
|
4823
|
+
const { writeFileSync: writeFileSync4, mkdirSync: mkdirSync3, existsSync: existsSync5 } = await import("node:fs");
|
|
4106
4824
|
const { join: joinPath } = await import("node:path");
|
|
4107
4825
|
const { homedir: homedir3 } = await import("node:os");
|
|
4108
4826
|
const dir = joinPath(homedir3(), ".claudemesh");
|
|
4109
|
-
if (!
|
|
4827
|
+
if (!existsSync5(dir))
|
|
4110
4828
|
mkdirSync3(dir, { recursive: true });
|
|
4111
|
-
|
|
4829
|
+
writeFileSync4(joinPath(dir, "peer-cache.json"), JSON.stringify(statusCache));
|
|
4112
4830
|
} catch {}
|
|
4113
4831
|
return text(sections.join(`
|
|
4114
4832
|
|
|
@@ -4350,15 +5068,15 @@ ${lines.join(`
|
|
|
4350
5068
|
const { path: filePath, name: fileName, tags, to: fileTo } = args ?? {};
|
|
4351
5069
|
if (!filePath)
|
|
4352
5070
|
return text("share_file: `path` required", true);
|
|
4353
|
-
const { existsSync:
|
|
4354
|
-
if (!
|
|
5071
|
+
const { existsSync: existsSync5 } = await import("node:fs");
|
|
5072
|
+
if (!existsSync5(filePath))
|
|
4355
5073
|
return text(`share_file: file not found: ${filePath}`, true);
|
|
4356
5074
|
const client = allClients()[0];
|
|
4357
5075
|
if (!client)
|
|
4358
5076
|
return text("share_file: not connected", true);
|
|
4359
5077
|
if (fileTo) {
|
|
4360
5078
|
const { encryptFile: encryptFile2, sealKeyForPeer: sealKeyForPeer2 } = await Promise.resolve().then(() => (init_file_crypto(), exports_file_crypto));
|
|
4361
|
-
const { readFileSync:
|
|
5079
|
+
const { readFileSync: readFileSync4, writeFileSync: writeFileSync4, mkdtempSync, unlinkSync: unlinkSync2, rmdirSync } = await import("node:fs");
|
|
4362
5080
|
const { tmpdir } = await import("node:os");
|
|
4363
5081
|
const { join: join3, basename } = await import("node:path");
|
|
4364
5082
|
const peers = await client.listPeers();
|
|
@@ -4366,7 +5084,7 @@ ${lines.join(`
|
|
|
4366
5084
|
if (!targetPeer) {
|
|
4367
5085
|
return text(`share_file: peer not found: ${fileTo}`, true);
|
|
4368
5086
|
}
|
|
4369
|
-
const plaintext =
|
|
5087
|
+
const plaintext = readFileSync4(filePath);
|
|
4370
5088
|
const { ciphertext, nonce, key } = await encryptFile2(new Uint8Array(plaintext));
|
|
4371
5089
|
const sealedForTarget = await sealKeyForPeer2(key, targetPeer.pubkey);
|
|
4372
5090
|
const myPubkey = client.getSessionPubkey();
|
|
@@ -4385,7 +5103,7 @@ ${lines.join(`
|
|
|
4385
5103
|
const baseName = basename(rawName).replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 255);
|
|
4386
5104
|
const tmpDir = mkdtempSync(join3(tmpdir(), "cm-"));
|
|
4387
5105
|
const tmpPath = join3(tmpDir, baseName);
|
|
4388
|
-
|
|
5106
|
+
writeFileSync4(tmpPath, combined);
|
|
4389
5107
|
try {
|
|
4390
5108
|
const fileId = await client.uploadFile(tmpPath, client.meshId, client.meshSlug, {
|
|
4391
5109
|
name: baseName,
|
|
@@ -4400,7 +5118,7 @@ ${lines.join(`
|
|
|
4400
5118
|
return text(`share_file: upload failed — ${e instanceof Error ? e.message : String(e)}`, true);
|
|
4401
5119
|
} finally {
|
|
4402
5120
|
try {
|
|
4403
|
-
|
|
5121
|
+
unlinkSync2(tmpPath);
|
|
4404
5122
|
} catch {}
|
|
4405
5123
|
try {
|
|
4406
5124
|
rmdirSync(tmpDir);
|
|
@@ -4460,10 +5178,10 @@ ${lines.join(`
|
|
|
4460
5178
|
const plaintext = await decryptFile2(ciphertext, nonce, kf);
|
|
4461
5179
|
if (!plaintext)
|
|
4462
5180
|
return text(genericErr, true);
|
|
4463
|
-
const { writeFileSync:
|
|
5181
|
+
const { writeFileSync: writeFileSync5, mkdirSync: mkdirSync4 } = await import("node:fs");
|
|
4464
5182
|
const { dirname: dirname2 } = await import("node:path");
|
|
4465
5183
|
mkdirSync4(dirname2(save_to), { recursive: true });
|
|
4466
|
-
|
|
5184
|
+
writeFileSync5(save_to, plaintext);
|
|
4467
5185
|
return text(`Downloaded and decrypted: ${result.name} → ${save_to}`);
|
|
4468
5186
|
}
|
|
4469
5187
|
let res = await fetch(result.url, { signal: AbortSignal.timeout(1e4) }).catch(() => null);
|
|
@@ -4473,10 +5191,10 @@ ${lines.join(`
|
|
|
4473
5191
|
}
|
|
4474
5192
|
if (!res.ok)
|
|
4475
5193
|
return text(`get_file: download failed (${res.status})`, true);
|
|
4476
|
-
const { writeFileSync:
|
|
5194
|
+
const { writeFileSync: writeFileSync4, mkdirSync: mkdirSync3 } = await import("node:fs");
|
|
4477
5195
|
const { dirname } = await import("node:path");
|
|
4478
5196
|
mkdirSync3(dirname(save_to), { recursive: true });
|
|
4479
|
-
|
|
5197
|
+
writeFileSync4(save_to, Buffer.from(await res.arrayBuffer()));
|
|
4480
5198
|
return text(`Downloaded: ${result.name} → ${save_to}`);
|
|
4481
5199
|
}
|
|
4482
5200
|
case "list_files": {
|
|
@@ -5234,10 +5952,10 @@ ${lines.join(`
|
|
|
5234
5952
|
const entryType = vType ?? "env";
|
|
5235
5953
|
let plaintextBytes;
|
|
5236
5954
|
if (entryType === "file") {
|
|
5237
|
-
const { existsSync:
|
|
5238
|
-
if (!
|
|
5955
|
+
const { existsSync: existsSync5, readFileSync: readFileSync4 } = await import("node:fs");
|
|
5956
|
+
if (!existsSync5(value))
|
|
5239
5957
|
return text(`vault_set: file not found: ${value}`, true);
|
|
5240
|
-
plaintextBytes = new Uint8Array(
|
|
5958
|
+
plaintextBytes = new Uint8Array(readFileSync4(value));
|
|
5241
5959
|
} else {
|
|
5242
5960
|
plaintextBytes = new TextEncoder().encode(value);
|
|
5243
5961
|
}
|
|
@@ -5804,4 +6522,4 @@ startMcpServer().catch((err) => {
|
|
|
5804
6522
|
process.exit(1);
|
|
5805
6523
|
});
|
|
5806
6524
|
|
|
5807
|
-
//# debugId=
|
|
6525
|
+
//# debugId=1491A1F07755C64D64756E2164756E21
|