happy-coder 0.10.0-2 → 0.10.0-3
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/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-DPVbp4Yx.mjs +6048 -0
- package/dist/index-tqOLc1Il.cjs +6056 -0
- package/dist/index.cjs +33 -6024
- package/dist/index.mjs +33 -6024
- package/dist/lib.cjs +2 -1
- package/dist/lib.d.cts +12 -2
- package/dist/lib.d.mts +12 -2
- package/dist/lib.mjs +2 -1
- package/dist/runCodex-BxLD6H6G.cjs +1155 -0
- package/dist/runCodex-C07HQlsW.mjs +1153 -0
- package/dist/{types-WP9wteZE.cjs → types-CsJGQvQ3.cjs} +142 -45
- package/dist/{types-xfXKJHdM.mjs → types-xds_c-JJ.mjs} +106 -9
- package/package.json +18 -5
- 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
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
var axios = require('axios');
|
|
4
4
|
var chalk = require('chalk');
|
|
5
|
-
var fs = require('fs');
|
|
6
|
-
var
|
|
5
|
+
var fs$1 = require('fs');
|
|
6
|
+
var fs = require('node:fs');
|
|
7
7
|
var os = require('node:os');
|
|
8
8
|
var node_path = require('node:path');
|
|
9
9
|
var promises = require('node:fs/promises');
|
|
@@ -14,10 +14,11 @@ var node_events = require('node:events');
|
|
|
14
14
|
var socket_ioClient = require('socket.io-client');
|
|
15
15
|
var child_process = require('child_process');
|
|
16
16
|
var util = require('util');
|
|
17
|
-
var fs$
|
|
17
|
+
var fs$2 = require('fs/promises');
|
|
18
18
|
var crypto = require('crypto');
|
|
19
19
|
var path = require('path');
|
|
20
20
|
var url = require('url');
|
|
21
|
+
var os$1 = require('os');
|
|
21
22
|
var expoServerSdk = require('expo-server-sdk');
|
|
22
23
|
|
|
23
24
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
@@ -41,8 +42,8 @@ function _interopNamespaceDefault(e) {
|
|
|
41
42
|
var z__namespace = /*#__PURE__*/_interopNamespaceDefault(z);
|
|
42
43
|
|
|
43
44
|
var name = "happy-coder";
|
|
44
|
-
var version = "0.10.0-
|
|
45
|
-
var description = "Claude Code
|
|
45
|
+
var version = "0.10.0-3";
|
|
46
|
+
var description = "Mobile and Web client for Claude Code and Codex";
|
|
46
47
|
var author = "Kirill Dubovitskiy";
|
|
47
48
|
var license = "MIT";
|
|
48
49
|
var type = "module";
|
|
@@ -50,7 +51,8 @@ var homepage = "https://github.com/slopus/happy-cli";
|
|
|
50
51
|
var bugs = "https://github.com/slopus/happy-cli/issues";
|
|
51
52
|
var repository = "slopus/happy-cli";
|
|
52
53
|
var bin = {
|
|
53
|
-
happy: "./bin/happy.mjs"
|
|
54
|
+
happy: "./bin/happy.mjs",
|
|
55
|
+
"happy-mcp": "./bin/happy-mcp.mjs"
|
|
54
56
|
};
|
|
55
57
|
var main = "./dist/index.cjs";
|
|
56
58
|
var module$1 = "./dist/index.mjs";
|
|
@@ -75,13 +77,23 @@ var exports$1 = {
|
|
|
75
77
|
types: "./dist/lib.d.mts",
|
|
76
78
|
"default": "./dist/lib.mjs"
|
|
77
79
|
}
|
|
80
|
+
},
|
|
81
|
+
"./codex/happyMcpStdioBridge": {
|
|
82
|
+
require: {
|
|
83
|
+
types: "./dist/codex/happyMcpStdioBridge.d.cts",
|
|
84
|
+
"default": "./dist/codex/happyMcpStdioBridge.cjs"
|
|
85
|
+
},
|
|
86
|
+
"import": {
|
|
87
|
+
types: "./dist/codex/happyMcpStdioBridge.d.mts",
|
|
88
|
+
"default": "./dist/codex/happyMcpStdioBridge.mjs"
|
|
89
|
+
}
|
|
78
90
|
}
|
|
79
91
|
};
|
|
80
92
|
var files = [
|
|
81
93
|
"dist",
|
|
82
94
|
"bin",
|
|
83
95
|
"scripts",
|
|
84
|
-
"
|
|
96
|
+
"tools",
|
|
85
97
|
"package.json"
|
|
86
98
|
];
|
|
87
99
|
var scripts = {
|
|
@@ -94,7 +106,8 @@ var scripts = {
|
|
|
94
106
|
"dev:local-server": "yarn build && tsx --env-file .env.dev-local-server src/index.ts",
|
|
95
107
|
"dev:integration-test-env": "yarn build && tsx --env-file .env.integration-test src/index.ts",
|
|
96
108
|
prepublishOnly: "yarn build && yarn test",
|
|
97
|
-
release: "release-it"
|
|
109
|
+
release: "release-it",
|
|
110
|
+
postinstall: "node scripts/unpack-tools.cjs"
|
|
98
111
|
};
|
|
99
112
|
var dependencies = {
|
|
100
113
|
"@anthropic-ai/claude-code": "^1.0.102",
|
|
@@ -120,6 +133,7 @@ var dependencies = {
|
|
|
120
133
|
"qrcode-terminal": "^0.12.0",
|
|
121
134
|
react: "^19.1.1",
|
|
122
135
|
"socket.io-client": "^4.8.1",
|
|
136
|
+
tar: "^7.4.3",
|
|
123
137
|
tweetnacl: "^1.0.3",
|
|
124
138
|
zod: "^3.23.8"
|
|
125
139
|
};
|
|
@@ -200,11 +214,11 @@ class Configuration {
|
|
|
200
214
|
this.daemonLockFile = node_path.join(this.happyHomeDir, "daemon.state.json.lock");
|
|
201
215
|
this.isExperimentalEnabled = ["true", "1", "yes"].includes(process.env.HAPPY_EXPERIMENTAL?.toLowerCase() || "");
|
|
202
216
|
this.currentCliVersion = packageJson.version;
|
|
203
|
-
if (!
|
|
204
|
-
|
|
217
|
+
if (!fs.existsSync(this.happyHomeDir)) {
|
|
218
|
+
fs.mkdirSync(this.happyHomeDir, { recursive: true });
|
|
205
219
|
}
|
|
206
|
-
if (!
|
|
207
|
-
|
|
220
|
+
if (!fs.existsSync(this.logsDir)) {
|
|
221
|
+
fs.mkdirSync(this.logsDir, { recursive: true });
|
|
208
222
|
}
|
|
209
223
|
}
|
|
210
224
|
}
|
|
@@ -251,7 +265,7 @@ const defaultSettings = {
|
|
|
251
265
|
onboardingCompleted: false
|
|
252
266
|
};
|
|
253
267
|
async function readSettings() {
|
|
254
|
-
if (!
|
|
268
|
+
if (!fs.existsSync(configuration.settingsFile)) {
|
|
255
269
|
return { ...defaultSettings };
|
|
256
270
|
}
|
|
257
271
|
try {
|
|
@@ -271,7 +285,7 @@ async function updateSettings(updater) {
|
|
|
271
285
|
let attempts = 0;
|
|
272
286
|
while (attempts < MAX_LOCK_ATTEMPTS) {
|
|
273
287
|
try {
|
|
274
|
-
fileHandle = await promises.open(lockFile,
|
|
288
|
+
fileHandle = await promises.open(lockFile, fs.constants.O_CREAT | fs.constants.O_EXCL | fs.constants.O_WRONLY);
|
|
275
289
|
break;
|
|
276
290
|
} catch (err) {
|
|
277
291
|
if (err.code === "EEXIST") {
|
|
@@ -296,7 +310,7 @@ async function updateSettings(updater) {
|
|
|
296
310
|
try {
|
|
297
311
|
const current = await readSettings() || { ...defaultSettings };
|
|
298
312
|
const updated = await updater(current);
|
|
299
|
-
if (!
|
|
313
|
+
if (!fs.existsSync(configuration.happyHomeDir)) {
|
|
300
314
|
await promises.mkdir(configuration.happyHomeDir, { recursive: true });
|
|
301
315
|
}
|
|
302
316
|
await promises.writeFile(tmpFile, JSON.stringify(updated, null, 2));
|
|
@@ -313,7 +327,7 @@ const credentialsSchema = z__namespace.object({
|
|
|
313
327
|
token: z__namespace.string()
|
|
314
328
|
});
|
|
315
329
|
async function readCredentials() {
|
|
316
|
-
if (!
|
|
330
|
+
if (!fs.existsSync(configuration.privateKeyFile)) {
|
|
317
331
|
return null;
|
|
318
332
|
}
|
|
319
333
|
try {
|
|
@@ -328,7 +342,7 @@ async function readCredentials() {
|
|
|
328
342
|
}
|
|
329
343
|
}
|
|
330
344
|
async function writeCredentials(credentials) {
|
|
331
|
-
if (!
|
|
345
|
+
if (!fs.existsSync(configuration.happyHomeDir)) {
|
|
332
346
|
await promises.mkdir(configuration.happyHomeDir, { recursive: true });
|
|
333
347
|
}
|
|
334
348
|
await promises.writeFile(configuration.privateKeyFile, JSON.stringify({
|
|
@@ -337,7 +351,7 @@ async function writeCredentials(credentials) {
|
|
|
337
351
|
}, null, 2));
|
|
338
352
|
}
|
|
339
353
|
async function clearCredentials() {
|
|
340
|
-
if (
|
|
354
|
+
if (fs.existsSync(configuration.privateKeyFile)) {
|
|
341
355
|
await promises.unlink(configuration.privateKeyFile);
|
|
342
356
|
}
|
|
343
357
|
}
|
|
@@ -349,7 +363,7 @@ async function clearMachineId() {
|
|
|
349
363
|
}
|
|
350
364
|
async function readDaemonState() {
|
|
351
365
|
try {
|
|
352
|
-
if (!
|
|
366
|
+
if (!fs.existsSync(configuration.daemonStateFile)) {
|
|
353
367
|
return null;
|
|
354
368
|
}
|
|
355
369
|
const content = await promises.readFile(configuration.daemonStateFile, "utf-8");
|
|
@@ -360,13 +374,13 @@ async function readDaemonState() {
|
|
|
360
374
|
}
|
|
361
375
|
}
|
|
362
376
|
function writeDaemonState(state) {
|
|
363
|
-
|
|
377
|
+
fs.writeFileSync(configuration.daemonStateFile, JSON.stringify(state, null, 2), "utf-8");
|
|
364
378
|
}
|
|
365
379
|
async function clearDaemonState() {
|
|
366
|
-
if (
|
|
380
|
+
if (fs.existsSync(configuration.daemonStateFile)) {
|
|
367
381
|
await promises.unlink(configuration.daemonStateFile);
|
|
368
382
|
}
|
|
369
|
-
if (
|
|
383
|
+
if (fs.existsSync(configuration.daemonLockFile)) {
|
|
370
384
|
try {
|
|
371
385
|
await promises.unlink(configuration.daemonLockFile);
|
|
372
386
|
} catch {
|
|
@@ -378,19 +392,19 @@ async function acquireDaemonLock(maxAttempts = 5, delayIncrementMs = 200) {
|
|
|
378
392
|
try {
|
|
379
393
|
const fileHandle = await promises.open(
|
|
380
394
|
configuration.daemonLockFile,
|
|
381
|
-
|
|
395
|
+
fs.constants.O_CREAT | fs.constants.O_EXCL | fs.constants.O_WRONLY
|
|
382
396
|
);
|
|
383
397
|
await fileHandle.writeFile(String(process.pid));
|
|
384
398
|
return fileHandle;
|
|
385
399
|
} catch (error) {
|
|
386
400
|
if (error.code === "EEXIST") {
|
|
387
401
|
try {
|
|
388
|
-
const lockPid =
|
|
402
|
+
const lockPid = fs.readFileSync(configuration.daemonLockFile, "utf-8").trim();
|
|
389
403
|
if (lockPid && !isNaN(Number(lockPid))) {
|
|
390
404
|
try {
|
|
391
405
|
process.kill(Number(lockPid), 0);
|
|
392
406
|
} catch {
|
|
393
|
-
|
|
407
|
+
fs.unlinkSync(configuration.daemonLockFile);
|
|
394
408
|
continue;
|
|
395
409
|
}
|
|
396
410
|
}
|
|
@@ -412,8 +426,8 @@ async function releaseDaemonLock(lockHandle) {
|
|
|
412
426
|
} catch {
|
|
413
427
|
}
|
|
414
428
|
try {
|
|
415
|
-
if (
|
|
416
|
-
|
|
429
|
+
if (fs.existsSync(configuration.daemonLockFile)) {
|
|
430
|
+
fs.unlinkSync(configuration.daemonLockFile);
|
|
417
431
|
}
|
|
418
432
|
} catch {
|
|
419
433
|
}
|
|
@@ -503,6 +517,13 @@ class Logger {
|
|
|
503
517
|
this.logToConsole("info", "[DEV]", message, ...args);
|
|
504
518
|
}
|
|
505
519
|
}
|
|
520
|
+
warn(message, ...args) {
|
|
521
|
+
this.logToConsole("warn", "", message, ...args);
|
|
522
|
+
this.debug(`[WARN] ${message}`, ...args);
|
|
523
|
+
}
|
|
524
|
+
getLogPath() {
|
|
525
|
+
return this.logFilePath;
|
|
526
|
+
}
|
|
506
527
|
logToConsole(level, prefix, message, ...args) {
|
|
507
528
|
switch (level) {
|
|
508
529
|
case "debug": {
|
|
@@ -561,7 +582,7 @@ class Logger {
|
|
|
561
582
|
});
|
|
562
583
|
}
|
|
563
584
|
try {
|
|
564
|
-
fs.appendFileSync(this.logFilePath, logLine);
|
|
585
|
+
fs$1.appendFileSync(this.logFilePath, logLine);
|
|
565
586
|
} catch (appendError) {
|
|
566
587
|
if (process.env.DEBUG) {
|
|
567
588
|
console.error("[DEV MODE ONLY THROWING] Failed to append to log file:", appendError);
|
|
@@ -574,12 +595,12 @@ let logger = new Logger();
|
|
|
574
595
|
async function listDaemonLogFiles(limit = 50) {
|
|
575
596
|
try {
|
|
576
597
|
const logsDir = configuration.logsDir;
|
|
577
|
-
if (!
|
|
598
|
+
if (!fs.existsSync(logsDir)) {
|
|
578
599
|
return [];
|
|
579
600
|
}
|
|
580
|
-
const logs =
|
|
601
|
+
const logs = fs.readdirSync(logsDir).filter((file) => file.endsWith("-daemon.log")).map((file) => {
|
|
581
602
|
const fullPath = node_path.join(logsDir, file);
|
|
582
|
-
const stats =
|
|
603
|
+
const stats = fs.statSync(fullPath);
|
|
583
604
|
return { file, path: fullPath, modified: stats.mtime };
|
|
584
605
|
}).sort((a, b) => b.modified.getTime() - a.modified.getTime());
|
|
585
606
|
try {
|
|
@@ -587,8 +608,8 @@ async function listDaemonLogFiles(limit = 50) {
|
|
|
587
608
|
if (!state) {
|
|
588
609
|
return logs;
|
|
589
610
|
}
|
|
590
|
-
if (state.daemonLogPath &&
|
|
591
|
-
const stats =
|
|
611
|
+
if (state.daemonLogPath && fs.existsSync(state.daemonLogPath)) {
|
|
612
|
+
const stats = fs.statSync(state.daemonLogPath);
|
|
592
613
|
const persisted = {
|
|
593
614
|
file: node_path.basename(state.daemonLogPath),
|
|
594
615
|
path: state.daemonLogPath,
|
|
@@ -694,7 +715,8 @@ z.z.object({
|
|
|
694
715
|
platform: z.z.string(),
|
|
695
716
|
happyCliVersion: z.z.string(),
|
|
696
717
|
homeDir: z.z.string(),
|
|
697
|
-
happyHomeDir: z.z.string()
|
|
718
|
+
happyHomeDir: z.z.string(),
|
|
719
|
+
happyLibDir: z.z.string()
|
|
698
720
|
});
|
|
699
721
|
z.z.object({
|
|
700
722
|
status: z.z.union([
|
|
@@ -952,13 +974,13 @@ class RpcHandlerManager {
|
|
|
952
974
|
}
|
|
953
975
|
}
|
|
954
976
|
|
|
955
|
-
const __dirname$1 = path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('types-
|
|
977
|
+
const __dirname$1 = path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('types-CsJGQvQ3.cjs', document.baseURI).href))));
|
|
956
978
|
function projectPath() {
|
|
957
979
|
const path$1 = path.resolve(__dirname$1, "..");
|
|
958
980
|
return path$1;
|
|
959
981
|
}
|
|
960
982
|
|
|
961
|
-
function run(args, options) {
|
|
983
|
+
function run$1(args, options) {
|
|
962
984
|
const RUNNER_PATH = path.resolve(path.join(projectPath(), "scripts", "ripgrep_launcher.cjs"));
|
|
963
985
|
return new Promise((resolve2, reject) => {
|
|
964
986
|
const child = child_process.spawn("node", [RUNNER_PATH, JSON.stringify(args)], {
|
|
@@ -986,6 +1008,44 @@ function run(args, options) {
|
|
|
986
1008
|
});
|
|
987
1009
|
}
|
|
988
1010
|
|
|
1011
|
+
function getBinaryPath() {
|
|
1012
|
+
const platformName = os$1.platform();
|
|
1013
|
+
const binaryName = platformName === "win32" ? "difft.exe" : "difft";
|
|
1014
|
+
return path.resolve(path.join(projectPath(), "tools", "unpacked", binaryName));
|
|
1015
|
+
}
|
|
1016
|
+
function run(args, options) {
|
|
1017
|
+
const binaryPath = getBinaryPath();
|
|
1018
|
+
return new Promise((resolve2, reject) => {
|
|
1019
|
+
const child = child_process.spawn(binaryPath, args, {
|
|
1020
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
1021
|
+
cwd: options?.cwd,
|
|
1022
|
+
env: {
|
|
1023
|
+
...process.env,
|
|
1024
|
+
// Force color output when needed
|
|
1025
|
+
FORCE_COLOR: "1"
|
|
1026
|
+
}
|
|
1027
|
+
});
|
|
1028
|
+
let stdout = "";
|
|
1029
|
+
let stderr = "";
|
|
1030
|
+
child.stdout.on("data", (data) => {
|
|
1031
|
+
stdout += data.toString();
|
|
1032
|
+
});
|
|
1033
|
+
child.stderr.on("data", (data) => {
|
|
1034
|
+
stderr += data.toString();
|
|
1035
|
+
});
|
|
1036
|
+
child.on("close", (code) => {
|
|
1037
|
+
resolve2({
|
|
1038
|
+
exitCode: code || 0,
|
|
1039
|
+
stdout,
|
|
1040
|
+
stderr
|
|
1041
|
+
});
|
|
1042
|
+
});
|
|
1043
|
+
child.on("error", (err) => {
|
|
1044
|
+
reject(err);
|
|
1045
|
+
});
|
|
1046
|
+
});
|
|
1047
|
+
}
|
|
1048
|
+
|
|
989
1049
|
const execAsync = util.promisify(child_process.exec);
|
|
990
1050
|
function registerCommonHandlers(rpcHandlerManager) {
|
|
991
1051
|
rpcHandlerManager.registerHandler("bash", async (data) => {
|
|
@@ -1026,7 +1086,7 @@ function registerCommonHandlers(rpcHandlerManager) {
|
|
|
1026
1086
|
rpcHandlerManager.registerHandler("readFile", async (data) => {
|
|
1027
1087
|
logger.debug("Read file request:", data.path);
|
|
1028
1088
|
try {
|
|
1029
|
-
const buffer = await fs$
|
|
1089
|
+
const buffer = await fs$2.readFile(data.path);
|
|
1030
1090
|
const content = buffer.toString("base64");
|
|
1031
1091
|
return { success: true, content };
|
|
1032
1092
|
} catch (error) {
|
|
@@ -1039,7 +1099,7 @@ function registerCommonHandlers(rpcHandlerManager) {
|
|
|
1039
1099
|
try {
|
|
1040
1100
|
if (data.expectedHash !== null && data.expectedHash !== void 0) {
|
|
1041
1101
|
try {
|
|
1042
|
-
const existingBuffer = await fs$
|
|
1102
|
+
const existingBuffer = await fs$2.readFile(data.path);
|
|
1043
1103
|
const existingHash = crypto.createHash("sha256").update(existingBuffer).digest("hex");
|
|
1044
1104
|
if (existingHash !== data.expectedHash) {
|
|
1045
1105
|
return {
|
|
@@ -1059,7 +1119,7 @@ function registerCommonHandlers(rpcHandlerManager) {
|
|
|
1059
1119
|
}
|
|
1060
1120
|
} else {
|
|
1061
1121
|
try {
|
|
1062
|
-
await fs$
|
|
1122
|
+
await fs$2.stat(data.path);
|
|
1063
1123
|
return {
|
|
1064
1124
|
success: false,
|
|
1065
1125
|
error: "File already exists but was expected to be new"
|
|
@@ -1072,7 +1132,7 @@ function registerCommonHandlers(rpcHandlerManager) {
|
|
|
1072
1132
|
}
|
|
1073
1133
|
}
|
|
1074
1134
|
const buffer = Buffer.from(data.content, "base64");
|
|
1075
|
-
await fs$
|
|
1135
|
+
await fs$2.writeFile(data.path, buffer);
|
|
1076
1136
|
const hash = crypto.createHash("sha256").update(buffer).digest("hex");
|
|
1077
1137
|
return { success: true, hash };
|
|
1078
1138
|
} catch (error) {
|
|
@@ -1083,7 +1143,7 @@ function registerCommonHandlers(rpcHandlerManager) {
|
|
|
1083
1143
|
rpcHandlerManager.registerHandler("listDirectory", async (data) => {
|
|
1084
1144
|
logger.debug("List directory request:", data.path);
|
|
1085
1145
|
try {
|
|
1086
|
-
const entries = await fs$
|
|
1146
|
+
const entries = await fs$2.readdir(data.path, { withFileTypes: true });
|
|
1087
1147
|
const directoryEntries = await Promise.all(
|
|
1088
1148
|
entries.map(async (entry) => {
|
|
1089
1149
|
const fullPath = path.join(data.path, entry.name);
|
|
@@ -1096,7 +1156,7 @@ function registerCommonHandlers(rpcHandlerManager) {
|
|
|
1096
1156
|
type = "file";
|
|
1097
1157
|
}
|
|
1098
1158
|
try {
|
|
1099
|
-
const stats = await fs$
|
|
1159
|
+
const stats = await fs$2.stat(fullPath);
|
|
1100
1160
|
size = stats.size;
|
|
1101
1161
|
modified = stats.mtime.getTime();
|
|
1102
1162
|
} catch (error) {
|
|
@@ -1125,7 +1185,7 @@ function registerCommonHandlers(rpcHandlerManager) {
|
|
|
1125
1185
|
logger.debug("Get directory tree request:", data.path, "maxDepth:", data.maxDepth);
|
|
1126
1186
|
async function buildTree(path$1, name, currentDepth) {
|
|
1127
1187
|
try {
|
|
1128
|
-
const stats = await fs$
|
|
1188
|
+
const stats = await fs$2.stat(path$1);
|
|
1129
1189
|
const node = {
|
|
1130
1190
|
name,
|
|
1131
1191
|
path: path$1,
|
|
@@ -1134,7 +1194,7 @@ function registerCommonHandlers(rpcHandlerManager) {
|
|
|
1134
1194
|
modified: stats.mtime.getTime()
|
|
1135
1195
|
};
|
|
1136
1196
|
if (stats.isDirectory() && currentDepth < data.maxDepth) {
|
|
1137
|
-
const entries = await fs$
|
|
1197
|
+
const entries = await fs$2.readdir(path$1, { withFileTypes: true });
|
|
1138
1198
|
const children = [];
|
|
1139
1199
|
await Promise.all(
|
|
1140
1200
|
entries.map(async (entry) => {
|
|
@@ -1180,7 +1240,7 @@ function registerCommonHandlers(rpcHandlerManager) {
|
|
|
1180
1240
|
rpcHandlerManager.registerHandler("ripgrep", async (data) => {
|
|
1181
1241
|
logger.debug("Ripgrep request with args:", data.args, "cwd:", data.cwd);
|
|
1182
1242
|
try {
|
|
1183
|
-
const result = await run(data.args, { cwd: data.cwd });
|
|
1243
|
+
const result = await run$1(data.args, { cwd: data.cwd });
|
|
1184
1244
|
return {
|
|
1185
1245
|
success: true,
|
|
1186
1246
|
exitCode: result.exitCode,
|
|
@@ -1195,6 +1255,24 @@ function registerCommonHandlers(rpcHandlerManager) {
|
|
|
1195
1255
|
};
|
|
1196
1256
|
}
|
|
1197
1257
|
});
|
|
1258
|
+
rpcHandlerManager.registerHandler("difftastic", async (data) => {
|
|
1259
|
+
logger.debug("Difftastic request with args:", data.args, "cwd:", data.cwd);
|
|
1260
|
+
try {
|
|
1261
|
+
const result = await run(data.args, { cwd: data.cwd });
|
|
1262
|
+
return {
|
|
1263
|
+
success: true,
|
|
1264
|
+
exitCode: result.exitCode,
|
|
1265
|
+
stdout: result.stdout.toString(),
|
|
1266
|
+
stderr: result.stderr.toString()
|
|
1267
|
+
};
|
|
1268
|
+
} catch (error) {
|
|
1269
|
+
logger.debug("Failed to run difftastic:", error);
|
|
1270
|
+
return {
|
|
1271
|
+
success: false,
|
|
1272
|
+
error: error instanceof Error ? error.message : "Failed to run difftastic"
|
|
1273
|
+
};
|
|
1274
|
+
}
|
|
1275
|
+
});
|
|
1198
1276
|
}
|
|
1199
1277
|
|
|
1200
1278
|
class ApiSessionClient extends node_events.EventEmitter {
|
|
@@ -1358,6 +1436,24 @@ class ApiSessionClient extends node_events.EventEmitter {
|
|
|
1358
1436
|
}));
|
|
1359
1437
|
}
|
|
1360
1438
|
}
|
|
1439
|
+
sendCodexMessage(body) {
|
|
1440
|
+
let content = {
|
|
1441
|
+
role: "agent",
|
|
1442
|
+
content: {
|
|
1443
|
+
type: "codex",
|
|
1444
|
+
data: body
|
|
1445
|
+
// This wraps the entire Claude message
|
|
1446
|
+
},
|
|
1447
|
+
meta: {
|
|
1448
|
+
sentFrom: "cli"
|
|
1449
|
+
}
|
|
1450
|
+
};
|
|
1451
|
+
const encrypted = encodeBase64(encrypt(content, this.secret));
|
|
1452
|
+
this.socket.emit("message", {
|
|
1453
|
+
sid: this.sessionId,
|
|
1454
|
+
message: encrypted
|
|
1455
|
+
});
|
|
1456
|
+
}
|
|
1361
1457
|
sendSessionEvent(event, id) {
|
|
1362
1458
|
let content = {
|
|
1363
1459
|
role: "agent",
|
|
@@ -1482,6 +1578,7 @@ class ApiSessionClient extends node_events.EventEmitter {
|
|
|
1482
1578
|
});
|
|
1483
1579
|
}
|
|
1484
1580
|
async close() {
|
|
1581
|
+
logger.debug("[API] socket.close() called");
|
|
1485
1582
|
this.socket.close();
|
|
1486
1583
|
}
|
|
1487
1584
|
}
|
|
@@ -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-3";
|
|
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 = {
|
|
@@ -73,7 +85,8 @@ var scripts = {
|
|
|
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",
|
|
@@ -99,6 +112,7 @@ var dependencies = {
|
|
|
99
112
|
"qrcode-terminal": "^0.12.0",
|
|
100
113
|
react: "^19.1.1",
|
|
101
114
|
"socket.io-client": "^4.8.1",
|
|
115
|
+
tar: "^7.4.3",
|
|
102
116
|
tweetnacl: "^1.0.3",
|
|
103
117
|
zod: "^3.23.8"
|
|
104
118
|
};
|
|
@@ -482,6 +496,13 @@ class Logger {
|
|
|
482
496
|
this.logToConsole("info", "[DEV]", message, ...args);
|
|
483
497
|
}
|
|
484
498
|
}
|
|
499
|
+
warn(message, ...args) {
|
|
500
|
+
this.logToConsole("warn", "", message, ...args);
|
|
501
|
+
this.debug(`[WARN] ${message}`, ...args);
|
|
502
|
+
}
|
|
503
|
+
getLogPath() {
|
|
504
|
+
return this.logFilePath;
|
|
505
|
+
}
|
|
485
506
|
logToConsole(level, prefix, message, ...args) {
|
|
486
507
|
switch (level) {
|
|
487
508
|
case "debug": {
|
|
@@ -673,7 +694,8 @@ z$1.object({
|
|
|
673
694
|
platform: z$1.string(),
|
|
674
695
|
happyCliVersion: z$1.string(),
|
|
675
696
|
homeDir: z$1.string(),
|
|
676
|
-
happyHomeDir: z$1.string()
|
|
697
|
+
happyHomeDir: z$1.string(),
|
|
698
|
+
happyLibDir: z$1.string()
|
|
677
699
|
});
|
|
678
700
|
z$1.object({
|
|
679
701
|
status: z$1.union([
|
|
@@ -937,7 +959,7 @@ function projectPath() {
|
|
|
937
959
|
return path;
|
|
938
960
|
}
|
|
939
961
|
|
|
940
|
-
function run(args, options) {
|
|
962
|
+
function run$1(args, options) {
|
|
941
963
|
const RUNNER_PATH = resolve(join$1(projectPath(), "scripts", "ripgrep_launcher.cjs"));
|
|
942
964
|
return new Promise((resolve2, reject) => {
|
|
943
965
|
const child = spawn("node", [RUNNER_PATH, JSON.stringify(args)], {
|
|
@@ -965,6 +987,44 @@ function run(args, options) {
|
|
|
965
987
|
});
|
|
966
988
|
}
|
|
967
989
|
|
|
990
|
+
function getBinaryPath() {
|
|
991
|
+
const platformName = platform();
|
|
992
|
+
const binaryName = platformName === "win32" ? "difft.exe" : "difft";
|
|
993
|
+
return resolve(join$1(projectPath(), "tools", "unpacked", binaryName));
|
|
994
|
+
}
|
|
995
|
+
function run(args, options) {
|
|
996
|
+
const binaryPath = getBinaryPath();
|
|
997
|
+
return new Promise((resolve2, reject) => {
|
|
998
|
+
const child = spawn(binaryPath, args, {
|
|
999
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
1000
|
+
cwd: options?.cwd,
|
|
1001
|
+
env: {
|
|
1002
|
+
...process.env,
|
|
1003
|
+
// Force color output when needed
|
|
1004
|
+
FORCE_COLOR: "1"
|
|
1005
|
+
}
|
|
1006
|
+
});
|
|
1007
|
+
let stdout = "";
|
|
1008
|
+
let stderr = "";
|
|
1009
|
+
child.stdout.on("data", (data) => {
|
|
1010
|
+
stdout += data.toString();
|
|
1011
|
+
});
|
|
1012
|
+
child.stderr.on("data", (data) => {
|
|
1013
|
+
stderr += data.toString();
|
|
1014
|
+
});
|
|
1015
|
+
child.on("close", (code) => {
|
|
1016
|
+
resolve2({
|
|
1017
|
+
exitCode: code || 0,
|
|
1018
|
+
stdout,
|
|
1019
|
+
stderr
|
|
1020
|
+
});
|
|
1021
|
+
});
|
|
1022
|
+
child.on("error", (err) => {
|
|
1023
|
+
reject(err);
|
|
1024
|
+
});
|
|
1025
|
+
});
|
|
1026
|
+
}
|
|
1027
|
+
|
|
968
1028
|
const execAsync = promisify(exec);
|
|
969
1029
|
function registerCommonHandlers(rpcHandlerManager) {
|
|
970
1030
|
rpcHandlerManager.registerHandler("bash", async (data) => {
|
|
@@ -1159,7 +1219,7 @@ function registerCommonHandlers(rpcHandlerManager) {
|
|
|
1159
1219
|
rpcHandlerManager.registerHandler("ripgrep", async (data) => {
|
|
1160
1220
|
logger.debug("Ripgrep request with args:", data.args, "cwd:", data.cwd);
|
|
1161
1221
|
try {
|
|
1162
|
-
const result = await run(data.args, { cwd: data.cwd });
|
|
1222
|
+
const result = await run$1(data.args, { cwd: data.cwd });
|
|
1163
1223
|
return {
|
|
1164
1224
|
success: true,
|
|
1165
1225
|
exitCode: result.exitCode,
|
|
@@ -1174,6 +1234,24 @@ function registerCommonHandlers(rpcHandlerManager) {
|
|
|
1174
1234
|
};
|
|
1175
1235
|
}
|
|
1176
1236
|
});
|
|
1237
|
+
rpcHandlerManager.registerHandler("difftastic", async (data) => {
|
|
1238
|
+
logger.debug("Difftastic request with args:", data.args, "cwd:", data.cwd);
|
|
1239
|
+
try {
|
|
1240
|
+
const result = await run(data.args, { cwd: data.cwd });
|
|
1241
|
+
return {
|
|
1242
|
+
success: true,
|
|
1243
|
+
exitCode: result.exitCode,
|
|
1244
|
+
stdout: result.stdout.toString(),
|
|
1245
|
+
stderr: result.stderr.toString()
|
|
1246
|
+
};
|
|
1247
|
+
} catch (error) {
|
|
1248
|
+
logger.debug("Failed to run difftastic:", error);
|
|
1249
|
+
return {
|
|
1250
|
+
success: false,
|
|
1251
|
+
error: error instanceof Error ? error.message : "Failed to run difftastic"
|
|
1252
|
+
};
|
|
1253
|
+
}
|
|
1254
|
+
});
|
|
1177
1255
|
}
|
|
1178
1256
|
|
|
1179
1257
|
class ApiSessionClient extends EventEmitter {
|
|
@@ -1337,6 +1415,24 @@ class ApiSessionClient extends EventEmitter {
|
|
|
1337
1415
|
}));
|
|
1338
1416
|
}
|
|
1339
1417
|
}
|
|
1418
|
+
sendCodexMessage(body) {
|
|
1419
|
+
let content = {
|
|
1420
|
+
role: "agent",
|
|
1421
|
+
content: {
|
|
1422
|
+
type: "codex",
|
|
1423
|
+
data: body
|
|
1424
|
+
// This wraps the entire Claude message
|
|
1425
|
+
},
|
|
1426
|
+
meta: {
|
|
1427
|
+
sentFrom: "cli"
|
|
1428
|
+
}
|
|
1429
|
+
};
|
|
1430
|
+
const encrypted = encodeBase64(encrypt(content, this.secret));
|
|
1431
|
+
this.socket.emit("message", {
|
|
1432
|
+
sid: this.sessionId,
|
|
1433
|
+
message: encrypted
|
|
1434
|
+
});
|
|
1435
|
+
}
|
|
1340
1436
|
sendSessionEvent(event, id) {
|
|
1341
1437
|
let content = {
|
|
1342
1438
|
role: "agent",
|
|
@@ -1461,6 +1557,7 @@ class ApiSessionClient extends EventEmitter {
|
|
|
1461
1557
|
});
|
|
1462
1558
|
}
|
|
1463
1559
|
async close() {
|
|
1560
|
+
logger.debug("[API] socket.close() called");
|
|
1464
1561
|
this.socket.close();
|
|
1465
1562
|
}
|
|
1466
1563
|
}
|
|
@@ -1996,4 +2093,4 @@ const RawJSONLinesSchema = z$1.discriminatedUnion("type", [
|
|
|
1996
2093
|
}).passthrough()
|
|
1997
2094
|
]);
|
|
1998
2095
|
|
|
1999
|
-
export { ApiClient as A, RawJSONLinesSchema as R, ApiSessionClient as a,
|
|
2096
|
+
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, acquireDaemonLock as n, writeDaemonState as o, projectPath as p, releaseDaemonLock as q, readSettings as r, clearCredentials as s, clearMachineId as t, updateSettings as u, getLatestDaemonLog as v, writeCredentials as w };
|