happy-coder 0.10.0-2 → 0.10.0-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/README.md +10 -1
- package/bin/happy-mcp.mjs +32 -0
- package/dist/codex/happyMcpStdioBridge.cjs +80 -0
- package/dist/codex/happyMcpStdioBridge.d.cts +2 -0
- package/dist/codex/happyMcpStdioBridge.d.mts +2 -0
- package/dist/codex/happyMcpStdioBridge.mjs +78 -0
- package/dist/index-67rskwL7.cjs +6033 -0
- package/dist/index-Dw96QD4T.mjs +6025 -0
- package/dist/index.cjs +33 -6024
- package/dist/index.mjs +33 -6024
- package/dist/lib.cjs +2 -1
- package/dist/lib.d.cts +54 -112
- package/dist/lib.d.mts +54 -112
- package/dist/lib.mjs +2 -1
- package/dist/runCodex-BLNf5zb1.cjs +1155 -0
- package/dist/runCodex-BNH8w4O9.mjs +1153 -0
- package/dist/{types-xfXKJHdM.mjs → types-2wHnX7UW.mjs} +311 -170
- package/dist/{types-WP9wteZE.cjs → types-BcDnTXMg.cjs} +348 -206
- package/package.json +20 -6
- package/scripts/ripgrep_launcher.cjs +2 -26
- package/scripts/unpack-tools.cjs +163 -0
- package/tools/archives/difftastic-LICENSE +21 -0
- package/tools/archives/difftastic-arm64-darwin.tar.gz +0 -0
- package/tools/archives/difftastic-arm64-linux.tar.gz +0 -0
- package/tools/archives/difftastic-x64-darwin.tar.gz +0 -0
- package/tools/archives/difftastic-x64-linux.tar.gz +0 -0
- package/tools/archives/difftastic-x64-win32.tar.gz +0 -0
- package/tools/archives/ripgrep-arm64-darwin.tar.gz +0 -0
- package/tools/archives/ripgrep-arm64-linux.tar.gz +0 -0
- package/tools/archives/ripgrep-x64-darwin.tar.gz +0 -0
- package/tools/archives/ripgrep-x64-linux.tar.gz +0 -0
- package/tools/archives/ripgrep-x64-win32.tar.gz +0 -0
- package/tools/licenses/difftastic-LICENSE +21 -0
- package/tools/licenses/ripgrep-LICENSE +3 -0
- package/tools/unpacked/difft +0 -0
- package/ripgrep/arm64-linux/rg +0 -0
- package/ripgrep/arm64-linux/ripgrep.node +0 -0
- package/ripgrep/x64-darwin/rg +0 -0
- package/ripgrep/x64-darwin/ripgrep.node +0 -0
- package/ripgrep/x64-linux/rg +0 -0
- package/ripgrep/x64-linux/ripgrep.node +0 -0
- package/ripgrep/x64-win32/rg.exe +0 -0
- package/ripgrep/x64-win32/ripgrep.node +0 -0
- /package/{ripgrep/COPYING → tools/archives/ripgrep-LICENSE} +0 -0
- /package/{ripgrep/arm64-darwin → tools/unpacked}/rg +0 -0
- /package/{ripgrep/arm64-darwin → tools/unpacked}/ripgrep.node +0 -0
|
@@ -7,7 +7,7 @@ import { join, basename } from 'node:path';
|
|
|
7
7
|
import { readFile, open, stat, unlink, mkdir, writeFile, rename } from 'node:fs/promises';
|
|
8
8
|
import * as z from 'zod';
|
|
9
9
|
import { z as z$1 } from 'zod';
|
|
10
|
-
import { randomBytes, randomUUID } from 'node:crypto';
|
|
10
|
+
import { randomBytes, createCipheriv, createDecipheriv, randomUUID } from 'node:crypto';
|
|
11
11
|
import tweetnacl from 'tweetnacl';
|
|
12
12
|
import { EventEmitter } from 'node:events';
|
|
13
13
|
import { io } from 'socket.io-client';
|
|
@@ -17,11 +17,12 @@ import { readFile as readFile$1, stat as stat$1, writeFile as writeFile$1, readd
|
|
|
17
17
|
import { createHash } from 'crypto';
|
|
18
18
|
import { dirname, resolve, join as join$1 } from 'path';
|
|
19
19
|
import { fileURLToPath } from 'url';
|
|
20
|
+
import { platform } from 'os';
|
|
20
21
|
import { Expo } from 'expo-server-sdk';
|
|
21
22
|
|
|
22
23
|
var name = "happy-coder";
|
|
23
|
-
var version = "0.10.0-
|
|
24
|
-
var description = "Claude Code
|
|
24
|
+
var version = "0.10.0-4";
|
|
25
|
+
var description = "Mobile and Web client for Claude Code and Codex";
|
|
25
26
|
var author = "Kirill Dubovitskiy";
|
|
26
27
|
var license = "MIT";
|
|
27
28
|
var type = "module";
|
|
@@ -29,7 +30,8 @@ var homepage = "https://github.com/slopus/happy-cli";
|
|
|
29
30
|
var bugs = "https://github.com/slopus/happy-cli/issues";
|
|
30
31
|
var repository = "slopus/happy-cli";
|
|
31
32
|
var bin = {
|
|
32
|
-
happy: "./bin/happy.mjs"
|
|
33
|
+
happy: "./bin/happy.mjs",
|
|
34
|
+
"happy-mcp": "./bin/happy-mcp.mjs"
|
|
33
35
|
};
|
|
34
36
|
var main = "./dist/index.cjs";
|
|
35
37
|
var module = "./dist/index.mjs";
|
|
@@ -54,13 +56,23 @@ var exports = {
|
|
|
54
56
|
types: "./dist/lib.d.mts",
|
|
55
57
|
"default": "./dist/lib.mjs"
|
|
56
58
|
}
|
|
59
|
+
},
|
|
60
|
+
"./codex/happyMcpStdioBridge": {
|
|
61
|
+
require: {
|
|
62
|
+
types: "./dist/codex/happyMcpStdioBridge.d.cts",
|
|
63
|
+
"default": "./dist/codex/happyMcpStdioBridge.cjs"
|
|
64
|
+
},
|
|
65
|
+
"import": {
|
|
66
|
+
types: "./dist/codex/happyMcpStdioBridge.d.mts",
|
|
67
|
+
"default": "./dist/codex/happyMcpStdioBridge.mjs"
|
|
68
|
+
}
|
|
57
69
|
}
|
|
58
70
|
};
|
|
59
71
|
var files = [
|
|
60
72
|
"dist",
|
|
61
73
|
"bin",
|
|
62
74
|
"scripts",
|
|
63
|
-
"
|
|
75
|
+
"tools",
|
|
64
76
|
"package.json"
|
|
65
77
|
];
|
|
66
78
|
var scripts = {
|
|
@@ -69,17 +81,19 @@ var scripts = {
|
|
|
69
81
|
build: "shx rm -rf dist && npx tsc --noEmit && pkgroll",
|
|
70
82
|
test: "yarn build && tsx --env-file .env.integration-test node_modules/.bin/vitest run",
|
|
71
83
|
start: "yarn build && ./bin/happy.mjs",
|
|
72
|
-
dev: "
|
|
84
|
+
dev: "tsx --env-file .env.dev src/index.ts",
|
|
73
85
|
"dev:local-server": "yarn build && tsx --env-file .env.dev-local-server src/index.ts",
|
|
74
86
|
"dev:integration-test-env": "yarn build && tsx --env-file .env.integration-test src/index.ts",
|
|
75
87
|
prepublishOnly: "yarn build && yarn test",
|
|
76
|
-
release: "release-it"
|
|
88
|
+
release: "release-it",
|
|
89
|
+
postinstall: "node scripts/unpack-tools.cjs"
|
|
77
90
|
};
|
|
78
91
|
var dependencies = {
|
|
79
92
|
"@anthropic-ai/claude-code": "^1.0.102",
|
|
80
93
|
"@anthropic-ai/sdk": "^0.56.0",
|
|
81
94
|
"@modelcontextprotocol/sdk": "^1.15.1",
|
|
82
95
|
"@stablelib/base64": "^2.0.1",
|
|
96
|
+
"@stablelib/hex": "^2.0.1",
|
|
83
97
|
"@types/cross-spawn": "^6.0.6",
|
|
84
98
|
"@types/http-proxy": "^1.17.16",
|
|
85
99
|
"@types/ps-list": "^6.2.1",
|
|
@@ -99,6 +113,7 @@ var dependencies = {
|
|
|
99
113
|
"qrcode-terminal": "^0.12.0",
|
|
100
114
|
react: "^19.1.1",
|
|
101
115
|
"socket.io-client": "^4.8.1",
|
|
116
|
+
tar: "^7.4.3",
|
|
102
117
|
tweetnacl: "^1.0.3",
|
|
103
118
|
zod: "^3.23.8"
|
|
104
119
|
};
|
|
@@ -152,6 +167,7 @@ var packageJson = {
|
|
|
152
167
|
|
|
153
168
|
class Configuration {
|
|
154
169
|
serverUrl;
|
|
170
|
+
webappUrl;
|
|
155
171
|
isDaemonProcess;
|
|
156
172
|
// Directories and paths (from persistence)
|
|
157
173
|
happyHomeDir;
|
|
@@ -164,6 +180,7 @@ class Configuration {
|
|
|
164
180
|
isExperimentalEnabled;
|
|
165
181
|
constructor() {
|
|
166
182
|
this.serverUrl = process.env.HAPPY_SERVER_URL || "https://api.cluster-fluster.com";
|
|
183
|
+
this.webappUrl = process.env.HAPPY_WEBAPP_URL || "https://app.happy.engineering";
|
|
167
184
|
const args = process.argv.slice(2);
|
|
168
185
|
this.isDaemonProcess = args.length >= 2 && args[0] === "daemon" && args[1] === "start-sync";
|
|
169
186
|
if (process.env.HAPPY_HOME_DIR) {
|
|
@@ -208,7 +225,17 @@ function decodeBase64(base64, variant = "base64") {
|
|
|
208
225
|
function getRandomBytes(size) {
|
|
209
226
|
return new Uint8Array(randomBytes(size));
|
|
210
227
|
}
|
|
211
|
-
function
|
|
228
|
+
function libsodiumEncryptForPublicKey(data, recipientPublicKey) {
|
|
229
|
+
const ephemeralKeyPair = tweetnacl.box.keyPair();
|
|
230
|
+
const nonce = getRandomBytes(tweetnacl.box.nonceLength);
|
|
231
|
+
const encrypted = tweetnacl.box(data, nonce, recipientPublicKey, ephemeralKeyPair.secretKey);
|
|
232
|
+
const result = new Uint8Array(ephemeralKeyPair.publicKey.length + nonce.length + encrypted.length);
|
|
233
|
+
result.set(ephemeralKeyPair.publicKey, 0);
|
|
234
|
+
result.set(nonce, ephemeralKeyPair.publicKey.length);
|
|
235
|
+
result.set(encrypted, ephemeralKeyPair.publicKey.length + nonce.length);
|
|
236
|
+
return result;
|
|
237
|
+
}
|
|
238
|
+
function encryptLegacy(data, secret) {
|
|
212
239
|
const nonce = getRandomBytes(tweetnacl.secretbox.nonceLength);
|
|
213
240
|
const encrypted = tweetnacl.secretbox(new TextEncoder().encode(JSON.stringify(data)), nonce, secret);
|
|
214
241
|
const result = new Uint8Array(nonce.length + encrypted.length);
|
|
@@ -216,7 +243,7 @@ function encrypt(data, secret) {
|
|
|
216
243
|
result.set(encrypted, nonce.length);
|
|
217
244
|
return result;
|
|
218
245
|
}
|
|
219
|
-
function
|
|
246
|
+
function decryptLegacy(data, secret) {
|
|
220
247
|
const nonce = data.slice(0, tweetnacl.secretbox.nonceLength);
|
|
221
248
|
const encrypted = data.slice(tweetnacl.secretbox.nonceLength);
|
|
222
249
|
const decrypted = tweetnacl.secretbox.open(encrypted, nonce, secret);
|
|
@@ -225,6 +252,61 @@ function decrypt(data, secret) {
|
|
|
225
252
|
}
|
|
226
253
|
return JSON.parse(new TextDecoder().decode(decrypted));
|
|
227
254
|
}
|
|
255
|
+
function encryptWithDataKey(data, dataKey) {
|
|
256
|
+
const nonce = getRandomBytes(12);
|
|
257
|
+
const cipher = createCipheriv("aes-256-gcm", dataKey, nonce);
|
|
258
|
+
const plaintext = new TextEncoder().encode(JSON.stringify(data));
|
|
259
|
+
const encrypted = Buffer.concat([
|
|
260
|
+
cipher.update(plaintext),
|
|
261
|
+
cipher.final()
|
|
262
|
+
]);
|
|
263
|
+
const authTag = cipher.getAuthTag();
|
|
264
|
+
const bundle = new Uint8Array(12 + encrypted.length + 16 + 1);
|
|
265
|
+
bundle.set([0], 0);
|
|
266
|
+
bundle.set(nonce, 1);
|
|
267
|
+
bundle.set(new Uint8Array(encrypted), 13);
|
|
268
|
+
bundle.set(new Uint8Array(authTag), 13 + encrypted.length);
|
|
269
|
+
return bundle;
|
|
270
|
+
}
|
|
271
|
+
function decryptWithDataKey(bundle, dataKey) {
|
|
272
|
+
if (bundle.length < 1) {
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
if (bundle[0] !== 0) {
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
if (bundle.length < 12 + 16 + 1) {
|
|
279
|
+
return null;
|
|
280
|
+
}
|
|
281
|
+
const nonce = bundle.slice(1, 13);
|
|
282
|
+
const authTag = bundle.slice(bundle.length - 16);
|
|
283
|
+
const ciphertext = bundle.slice(13, bundle.length - 16);
|
|
284
|
+
try {
|
|
285
|
+
const decipher = createDecipheriv("aes-256-gcm", dataKey, nonce);
|
|
286
|
+
decipher.setAuthTag(authTag);
|
|
287
|
+
const decrypted = Buffer.concat([
|
|
288
|
+
decipher.update(ciphertext),
|
|
289
|
+
decipher.final()
|
|
290
|
+
]);
|
|
291
|
+
return JSON.parse(new TextDecoder().decode(decrypted));
|
|
292
|
+
} catch (error) {
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
function encrypt(key, variant, data) {
|
|
297
|
+
if (variant === "legacy") {
|
|
298
|
+
return encryptLegacy(data, key);
|
|
299
|
+
} else {
|
|
300
|
+
return encryptWithDataKey(data, key);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
function decrypt(key, variant, data) {
|
|
304
|
+
if (variant === "legacy") {
|
|
305
|
+
return decryptLegacy(data, key);
|
|
306
|
+
} else {
|
|
307
|
+
return decryptWithDataKey(data, key);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
228
310
|
|
|
229
311
|
const defaultSettings = {
|
|
230
312
|
onboardingCompleted: false
|
|
@@ -288,8 +370,13 @@ async function updateSettings(updater) {
|
|
|
288
370
|
}
|
|
289
371
|
}
|
|
290
372
|
const credentialsSchema = z.object({
|
|
291
|
-
|
|
292
|
-
|
|
373
|
+
token: z.string(),
|
|
374
|
+
secret: z.string().base64().nullish(),
|
|
375
|
+
// Legacy
|
|
376
|
+
encryption: z.object({
|
|
377
|
+
publicKey: z.string().base64(),
|
|
378
|
+
machineKey: z.string().base64()
|
|
379
|
+
}).nullish()
|
|
293
380
|
});
|
|
294
381
|
async function readCredentials() {
|
|
295
382
|
if (!existsSync(configuration.privateKeyFile)) {
|
|
@@ -298,15 +385,30 @@ async function readCredentials() {
|
|
|
298
385
|
try {
|
|
299
386
|
const keyBase64 = await readFile(configuration.privateKeyFile, "utf8");
|
|
300
387
|
const credentials = credentialsSchema.parse(JSON.parse(keyBase64));
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
388
|
+
if (credentials.secret) {
|
|
389
|
+
return {
|
|
390
|
+
token: credentials.token,
|
|
391
|
+
encryption: {
|
|
392
|
+
type: "legacy",
|
|
393
|
+
secret: new Uint8Array(Buffer.from(credentials.secret, "base64"))
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
} else if (credentials.encryption) {
|
|
397
|
+
return {
|
|
398
|
+
token: credentials.token,
|
|
399
|
+
encryption: {
|
|
400
|
+
type: "dataKey",
|
|
401
|
+
publicKey: new Uint8Array(Buffer.from(credentials.encryption.publicKey, "base64")),
|
|
402
|
+
machineKey: new Uint8Array(Buffer.from(credentials.encryption.machineKey, "base64"))
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
}
|
|
305
406
|
} catch {
|
|
306
407
|
return null;
|
|
307
408
|
}
|
|
409
|
+
return null;
|
|
308
410
|
}
|
|
309
|
-
async function
|
|
411
|
+
async function writeCredentialsLegacy(credentials) {
|
|
310
412
|
if (!existsSync(configuration.happyHomeDir)) {
|
|
311
413
|
await mkdir(configuration.happyHomeDir, { recursive: true });
|
|
312
414
|
}
|
|
@@ -315,6 +417,15 @@ async function writeCredentials(credentials) {
|
|
|
315
417
|
token: credentials.token
|
|
316
418
|
}, null, 2));
|
|
317
419
|
}
|
|
420
|
+
async function writeCredentialsDataKey(credentials) {
|
|
421
|
+
if (!existsSync(configuration.happyHomeDir)) {
|
|
422
|
+
await mkdir(configuration.happyHomeDir, { recursive: true });
|
|
423
|
+
}
|
|
424
|
+
await writeFile(configuration.privateKeyFile, JSON.stringify({
|
|
425
|
+
encryption: { publicKey: encodeBase64(credentials.publicKey), machineKey: encodeBase64(credentials.machineKey) },
|
|
426
|
+
token: credentials.token
|
|
427
|
+
}, null, 2));
|
|
428
|
+
}
|
|
318
429
|
async function clearCredentials() {
|
|
319
430
|
if (existsSync(configuration.privateKeyFile)) {
|
|
320
431
|
await unlink(configuration.privateKeyFile);
|
|
@@ -482,6 +593,13 @@ class Logger {
|
|
|
482
593
|
this.logToConsole("info", "[DEV]", message, ...args);
|
|
483
594
|
}
|
|
484
595
|
}
|
|
596
|
+
warn(message, ...args) {
|
|
597
|
+
this.logToConsole("warn", "", message, ...args);
|
|
598
|
+
this.debug(`[WARN] ${message}`, ...args);
|
|
599
|
+
}
|
|
600
|
+
getLogPath() {
|
|
601
|
+
return this.logFilePath;
|
|
602
|
+
}
|
|
485
603
|
logToConsole(level, prefix, message, ...args) {
|
|
486
604
|
switch (level) {
|
|
487
605
|
case "debug": {
|
|
@@ -642,38 +760,13 @@ z$1.object({
|
|
|
642
760
|
]),
|
|
643
761
|
createdAt: z$1.number()
|
|
644
762
|
});
|
|
645
|
-
z$1.object({
|
|
646
|
-
createdAt: z$1.number(),
|
|
647
|
-
id: z$1.string(),
|
|
648
|
-
seq: z$1.number(),
|
|
649
|
-
updatedAt: z$1.number(),
|
|
650
|
-
metadata: z$1.any(),
|
|
651
|
-
metadataVersion: z$1.number(),
|
|
652
|
-
agentState: z$1.any().nullable(),
|
|
653
|
-
agentStateVersion: z$1.number(),
|
|
654
|
-
// Connectivity tracking (from server)
|
|
655
|
-
connectivityStatus: z$1.union([
|
|
656
|
-
z$1.enum(["neverConnected", "online", "offline"]),
|
|
657
|
-
z$1.string()
|
|
658
|
-
// Forward compatibility
|
|
659
|
-
]).optional(),
|
|
660
|
-
connectivityStatusSince: z$1.number().optional(),
|
|
661
|
-
connectivityStatusReason: z$1.string().optional(),
|
|
662
|
-
// State tracking (from server)
|
|
663
|
-
state: z$1.union([
|
|
664
|
-
z$1.enum(["running", "archiveRequested", "archived"]),
|
|
665
|
-
z$1.string()
|
|
666
|
-
// Forward compatibility
|
|
667
|
-
]).optional(),
|
|
668
|
-
stateSince: z$1.number().optional(),
|
|
669
|
-
stateReason: z$1.string().optional()
|
|
670
|
-
});
|
|
671
763
|
z$1.object({
|
|
672
764
|
host: z$1.string(),
|
|
673
765
|
platform: z$1.string(),
|
|
674
766
|
happyCliVersion: z$1.string(),
|
|
675
767
|
homeDir: z$1.string(),
|
|
676
|
-
happyHomeDir: z$1.string()
|
|
768
|
+
happyHomeDir: z$1.string(),
|
|
769
|
+
happyLibDir: z$1.string()
|
|
677
770
|
});
|
|
678
771
|
z$1.object({
|
|
679
772
|
status: z$1.union([
|
|
@@ -691,37 +784,6 @@ z$1.object({
|
|
|
691
784
|
// Forward compatibility
|
|
692
785
|
]).optional()
|
|
693
786
|
});
|
|
694
|
-
z$1.object({
|
|
695
|
-
id: z$1.string(),
|
|
696
|
-
metadata: z$1.any(),
|
|
697
|
-
// Decrypted MachineMetadata
|
|
698
|
-
metadataVersion: z$1.number(),
|
|
699
|
-
daemonState: z$1.any().nullable(),
|
|
700
|
-
// Decrypted DaemonState
|
|
701
|
-
daemonStateVersion: z$1.number(),
|
|
702
|
-
// We don't really care about these on the CLI for now
|
|
703
|
-
// ApiMachineClient will not sync these
|
|
704
|
-
active: z$1.boolean(),
|
|
705
|
-
activeAt: z$1.number(),
|
|
706
|
-
createdAt: z$1.number(),
|
|
707
|
-
updatedAt: z$1.number(),
|
|
708
|
-
// Connectivity tracking (from server)
|
|
709
|
-
connectivityStatus: z$1.union([
|
|
710
|
-
z$1.enum(["neverConnected", "online", "offline"]),
|
|
711
|
-
z$1.string()
|
|
712
|
-
// Forward compatibility
|
|
713
|
-
]).optional(),
|
|
714
|
-
connectivityStatusSince: z$1.number().optional(),
|
|
715
|
-
connectivityStatusReason: z$1.string().optional(),
|
|
716
|
-
// State tracking (from server)
|
|
717
|
-
state: z$1.union([
|
|
718
|
-
z$1.enum(["running", "archiveRequested", "archived"]),
|
|
719
|
-
z$1.string()
|
|
720
|
-
// Forward compatibility
|
|
721
|
-
]).optional(),
|
|
722
|
-
stateSince: z$1.number().optional(),
|
|
723
|
-
stateReason: z$1.string().optional()
|
|
724
|
-
});
|
|
725
787
|
z$1.object({
|
|
726
788
|
content: SessionMessageContentSchema,
|
|
727
789
|
createdAt: z$1.number(),
|
|
@@ -845,12 +907,14 @@ class AsyncLock {
|
|
|
845
907
|
class RpcHandlerManager {
|
|
846
908
|
handlers = /* @__PURE__ */ new Map();
|
|
847
909
|
scopePrefix;
|
|
848
|
-
|
|
910
|
+
encryptionKey;
|
|
911
|
+
encryptionVariant;
|
|
849
912
|
logger;
|
|
850
913
|
socket = null;
|
|
851
914
|
constructor(config) {
|
|
852
915
|
this.scopePrefix = config.scopePrefix;
|
|
853
|
-
this.
|
|
916
|
+
this.encryptionKey = config.encryptionKey;
|
|
917
|
+
this.encryptionVariant = config.encryptionVariant;
|
|
854
918
|
this.logger = config.logger || ((msg, data) => logger.debug(msg, data));
|
|
855
919
|
}
|
|
856
920
|
/**
|
|
@@ -876,20 +940,19 @@ class RpcHandlerManager {
|
|
|
876
940
|
if (!handler) {
|
|
877
941
|
this.logger("[RPC] [ERROR] Method not found", { method: request.method });
|
|
878
942
|
const errorResponse = { error: "Method not found" };
|
|
879
|
-
const encryptedError = encodeBase64(encrypt(
|
|
943
|
+
const encryptedError = encodeBase64(encrypt(this.encryptionKey, this.encryptionVariant, errorResponse));
|
|
880
944
|
return encryptedError;
|
|
881
945
|
}
|
|
882
|
-
const decryptedParams = decrypt(decodeBase64(request.params)
|
|
946
|
+
const decryptedParams = decrypt(this.encryptionKey, this.encryptionVariant, decodeBase64(request.params));
|
|
883
947
|
const result = await handler(decryptedParams);
|
|
884
|
-
const encryptedResponse = encodeBase64(encrypt(
|
|
948
|
+
const encryptedResponse = encodeBase64(encrypt(this.encryptionKey, this.encryptionVariant, result));
|
|
885
949
|
return encryptedResponse;
|
|
886
950
|
} catch (error) {
|
|
887
951
|
this.logger("[RPC] [ERROR] Error handling request", { error });
|
|
888
952
|
const errorResponse = {
|
|
889
953
|
error: error instanceof Error ? error.message : "Unknown error"
|
|
890
954
|
};
|
|
891
|
-
|
|
892
|
-
return encryptedError;
|
|
955
|
+
return encodeBase64(encrypt(this.encryptionKey, this.encryptionVariant, errorResponse));
|
|
893
956
|
}
|
|
894
957
|
}
|
|
895
958
|
onSocketConnect(socket) {
|
|
@@ -937,7 +1000,7 @@ function projectPath() {
|
|
|
937
1000
|
return path;
|
|
938
1001
|
}
|
|
939
1002
|
|
|
940
|
-
function run(args, options) {
|
|
1003
|
+
function run$1(args, options) {
|
|
941
1004
|
const RUNNER_PATH = resolve(join$1(projectPath(), "scripts", "ripgrep_launcher.cjs"));
|
|
942
1005
|
return new Promise((resolve2, reject) => {
|
|
943
1006
|
const child = spawn("node", [RUNNER_PATH, JSON.stringify(args)], {
|
|
@@ -965,6 +1028,44 @@ function run(args, options) {
|
|
|
965
1028
|
});
|
|
966
1029
|
}
|
|
967
1030
|
|
|
1031
|
+
function getBinaryPath() {
|
|
1032
|
+
const platformName = platform();
|
|
1033
|
+
const binaryName = platformName === "win32" ? "difft.exe" : "difft";
|
|
1034
|
+
return resolve(join$1(projectPath(), "tools", "unpacked", binaryName));
|
|
1035
|
+
}
|
|
1036
|
+
function run(args, options) {
|
|
1037
|
+
const binaryPath = getBinaryPath();
|
|
1038
|
+
return new Promise((resolve2, reject) => {
|
|
1039
|
+
const child = spawn(binaryPath, args, {
|
|
1040
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
1041
|
+
cwd: options?.cwd,
|
|
1042
|
+
env: {
|
|
1043
|
+
...process.env,
|
|
1044
|
+
// Force color output when needed
|
|
1045
|
+
FORCE_COLOR: "1"
|
|
1046
|
+
}
|
|
1047
|
+
});
|
|
1048
|
+
let stdout = "";
|
|
1049
|
+
let stderr = "";
|
|
1050
|
+
child.stdout.on("data", (data) => {
|
|
1051
|
+
stdout += data.toString();
|
|
1052
|
+
});
|
|
1053
|
+
child.stderr.on("data", (data) => {
|
|
1054
|
+
stderr += data.toString();
|
|
1055
|
+
});
|
|
1056
|
+
child.on("close", (code) => {
|
|
1057
|
+
resolve2({
|
|
1058
|
+
exitCode: code || 0,
|
|
1059
|
+
stdout,
|
|
1060
|
+
stderr
|
|
1061
|
+
});
|
|
1062
|
+
});
|
|
1063
|
+
child.on("error", (err) => {
|
|
1064
|
+
reject(err);
|
|
1065
|
+
});
|
|
1066
|
+
});
|
|
1067
|
+
}
|
|
1068
|
+
|
|
968
1069
|
const execAsync = promisify(exec);
|
|
969
1070
|
function registerCommonHandlers(rpcHandlerManager) {
|
|
970
1071
|
rpcHandlerManager.registerHandler("bash", async (data) => {
|
|
@@ -1159,7 +1260,7 @@ function registerCommonHandlers(rpcHandlerManager) {
|
|
|
1159
1260
|
rpcHandlerManager.registerHandler("ripgrep", async (data) => {
|
|
1160
1261
|
logger.debug("Ripgrep request with args:", data.args, "cwd:", data.cwd);
|
|
1161
1262
|
try {
|
|
1162
|
-
const result = await run(data.args, { cwd: data.cwd });
|
|
1263
|
+
const result = await run$1(data.args, { cwd: data.cwd });
|
|
1163
1264
|
return {
|
|
1164
1265
|
success: true,
|
|
1165
1266
|
exitCode: result.exitCode,
|
|
@@ -1174,11 +1275,28 @@ function registerCommonHandlers(rpcHandlerManager) {
|
|
|
1174
1275
|
};
|
|
1175
1276
|
}
|
|
1176
1277
|
});
|
|
1278
|
+
rpcHandlerManager.registerHandler("difftastic", async (data) => {
|
|
1279
|
+
logger.debug("Difftastic request with args:", data.args, "cwd:", data.cwd);
|
|
1280
|
+
try {
|
|
1281
|
+
const result = await run(data.args, { cwd: data.cwd });
|
|
1282
|
+
return {
|
|
1283
|
+
success: true,
|
|
1284
|
+
exitCode: result.exitCode,
|
|
1285
|
+
stdout: result.stdout.toString(),
|
|
1286
|
+
stderr: result.stderr.toString()
|
|
1287
|
+
};
|
|
1288
|
+
} catch (error) {
|
|
1289
|
+
logger.debug("Failed to run difftastic:", error);
|
|
1290
|
+
return {
|
|
1291
|
+
success: false,
|
|
1292
|
+
error: error instanceof Error ? error.message : "Failed to run difftastic"
|
|
1293
|
+
};
|
|
1294
|
+
}
|
|
1295
|
+
});
|
|
1177
1296
|
}
|
|
1178
1297
|
|
|
1179
1298
|
class ApiSessionClient extends EventEmitter {
|
|
1180
1299
|
token;
|
|
1181
|
-
secret;
|
|
1182
1300
|
sessionId;
|
|
1183
1301
|
metadata;
|
|
1184
1302
|
metadataVersion;
|
|
@@ -1190,18 +1308,22 @@ class ApiSessionClient extends EventEmitter {
|
|
|
1190
1308
|
rpcHandlerManager;
|
|
1191
1309
|
agentStateLock = new AsyncLock();
|
|
1192
1310
|
metadataLock = new AsyncLock();
|
|
1193
|
-
|
|
1311
|
+
encryptionKey;
|
|
1312
|
+
encryptionVariant;
|
|
1313
|
+
constructor(token, session) {
|
|
1194
1314
|
super();
|
|
1195
1315
|
this.token = token;
|
|
1196
|
-
this.secret = secret;
|
|
1197
1316
|
this.sessionId = session.id;
|
|
1198
1317
|
this.metadata = session.metadata;
|
|
1199
1318
|
this.metadataVersion = session.metadataVersion;
|
|
1200
1319
|
this.agentState = session.agentState;
|
|
1201
1320
|
this.agentStateVersion = session.agentStateVersion;
|
|
1321
|
+
this.encryptionKey = session.encryptionKey;
|
|
1322
|
+
this.encryptionVariant = session.encryptionVariant;
|
|
1202
1323
|
this.rpcHandlerManager = new RpcHandlerManager({
|
|
1203
1324
|
scopePrefix: this.sessionId,
|
|
1204
|
-
|
|
1325
|
+
encryptionKey: this.encryptionKey,
|
|
1326
|
+
encryptionVariant: this.encryptionVariant,
|
|
1205
1327
|
logger: (msg, data) => logger.debug(msg, data)
|
|
1206
1328
|
});
|
|
1207
1329
|
registerCommonHandlers(this.rpcHandlerManager);
|
|
@@ -1243,7 +1365,7 @@ class ApiSessionClient extends EventEmitter {
|
|
|
1243
1365
|
return;
|
|
1244
1366
|
}
|
|
1245
1367
|
if (data.body.t === "new-message" && data.body.message.content.t === "encrypted") {
|
|
1246
|
-
const body = decrypt(decodeBase64(data.body.message.content.c)
|
|
1368
|
+
const body = decrypt(this.encryptionKey, this.encryptionVariant, decodeBase64(data.body.message.content.c));
|
|
1247
1369
|
logger.debugLargeJson("[SOCKET] [UPDATE] Received update:", body);
|
|
1248
1370
|
const userResult = UserMessageSchema.safeParse(body);
|
|
1249
1371
|
if (userResult.success) {
|
|
@@ -1257,11 +1379,11 @@ class ApiSessionClient extends EventEmitter {
|
|
|
1257
1379
|
}
|
|
1258
1380
|
} else if (data.body.t === "update-session") {
|
|
1259
1381
|
if (data.body.metadata && data.body.metadata.version > this.metadataVersion) {
|
|
1260
|
-
this.metadata = decrypt(decodeBase64(data.body.metadata.value)
|
|
1382
|
+
this.metadata = decrypt(this.encryptionKey, this.encryptionVariant, decodeBase64(data.body.metadata.value));
|
|
1261
1383
|
this.metadataVersion = data.body.metadata.version;
|
|
1262
1384
|
}
|
|
1263
1385
|
if (data.body.agentState && data.body.agentState.version > this.agentStateVersion) {
|
|
1264
|
-
this.agentState = data.body.agentState.value ? decrypt(decodeBase64(data.body.agentState.value)
|
|
1386
|
+
this.agentState = data.body.agentState.value ? decrypt(this.encryptionKey, this.encryptionVariant, decodeBase64(data.body.agentState.value)) : null;
|
|
1265
1387
|
this.agentStateVersion = data.body.agentState.version;
|
|
1266
1388
|
}
|
|
1267
1389
|
} else if (data.body.t === "update-machine") {
|
|
@@ -1315,7 +1437,7 @@ class ApiSessionClient extends EventEmitter {
|
|
|
1315
1437
|
};
|
|
1316
1438
|
}
|
|
1317
1439
|
logger.debugLargeJson("[SOCKET] Sending message through socket:", content);
|
|
1318
|
-
const encrypted = encodeBase64(encrypt(
|
|
1440
|
+
const encrypted = encodeBase64(encrypt(this.encryptionKey, this.encryptionVariant, content));
|
|
1319
1441
|
this.socket.emit("message", {
|
|
1320
1442
|
sid: this.sessionId,
|
|
1321
1443
|
message: encrypted
|
|
@@ -1337,6 +1459,24 @@ class ApiSessionClient extends EventEmitter {
|
|
|
1337
1459
|
}));
|
|
1338
1460
|
}
|
|
1339
1461
|
}
|
|
1462
|
+
sendCodexMessage(body) {
|
|
1463
|
+
let content = {
|
|
1464
|
+
role: "agent",
|
|
1465
|
+
content: {
|
|
1466
|
+
type: "codex",
|
|
1467
|
+
data: body
|
|
1468
|
+
// This wraps the entire Claude message
|
|
1469
|
+
},
|
|
1470
|
+
meta: {
|
|
1471
|
+
sentFrom: "cli"
|
|
1472
|
+
}
|
|
1473
|
+
};
|
|
1474
|
+
const encrypted = encodeBase64(encrypt(this.encryptionKey, this.encryptionVariant, content));
|
|
1475
|
+
this.socket.emit("message", {
|
|
1476
|
+
sid: this.sessionId,
|
|
1477
|
+
message: encrypted
|
|
1478
|
+
});
|
|
1479
|
+
}
|
|
1340
1480
|
sendSessionEvent(event, id) {
|
|
1341
1481
|
let content = {
|
|
1342
1482
|
role: "agent",
|
|
@@ -1346,7 +1486,7 @@ class ApiSessionClient extends EventEmitter {
|
|
|
1346
1486
|
data: event
|
|
1347
1487
|
}
|
|
1348
1488
|
};
|
|
1349
|
-
const encrypted = encodeBase64(encrypt(
|
|
1489
|
+
const encrypted = encodeBase64(encrypt(this.encryptionKey, this.encryptionVariant, content));
|
|
1350
1490
|
this.socket.emit("message", {
|
|
1351
1491
|
sid: this.sessionId,
|
|
1352
1492
|
message: encrypted
|
|
@@ -1406,14 +1546,14 @@ class ApiSessionClient extends EventEmitter {
|
|
|
1406
1546
|
this.metadataLock.inLock(async () => {
|
|
1407
1547
|
await backoff(async () => {
|
|
1408
1548
|
let updated = handler(this.metadata);
|
|
1409
|
-
const answer = await this.socket.emitWithAck("update-metadata", { sid: this.sessionId, expectedVersion: this.metadataVersion, metadata: encodeBase64(encrypt(
|
|
1549
|
+
const answer = await this.socket.emitWithAck("update-metadata", { sid: this.sessionId, expectedVersion: this.metadataVersion, metadata: encodeBase64(encrypt(this.encryptionKey, this.encryptionVariant, updated)) });
|
|
1410
1550
|
if (answer.result === "success") {
|
|
1411
|
-
this.metadata = decrypt(decodeBase64(answer.metadata)
|
|
1551
|
+
this.metadata = decrypt(this.encryptionKey, this.encryptionVariant, decodeBase64(answer.metadata));
|
|
1412
1552
|
this.metadataVersion = answer.version;
|
|
1413
1553
|
} else if (answer.result === "version-mismatch") {
|
|
1414
1554
|
if (answer.version > this.metadataVersion) {
|
|
1415
1555
|
this.metadataVersion = answer.version;
|
|
1416
|
-
this.metadata = decrypt(decodeBase64(answer.metadata)
|
|
1556
|
+
this.metadata = decrypt(this.encryptionKey, this.encryptionVariant, decodeBase64(answer.metadata));
|
|
1417
1557
|
}
|
|
1418
1558
|
throw new Error("Metadata version mismatch");
|
|
1419
1559
|
} else if (answer.result === "error") ;
|
|
@@ -1429,15 +1569,15 @@ class ApiSessionClient extends EventEmitter {
|
|
|
1429
1569
|
this.agentStateLock.inLock(async () => {
|
|
1430
1570
|
await backoff(async () => {
|
|
1431
1571
|
let updated = handler(this.agentState || {});
|
|
1432
|
-
const answer = await this.socket.emitWithAck("update-state", { sid: this.sessionId, expectedVersion: this.agentStateVersion, agentState: updated ? encodeBase64(encrypt(
|
|
1572
|
+
const answer = await this.socket.emitWithAck("update-state", { sid: this.sessionId, expectedVersion: this.agentStateVersion, agentState: updated ? encodeBase64(encrypt(this.encryptionKey, this.encryptionVariant, updated)) : null });
|
|
1433
1573
|
if (answer.result === "success") {
|
|
1434
|
-
this.agentState = answer.agentState ? decrypt(decodeBase64(answer.agentState)
|
|
1574
|
+
this.agentState = answer.agentState ? decrypt(this.encryptionKey, this.encryptionVariant, decodeBase64(answer.agentState)) : null;
|
|
1435
1575
|
this.agentStateVersion = answer.version;
|
|
1436
1576
|
logger.debug("Agent state updated", this.agentState);
|
|
1437
1577
|
} else if (answer.result === "version-mismatch") {
|
|
1438
1578
|
if (answer.version > this.agentStateVersion) {
|
|
1439
1579
|
this.agentStateVersion = answer.version;
|
|
1440
|
-
this.agentState = answer.agentState ? decrypt(decodeBase64(answer.agentState)
|
|
1580
|
+
this.agentState = answer.agentState ? decrypt(this.encryptionKey, this.encryptionVariant, decodeBase64(answer.agentState)) : null;
|
|
1441
1581
|
}
|
|
1442
1582
|
throw new Error("Agent state version mismatch");
|
|
1443
1583
|
} else if (answer.result === "error") ;
|
|
@@ -1461,18 +1601,19 @@ class ApiSessionClient extends EventEmitter {
|
|
|
1461
1601
|
});
|
|
1462
1602
|
}
|
|
1463
1603
|
async close() {
|
|
1604
|
+
logger.debug("[API] socket.close() called");
|
|
1464
1605
|
this.socket.close();
|
|
1465
1606
|
}
|
|
1466
1607
|
}
|
|
1467
1608
|
|
|
1468
1609
|
class ApiMachineClient {
|
|
1469
|
-
constructor(token,
|
|
1610
|
+
constructor(token, machine) {
|
|
1470
1611
|
this.token = token;
|
|
1471
|
-
this.secret = secret;
|
|
1472
1612
|
this.machine = machine;
|
|
1473
1613
|
this.rpcHandlerManager = new RpcHandlerManager({
|
|
1474
1614
|
scopePrefix: this.machine.id,
|
|
1475
|
-
|
|
1615
|
+
encryptionKey: this.machine.encryptionKey,
|
|
1616
|
+
encryptionVariant: this.machine.encryptionVariant,
|
|
1476
1617
|
logger: (msg, data) => logger.debug(msg, data)
|
|
1477
1618
|
});
|
|
1478
1619
|
registerCommonHandlers(this.rpcHandlerManager);
|
|
@@ -1533,17 +1674,17 @@ class ApiMachineClient {
|
|
|
1533
1674
|
const updated = handler(this.machine.metadata);
|
|
1534
1675
|
const answer = await this.socket.emitWithAck("machine-update-metadata", {
|
|
1535
1676
|
machineId: this.machine.id,
|
|
1536
|
-
metadata: encodeBase64(encrypt(
|
|
1677
|
+
metadata: encodeBase64(encrypt(this.machine.encryptionKey, this.machine.encryptionVariant, updated)),
|
|
1537
1678
|
expectedVersion: this.machine.metadataVersion
|
|
1538
1679
|
});
|
|
1539
1680
|
if (answer.result === "success") {
|
|
1540
|
-
this.machine.metadata = decrypt(decodeBase64(answer.metadata)
|
|
1681
|
+
this.machine.metadata = decrypt(this.machine.encryptionKey, this.machine.encryptionVariant, decodeBase64(answer.metadata));
|
|
1541
1682
|
this.machine.metadataVersion = answer.version;
|
|
1542
1683
|
logger.debug("[API MACHINE] Metadata updated successfully");
|
|
1543
1684
|
} else if (answer.result === "version-mismatch") {
|
|
1544
1685
|
if (answer.version > this.machine.metadataVersion) {
|
|
1545
1686
|
this.machine.metadataVersion = answer.version;
|
|
1546
|
-
this.machine.metadata = decrypt(decodeBase64(answer.metadata)
|
|
1687
|
+
this.machine.metadata = decrypt(this.machine.encryptionKey, this.machine.encryptionVariant, decodeBase64(answer.metadata));
|
|
1547
1688
|
}
|
|
1548
1689
|
throw new Error("Metadata version mismatch");
|
|
1549
1690
|
}
|
|
@@ -1558,17 +1699,17 @@ class ApiMachineClient {
|
|
|
1558
1699
|
const updated = handler(this.machine.daemonState);
|
|
1559
1700
|
const answer = await this.socket.emitWithAck("machine-update-state", {
|
|
1560
1701
|
machineId: this.machine.id,
|
|
1561
|
-
daemonState: encodeBase64(encrypt(
|
|
1702
|
+
daemonState: encodeBase64(encrypt(this.machine.encryptionKey, this.machine.encryptionVariant, updated)),
|
|
1562
1703
|
expectedVersion: this.machine.daemonStateVersion
|
|
1563
1704
|
});
|
|
1564
1705
|
if (answer.result === "success") {
|
|
1565
|
-
this.machine.daemonState = decrypt(decodeBase64(answer.daemonState)
|
|
1706
|
+
this.machine.daemonState = decrypt(this.machine.encryptionKey, this.machine.encryptionVariant, decodeBase64(answer.daemonState));
|
|
1566
1707
|
this.machine.daemonStateVersion = answer.version;
|
|
1567
1708
|
logger.debug("[API MACHINE] Daemon state updated successfully");
|
|
1568
1709
|
} else if (answer.result === "version-mismatch") {
|
|
1569
1710
|
if (answer.version > this.machine.daemonStateVersion) {
|
|
1570
1711
|
this.machine.daemonStateVersion = answer.version;
|
|
1571
|
-
this.machine.daemonState = decrypt(decodeBase64(answer.daemonState)
|
|
1712
|
+
this.machine.daemonState = decrypt(this.machine.encryptionKey, this.machine.encryptionVariant, decodeBase64(answer.daemonState));
|
|
1572
1713
|
}
|
|
1573
1714
|
throw new Error("Daemon state version mismatch");
|
|
1574
1715
|
}
|
|
@@ -1615,12 +1756,12 @@ class ApiMachineClient {
|
|
|
1615
1756
|
const update = data.body;
|
|
1616
1757
|
if (update.metadata) {
|
|
1617
1758
|
logger.debug("[API MACHINE] Received external metadata update");
|
|
1618
|
-
this.machine.metadata = decrypt(decodeBase64(update.metadata.value)
|
|
1759
|
+
this.machine.metadata = decrypt(this.machine.encryptionKey, this.machine.encryptionVariant, decodeBase64(update.metadata.value));
|
|
1619
1760
|
this.machine.metadataVersion = update.metadata.version;
|
|
1620
1761
|
}
|
|
1621
1762
|
if (update.daemonState) {
|
|
1622
1763
|
logger.debug("[API MACHINE] Received external daemon state update");
|
|
1623
|
-
this.machine.daemonState = decrypt(decodeBase64(update.daemonState.value)
|
|
1764
|
+
this.machine.daemonState = decrypt(this.machine.encryptionKey, this.machine.encryptionVariant, decodeBase64(update.daemonState.value));
|
|
1624
1765
|
this.machine.daemonStateVersion = update.daemonState.version;
|
|
1625
1766
|
}
|
|
1626
1767
|
} else {
|
|
@@ -1792,46 +1933,62 @@ class PushNotificationClient {
|
|
|
1792
1933
|
}
|
|
1793
1934
|
|
|
1794
1935
|
class ApiClient {
|
|
1795
|
-
|
|
1796
|
-
|
|
1936
|
+
static async create(credential) {
|
|
1937
|
+
return new ApiClient(credential);
|
|
1938
|
+
}
|
|
1939
|
+
credential;
|
|
1797
1940
|
pushClient;
|
|
1798
|
-
constructor(
|
|
1799
|
-
this.
|
|
1800
|
-
this.
|
|
1801
|
-
this.pushClient = new PushNotificationClient(token);
|
|
1941
|
+
constructor(credential) {
|
|
1942
|
+
this.credential = credential;
|
|
1943
|
+
this.pushClient = new PushNotificationClient(credential.token, configuration.serverUrl);
|
|
1802
1944
|
}
|
|
1803
1945
|
/**
|
|
1804
1946
|
* Create a new session or load existing one with the given tag
|
|
1805
1947
|
*/
|
|
1806
1948
|
async getOrCreateSession(opts) {
|
|
1949
|
+
let dataEncryptionKey = null;
|
|
1950
|
+
let encryptionKey;
|
|
1951
|
+
let encryptionVariant;
|
|
1952
|
+
if (this.credential.encryption.type === "dataKey") {
|
|
1953
|
+
encryptionKey = getRandomBytes(32);
|
|
1954
|
+
encryptionVariant = "dataKey";
|
|
1955
|
+
let encryptedDataKey = libsodiumEncryptForPublicKey(encryptionKey, this.credential.encryption.publicKey);
|
|
1956
|
+
dataEncryptionKey = new Uint8Array(encryptedDataKey.length + 1);
|
|
1957
|
+
dataEncryptionKey.set([0], 0);
|
|
1958
|
+
dataEncryptionKey.set(encryptedDataKey, 1);
|
|
1959
|
+
} else {
|
|
1960
|
+
encryptionKey = this.credential.encryption.secret;
|
|
1961
|
+
encryptionVariant = "legacy";
|
|
1962
|
+
}
|
|
1807
1963
|
try {
|
|
1808
1964
|
const response = await axios.post(
|
|
1809
1965
|
`${configuration.serverUrl}/v1/sessions`,
|
|
1810
1966
|
{
|
|
1811
1967
|
tag: opts.tag,
|
|
1812
|
-
metadata: encodeBase64(encrypt(opts.metadata
|
|
1813
|
-
agentState: opts.state ? encodeBase64(encrypt(opts.state
|
|
1968
|
+
metadata: encodeBase64(encrypt(encryptionKey, encryptionVariant, opts.metadata)),
|
|
1969
|
+
agentState: opts.state ? encodeBase64(encrypt(encryptionKey, encryptionVariant, opts.state)) : null,
|
|
1970
|
+
dataEncryptionKey: dataEncryptionKey ? encodeBase64(dataEncryptionKey) : null
|
|
1814
1971
|
},
|
|
1815
1972
|
{
|
|
1816
1973
|
headers: {
|
|
1817
|
-
"Authorization": `Bearer ${this.token}`,
|
|
1974
|
+
"Authorization": `Bearer ${this.credential.token}`,
|
|
1818
1975
|
"Content-Type": "application/json"
|
|
1819
1976
|
},
|
|
1820
|
-
timeout:
|
|
1821
|
-
//
|
|
1977
|
+
timeout: 6e4
|
|
1978
|
+
// 1 minute timeout for very bad network connections
|
|
1822
1979
|
}
|
|
1823
1980
|
);
|
|
1824
1981
|
logger.debug(`Session created/loaded: ${response.data.session.id} (tag: ${opts.tag})`);
|
|
1825
1982
|
let raw = response.data.session;
|
|
1826
1983
|
let session = {
|
|
1827
1984
|
id: raw.id,
|
|
1828
|
-
createdAt: raw.createdAt,
|
|
1829
|
-
updatedAt: raw.updatedAt,
|
|
1830
1985
|
seq: raw.seq,
|
|
1831
|
-
metadata: decrypt(decodeBase64(raw.metadata)
|
|
1986
|
+
metadata: decrypt(encryptionKey, encryptionVariant, decodeBase64(raw.metadata)),
|
|
1832
1987
|
metadataVersion: raw.metadataVersion,
|
|
1833
|
-
agentState: raw.agentState ? decrypt(decodeBase64(raw.agentState)
|
|
1834
|
-
agentStateVersion: raw.agentStateVersion
|
|
1988
|
+
agentState: raw.agentState ? decrypt(encryptionKey, encryptionVariant, decodeBase64(raw.agentState)) : null,
|
|
1989
|
+
agentStateVersion: raw.agentStateVersion,
|
|
1990
|
+
encryptionKey,
|
|
1991
|
+
encryptionVariant
|
|
1835
1992
|
};
|
|
1836
1993
|
return session;
|
|
1837
1994
|
} catch (error) {
|
|
@@ -1839,54 +1996,40 @@ class ApiClient {
|
|
|
1839
1996
|
throw new Error(`Failed to get or create session: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1840
1997
|
}
|
|
1841
1998
|
}
|
|
1842
|
-
/**
|
|
1843
|
-
* Get machine by ID from the server
|
|
1844
|
-
* Returns the current machine state from the server with decrypted metadata and daemonState
|
|
1845
|
-
*/
|
|
1846
|
-
async getMachine(machineId) {
|
|
1847
|
-
const response = await axios.get(`${configuration.serverUrl}/v1/machines/${machineId}`, {
|
|
1848
|
-
headers: {
|
|
1849
|
-
"Authorization": `Bearer ${this.token}`,
|
|
1850
|
-
"Content-Type": "application/json"
|
|
1851
|
-
},
|
|
1852
|
-
timeout: 2e3
|
|
1853
|
-
});
|
|
1854
|
-
const raw = response.data.machine;
|
|
1855
|
-
if (!raw) {
|
|
1856
|
-
return null;
|
|
1857
|
-
}
|
|
1858
|
-
logger.debug(`[API] Machine ${machineId} fetched from server`);
|
|
1859
|
-
const machine = {
|
|
1860
|
-
id: raw.id,
|
|
1861
|
-
metadata: raw.metadata ? decrypt(decodeBase64(raw.metadata), this.secret) : null,
|
|
1862
|
-
metadataVersion: raw.metadataVersion || 0,
|
|
1863
|
-
daemonState: raw.daemonState ? decrypt(decodeBase64(raw.daemonState), this.secret) : null,
|
|
1864
|
-
daemonStateVersion: raw.daemonStateVersion || 0,
|
|
1865
|
-
active: raw.active,
|
|
1866
|
-
activeAt: raw.activeAt,
|
|
1867
|
-
createdAt: raw.createdAt,
|
|
1868
|
-
updatedAt: raw.updatedAt
|
|
1869
|
-
};
|
|
1870
|
-
return machine;
|
|
1871
|
-
}
|
|
1872
1999
|
/**
|
|
1873
2000
|
* Register or update machine with the server
|
|
1874
2001
|
* Returns the current machine state from the server with decrypted metadata and daemonState
|
|
1875
2002
|
*/
|
|
1876
2003
|
async getOrCreateMachine(opts) {
|
|
2004
|
+
let dataEncryptionKey = null;
|
|
2005
|
+
let encryptionKey;
|
|
2006
|
+
let encryptionVariant;
|
|
2007
|
+
if (this.credential.encryption.type === "dataKey") {
|
|
2008
|
+
encryptionVariant = "dataKey";
|
|
2009
|
+
encryptionKey = this.credential.encryption.machineKey;
|
|
2010
|
+
let encryptedDataKey = libsodiumEncryptForPublicKey(this.credential.encryption.machineKey, this.credential.encryption.publicKey);
|
|
2011
|
+
dataEncryptionKey = new Uint8Array(encryptedDataKey.length + 1);
|
|
2012
|
+
dataEncryptionKey.set([0], 0);
|
|
2013
|
+
dataEncryptionKey.set(encryptedDataKey, 1);
|
|
2014
|
+
} else {
|
|
2015
|
+
encryptionKey = this.credential.encryption.secret;
|
|
2016
|
+
encryptionVariant = "legacy";
|
|
2017
|
+
}
|
|
1877
2018
|
const response = await axios.post(
|
|
1878
2019
|
`${configuration.serverUrl}/v1/machines`,
|
|
1879
2020
|
{
|
|
1880
2021
|
id: opts.machineId,
|
|
1881
|
-
metadata: encodeBase64(encrypt(opts.metadata
|
|
1882
|
-
daemonState: opts.daemonState ? encodeBase64(encrypt(opts.daemonState
|
|
2022
|
+
metadata: encodeBase64(encrypt(encryptionKey, encryptionVariant, opts.metadata)),
|
|
2023
|
+
daemonState: opts.daemonState ? encodeBase64(encrypt(encryptionKey, encryptionVariant, opts.daemonState)) : void 0,
|
|
2024
|
+
dataEncryptionKey: dataEncryptionKey ? encodeBase64(dataEncryptionKey) : void 0
|
|
1883
2025
|
},
|
|
1884
2026
|
{
|
|
1885
2027
|
headers: {
|
|
1886
|
-
"Authorization": `Bearer ${this.token}`,
|
|
2028
|
+
"Authorization": `Bearer ${this.credential.token}`,
|
|
1887
2029
|
"Content-Type": "application/json"
|
|
1888
2030
|
},
|
|
1889
|
-
timeout:
|
|
2031
|
+
timeout: 6e4
|
|
2032
|
+
// 1 minute timeout for very bad network connections
|
|
1890
2033
|
}
|
|
1891
2034
|
);
|
|
1892
2035
|
if (response.status !== 200) {
|
|
@@ -1898,22 +2041,20 @@ class ApiClient {
|
|
|
1898
2041
|
logger.debug(`[API] Machine ${opts.machineId} registered/updated with server`);
|
|
1899
2042
|
const machine = {
|
|
1900
2043
|
id: raw.id,
|
|
1901
|
-
|
|
2044
|
+
encryptionKey,
|
|
2045
|
+
encryptionVariant,
|
|
2046
|
+
metadata: raw.metadata ? decrypt(encryptionKey, encryptionVariant, decodeBase64(raw.metadata)) : null,
|
|
1902
2047
|
metadataVersion: raw.metadataVersion || 0,
|
|
1903
|
-
daemonState: raw.daemonState ? decrypt(decodeBase64(raw.daemonState)
|
|
1904
|
-
daemonStateVersion: raw.daemonStateVersion || 0
|
|
1905
|
-
active: raw.active,
|
|
1906
|
-
activeAt: raw.activeAt,
|
|
1907
|
-
createdAt: raw.createdAt,
|
|
1908
|
-
updatedAt: raw.updatedAt
|
|
2048
|
+
daemonState: raw.daemonState ? decrypt(encryptionKey, encryptionVariant, decodeBase64(raw.daemonState)) : null,
|
|
2049
|
+
daemonStateVersion: raw.daemonStateVersion || 0
|
|
1909
2050
|
};
|
|
1910
2051
|
return machine;
|
|
1911
2052
|
}
|
|
1912
2053
|
sessionSyncClient(session) {
|
|
1913
|
-
return new ApiSessionClient(this.token,
|
|
2054
|
+
return new ApiSessionClient(this.credential.token, session);
|
|
1914
2055
|
}
|
|
1915
2056
|
machineSyncClient(machine) {
|
|
1916
|
-
return new ApiMachineClient(this.token,
|
|
2057
|
+
return new ApiMachineClient(this.credential.token, machine);
|
|
1917
2058
|
}
|
|
1918
2059
|
push() {
|
|
1919
2060
|
return this.pushClient;
|
|
@@ -1931,7 +2072,7 @@ class ApiClient {
|
|
|
1931
2072
|
},
|
|
1932
2073
|
{
|
|
1933
2074
|
headers: {
|
|
1934
|
-
"Authorization": `Bearer ${this.token}`,
|
|
2075
|
+
"Authorization": `Bearer ${this.credential.token}`,
|
|
1935
2076
|
"Content-Type": "application/json"
|
|
1936
2077
|
},
|
|
1937
2078
|
timeout: 5e3
|
|
@@ -1996,4 +2137,4 @@ const RawJSONLinesSchema = z$1.discriminatedUnion("type", [
|
|
|
1996
2137
|
}).passthrough()
|
|
1997
2138
|
]);
|
|
1998
2139
|
|
|
1999
|
-
export { ApiClient as A, RawJSONLinesSchema as R, ApiSessionClient as a,
|
|
2140
|
+
export { ApiClient as A, RawJSONLinesSchema as R, ApiSessionClient as a, packageJson as b, configuration as c, backoff as d, delay as e, AsyncLock as f, readDaemonState as g, clearDaemonState as h, readCredentials as i, encodeBase64 as j, encodeBase64Url as k, logger as l, decodeBase64 as m, writeCredentialsDataKey as n, acquireDaemonLock as o, projectPath as p, writeDaemonState as q, readSettings as r, releaseDaemonLock as s, clearCredentials as t, updateSettings as u, clearMachineId as v, writeCredentialsLegacy as w, getLatestDaemonLog as x };
|