@usebitl/cli 0.1.3 → 0.1.4
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/adapters/dist/core.mjs +5 -1
- package/dist/cli.mjs +332 -94
- package/package.json +1 -1
package/adapters/dist/core.mjs
CHANGED
|
@@ -466,13 +466,17 @@ function readCloudConfig(home = bitlHome()) {
|
|
|
466
466
|
return null;
|
|
467
467
|
}
|
|
468
468
|
}
|
|
469
|
+
function clientVersionHeader() {
|
|
470
|
+
const v = "0.1.4";
|
|
471
|
+
return v ? { "x-bitl-client": v } : {};
|
|
472
|
+
}
|
|
469
473
|
function resolveTarget(home = bitlHome()) {
|
|
470
474
|
const cloud = readCloudConfig(home);
|
|
471
475
|
if (cloud) {
|
|
472
476
|
return {
|
|
473
477
|
kind: "cloud",
|
|
474
478
|
url: cloud.url.replace(/\/+$/, ""),
|
|
475
|
-
headers: { authorization: `Bearer ${cloud.apiKey}
|
|
479
|
+
headers: { authorization: `Bearer ${cloud.apiKey}`, ...clientVersionHeader() },
|
|
476
480
|
keys: () => keysFromBase64Url(readFileSync2(cloudKeyPath(home), "utf8"))
|
|
477
481
|
};
|
|
478
482
|
}
|
package/dist/cli.mjs
CHANGED
|
@@ -7,7 +7,7 @@ var __export = (target, all) => {
|
|
|
7
7
|
|
|
8
8
|
// ../src/index.ts
|
|
9
9
|
import { homedir as homedir3 } from "node:os";
|
|
10
|
-
import { join as
|
|
10
|
+
import { join as join5, resolve as resolve2 } from "node:path";
|
|
11
11
|
|
|
12
12
|
// ../../shared/src/crypto.ts
|
|
13
13
|
var MASTER_KEY_BYTES = 32;
|
|
@@ -61,14 +61,14 @@ async function open(keys, sealed, aad) {
|
|
|
61
61
|
return fromUtf8.decode(unpad(new Uint8Array(pt)));
|
|
62
62
|
}
|
|
63
63
|
var INBOX_CURVE = { name: "ECDH", namedCurve: "P-256" };
|
|
64
|
-
async function inboxKey(shared, ephemeralPublic,
|
|
64
|
+
async function inboxKey(shared, ephemeralPublic, usage2) {
|
|
65
65
|
const base = await subtle().importKey("raw", shared, "HKDF", false, ["deriveKey"]);
|
|
66
66
|
return subtle().deriveKey(
|
|
67
67
|
{ name: "HKDF", hash: "SHA-256", salt: new Uint8Array(ephemeralPublic), info: utf8.encode("bitl/v1/inbox") },
|
|
68
68
|
base,
|
|
69
69
|
{ name: "AES-GCM", length: 256 },
|
|
70
70
|
false,
|
|
71
|
-
[
|
|
71
|
+
[usage2]
|
|
72
72
|
);
|
|
73
73
|
}
|
|
74
74
|
var importInboxPrivateKey = (pkcs8) => subtle().importKey("pkcs8", fromBase64Url(pkcs8), INBOX_CURVE, false, ["deriveBits"]);
|
|
@@ -154,7 +154,7 @@ async function verifyPublicKey(secret, role, publicKey, mac3) {
|
|
|
154
154
|
return false;
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
|
-
async function wrappingKey(ownPrivate, peerPublic, pairingId,
|
|
157
|
+
async function wrappingKey(ownPrivate, peerPublic, pairingId, usage2) {
|
|
158
158
|
const shared = await subtle2().deriveBits({ name: "ECDH", public: await importPublicKey(peerPublic) }, ownPrivate, 256);
|
|
159
159
|
const base = await subtle2().importKey("raw", shared, "HKDF", false, ["deriveKey"]);
|
|
160
160
|
return subtle2().deriveKey(
|
|
@@ -162,7 +162,7 @@ async function wrappingKey(ownPrivate, peerPublic, pairingId, usage) {
|
|
|
162
162
|
base,
|
|
163
163
|
{ name: "AES-GCM", length: 256 },
|
|
164
164
|
false,
|
|
165
|
-
[
|
|
165
|
+
[usage2]
|
|
166
166
|
);
|
|
167
167
|
}
|
|
168
168
|
async function wrapMasterKey(master, ownPrivate, peerPublic, pairingId) {
|
|
@@ -204,6 +204,18 @@ var EVENT_CONTENT_FIELDS = [
|
|
|
204
204
|
"model"
|
|
205
205
|
];
|
|
206
206
|
|
|
207
|
+
// ../../shared/src/release.ts
|
|
208
|
+
function compareVersions(a, b) {
|
|
209
|
+
const pa = a.split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
210
|
+
const pb = b.split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
211
|
+
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
212
|
+
const d = (pa[i] ?? 0) - (pb[i] ?? 0);
|
|
213
|
+
if (d !== 0) return Math.sign(d);
|
|
214
|
+
}
|
|
215
|
+
return 0;
|
|
216
|
+
}
|
|
217
|
+
var VERSION_PATTERN = /^\d{1,4}\.\d{1,4}\.\d{1,4}$/;
|
|
218
|
+
|
|
207
219
|
// ../../shared/src/view.ts
|
|
208
220
|
async function tryOpen(keys, sealed, aad) {
|
|
209
221
|
if (sealed === void 0) return { failed: false };
|
|
@@ -1135,8 +1147,8 @@ function numKeys(data) {
|
|
|
1135
1147
|
return keyCount;
|
|
1136
1148
|
}
|
|
1137
1149
|
var getParsedType = (data) => {
|
|
1138
|
-
const
|
|
1139
|
-
switch (
|
|
1150
|
+
const t2 = typeof data;
|
|
1151
|
+
switch (t2) {
|
|
1140
1152
|
case "undefined":
|
|
1141
1153
|
return "undefined";
|
|
1142
1154
|
case "string":
|
|
@@ -1175,7 +1187,7 @@ var getParsedType = (data) => {
|
|
|
1175
1187
|
}
|
|
1176
1188
|
return "object";
|
|
1177
1189
|
default:
|
|
1178
|
-
throw new Error(`Unknown data type: ${
|
|
1190
|
+
throw new Error(`Unknown data type: ${t2}`);
|
|
1179
1191
|
}
|
|
1180
1192
|
};
|
|
1181
1193
|
var propertyKeyTypes = /* @__PURE__ */ new Set(["string", "number", "symbol"]);
|
|
@@ -1463,8 +1475,8 @@ function getLengthableOrigin(input2) {
|
|
|
1463
1475
|
return "unknown";
|
|
1464
1476
|
}
|
|
1465
1477
|
function parsedType(data) {
|
|
1466
|
-
const
|
|
1467
|
-
switch (
|
|
1478
|
+
const t2 = typeof data;
|
|
1479
|
+
switch (t2) {
|
|
1468
1480
|
case "number": {
|
|
1469
1481
|
return Number.isNaN(data) ? "nan" : "number";
|
|
1470
1482
|
}
|
|
@@ -1481,7 +1493,7 @@ function parsedType(data) {
|
|
|
1481
1493
|
}
|
|
1482
1494
|
}
|
|
1483
1495
|
}
|
|
1484
|
-
return
|
|
1496
|
+
return t2;
|
|
1485
1497
|
}
|
|
1486
1498
|
function issue(...args) {
|
|
1487
1499
|
const [iss, input2, inst] = args;
|
|
@@ -3679,7 +3691,7 @@ function handleCatchall(proms, input2, payload, ctx, def, inst, abortEarly) {
|
|
|
3679
3691
|
const unrecognized = [];
|
|
3680
3692
|
const keySet = def.keySet;
|
|
3681
3693
|
const _catchall = def.catchall._zod;
|
|
3682
|
-
const
|
|
3694
|
+
const t2 = _catchall.def.type;
|
|
3683
3695
|
const optin = _catchall.optin;
|
|
3684
3696
|
const optout = _catchall.optout;
|
|
3685
3697
|
let seen = 0;
|
|
@@ -3692,11 +3704,11 @@ function handleCatchall(proms, input2, payload, ctx, def, inst, abortEarly) {
|
|
|
3692
3704
|
if (keySet.has(key))
|
|
3693
3705
|
continue;
|
|
3694
3706
|
if (key === "__proto__") {
|
|
3695
|
-
if (
|
|
3707
|
+
if (t2 === "never")
|
|
3696
3708
|
unrecognized.push(key);
|
|
3697
3709
|
continue;
|
|
3698
3710
|
}
|
|
3699
|
-
if (
|
|
3711
|
+
if (t2 === "never") {
|
|
3700
3712
|
unrecognized.push(key);
|
|
3701
3713
|
continue;
|
|
3702
3714
|
}
|
|
@@ -7930,16 +7942,16 @@ var error20 = () => {
|
|
|
7930
7942
|
number: { unit: "", shortLabel: "\u05E7\u05D8\u05DF", longLabel: "\u05D2\u05D3\u05D5\u05DC" }
|
|
7931
7943
|
// no unit
|
|
7932
7944
|
};
|
|
7933
|
-
const typeEntry = (
|
|
7934
|
-
const typeLabel = (
|
|
7935
|
-
const e = typeEntry(
|
|
7945
|
+
const typeEntry = (t2) => t2 ? TypeNames[t2] : void 0;
|
|
7946
|
+
const typeLabel = (t2) => {
|
|
7947
|
+
const e = typeEntry(t2);
|
|
7936
7948
|
if (e)
|
|
7937
7949
|
return e.label;
|
|
7938
|
-
return
|
|
7950
|
+
return t2 ?? TypeNames.unknown.label;
|
|
7939
7951
|
};
|
|
7940
|
-
const withDefinite = (
|
|
7941
|
-
const verbFor = (
|
|
7942
|
-
const e = typeEntry(
|
|
7952
|
+
const withDefinite = (t2) => `\u05D4${typeLabel(t2)}`;
|
|
7953
|
+
const verbFor = (t2) => {
|
|
7954
|
+
const e = typeEntry(t2);
|
|
7943
7955
|
const gender = e?.gender ?? "m";
|
|
7944
7956
|
return gender === "f" ? "\u05E6\u05E8\u05D9\u05DB\u05D4 \u05DC\u05D4\u05D9\u05D5\u05EA" : "\u05E6\u05E8\u05D9\u05DA \u05DC\u05D4\u05D9\u05D5\u05EA";
|
|
7945
7957
|
};
|
|
@@ -16812,7 +16824,7 @@ function stringifyKeyNames(bySchema, json2, visited) {
|
|
|
16812
16824
|
json2 = { ...json2, [keyword]: mapped };
|
|
16813
16825
|
}
|
|
16814
16826
|
const types = Array.isArray(json2.type) ? json2.type : [json2.type];
|
|
16815
|
-
const numericType = !types.includes("string") && types.some((
|
|
16827
|
+
const numericType = !types.includes("string") && types.some((t2) => t2 === "number" || t2 === "integer");
|
|
16816
16828
|
const values = json2.enum ?? (json2.const !== void 0 ? [json2.const] : void 0);
|
|
16817
16829
|
if (!numericType && !values?.some((v) => typeof v === "number"))
|
|
16818
16830
|
return json2;
|
|
@@ -19315,8 +19327,8 @@ function convertBaseSchema(schema, ctx) {
|
|
|
19315
19327
|
}
|
|
19316
19328
|
const type = schema.type;
|
|
19317
19329
|
if (Array.isArray(type)) {
|
|
19318
|
-
const typeSchemas = type.map((
|
|
19319
|
-
const typeSchema = { ...schema, type:
|
|
19330
|
+
const typeSchemas = type.map((t2) => {
|
|
19331
|
+
const typeSchema = { ...schema, type: t2 };
|
|
19320
19332
|
return convertBaseSchema(typeSchema, ctx);
|
|
19321
19333
|
});
|
|
19322
19334
|
if (typeSchemas.length === 0) {
|
|
@@ -20012,13 +20024,17 @@ function removeCloudLogin(home = bitlHome()) {
|
|
|
20012
20024
|
rmSync(cloudConfigPath(home), { force: true });
|
|
20013
20025
|
rmSync(cloudKeyPath(home), { force: true });
|
|
20014
20026
|
}
|
|
20027
|
+
function clientVersionHeader() {
|
|
20028
|
+
const v = "0.1.4";
|
|
20029
|
+
return v ? { "x-bitl-client": v } : {};
|
|
20030
|
+
}
|
|
20015
20031
|
function resolveTarget(home = bitlHome()) {
|
|
20016
20032
|
const cloud = readCloudConfig(home);
|
|
20017
20033
|
if (cloud) {
|
|
20018
20034
|
return {
|
|
20019
20035
|
kind: "cloud",
|
|
20020
20036
|
url: cloud.url.replace(/\/+$/, ""),
|
|
20021
|
-
headers: { authorization: `Bearer ${cloud.apiKey}
|
|
20037
|
+
headers: { authorization: `Bearer ${cloud.apiKey}`, ...clientVersionHeader() },
|
|
20022
20038
|
keys: () => keysFromBase64Url(readFileSync2(cloudKeyPath(home), "utf8"))
|
|
20023
20039
|
};
|
|
20024
20040
|
}
|
|
@@ -20037,13 +20053,181 @@ var MAX_TRANSCRIPT_BYTES2 = 20 * 1024 * 1024;
|
|
|
20037
20053
|
var DEFAULT_APPROVAL_WAIT_MS = 10 * 6e4;
|
|
20038
20054
|
|
|
20039
20055
|
// ../src/index.ts
|
|
20040
|
-
import { readFileSync as
|
|
20056
|
+
import { readFileSync as readFileSync5 } from "node:fs";
|
|
20041
20057
|
|
|
20042
20058
|
// ../src/install.ts
|
|
20043
20059
|
import { copyFileSync, existsSync, mkdirSync as mkdirSync3, readdirSync, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
20044
20060
|
import { homedir as homedir2 } from "node:os";
|
|
20045
20061
|
import { dirname as dirname3, join as join3, resolve } from "node:path";
|
|
20046
20062
|
import { fileURLToPath } from "node:url";
|
|
20063
|
+
|
|
20064
|
+
// ../src/i18n.ts
|
|
20065
|
+
var ko = {
|
|
20066
|
+
"usage.title": "bitl \u2014 AI \uC5D0\uC774\uC804\uD2B8 \uC791\uC5C5 \uD604\uD669\uD310 (https://usebitl.com)",
|
|
20067
|
+
"update.available": "\u2191 bitl {latest} \uAC00 \uB098\uC654\uC2B5\uB2C8\uB2E4 (\uC9C0\uAE08 {current}) \u2014 npm i -g @usebitl/cli",
|
|
20068
|
+
"update.changelog": " \uBC14\uB010 \uC810: https://usebitl.com/changelog",
|
|
20069
|
+
"usage.start": "\uC11C\uBC84 \uC2DC\uC791 (http://127.0.0.1:7777)",
|
|
20070
|
+
"usage.status": "\uD604\uC7AC \uC138\uC158 \uC694\uC57D (\uC774 PC \uC758 \uD0A4\uB85C \uBCF5\uD638\uD654)",
|
|
20071
|
+
"usage.pair": "\uBE0C\uB77C\uC6B0\uC800\uC5D0 \uC554\uD638\uD654 \uD0A4\uB97C \uB118\uAE30\uB294 \uB9C1\uD06C (\uBE0C\uB77C\uC6B0\uC800\xB7\uC8FC\uC18C\uB9C8\uB2E4 \uD55C \uBC88)",
|
|
20072
|
+
"usage.pairArgs": "[--url \uC8FC\uC18C]",
|
|
20073
|
+
"usage.loginArgsDefault": "[--url <\uC8FC\uC18C>] [--name \uC774\uB984] [--no-browser]",
|
|
20074
|
+
"usage.loginArgs": "--url <\uC8FC\uC18C> [--name \uC774\uB984] [--no-browser]",
|
|
20075
|
+
"usage.loginDefault": "\uC774 PC \uB97C \uACC4\uC815\uC5D0 \uC5F0\uACB0 (\uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uC2B9\uC778, \uAE30\uBCF8 {url})",
|
|
20076
|
+
"usage.login": "\uC774 PC \uB97C \uD074\uB77C\uC6B0\uB4DC \uACC4\uC815\uC5D0 \uC5F0\uACB0 (\uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uC2B9\uC778)",
|
|
20077
|
+
"usage.logoutCloud": "\uC5F0\uACB0 \uD574\uC81C",
|
|
20078
|
+
"usage.logout": "\uC5F0\uACB0 \uD574\uC81C \u2192 \uB2E4\uC2DC \uB85C\uCEEC \uC11C\uBC84\uB85C",
|
|
20079
|
+
"usage.installClaude": "Claude Code hook \uB4F1\uB85D (\uAE30\uBCF8: ~/.claude/settings.json)",
|
|
20080
|
+
"usage.installCodex": "Codex hook \uB4F1\uB85D (~/.codex/config.toml)",
|
|
20081
|
+
"usage.installAgy": "Antigravity hook \uB4F1\uB85D (~/.gemini/config/hooks.json, CLI\xB7IDE \uACF5\uC6A9)",
|
|
20082
|
+
"usage.installDesktop": "Claude Desktop \uC5D0 MCP \uC11C\uBC84 \uB4F1\uB85D",
|
|
20083
|
+
"usage.remote": "\uC6D0\uACA9 \uC2B9\uC778: \uCF1C\uBA74 Claude Code \uC758 \uAD8C\uD55C \uC694\uCCAD\uC744 \uD734\uB300\uD3F0\xB7\uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uD5C8\uC6A9\xB7\uAC70\uBD80",
|
|
20084
|
+
"usage.remote2": "\u2014 \uD130\uBBF8\uB110\xB7\uBE0C\uB77C\uC6B0\uC800\xB7\uD734\uB300\uD3F0 \uC911 \uBA3C\uC800 \uB2F5\uD55C \uCABD\uC774 \uC801\uC6A9\uB41C\uB2E4 (\uD3F0\uC758 \uB2F5\uC740 \uCD5C\uB300 10\uBD84 \uAE30\uB2E4\uB9BC)",
|
|
20085
|
+
"err.optionValue": "{name} \uB4A4\uC5D0 \uAC12\uC744 \uC9C0\uC815\uD558\uC138\uC694",
|
|
20086
|
+
"err.cloudUnreachable": "\uD074\uB77C\uC6B0\uB4DC \uC11C\uBC84\uC5D0 \uC5F0\uACB0\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 ({url})",
|
|
20087
|
+
"err.localUnreachable": "\uC11C\uBC84\uC5D0 \uC5F0\uACB0\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 ({url}). bitl start \uB85C \uC2DC\uC791\uD558\uC138\uC694.",
|
|
20088
|
+
"err.revoked": "\uC774 PC \uC758 \uC5F0\uACB0\uC774 \uB04A\uACBC\uC2B5\uB2C8\uB2E4 (\uAE30\uAE30\uAC00 \uC81C\uAC70\uB428). bitl logout \uD6C4 bitl login \uC73C\uB85C \uB2E4\uC2DC \uC5F0\uACB0\uD558\uC138\uC694.",
|
|
20089
|
+
"err.remoteUsage": "\uC0AC\uC6A9\uBC95: bitl remote [on|off]",
|
|
20090
|
+
"err.remoteUnsupported": "\uC774 \uC11C\uBC84\uB294 \uC6D0\uACA9 \uC2B9\uC778\uC744 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 (\uC11C\uBC84\uB97C \uC0C8 \uBC84\uC804\uC73C\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694)",
|
|
20091
|
+
"err.noDesktop": "claude-desktop(\uB85C\uCEEC MCP)\uC740 \uC774 \uD328\uD0A4\uC9C0\uC5D0 \uC5C6\uC2B5\uB2C8\uB2E4. claude.ai \uCEE4\uB125\uD130\uB97C \uC4F0\uC138\uC694: https://usebitl.com/app",
|
|
20092
|
+
"err.unknownTarget": "\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uB300\uC0C1: {target} \u2014 {list}",
|
|
20093
|
+
"err.none": "(\uC5C6\uC74C)",
|
|
20094
|
+
"err.noStart": "bitl start(\uB85C\uCEEC \uC11C\uBC84)\uB294 \uC774 \uD328\uD0A4\uC9C0\uC5D0 \uC5C6\uC2B5\uB2C8\uB2E4. https://usebitl.com \uC5D0\uC11C \uC4F0\uC138\uC694.",
|
|
20095
|
+
"err.loginUrl": "\uC5F0\uACB0\uD560 \uC11C\uBE44\uC2A4 \uC8FC\uC18C\uB97C \uC9C0\uC815\uD558\uC138\uC694: bitl login --url https://\u2026",
|
|
20096
|
+
"err.agySpace": "Antigravity \uB294 \uACF5\uBC31\uC774 \uC788\uB294 \uACBD\uB85C\uB97C \uC2E4\uD589\uD558\uC9C0 \uBABB\uD569\uB2C8\uB2E4: {path}",
|
|
20097
|
+
"pair.intro": "\uC774 \uB9C1\uD06C\uB97C \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uD55C \uBC88 \uC5F4\uBA74 \uADF8 \uBE0C\uB77C\uC6B0\uC800\uAC00 \uD0A4\uB97C \uAE30\uC5B5\uD569\uB2C8\uB2E4 (\uB2E4\uB978 \uC0AC\uB78C\uC5D0\uAC8C \uBCF4\uB0B4\uC9C0 \uB9C8\uC138\uC694):",
|
|
20098
|
+
"pair.otherUrl": " BITL \uC744 \uB2E4\uB978 \uC8FC\uC18C\uB85C \uC5F0\uB2E4\uBA74 \uADF8 \uC8FC\uC18C\uB85C: bitl pair --url http://localhost:7788",
|
|
20099
|
+
"pair.cloud": ' \uD074\uB77C\uC6B0\uB4DC \uACC4\uC815\uC740 \uBCF4\uD1B5 \uC6F9\uC758 "\uAE30\uAE30" \u2192 "\uAE30\uAE30 \uCD94\uAC00"(QR) \uB85C \uD0A4\uB97C \uB118\uAE41\uB2C8\uB2E4. \uC774 \uB9C1\uD06C\uB294 \uC608\uBE44 \uBC29\uBC95\uC785\uB2C8\uB2E4.',
|
|
20100
|
+
"pair.keyFile": " \uD0A4 \uD30C\uC77C: {path} \u2014 \uC9C0\uC6B0\uBA74 \uC774\uC804 \uAE30\uB85D\uC744 \uBCFC \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
20101
|
+
"status.cloud": "(\uD074\uB77C\uC6B0\uB4DC \uACC4\uC815: {url})",
|
|
20102
|
+
"status.none": "\uC9C4\uD589 \uC911\uC778 \uC138\uC158 \uC5C6\uC74C",
|
|
20103
|
+
"remote.on": "\uC6D0\uACA9 \uC2B9\uC778: \uCF1C\uC9D0 \u2014 Claude Code \uC758 \uAD8C\uD55C \uC694\uCCAD\uC774 \uD734\uB300\uD3F0\xB7\uBE0C\uB77C\uC6B0\uC800\uB85C \uAC11\uB2C8\uB2E4 (\uD654\uBA74\xB7\uC54C\uB9BC\uC5D0\uC11C \uD5C8\uC6A9\xB7\uAC70\uBD80)",
|
|
20104
|
+
"remote.off": "\uC6D0\uACA9 \uC2B9\uC778: \uAEBC\uC9D0 \u2014 \uAD8C\uD55C \uC694\uCCAD\uC740 \uD130\uBBF8\uB110\uC5D0\uC11C \uC2B9\uC778\uD569\uB2C8\uB2E4",
|
|
20105
|
+
"remote.needHook": " hook \uC774 \uC5C6\uC73C\uBA74 \uB3D9\uC791\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: bitl install claude \uB97C \uD55C \uBC88 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694 (\uC6D0\uACA9 \uC2B9\uC778 hook \uCD94\uAC00)",
|
|
20106
|
+
"install.adapter": "\uC5B4\uB311\uD130: {path}",
|
|
20107
|
+
"install.codexTrust": "\uC544\uC9C1 \uB3D9\uC791\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: Codex \uB97C \uC5F4\uACE0 /hooks \uC5D0\uC11C bitl hook \uC744 \uC2E0\uB8B0(trust)\uD558\uC138\uC694.",
|
|
20108
|
+
"install.agyRestart": "\uC2E4\uD589 \uC911\uC778 agy \uB294 \uB2E4\uC2DC \uC2DC\uC791\uD574\uC57C \uC801\uC6A9\uB429\uB2C8\uB2E4.",
|
|
20109
|
+
"install.mcp": "MCP \uC11C\uBC84: {path}",
|
|
20110
|
+
"install.desktopRestart": "Claude Desktop \uC744 \uC7AC\uC2DC\uC791\uD574\uC57C \uC801\uC6A9\uB429\uB2C8\uB2E4.",
|
|
20111
|
+
"install.unchanged": "\uBCC0\uACBD \uC5C6\uC74C: {file}",
|
|
20112
|
+
"install.added": "\uB4F1\uB85D \uC644\uB8CC: {file}",
|
|
20113
|
+
"install.removed": "\uC81C\uAC70 \uC644\uB8CC: {file}",
|
|
20114
|
+
"install.backup": " \uBC31\uC5C5: {path}",
|
|
20115
|
+
"start.pair": " \uBE0C\uB77C\uC6B0\uC800 \uC5F0\uACB0(\uCC98\uC74C \uD55C \uBC88): {url}",
|
|
20116
|
+
"login.unreachable": "\uC11C\uBC84\uC5D0 \uC5F0\uACB0\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 ({where}).",
|
|
20117
|
+
"login.unreachableHint": ' \uC11C\uBC84\uAC00 \uCF1C\uC838 \uC788\uB294\uC9C0 \uD655\uC778\uD558\uC138\uC694 \u2014 \uBE0C\uB77C\uC6B0\uC800\uB85C {origin}/api/health \uB97C \uC5F4\uBA74 {"ok":true} \uAC00 \uBCF4\uC5EC\uC57C \uD569\uB2C8\uB2E4.',
|
|
20118
|
+
"login.already": "\uC774\uBBF8 \uC5F0\uACB0\uB3FC \uC788\uC2B5\uB2C8\uB2E4: {url} ({name}). \uB2E4\uC2DC \uC5F0\uACB0\uD558\uB824\uBA74 \uBA3C\uC800 bitl logout",
|
|
20119
|
+
"login.notBitl": "{url} \uB294 \uD074\uB77C\uC6B0\uB4DC \uBAA8\uB4DC BITL \uC11C\uBC84\uAC00 \uC544\uB2D9\uB2C8\uB2E4 (\uAE30\uAE30 \uC5F0\uACB0 API \uAC00 \uC5C6\uC74C)",
|
|
20120
|
+
"login.tooMany": "\uC5F0\uACB0 \uC694\uCCAD\uC774 \uB108\uBB34 \uB9CE\uC2B5\uB2C8\uB2E4. \uC7A0\uC2DC \uB4A4 \uB2E4\uC2DC \uD558\uC138\uC694",
|
|
20121
|
+
"login.cannotStart": "\uC5F0\uACB0\uC744 \uC2DC\uC791\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 ({status})",
|
|
20122
|
+
"login.approve": "\uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uC774 PC \uC758 \uC5F0\uACB0\uC744 \uC2B9\uC778\uD558\uC138\uC694:",
|
|
20123
|
+
"login.manual": " (\uBE0C\uB77C\uC6B0\uC800\uAC00 \uC5F4\uB9AC\uC9C0 \uC54A\uC73C\uBA74 \uC704 \uC8FC\uC18C\uB97C \uC9C1\uC811 \uC5EC\uC138\uC694. {min}\uBD84 \uC548\uC5D0)",
|
|
20124
|
+
"login.expired": "\uC5F0\uACB0 \uC694\uCCAD\uC774 \uB9CC\uB8CC\uB410\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC bitl login \uD558\uC138\uC694",
|
|
20125
|
+
"login.timeout": "\uC2DC\uAC04 \uC548\uC5D0 \uC2B9\uC778\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC bitl login \uD558\uC138\uC694",
|
|
20126
|
+
"login.denied": "\uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uC5F0\uACB0\uC744 \uAC70\uC808\uD588\uC2B5\uB2C8\uB2E4",
|
|
20127
|
+
"login.noResult": "\uC2B9\uC778 \uACB0\uACFC\uB97C \uBC1B\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC bitl login \uD558\uC138\uC694",
|
|
20128
|
+
"login.badSignature": "\uACBD\uACE0: \uC2B9\uC778\uD55C \uBE0C\uB77C\uC6B0\uC800\uB97C \uD655\uC778\uD560 \uC218 \uC5C6\uC5B4 \uC5F0\uACB0\uC744 \uC911\uB2E8\uD588\uC2B5\uB2C8\uB2E4 (\uACF5\uAC1C\uD0A4 \uC11C\uBA85\uC774 \uB9DE\uC9C0 \uC54A\uC74C)",
|
|
20129
|
+
"login.noKeyBrowser": "\uC774 \uACC4\uC815\uC758 \uD0A4\uAC00 \uC5C6\uB294 \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uC2B9\uC778\uD588\uC2B5\uB2C8\uB2E4. \uCE74\uB4DC \uB0B4\uC6A9\uC774 \uBCF4\uC774\uB294 \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uC2B9\uC778\uD558\uB3C4\uB85D \uB2E4\uC2DC bitl login \uD558\uC138\uC694",
|
|
20130
|
+
"login.keyMismatch": "\uACC4\uC815\uC5D0 \uC774\uBBF8 \uB2E4\uB978 \uD0A4\uAC00 \uC788\uC2B5\uB2C8\uB2E4. \uCE74\uB4DC \uB0B4\uC6A9\uC774 \uBCF4\uC774\uB294 \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uC2B9\uC778\uD558\uC138\uC694",
|
|
20131
|
+
"login.deliverFailed": "\uD0A4\uB97C \uB118\uAE30\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4 ({status})",
|
|
20132
|
+
"login.connected": "\uC5F0\uACB0\uB428: \uC774 PC({name})\uC758 \uC5D0\uC774\uC804\uD2B8 \uC791\uC5C5\uC774 {web} \uACC4\uC815\uC73C\uB85C \uAC11\uB2C8\uB2E4{via}.",
|
|
20133
|
+
"login.via": " (\uBCF4\uB0B4\uB294 \uC8FC\uC18C: {api})",
|
|
20134
|
+
"login.next": " hook \uC774 \uC544\uC9C1 \uC5C6\uB2E4\uBA74: bitl install claude",
|
|
20135
|
+
"logout.notConnected": "\uD074\uB77C\uC6B0\uB4DC \uACC4\uC815\uC5D0 \uC5F0\uACB0\uB3FC \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 (\uB85C\uCEEC \uBAA8\uB4DC).",
|
|
20136
|
+
"logout.done": "\uC5F0\uACB0 \uD574\uC81C: {url} ({name}). \uC774\uC81C \uC774 PC \uC758 \uB85C\uCEEC \uC11C\uBC84\uB85C \uBCF4\uB0C5\uB2C8\uB2E4.",
|
|
20137
|
+
"logout.doneCloud": "\uC5F0\uACB0 \uD574\uC81C: {url} ({name}). \uC774 PC \uC758 \uC5D0\uC774\uC804\uD2B8 \uC791\uC5C5\uC740 \uB354 \uC774\uC0C1 \uBCF4\uB0B4\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4."
|
|
20138
|
+
};
|
|
20139
|
+
var en = {
|
|
20140
|
+
"usage.title": "bitl \u2014 all your AI coding agents in one place (https://usebitl.com)",
|
|
20141
|
+
"update.available": "\u2191 bitl {latest} is available (you have {current}) \u2014 npm i -g @usebitl/cli",
|
|
20142
|
+
"update.changelog": " What changed: https://usebitl.com/changelog",
|
|
20143
|
+
"usage.start": "Start the server (http://127.0.0.1:7777)",
|
|
20144
|
+
"usage.status": "Summary of current sessions (decrypted with this PC\u2019s key)",
|
|
20145
|
+
"usage.pair": "Link that hands the encryption key to a browser (once per browser and address)",
|
|
20146
|
+
"usage.pairArgs": "[--url URL]",
|
|
20147
|
+
"usage.loginArgsDefault": "[--url <URL>] [--name NAME] [--no-browser]",
|
|
20148
|
+
"usage.loginArgs": "--url <URL> [--name NAME] [--no-browser]",
|
|
20149
|
+
"usage.loginDefault": "Connect this PC to your account (approve in the browser; default {url})",
|
|
20150
|
+
"usage.login": "Connect this PC to your cloud account (approve in the browser)",
|
|
20151
|
+
"usage.logoutCloud": "Disconnect",
|
|
20152
|
+
"usage.logout": "Disconnect \u2192 back to the local server",
|
|
20153
|
+
"usage.installClaude": "Add Claude Code hooks (default: ~/.claude/settings.json)",
|
|
20154
|
+
"usage.installCodex": "Add Codex hooks (~/.codex/config.toml)",
|
|
20155
|
+
"usage.installAgy": "Add Antigravity hooks (~/.gemini/config/hooks.json, shared by CLI and IDE)",
|
|
20156
|
+
"usage.installDesktop": "Add the MCP server to Claude Desktop",
|
|
20157
|
+
"usage.remote": "Remote approval: when on, allow or deny Claude Code permission requests from your phone or browser",
|
|
20158
|
+
"usage.remote2": "\u2014 whichever of terminal, browser or phone answers first wins (waits up to 10 minutes for the phone)",
|
|
20159
|
+
"err.optionValue": "Give a value after {name}",
|
|
20160
|
+
"err.cloudUnreachable": "Can't reach the cloud server ({url})",
|
|
20161
|
+
"err.localUnreachable": "Can't reach the server ({url}). Start it with bitl start.",
|
|
20162
|
+
"err.revoked": "This PC was disconnected (the device was removed). Run bitl logout, then bitl login to connect again.",
|
|
20163
|
+
"err.remoteUsage": "Usage: bitl remote [on|off]",
|
|
20164
|
+
"err.remoteUnsupported": "This server doesn't support remote approval (update the server to a newer version)",
|
|
20165
|
+
"err.noDesktop": "claude-desktop (local MCP) is not in this package. Use the claude.ai connector: https://usebitl.com/app",
|
|
20166
|
+
"err.unknownTarget": "Unsupported target: {target} \u2014 {list}",
|
|
20167
|
+
"err.none": "(none)",
|
|
20168
|
+
"err.noStart": "bitl start (local server) is not in this package. Use https://usebitl.com.",
|
|
20169
|
+
"err.loginUrl": "Give the service URL to connect to: bitl login --url https://\u2026",
|
|
20170
|
+
"err.agySpace": "Antigravity can't run a path that contains spaces: {path}",
|
|
20171
|
+
"pair.intro": "Open this link once in a browser and that browser remembers the key (do not share it):",
|
|
20172
|
+
"pair.otherUrl": " If you open BITL at another address, use it: bitl pair --url http://localhost:7788",
|
|
20173
|
+
"pair.cloud": ' Cloud accounts usually hand over the key on the web with "Devices" \u2192 "Add device" (QR). This link is a fallback.',
|
|
20174
|
+
"pair.keyFile": " Key file: {path} \u2014 deleting it makes your earlier history unreadable.",
|
|
20175
|
+
"status.cloud": "(cloud account: {url})",
|
|
20176
|
+
"status.none": "No active sessions",
|
|
20177
|
+
"remote.on": "Remote approval: on \u2014 Claude Code permission requests go to your phone and browser (allow or deny on screen or from notifications)",
|
|
20178
|
+
"remote.off": "Remote approval: off \u2014 approve permission requests in the terminal",
|
|
20179
|
+
"remote.needHook": " It won't work without the hook: run bitl install claude once more (adds the remote approval hook)",
|
|
20180
|
+
"install.adapter": "Adapter: {path}",
|
|
20181
|
+
"install.codexTrust": "Not active yet: open Codex and trust the bitl hooks in /hooks.",
|
|
20182
|
+
"install.agyRestart": "Restart any running agy for this to take effect.",
|
|
20183
|
+
"install.mcp": "MCP server: {path}",
|
|
20184
|
+
"install.desktopRestart": "Restart Claude Desktop for this to take effect.",
|
|
20185
|
+
"install.unchanged": "No change: {file}",
|
|
20186
|
+
"install.added": "Added: {file}",
|
|
20187
|
+
"install.removed": "Removed: {file}",
|
|
20188
|
+
"install.backup": " Backup: {path}",
|
|
20189
|
+
"start.pair": " Connect a browser (first time only): {url}",
|
|
20190
|
+
"login.unreachable": "Can't reach the server ({where}).",
|
|
20191
|
+
"login.unreachableHint": ' Check that the server is running \u2014 opening {origin}/api/health in a browser should show {"ok":true}.',
|
|
20192
|
+
"login.already": "Already connected: {url} ({name}). To connect again, run bitl logout first",
|
|
20193
|
+
"login.notBitl": "{url} isn't a cloud-mode BITL server (no device connection API)",
|
|
20194
|
+
"login.tooMany": "Too many connection requests. Try again in a moment",
|
|
20195
|
+
"login.cannotStart": "Couldn't start connecting ({status})",
|
|
20196
|
+
"login.approve": "Approve connecting this PC in your browser:",
|
|
20197
|
+
"login.manual": " (If the browser doesn't open, open the URL above yourself within {min} min)",
|
|
20198
|
+
"login.expired": "The connection request expired. Run bitl login again",
|
|
20199
|
+
"login.timeout": "It wasn't approved in time. Run bitl login again",
|
|
20200
|
+
"login.denied": "The connection was denied in the browser",
|
|
20201
|
+
"login.noResult": "Didn't receive the approval result. Run bitl login again",
|
|
20202
|
+
"login.badSignature": "Warning: couldn't verify the approving browser, so the connection was stopped (public key signature mismatch)",
|
|
20203
|
+
"login.noKeyBrowser": "You approved from a browser that doesn't have this account's key. Run bitl login again and approve in a browser that shows card contents",
|
|
20204
|
+
"login.keyMismatch": "This account already has a different key. Approve in a browser that shows card contents",
|
|
20205
|
+
"login.deliverFailed": "Couldn't hand over the key ({status})",
|
|
20206
|
+
"login.connected": "Connected: agent work on this PC ({name}) now goes to your account at {web}{via}.",
|
|
20207
|
+
"login.via": " (sending to {api})",
|
|
20208
|
+
"login.next": " If you have no hooks yet: bitl install claude",
|
|
20209
|
+
"logout.notConnected": "Not connected to a cloud account (local mode).",
|
|
20210
|
+
"logout.done": "Disconnected: {url} ({name}). This PC now sends to its local server.",
|
|
20211
|
+
"logout.doneCloud": "Disconnected: {url} ({name}). Agent work on this PC is no longer sent."
|
|
20212
|
+
};
|
|
20213
|
+
var DICT = { ko, en };
|
|
20214
|
+
function detectLang(env = process.env, systemLocale = Intl.DateTimeFormat().resolvedOptions().locale) {
|
|
20215
|
+
const forced = env.BITL_LANG?.trim().toLowerCase();
|
|
20216
|
+
if (forced === "ko" || forced === "en") return forced;
|
|
20217
|
+
for (const v of [env.LC_ALL, env.LC_MESSAGES, env.LANG]) {
|
|
20218
|
+
const s = v?.trim();
|
|
20219
|
+
if (!s || s === "C" || s === "POSIX" || s.startsWith("C.")) continue;
|
|
20220
|
+
return s.toLowerCase().startsWith("ko") ? "ko" : "en";
|
|
20221
|
+
}
|
|
20222
|
+
return systemLocale.toLowerCase().startsWith("ko") ? "ko" : "en";
|
|
20223
|
+
}
|
|
20224
|
+
var lang = () => detectLang();
|
|
20225
|
+
function t(key, vars) {
|
|
20226
|
+
const text = DICT[lang()][key] ?? ko[key];
|
|
20227
|
+
return vars ? text.replace(/\{(\w+)\}/g, (m, k) => k in vars ? String(vars[k]) : m) : text;
|
|
20228
|
+
}
|
|
20229
|
+
|
|
20230
|
+
// ../src/install.ts
|
|
20047
20231
|
var CLAUDE_EVENTS = [
|
|
20048
20232
|
"SessionStart",
|
|
20049
20233
|
"SessionEnd",
|
|
@@ -20131,9 +20315,9 @@ var codexConfigPath = () => join3(process.env.CODEX_HOME ?? join3(homedir2(), ".
|
|
|
20131
20315
|
function removeCodexBlock(toml) {
|
|
20132
20316
|
const sections = [[]];
|
|
20133
20317
|
for (const line of toml.split("\n")) {
|
|
20134
|
-
const
|
|
20135
|
-
if (
|
|
20136
|
-
if (
|
|
20318
|
+
const t2 = line.trim();
|
|
20319
|
+
if (t2 === CODEX_BEGIN || t2 === CODEX_END) continue;
|
|
20320
|
+
if (t2.startsWith("[")) sections.push([]);
|
|
20137
20321
|
sections[sections.length - 1].push(line);
|
|
20138
20322
|
}
|
|
20139
20323
|
const header = (sec) => sec[0]?.trim() ?? "";
|
|
@@ -20163,7 +20347,7 @@ var ANTIGRAVITY_TOOL_EVENTS = /* @__PURE__ */ new Set(["PreToolUse", "PostToolUs
|
|
|
20163
20347
|
var ANTIGRAVITY_HOOK_NAME = "bitl";
|
|
20164
20348
|
var antigravityHooksPath = () => join3(homedir2(), ".gemini", "config", "hooks.json");
|
|
20165
20349
|
function addAntigravityHooks(config2, adapter = ADAPTER_PATH) {
|
|
20166
|
-
if (/\s/.test(adapter)) throw new Error(
|
|
20350
|
+
if (/\s/.test(adapter)) throw new Error(t("err.agySpace", { path: adapter }));
|
|
20167
20351
|
const group = { enabled: true };
|
|
20168
20352
|
for (const event of ANTIGRAVITY_EVENTS) {
|
|
20169
20353
|
const handler = { type: "command", command: `node ${adapter} --source antigravity --event ${event}`, timeout: 10 };
|
|
@@ -20213,8 +20397,8 @@ async function postJson(url2, body, headers = {}) {
|
|
|
20213
20397
|
const origin = new URL(url2).origin;
|
|
20214
20398
|
const code = err.cause?.code;
|
|
20215
20399
|
throw new Error(
|
|
20216
|
-
|
|
20217
|
-
|
|
20400
|
+
`${t("login.unreachable", { where: `${origin}${code ? `, ${code}` : ""}` })}
|
|
20401
|
+
${t("login.unreachableHint", { origin })}`
|
|
20218
20402
|
);
|
|
20219
20403
|
});
|
|
20220
20404
|
return { status: res.status, json: await res.json().catch(() => ({})) };
|
|
@@ -20234,45 +20418,45 @@ function openBrowser(url2) {
|
|
|
20234
20418
|
async function login(url2, name = hostname3(), opts = {}) {
|
|
20235
20419
|
const base = url2.trim().replace(/\/+$/, "");
|
|
20236
20420
|
const existing = readCloudConfig();
|
|
20237
|
-
if (existing) throw new Error(
|
|
20421
|
+
if (existing) throw new Error(t("login.already", { url: existing.url, name: existing.name }));
|
|
20238
20422
|
const secret = generatePairingSecret();
|
|
20239
20423
|
const kp = await generateDeviceKeyPair(false);
|
|
20240
20424
|
const mac3 = await signPublicKey(secret, "initiator", kp.publicKey);
|
|
20241
20425
|
const start = await postJson(`${base}/api/pairing/start`, { kind: "cli", name, publicKey: kp.publicKey, mac: mac3 });
|
|
20242
|
-
if (start.status === 404) throw new Error(
|
|
20243
|
-
if (start.status === 429) throw new Error("
|
|
20244
|
-
if (start.status !== 200) throw new Error(
|
|
20426
|
+
if (start.status === 404) throw new Error(t("login.notBitl", { url: base }));
|
|
20427
|
+
if (start.status === 429) throw new Error(t("login.tooMany"));
|
|
20428
|
+
if (start.status !== 200) throw new Error(t("login.cannotStart", { status: start.status }));
|
|
20245
20429
|
const { id: id2, pollToken, expiresAt, intervalMs, webUrl, apiUrl } = start.json;
|
|
20246
20430
|
const web = (webUrl ?? base).replace(/\/+$/, "");
|
|
20247
20431
|
const api = (apiUrl ?? base).replace(/\/+$/, "");
|
|
20248
20432
|
const link = `${web}/link?p=${encodeURIComponent(id2)}#s=${secret}`;
|
|
20249
|
-
console.log("
|
|
20433
|
+
console.log(t("login.approve"));
|
|
20250
20434
|
console.log(` ${link}`);
|
|
20251
|
-
console.log(
|
|
20435
|
+
console.log(t("login.manual", { min: Math.round((Date.parse(expiresAt) - Date.now()) / 6e4) }));
|
|
20252
20436
|
if (opts.openBrowser !== false) openBrowser(link);
|
|
20253
20437
|
let view;
|
|
20254
20438
|
while (Date.now() < Date.parse(expiresAt)) {
|
|
20255
20439
|
await sleep(intervalMs || 2e3);
|
|
20256
20440
|
const r = await postJson(`${base}/api/pairing/${encodeURIComponent(id2)}/poll`, { pollToken }).catch(() => void 0);
|
|
20257
20441
|
if (!r) continue;
|
|
20258
|
-
if (r.status === 404) throw new Error("
|
|
20442
|
+
if (r.status === 404) throw new Error(t("login.expired"));
|
|
20259
20443
|
view = r.json;
|
|
20260
20444
|
if (view.status !== "pending") break;
|
|
20261
20445
|
}
|
|
20262
|
-
if (!view || view.status === "pending") throw new Error("
|
|
20263
|
-
if (view.status === "denied") throw new Error("
|
|
20446
|
+
if (!view || view.status === "pending") throw new Error(t("login.timeout"));
|
|
20447
|
+
if (view.status === "denied") throw new Error(t("login.denied"));
|
|
20264
20448
|
const apiKey = view.device?.apiKey;
|
|
20265
|
-
if (!view.device || !view.peer) throw new Error("
|
|
20449
|
+
if (!view.device || !view.peer) throw new Error(t("login.noResult"));
|
|
20266
20450
|
if (!await verifyPublicKey(secret, "responder", view.peer.publicKey, view.peer.mac)) {
|
|
20267
20451
|
await revokeSelf(base, apiKey);
|
|
20268
|
-
throw new Error(
|
|
20452
|
+
throw new Error(t("login.badSignature"));
|
|
20269
20453
|
}
|
|
20270
20454
|
let masterB64;
|
|
20271
20455
|
if (view.wrapped) {
|
|
20272
20456
|
masterB64 = toBase64Url(await unwrapMasterKey(view.wrapped, kp.privateKey, view.peer.publicKey, id2));
|
|
20273
20457
|
} else if (view.accountKeyId) {
|
|
20274
20458
|
await revokeSelf(base, apiKey);
|
|
20275
|
-
throw new Error("
|
|
20459
|
+
throw new Error(t("login.noKeyBrowser"));
|
|
20276
20460
|
} else {
|
|
20277
20461
|
masterB64 = loadOrCreateMasterKey();
|
|
20278
20462
|
const master = fromBase64Url(masterB64);
|
|
@@ -20281,50 +20465,97 @@ async function login(url2, name = hostname3(), opts = {}) {
|
|
|
20281
20465
|
const d = await postJson(`${base}/api/pairing/${encodeURIComponent(id2)}/initiator-deliver`, { pollToken, wrapped, keyId: keys.kid });
|
|
20282
20466
|
if (d.status !== 200) {
|
|
20283
20467
|
await revokeSelf(base, apiKey);
|
|
20284
|
-
throw new Error(d.json.error === "key-mismatch" ? "
|
|
20468
|
+
throw new Error(d.json.error === "key-mismatch" ? t("login.keyMismatch") : t("login.deliverFailed", { status: d.status }));
|
|
20285
20469
|
}
|
|
20286
20470
|
}
|
|
20287
20471
|
saveCloudLogin({ url: api, deviceId: view.device.id, apiKey: view.device.apiKey, name }, masterB64);
|
|
20288
20472
|
console.log(`
|
|
20289
|
-
|
|
20290
|
-
console.log("
|
|
20473
|
+
${t("login.connected", { name, web, via: api !== web ? t("login.via", { api }) : "" })}`);
|
|
20474
|
+
console.log(t("login.next"));
|
|
20291
20475
|
}
|
|
20292
20476
|
async function logout() {
|
|
20293
20477
|
const cfg = readCloudConfig();
|
|
20294
|
-
if (!cfg) return console.log("
|
|
20478
|
+
if (!cfg) return console.log(t("logout.notConnected"));
|
|
20295
20479
|
await revokeSelf(cfg.url, cfg.apiKey);
|
|
20296
20480
|
removeCloudLogin();
|
|
20297
|
-
console.log(
|
|
20481
|
+
console.log(t(true ? "logout.doneCloud" : "logout.done", { url: cfg.url, name: cfg.name }));
|
|
20482
|
+
}
|
|
20483
|
+
|
|
20484
|
+
// ../src/update.ts
|
|
20485
|
+
import { mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "node:fs";
|
|
20486
|
+
import { join as join4 } from "node:path";
|
|
20487
|
+
var REGISTRY = "https://registry.npmjs.org/@usebitl/cli/latest";
|
|
20488
|
+
var DAY = 864e5;
|
|
20489
|
+
var TIMEOUT_MS = 1e3;
|
|
20490
|
+
var cachePath = () => join4(bitlHome(), "update-check.json");
|
|
20491
|
+
function readCache() {
|
|
20492
|
+
try {
|
|
20493
|
+
return JSON.parse(readFileSync4(cachePath(), "utf8"));
|
|
20494
|
+
} catch {
|
|
20495
|
+
return null;
|
|
20496
|
+
}
|
|
20497
|
+
}
|
|
20498
|
+
async function fetchLatest() {
|
|
20499
|
+
try {
|
|
20500
|
+
const res = await fetch(REGISTRY, { signal: AbortSignal.timeout(TIMEOUT_MS), headers: { accept: "application/json" } });
|
|
20501
|
+
if (!res.ok) return void 0;
|
|
20502
|
+
const v = (await res.json()).version;
|
|
20503
|
+
return typeof v === "string" && VERSION_PATTERN.test(v) ? v : void 0;
|
|
20504
|
+
} catch {
|
|
20505
|
+
return void 0;
|
|
20506
|
+
}
|
|
20507
|
+
}
|
|
20508
|
+
async function latestVersion(now = Date.now()) {
|
|
20509
|
+
const cache = readCache();
|
|
20510
|
+
if (cache && now - Date.parse(cache.checkedAt) < DAY) return cache.latest;
|
|
20511
|
+
const latest = await fetchLatest() ?? cache?.latest;
|
|
20512
|
+
try {
|
|
20513
|
+
mkdirSync4(bitlHome(), { recursive: true });
|
|
20514
|
+
writeFileSync4(cachePath(), JSON.stringify({ checkedAt: new Date(now).toISOString(), latest }) + "\n");
|
|
20515
|
+
} catch {
|
|
20516
|
+
}
|
|
20517
|
+
return latest;
|
|
20518
|
+
}
|
|
20519
|
+
async function updateNotice(current = "0.1.4") {
|
|
20520
|
+
if (!current || process.env.BITL_NO_UPDATE_CHECK === "1") return void 0;
|
|
20521
|
+
const latest = await latestVersion();
|
|
20522
|
+
if (!latest || compareVersions(latest, current) <= 0) return void 0;
|
|
20523
|
+
return `${t("update.available", { latest, current })}
|
|
20524
|
+
${t("update.changelog")}`;
|
|
20298
20525
|
}
|
|
20299
20526
|
|
|
20300
20527
|
// ../src/index.ts
|
|
20301
20528
|
var CLOUD_ONLY = true;
|
|
20302
20529
|
var DEFAULT_URL = "https://api.usebitl.com";
|
|
20303
|
-
var
|
|
20304
|
-
|
|
20530
|
+
var row = (cmd, desc) => {
|
|
20531
|
+
const width = cmd.length + (cmd.match(/[가-힣]/g)?.length ?? 0);
|
|
20532
|
+
return ` ${width < 40 ? cmd + " ".repeat(40 - width) : `${cmd} `}${desc}`;
|
|
20533
|
+
};
|
|
20534
|
+
var usage = () => [
|
|
20535
|
+
t("usage.title"),
|
|
20305
20536
|
"",
|
|
20306
|
-
...CLOUD_ONLY ? [] : ["
|
|
20307
|
-
"
|
|
20308
|
-
|
|
20537
|
+
...CLOUD_ONLY ? [] : [row("bitl start", t("usage.start"))],
|
|
20538
|
+
row("bitl status", t("usage.status")),
|
|
20539
|
+
row(`bitl pair ${t("usage.pairArgs")}`, t("usage.pair")),
|
|
20309
20540
|
"",
|
|
20310
|
-
DEFAULT_URL ? `
|
|
20311
|
-
|
|
20541
|
+
DEFAULT_URL ? row(`bitl login ${t("usage.loginArgsDefault")}`, t("usage.loginDefault", { url: DEFAULT_URL })) : row(`bitl login ${t("usage.loginArgs")}`, t("usage.login")),
|
|
20542
|
+
row("bitl logout", CLOUD_ONLY ? t("usage.logoutCloud") : t("usage.logout")),
|
|
20312
20543
|
"",
|
|
20313
|
-
"
|
|
20314
|
-
"
|
|
20315
|
-
"
|
|
20316
|
-
...CLOUD_ONLY ? [] : ["
|
|
20544
|
+
row("bitl install claude [--project D]", t("usage.installClaude")),
|
|
20545
|
+
row("bitl install codex", t("usage.installCodex")),
|
|
20546
|
+
row("bitl install antigravity", t("usage.installAgy")),
|
|
20547
|
+
...CLOUD_ONLY ? [] : [row("bitl install claude-desktop", t("usage.installDesktop"))],
|
|
20317
20548
|
` bitl uninstall <claude|codex|antigravity${CLOUD_ONLY ? "" : "|claude-desktop"}> [--project D]`,
|
|
20318
20549
|
"",
|
|
20319
|
-
"
|
|
20320
|
-
"
|
|
20550
|
+
row("bitl remote [on|off]", t("usage.remote")),
|
|
20551
|
+
row("", t("usage.remote2"))
|
|
20321
20552
|
].join("\n");
|
|
20322
20553
|
var serverUrl = () => process.env.BITL_URL ?? `http://127.0.0.1:${process.env.BITL_PORT ?? 7777}`;
|
|
20323
20554
|
function option(args, name) {
|
|
20324
20555
|
const i = args.indexOf(name);
|
|
20325
20556
|
if (i < 0) return void 0;
|
|
20326
20557
|
const v = args[i + 1];
|
|
20327
|
-
if (!v) throw new Error(
|
|
20558
|
+
if (!v) throw new Error(t("err.optionValue", { name }));
|
|
20328
20559
|
args.splice(i, 2);
|
|
20329
20560
|
return v;
|
|
20330
20561
|
}
|
|
@@ -20336,22 +20567,22 @@ async function request(path, init = {}) {
|
|
|
20336
20567
|
body: init.body === void 0 ? void 0 : JSON.stringify(init.body)
|
|
20337
20568
|
}).catch(() => {
|
|
20338
20569
|
throw new Error(
|
|
20339
|
-
target.kind === "cloud" ?
|
|
20570
|
+
target.kind === "cloud" ? t("err.cloudUnreachable", { url: target.url }) : t("err.localUnreachable", { url: target.url })
|
|
20340
20571
|
);
|
|
20341
20572
|
});
|
|
20342
|
-
if (res.status === 401) throw new Error("
|
|
20573
|
+
if (res.status === 401) throw new Error(t("err.revoked"));
|
|
20343
20574
|
return res;
|
|
20344
20575
|
}
|
|
20345
20576
|
var boardUrl = (override) => (override?.trim() || process.env.BITL_PUBLIC_URL?.trim() || readCloudConfig()?.url || serverUrl()).replace(/\/+$/, "");
|
|
20346
|
-
var masterForPair = () => readCloudConfig() ?
|
|
20577
|
+
var masterForPair = () => readCloudConfig() ? readFileSync5(cloudKeyPath(), "utf8").trim() : loadOrCreateMasterKey();
|
|
20347
20578
|
var pairUrl = (base) => `${boardUrl(base)}/#key=${masterForPair()}`;
|
|
20348
20579
|
function pair(args) {
|
|
20349
20580
|
const base = option(args, "--url");
|
|
20350
|
-
console.log(
|
|
20581
|
+
console.log(t("pair.intro"));
|
|
20351
20582
|
console.log(` ${pairUrl(base)}`);
|
|
20352
|
-
if (!base) console.log("
|
|
20353
|
-
if (readCloudConfig()) console.log(
|
|
20354
|
-
console.log(
|
|
20583
|
+
if (!base) console.log(t("pair.otherUrl"));
|
|
20584
|
+
if (readCloudConfig()) console.log(t("pair.cloud"));
|
|
20585
|
+
console.log(t("pair.keyFile", { path: readCloudConfig() ? cloudKeyPath() : keyPath(bitlHome()) }));
|
|
20355
20586
|
}
|
|
20356
20587
|
async function status() {
|
|
20357
20588
|
const target = resolveTarget();
|
|
@@ -20363,8 +20594,8 @@ async function status() {
|
|
|
20363
20594
|
process.exitCode = 1;
|
|
20364
20595
|
return;
|
|
20365
20596
|
}
|
|
20366
|
-
if (target.kind === "cloud") console.log(
|
|
20367
|
-
if (stored.length === 0) return console.log("
|
|
20597
|
+
if (target.kind === "cloud") console.log(t("status.cloud", { url: target.url }));
|
|
20598
|
+
if (stored.length === 0) return console.log(t("status.none"));
|
|
20368
20599
|
let keys = await target.keys();
|
|
20369
20600
|
if (target.kind === "cloud") {
|
|
20370
20601
|
const res = await request("/api/inbox-key").catch(() => null);
|
|
@@ -20380,12 +20611,12 @@ async function status() {
|
|
|
20380
20611
|
}
|
|
20381
20612
|
}
|
|
20382
20613
|
async function away(arg) {
|
|
20383
|
-
if (arg !== void 0 && arg !== "on" && arg !== "off") throw new Error("
|
|
20614
|
+
if (arg !== void 0 && arg !== "on" && arg !== "off") throw new Error(t("err.remoteUsage"));
|
|
20384
20615
|
const res = arg === void 0 ? await request("/api/approvals/mode") : await request("/api/approvals/mode", { method: "PUT", body: { away: arg === "on" } });
|
|
20385
|
-
if (res.status === 404) throw new Error(
|
|
20616
|
+
if (res.status === 404) throw new Error(t("err.remoteUnsupported"));
|
|
20386
20617
|
const { away: on } = await res.json();
|
|
20387
|
-
console.log(on ? "
|
|
20388
|
-
if (on) console.log(
|
|
20618
|
+
console.log(on ? t("remote.on") : t("remote.off"));
|
|
20619
|
+
if (on) console.log(t("remote.needHook"));
|
|
20389
20620
|
}
|
|
20390
20621
|
function install(cmd, target, args) {
|
|
20391
20622
|
const add = cmd === "install";
|
|
@@ -20395,47 +20626,49 @@ function install(cmd, target, args) {
|
|
|
20395
20626
|
switch (target) {
|
|
20396
20627
|
case "claude": {
|
|
20397
20628
|
const project = option(args, "--project");
|
|
20398
|
-
file2 = project ?
|
|
20629
|
+
file2 = project ? join5(resolve2(project), ".claude", "settings.json") : join5(homedir3(), ".claude", "settings.json");
|
|
20399
20630
|
result = updateSettingsFile(file2, add ? (s) => addHooks(s) : removeHooks);
|
|
20400
|
-
extra =
|
|
20631
|
+
extra = t("install.adapter", { path: ADAPTER_PATH });
|
|
20401
20632
|
break;
|
|
20402
20633
|
}
|
|
20403
20634
|
case "codex":
|
|
20404
20635
|
file2 = codexConfigPath();
|
|
20405
|
-
result = updateTextFile(file2, add ? (
|
|
20406
|
-
extra =
|
|
20407
|
-
|
|
20636
|
+
result = updateTextFile(file2, add ? (t2) => addCodexBlock(t2) : removeCodexBlock);
|
|
20637
|
+
extra = `${t("install.adapter", { path: ADAPTER_PATH })}
|
|
20638
|
+
${t("install.codexTrust")}`;
|
|
20408
20639
|
break;
|
|
20409
20640
|
case "antigravity":
|
|
20410
20641
|
file2 = antigravityHooksPath();
|
|
20411
20642
|
result = updateSettingsFile(file2, add ? (c) => addAntigravityHooks(c) : removeAntigravityHooks);
|
|
20412
|
-
extra =
|
|
20413
|
-
|
|
20643
|
+
extra = `${t("install.adapter", { path: ADAPTER_PATH })}
|
|
20644
|
+
${t("install.agyRestart")}`;
|
|
20414
20645
|
break;
|
|
20415
20646
|
case "claude-desktop":
|
|
20416
|
-
if (CLOUD_ONLY) throw new Error("
|
|
20647
|
+
if (CLOUD_ONLY) throw new Error(t("err.noDesktop"));
|
|
20417
20648
|
file2 = claudeDesktopConfigPath();
|
|
20418
20649
|
result = updateSettingsFile(file2, add ? (c) => addMcpServer(c) : removeMcpServer);
|
|
20419
|
-
extra =
|
|
20420
|
-
|
|
20650
|
+
extra = `${t("install.mcp", { path: MCP_PATH })}
|
|
20651
|
+
${t("install.desktopRestart")}`;
|
|
20421
20652
|
break;
|
|
20422
20653
|
default:
|
|
20423
|
-
throw new Error(
|
|
20654
|
+
throw new Error(
|
|
20655
|
+
t("err.unknownTarget", { target: target ?? t("err.none"), list: `claude, codex, antigravity${CLOUD_ONLY ? "" : ", claude-desktop"}` })
|
|
20656
|
+
);
|
|
20424
20657
|
}
|
|
20425
|
-
if (!result.changed) return console.log(
|
|
20426
|
-
console.log(
|
|
20427
|
-
if (result.backup) console.log(
|
|
20658
|
+
if (!result.changed) return console.log(t("install.unchanged", { file: file2 }));
|
|
20659
|
+
console.log(t(add ? "install.added" : "install.removed", { file: file2 }));
|
|
20660
|
+
if (result.backup) console.log(t("install.backup", { path: result.backup }));
|
|
20428
20661
|
if (add && extra) console.log(` ${extra}`);
|
|
20429
20662
|
}
|
|
20430
20663
|
async function main(argv) {
|
|
20431
20664
|
const [cmd, ...rest] = argv;
|
|
20432
20665
|
switch (cmd) {
|
|
20433
20666
|
case "start": {
|
|
20434
|
-
if (CLOUD_ONLY) throw new Error("
|
|
20667
|
+
if (CLOUD_ONLY) throw new Error(t("err.noStart"));
|
|
20435
20668
|
const { startServer } = await import("@bitl/server");
|
|
20436
20669
|
await startServer();
|
|
20437
20670
|
loadOrCreateMasterKey();
|
|
20438
|
-
console.log(
|
|
20671
|
+
console.log(t("start.pair", { url: pairUrl() }));
|
|
20439
20672
|
return;
|
|
20440
20673
|
}
|
|
20441
20674
|
case "install":
|
|
@@ -20447,7 +20680,7 @@ async function main(argv) {
|
|
|
20447
20680
|
return pair(rest);
|
|
20448
20681
|
case "login": {
|
|
20449
20682
|
const url2 = option(rest, "--url") ?? process.env.BITL_PUBLIC_URL?.trim() ?? DEFAULT_URL;
|
|
20450
|
-
if (!url2) throw new Error("
|
|
20683
|
+
if (!url2) throw new Error(t("err.loginUrl"));
|
|
20451
20684
|
return login(url2, option(rest, "--name"), { openBrowser: !rest.includes("--no-browser") });
|
|
20452
20685
|
}
|
|
20453
20686
|
case "logout":
|
|
@@ -20456,10 +20689,15 @@ async function main(argv) {
|
|
|
20456
20689
|
case "away":
|
|
20457
20690
|
return away(rest[0]);
|
|
20458
20691
|
default:
|
|
20459
|
-
console.log(
|
|
20692
|
+
console.log(usage());
|
|
20460
20693
|
}
|
|
20461
20694
|
}
|
|
20462
20695
|
main(process.argv.slice(2)).catch((err) => {
|
|
20463
20696
|
console.error(err instanceof Error ? err.message : err);
|
|
20464
20697
|
process.exitCode = 1;
|
|
20698
|
+
}).then(async () => {
|
|
20699
|
+
if (process.argv[2] === "start") return;
|
|
20700
|
+
const notice = await updateNotice();
|
|
20701
|
+
if (notice) console.error(`
|
|
20702
|
+
${notice}`);
|
|
20465
20703
|
});
|