happy-coder 0.9.0 → 0.10.0-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +851 -275
- package/dist/index.mjs +854 -278
- package/dist/lib.cjs +1 -1
- package/dist/lib.d.cts +64 -15
- package/dist/lib.d.mts +64 -15
- package/dist/lib.mjs +1 -1
- package/dist/{types-Cezp_n6O.mjs → types-CGbH1LGX.mjs} +102 -32
- package/dist/{types-CyOnnZ8M.cjs → types-fU2E-jQl.cjs} +102 -32
- package/package.json +6 -2
|
@@ -34,7 +34,7 @@ function _interopNamespaceDefault(e) {
|
|
|
34
34
|
var z__namespace = /*#__PURE__*/_interopNamespaceDefault(z);
|
|
35
35
|
|
|
36
36
|
var name = "happy-coder";
|
|
37
|
-
var version = "0.
|
|
37
|
+
var version = "0.10.0-0";
|
|
38
38
|
var description = "Claude Code session sharing CLI";
|
|
39
39
|
var author = "Kirill Dubovitskiy";
|
|
40
40
|
var license = "MIT";
|
|
@@ -99,6 +99,7 @@ var dependencies = {
|
|
|
99
99
|
"@types/react": "^19.1.9",
|
|
100
100
|
axios: "^1.10.0",
|
|
101
101
|
chalk: "^5.4.1",
|
|
102
|
+
"cross-spawn": "^7.0.6",
|
|
102
103
|
"expo-server-sdk": "^3.15.0",
|
|
103
104
|
fastify: "^5.5.0",
|
|
104
105
|
"fastify-type-provider-zod": "4.0.2",
|
|
@@ -106,6 +107,7 @@ var dependencies = {
|
|
|
106
107
|
"http-proxy-middleware": "^3.0.5",
|
|
107
108
|
ink: "^6.1.0",
|
|
108
109
|
open: "^10.2.0",
|
|
110
|
+
"ps-list": "^8.1.1",
|
|
109
111
|
"qrcode-terminal": "^0.12.0",
|
|
110
112
|
react: "^19.1.1",
|
|
111
113
|
"socket.io-client": "^4.8.1",
|
|
@@ -114,7 +116,9 @@ var dependencies = {
|
|
|
114
116
|
};
|
|
115
117
|
var devDependencies = {
|
|
116
118
|
"@eslint/compat": "^1",
|
|
119
|
+
"@types/cross-spawn": "^6.0.6",
|
|
117
120
|
"@types/node": ">=20",
|
|
121
|
+
"@types/ps-list": "^6.2.1",
|
|
118
122
|
"cross-env": "^10.0.0",
|
|
119
123
|
dotenv: "^16.6.1",
|
|
120
124
|
eslint: "^9",
|
|
@@ -173,7 +177,7 @@ class Configuration {
|
|
|
173
177
|
currentCliVersion;
|
|
174
178
|
isExperimentalEnabled;
|
|
175
179
|
constructor() {
|
|
176
|
-
this.serverUrl = process.env.HAPPY_SERVER_URL || "https://
|
|
180
|
+
this.serverUrl = process.env.HAPPY_SERVER_URL || "https://api.cluster-fluster.com";
|
|
177
181
|
const args = process.argv.slice(2);
|
|
178
182
|
this.isDaemonProcess = args.length >= 2 && args[0] === "daemon" && args[1] === "start-sync";
|
|
179
183
|
if (process.env.HAPPY_HOME_DIR) {
|
|
@@ -553,7 +557,7 @@ class Logger {
|
|
|
553
557
|
fs.appendFileSync(this.logFilePath, logLine);
|
|
554
558
|
} catch (appendError) {
|
|
555
559
|
if (process.env.DEBUG) {
|
|
556
|
-
console.error("Failed to append to log file:", appendError);
|
|
560
|
+
console.error("[DEV MODE ONLY THROWING] Failed to append to log file:", appendError);
|
|
557
561
|
throw appendError;
|
|
558
562
|
}
|
|
559
563
|
}
|
|
@@ -660,7 +664,23 @@ z.z.object({
|
|
|
660
664
|
metadata: z.z.any(),
|
|
661
665
|
metadataVersion: z.z.number(),
|
|
662
666
|
agentState: z.z.any().nullable(),
|
|
663
|
-
agentStateVersion: z.z.number()
|
|
667
|
+
agentStateVersion: z.z.number(),
|
|
668
|
+
// Connectivity tracking (from server)
|
|
669
|
+
connectivityStatus: z.z.union([
|
|
670
|
+
z.z.enum(["neverConnected", "online", "offline"]),
|
|
671
|
+
z.z.string()
|
|
672
|
+
// Forward compatibility
|
|
673
|
+
]).optional(),
|
|
674
|
+
connectivityStatusSince: z.z.number().optional(),
|
|
675
|
+
connectivityStatusReason: z.z.string().optional(),
|
|
676
|
+
// State tracking (from server)
|
|
677
|
+
state: z.z.union([
|
|
678
|
+
z.z.enum(["running", "archiveRequested", "archived"]),
|
|
679
|
+
z.z.string()
|
|
680
|
+
// Forward compatibility
|
|
681
|
+
]).optional(),
|
|
682
|
+
stateSince: z.z.number().optional(),
|
|
683
|
+
stateReason: z.z.string().optional()
|
|
664
684
|
});
|
|
665
685
|
z.z.object({
|
|
666
686
|
host: z.z.string(),
|
|
@@ -698,7 +718,23 @@ z.z.object({
|
|
|
698
718
|
active: z.z.boolean(),
|
|
699
719
|
activeAt: z.z.number(),
|
|
700
720
|
createdAt: z.z.number(),
|
|
701
|
-
updatedAt: z.z.number()
|
|
721
|
+
updatedAt: z.z.number(),
|
|
722
|
+
// Connectivity tracking (from server)
|
|
723
|
+
connectivityStatus: z.z.union([
|
|
724
|
+
z.z.enum(["neverConnected", "online", "offline"]),
|
|
725
|
+
z.z.string()
|
|
726
|
+
// Forward compatibility
|
|
727
|
+
]).optional(),
|
|
728
|
+
connectivityStatusSince: z.z.number().optional(),
|
|
729
|
+
connectivityStatusReason: z.z.string().optional(),
|
|
730
|
+
// State tracking (from server)
|
|
731
|
+
state: z.z.union([
|
|
732
|
+
z.z.enum(["running", "archiveRequested", "archived"]),
|
|
733
|
+
z.z.string()
|
|
734
|
+
// Forward compatibility
|
|
735
|
+
]).optional(),
|
|
736
|
+
stateSince: z.z.number().optional(),
|
|
737
|
+
stateReason: z.z.string().optional()
|
|
702
738
|
});
|
|
703
739
|
z.z.object({
|
|
704
740
|
content: SessionMessageContentSchema,
|
|
@@ -1011,7 +1047,9 @@ class ApiSessionClient extends node_events.EventEmitter {
|
|
|
1011
1047
|
* Send a ping message to keep the connection alive
|
|
1012
1048
|
*/
|
|
1013
1049
|
keepAlive(thinking, mode) {
|
|
1014
|
-
|
|
1050
|
+
if (process.env.DEBUG) {
|
|
1051
|
+
logger.debug(`[API] Sending keep alive message: ${thinking}`);
|
|
1052
|
+
}
|
|
1015
1053
|
this.socket.volatile.emit("session-alive", {
|
|
1016
1054
|
sid: this.sessionId,
|
|
1017
1055
|
time: Date.now(),
|
|
@@ -1249,37 +1287,39 @@ class ApiMachineClient {
|
|
|
1249
1287
|
this.socket.on("rpc-request", async (data, callback) => {
|
|
1250
1288
|
logger.debugLargeJson(`[API MACHINE] Received RPC request:`, data);
|
|
1251
1289
|
try {
|
|
1252
|
-
|
|
1253
|
-
const stopMethod2 = `${this.machine.id}:stop-session`;
|
|
1254
|
-
const stopDaemonMethod2 = `${this.machine.id}:stop-daemon`;
|
|
1255
|
-
if (data.method === spawnMethod2) {
|
|
1290
|
+
if (data.method === spawnMethod) {
|
|
1256
1291
|
if (!this.spawnSession) {
|
|
1257
1292
|
throw new Error("Spawn session handler not set");
|
|
1258
1293
|
}
|
|
1259
|
-
const { directory, sessionId } = decrypt(decodeBase64(data.params), this.secret) || {};
|
|
1294
|
+
const { directory, sessionId, machineId, approvedNewDirectoryCreation } = decrypt(decodeBase64(data.params), this.secret) || {};
|
|
1260
1295
|
if (!directory) {
|
|
1261
1296
|
throw new Error("Directory is required");
|
|
1262
1297
|
}
|
|
1263
|
-
const
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1298
|
+
const result = await this.spawnSession({ directory, sessionId, machineId, approvedNewDirectoryCreation });
|
|
1299
|
+
switch (result.type) {
|
|
1300
|
+
case "success": {
|
|
1301
|
+
logger.debug(`[API MACHINE] Spawned session ${result.sessionId}`);
|
|
1302
|
+
const response = {
|
|
1303
|
+
type: "success",
|
|
1304
|
+
sessionId: result.sessionId
|
|
1305
|
+
};
|
|
1306
|
+
logger.debug(`[API MACHINE] Sending RPC response:`, response);
|
|
1307
|
+
callback(encodeBase64(encrypt(response, this.secret)));
|
|
1308
|
+
return;
|
|
1309
|
+
}
|
|
1310
|
+
case "requestToApproveDirectoryCreation":
|
|
1311
|
+
const promptResponse = {
|
|
1312
|
+
type: "requestToApproveDirectoryCreation",
|
|
1313
|
+
directory: result.directory
|
|
1314
|
+
};
|
|
1315
|
+
logger.debug(`[API MACHINE] Requesting directory creation approval for: ${result.directory}`);
|
|
1316
|
+
callback(encodeBase64(encrypt(promptResponse, this.secret)));
|
|
1317
|
+
return;
|
|
1318
|
+
case "error":
|
|
1319
|
+
throw new Error(result.errorMessage);
|
|
1273
1320
|
}
|
|
1274
|
-
const response = {
|
|
1275
|
-
sessionId: session.happySessionId,
|
|
1276
|
-
message: session.message
|
|
1277
|
-
};
|
|
1278
|
-
logger.debug(`[API MACHINE] Sending RPC response:`, response);
|
|
1279
|
-
callback(encodeBase64(encrypt(response, this.secret)));
|
|
1280
|
-
return;
|
|
1281
1321
|
}
|
|
1282
|
-
if (data.method ===
|
|
1322
|
+
if (data.method === stopMethod) {
|
|
1283
1323
|
logger.debug("[API MACHINE] Received stop-session RPC request");
|
|
1284
1324
|
const decryptedParams = decrypt(decodeBase64(data.params), this.secret);
|
|
1285
1325
|
const { sessionId } = decryptedParams || {};
|
|
@@ -1299,7 +1339,7 @@ class ApiMachineClient {
|
|
|
1299
1339
|
callback(encryptedResponse);
|
|
1300
1340
|
return;
|
|
1301
1341
|
}
|
|
1302
|
-
if (data.method ===
|
|
1342
|
+
if (data.method === stopDaemonMethod) {
|
|
1303
1343
|
logger.debug("[API MACHINE] Received stop-daemon RPC request");
|
|
1304
1344
|
callback(encodeBase64(encrypt({
|
|
1305
1345
|
message: "Daemon stop request acknowledged, starting shutdown sequence..."
|
|
@@ -1360,7 +1400,9 @@ class ApiMachineClient {
|
|
|
1360
1400
|
machineId: this.machine.id,
|
|
1361
1401
|
time: Date.now()
|
|
1362
1402
|
};
|
|
1363
|
-
|
|
1403
|
+
if (process.env.DEBUG) {
|
|
1404
|
+
logger.debugLargeJson(`[API MACHINE] Emitting machine-alive`, payload);
|
|
1405
|
+
}
|
|
1364
1406
|
this.socket.emit("machine-alive", payload);
|
|
1365
1407
|
}, 2e4);
|
|
1366
1408
|
logger.debug("[API MACHINE] Keep-alive started (20s interval)");
|
|
@@ -1386,7 +1428,7 @@ class PushNotificationClient {
|
|
|
1386
1428
|
token;
|
|
1387
1429
|
baseUrl;
|
|
1388
1430
|
expo;
|
|
1389
|
-
constructor(token, baseUrl = "https://
|
|
1431
|
+
constructor(token, baseUrl = "https://api.cluster-fluster.com") {
|
|
1390
1432
|
this.token = token;
|
|
1391
1433
|
this.baseUrl = baseUrl;
|
|
1392
1434
|
this.expo = new expoServerSdk.Expo();
|
|
@@ -1635,6 +1677,34 @@ class ApiClient {
|
|
|
1635
1677
|
push() {
|
|
1636
1678
|
return this.pushClient;
|
|
1637
1679
|
}
|
|
1680
|
+
/**
|
|
1681
|
+
* Register a vendor API token with the server
|
|
1682
|
+
* The token is sent as a JSON string - server handles encryption
|
|
1683
|
+
*/
|
|
1684
|
+
async registerVendorToken(vendor, apiKey) {
|
|
1685
|
+
try {
|
|
1686
|
+
const response = await axios.post(
|
|
1687
|
+
`${configuration.serverUrl}/v1/connect/${vendor}/register`,
|
|
1688
|
+
{
|
|
1689
|
+
token: JSON.stringify(apiKey)
|
|
1690
|
+
},
|
|
1691
|
+
{
|
|
1692
|
+
headers: {
|
|
1693
|
+
"Authorization": `Bearer ${this.token}`,
|
|
1694
|
+
"Content-Type": "application/json"
|
|
1695
|
+
},
|
|
1696
|
+
timeout: 5e3
|
|
1697
|
+
}
|
|
1698
|
+
);
|
|
1699
|
+
if (response.status !== 200 && response.status !== 201) {
|
|
1700
|
+
throw new Error(`Server returned status ${response.status}`);
|
|
1701
|
+
}
|
|
1702
|
+
logger.debug(`[API] Vendor token for ${vendor} registered successfully`);
|
|
1703
|
+
} catch (error) {
|
|
1704
|
+
logger.debug(`[API] [ERROR] Failed to register vendor token:`, error);
|
|
1705
|
+
throw new Error(`Failed to register vendor token: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1638
1708
|
}
|
|
1639
1709
|
|
|
1640
1710
|
const UsageSchema = z.z.object({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "happy-coder",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0-0",
|
|
4
4
|
"description": "Claude Code session sharing CLI",
|
|
5
5
|
"author": "Kirill Dubovitskiy",
|
|
6
6
|
"license": "MIT",
|
|
@@ -65,6 +65,7 @@
|
|
|
65
65
|
"@types/react": "^19.1.9",
|
|
66
66
|
"axios": "^1.10.0",
|
|
67
67
|
"chalk": "^5.4.1",
|
|
68
|
+
"cross-spawn": "^7.0.6",
|
|
68
69
|
"expo-server-sdk": "^3.15.0",
|
|
69
70
|
"fastify": "^5.5.0",
|
|
70
71
|
"fastify-type-provider-zod": "4.0.2",
|
|
@@ -72,6 +73,7 @@
|
|
|
72
73
|
"http-proxy-middleware": "^3.0.5",
|
|
73
74
|
"ink": "^6.1.0",
|
|
74
75
|
"open": "^10.2.0",
|
|
76
|
+
"ps-list": "^8.1.1",
|
|
75
77
|
"qrcode-terminal": "^0.12.0",
|
|
76
78
|
"react": "^19.1.1",
|
|
77
79
|
"socket.io-client": "^4.8.1",
|
|
@@ -80,7 +82,9 @@
|
|
|
80
82
|
},
|
|
81
83
|
"devDependencies": {
|
|
82
84
|
"@eslint/compat": "^1",
|
|
85
|
+
"@types/cross-spawn": "^6.0.6",
|
|
83
86
|
"@types/node": ">=20",
|
|
87
|
+
"@types/ps-list": "^6.2.1",
|
|
84
88
|
"cross-env": "^10.0.0",
|
|
85
89
|
"dotenv": "^16.6.1",
|
|
86
90
|
"eslint": "^9",
|
|
@@ -102,4 +106,4 @@
|
|
|
102
106
|
"registry": "https://registry.npmjs.org"
|
|
103
107
|
},
|
|
104
108
|
"packageManager": "yarn@1.22.22"
|
|
105
|
-
}
|
|
109
|
+
}
|