happy-coder 0.3.1-beta.2 → 0.5.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 +240 -31
- package/dist/index.mjs +240 -31
- package/dist/lib.cjs +1 -1
- package/dist/lib.d.cts +31 -0
- package/dist/lib.d.mts +31 -0
- package/dist/lib.mjs +1 -1
- package/dist/{types-DXK5YldG.cjs → types-BBpJNhIN.cjs} +15 -1
- package/dist/{types-BX4xv8Ty.mjs → types-DDjn6Ovv.mjs} +15 -2
- package/package.json +5 -5
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chalk = require('chalk');
|
|
4
|
-
var types$1 = require('./types-
|
|
4
|
+
var types$1 = require('./types-BBpJNhIN.cjs');
|
|
5
5
|
var node_crypto = require('node:crypto');
|
|
6
6
|
var node_child_process = require('node:child_process');
|
|
7
7
|
var node_path = require('node:path');
|
|
@@ -480,6 +480,7 @@ function messageKey(message) {
|
|
|
480
480
|
}
|
|
481
481
|
async function readSessionLog(projectDir, sessionId) {
|
|
482
482
|
const expectedSessionFile = node_path.join(projectDir, `${sessionId}.jsonl`);
|
|
483
|
+
types$1.logger.debug(`[SESSION_SCANNER] Reading session file: ${expectedSessionFile}`);
|
|
483
484
|
let file;
|
|
484
485
|
try {
|
|
485
486
|
file = await promises$1.readFile(expectedSessionFile, "utf-8");
|
|
@@ -1252,6 +1253,12 @@ async function claudeRemote(opts) {
|
|
|
1252
1253
|
mcpServers: opts.mcpServers,
|
|
1253
1254
|
permissionPromptToolName: opts.permissionPromptToolName,
|
|
1254
1255
|
permissionMode: opts.permissionMode,
|
|
1256
|
+
model: opts.model,
|
|
1257
|
+
fallbackModel: opts.fallbackModel,
|
|
1258
|
+
customSystemPrompt: opts.customSystemPrompt,
|
|
1259
|
+
appendSystemPrompt: opts.appendSystemPrompt,
|
|
1260
|
+
allowedTools: opts.allowedTools,
|
|
1261
|
+
disallowedTools: opts.disallowedTools,
|
|
1255
1262
|
executable: "node",
|
|
1256
1263
|
abort: opts.signal,
|
|
1257
1264
|
pathToClaudeCodeExecutable: (() => {
|
|
@@ -1261,7 +1268,7 @@ async function claudeRemote(opts) {
|
|
|
1261
1268
|
if (opts.claudeArgs && opts.claudeArgs.length > 0) {
|
|
1262
1269
|
sdkOptions.executableArgs = [...sdkOptions.executableArgs || [], ...opts.claudeArgs];
|
|
1263
1270
|
}
|
|
1264
|
-
types$1.logger.debug(`[claudeRemote] Starting query with permission mode: ${opts.permissionMode}`);
|
|
1271
|
+
types$1.logger.debug(`[claudeRemote] Starting query with permission mode: ${opts.permissionMode}, model: ${opts.model || "default"}, fallbackModel: ${opts.fallbackModel || "none"}, customSystemPrompt: ${opts.customSystemPrompt ? "set" : "none"}, appendSystemPrompt: ${opts.appendSystemPrompt ? "set" : "none"}, allowedTools: ${opts.allowedTools ? opts.allowedTools.join(",") : "none"}, disallowedTools: ${opts.disallowedTools ? opts.disallowedTools.join(",") : "none"}`);
|
|
1265
1272
|
let message = new PushableAsyncIterable();
|
|
1266
1273
|
message.push({
|
|
1267
1274
|
type: "user",
|
|
@@ -1441,9 +1448,9 @@ async function startPermissionResolver(session) {
|
|
|
1441
1448
|
if (response.approved) {
|
|
1442
1449
|
types$1.logger.debug("Plan approved - injecting PLAN_FAKE_RESTART");
|
|
1443
1450
|
if (response.mode && ["default", "acceptEdits", "bypassPermissions"].includes(response.mode)) {
|
|
1444
|
-
session.queue.unshift(PLAN_FAKE_RESTART, response.mode);
|
|
1451
|
+
session.queue.unshift(PLAN_FAKE_RESTART, { permissionMode: response.mode });
|
|
1445
1452
|
} else {
|
|
1446
|
-
session.queue.unshift(PLAN_FAKE_RESTART, "default");
|
|
1453
|
+
session.queue.unshift(PLAN_FAKE_RESTART, { permissionMode: "default" });
|
|
1447
1454
|
}
|
|
1448
1455
|
resolve({ approved: false, reason: PLAN_FAKE_REJECT });
|
|
1449
1456
|
} else {
|
|
@@ -2152,7 +2159,13 @@ async function claudeRemoteLauncher(session) {
|
|
|
2152
2159
|
}
|
|
2153
2160
|
},
|
|
2154
2161
|
permissionPromptToolName: "mcp__permission__" + permissions.server.toolName,
|
|
2155
|
-
permissionMode: messageData.mode,
|
|
2162
|
+
permissionMode: messageData.mode.permissionMode,
|
|
2163
|
+
model: messageData.mode.model,
|
|
2164
|
+
fallbackModel: messageData.mode.fallbackModel,
|
|
2165
|
+
customSystemPrompt: messageData.mode.customSystemPrompt,
|
|
2166
|
+
appendSystemPrompt: messageData.mode.appendSystemPrompt,
|
|
2167
|
+
allowedTools: messageData.mode.allowedTools,
|
|
2168
|
+
disallowedTools: messageData.mode.disallowedTools,
|
|
2156
2169
|
onSessionFound: (sessionId) => {
|
|
2157
2170
|
sdkToLogConverter.updateSessionId(sessionId);
|
|
2158
2171
|
session.onSessionFound(sessionId);
|
|
@@ -2248,7 +2261,7 @@ async function loop(opts) {
|
|
|
2248
2261
|
}
|
|
2249
2262
|
|
|
2250
2263
|
var name = "happy-coder";
|
|
2251
|
-
var version = "0.
|
|
2264
|
+
var version = "0.5.0";
|
|
2252
2265
|
var description = "Claude Code session sharing CLI";
|
|
2253
2266
|
var author = "Kirill Dubovitskiy";
|
|
2254
2267
|
var license = "MIT";
|
|
@@ -2297,13 +2310,13 @@ var scripts = {
|
|
|
2297
2310
|
build: "shx rm -rf dist && tsc --noEmit && pkgroll",
|
|
2298
2311
|
prepublishOnly: "yarn build && yarn test",
|
|
2299
2312
|
typecheck: "tsc --noEmit",
|
|
2300
|
-
dev: "npx tsx --env-file .env.sample src/index.ts",
|
|
2301
|
-
"dev:local-server": "cross-env HANDY_SERVER_URL=http://localhost:3005 tsx --env-file .env.sample src/index.ts",
|
|
2313
|
+
dev: "yarn build && npx tsx --env-file .env.sample src/index.ts",
|
|
2314
|
+
"dev:local-server": "yarn build && cross-env HANDY_SERVER_URL=http://localhost:3005 tsx --env-file .env.sample src/index.ts",
|
|
2302
2315
|
"version:prerelease": "npm version prerelease --preid=beta",
|
|
2303
2316
|
"publish:prerelease": "npm publish --tag beta"
|
|
2304
2317
|
};
|
|
2305
2318
|
var dependencies = {
|
|
2306
|
-
"@anthropic-ai/claude-code": "^1.0.
|
|
2319
|
+
"@anthropic-ai/claude-code": "^1.0.73",
|
|
2307
2320
|
"@anthropic-ai/sdk": "^0.56.0",
|
|
2308
2321
|
"@modelcontextprotocol/sdk": "^1.15.1",
|
|
2309
2322
|
"@stablelib/base64": "^2.0.1",
|
|
@@ -2828,6 +2841,92 @@ class MessageQueue2 {
|
|
|
2828
2841
|
}
|
|
2829
2842
|
}
|
|
2830
2843
|
|
|
2844
|
+
function deterministicStringify(obj, options = {}) {
|
|
2845
|
+
const {
|
|
2846
|
+
undefinedBehavior = "omit",
|
|
2847
|
+
sortArrays = false,
|
|
2848
|
+
replacer,
|
|
2849
|
+
includeSymbols = false
|
|
2850
|
+
} = options;
|
|
2851
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
2852
|
+
function processValue(value, key) {
|
|
2853
|
+
if (replacer && key !== void 0) {
|
|
2854
|
+
value = replacer(key, value);
|
|
2855
|
+
}
|
|
2856
|
+
if (value === null) return null;
|
|
2857
|
+
if (value === void 0) {
|
|
2858
|
+
switch (undefinedBehavior) {
|
|
2859
|
+
case "omit":
|
|
2860
|
+
return void 0;
|
|
2861
|
+
case "null":
|
|
2862
|
+
return null;
|
|
2863
|
+
case "throw":
|
|
2864
|
+
throw new Error(`Undefined value at key: ${key}`);
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2867
|
+
if (typeof value === "boolean" || typeof value === "number" || typeof value === "string") {
|
|
2868
|
+
return value;
|
|
2869
|
+
}
|
|
2870
|
+
if (value instanceof Date) {
|
|
2871
|
+
return value.toISOString();
|
|
2872
|
+
}
|
|
2873
|
+
if (value instanceof RegExp) {
|
|
2874
|
+
return value.toString();
|
|
2875
|
+
}
|
|
2876
|
+
if (typeof value === "function") {
|
|
2877
|
+
return void 0;
|
|
2878
|
+
}
|
|
2879
|
+
if (typeof value === "symbol") {
|
|
2880
|
+
return includeSymbols ? value.toString() : void 0;
|
|
2881
|
+
}
|
|
2882
|
+
if (typeof value === "bigint") {
|
|
2883
|
+
return value.toString() + "n";
|
|
2884
|
+
}
|
|
2885
|
+
if (seen.has(value)) {
|
|
2886
|
+
throw new Error("Circular reference detected");
|
|
2887
|
+
}
|
|
2888
|
+
seen.add(value);
|
|
2889
|
+
if (Array.isArray(value)) {
|
|
2890
|
+
const processed2 = value.map((item, index) => processValue(item, String(index))).filter((item) => item !== void 0);
|
|
2891
|
+
if (sortArrays) {
|
|
2892
|
+
processed2.sort((a, b) => {
|
|
2893
|
+
const aStr = JSON.stringify(processValue(a));
|
|
2894
|
+
const bStr = JSON.stringify(processValue(b));
|
|
2895
|
+
return aStr.localeCompare(bStr);
|
|
2896
|
+
});
|
|
2897
|
+
}
|
|
2898
|
+
seen.delete(value);
|
|
2899
|
+
return processed2;
|
|
2900
|
+
}
|
|
2901
|
+
if (value.constructor === Object || value.constructor === void 0) {
|
|
2902
|
+
const processed2 = {};
|
|
2903
|
+
const keys = Object.keys(value).sort();
|
|
2904
|
+
for (const k of keys) {
|
|
2905
|
+
const processedValue = processValue(value[k], k);
|
|
2906
|
+
if (processedValue !== void 0) {
|
|
2907
|
+
processed2[k] = processedValue;
|
|
2908
|
+
}
|
|
2909
|
+
}
|
|
2910
|
+
seen.delete(value);
|
|
2911
|
+
return processed2;
|
|
2912
|
+
}
|
|
2913
|
+
try {
|
|
2914
|
+
const plain = { ...value };
|
|
2915
|
+
seen.delete(value);
|
|
2916
|
+
return processValue(plain, key);
|
|
2917
|
+
} catch {
|
|
2918
|
+
seen.delete(value);
|
|
2919
|
+
return String(value);
|
|
2920
|
+
}
|
|
2921
|
+
}
|
|
2922
|
+
const processed = processValue(obj);
|
|
2923
|
+
return JSON.stringify(processed);
|
|
2924
|
+
}
|
|
2925
|
+
function hashObject(obj, options, encoding = "hex") {
|
|
2926
|
+
const jsonString = deterministicStringify(obj, options);
|
|
2927
|
+
return crypto.createHash("sha256").update(jsonString).digest(encoding);
|
|
2928
|
+
}
|
|
2929
|
+
|
|
2831
2930
|
let caffeinateProcess = null;
|
|
2832
2931
|
function startCaffeinate() {
|
|
2833
2932
|
if (process.platform !== "darwin") {
|
|
@@ -2962,7 +3061,8 @@ async function start(credentials, options = {}) {
|
|
|
2962
3061
|
host: os.hostname(),
|
|
2963
3062
|
version: packageJson.version,
|
|
2964
3063
|
os: os.platform(),
|
|
2965
|
-
machineId: settings.machineId
|
|
3064
|
+
machineId: settings.machineId,
|
|
3065
|
+
homeDir: os.homedir()
|
|
2966
3066
|
};
|
|
2967
3067
|
const response = await api.getOrCreateSession({ tag: sessionTag, metadata, state });
|
|
2968
3068
|
types$1.logger.debug(`Session created: ${response.id}`);
|
|
@@ -2990,9 +3090,15 @@ async function start(credentials, options = {}) {
|
|
|
2990
3090
|
if (caffeinateStarted) {
|
|
2991
3091
|
types$1.logger.infoDeveloper("Sleep prevention enabled (macOS)");
|
|
2992
3092
|
}
|
|
2993
|
-
const messageQueue = new MessageQueue2((mode) => mode);
|
|
3093
|
+
const messageQueue = new MessageQueue2((mode) => hashObject(mode));
|
|
2994
3094
|
registerHandlers(session);
|
|
2995
3095
|
let currentPermissionMode = options.permissionMode;
|
|
3096
|
+
let currentModel = options.model;
|
|
3097
|
+
let currentFallbackModel = void 0;
|
|
3098
|
+
let currentCustomSystemPrompt = void 0;
|
|
3099
|
+
let currentAppendSystemPrompt = void 0;
|
|
3100
|
+
let currentAllowedTools = void 0;
|
|
3101
|
+
let currentDisallowedTools = void 0;
|
|
2996
3102
|
session.onUserMessage((message) => {
|
|
2997
3103
|
let messagePermissionMode = currentPermissionMode;
|
|
2998
3104
|
if (message.meta?.permissionMode) {
|
|
@@ -3007,7 +3113,64 @@ async function start(credentials, options = {}) {
|
|
|
3007
3113
|
} else {
|
|
3008
3114
|
types$1.logger.debug(`[loop] User message received with no permission mode override, using current: ${currentPermissionMode}`);
|
|
3009
3115
|
}
|
|
3010
|
-
|
|
3116
|
+
let messageModel = currentModel;
|
|
3117
|
+
if (message.meta?.hasOwnProperty("model")) {
|
|
3118
|
+
messageModel = message.meta.model || void 0;
|
|
3119
|
+
currentModel = messageModel;
|
|
3120
|
+
types$1.logger.debug(`[loop] Model updated from user message: ${messageModel || "reset to default"}`);
|
|
3121
|
+
} else {
|
|
3122
|
+
types$1.logger.debug(`[loop] User message received with no model override, using current: ${currentModel || "default"}`);
|
|
3123
|
+
}
|
|
3124
|
+
let messageCustomSystemPrompt = currentCustomSystemPrompt;
|
|
3125
|
+
if (message.meta?.hasOwnProperty("customSystemPrompt")) {
|
|
3126
|
+
messageCustomSystemPrompt = message.meta.customSystemPrompt || void 0;
|
|
3127
|
+
currentCustomSystemPrompt = messageCustomSystemPrompt;
|
|
3128
|
+
types$1.logger.debug(`[loop] Custom system prompt updated from user message: ${messageCustomSystemPrompt ? "set" : "reset to none"}`);
|
|
3129
|
+
} else {
|
|
3130
|
+
types$1.logger.debug(`[loop] User message received with no custom system prompt override, using current: ${currentCustomSystemPrompt ? "set" : "none"}`);
|
|
3131
|
+
}
|
|
3132
|
+
let messageFallbackModel = currentFallbackModel;
|
|
3133
|
+
if (message.meta?.hasOwnProperty("fallbackModel")) {
|
|
3134
|
+
messageFallbackModel = message.meta.fallbackModel || void 0;
|
|
3135
|
+
currentFallbackModel = messageFallbackModel;
|
|
3136
|
+
types$1.logger.debug(`[loop] Fallback model updated from user message: ${messageFallbackModel || "reset to none"}`);
|
|
3137
|
+
} else {
|
|
3138
|
+
types$1.logger.debug(`[loop] User message received with no fallback model override, using current: ${currentFallbackModel || "none"}`);
|
|
3139
|
+
}
|
|
3140
|
+
let messageAppendSystemPrompt = currentAppendSystemPrompt;
|
|
3141
|
+
if (message.meta?.hasOwnProperty("appendSystemPrompt")) {
|
|
3142
|
+
messageAppendSystemPrompt = message.meta.appendSystemPrompt || void 0;
|
|
3143
|
+
currentAppendSystemPrompt = messageAppendSystemPrompt;
|
|
3144
|
+
types$1.logger.debug(`[loop] Append system prompt updated from user message: ${messageAppendSystemPrompt ? "set" : "reset to none"}`);
|
|
3145
|
+
} else {
|
|
3146
|
+
types$1.logger.debug(`[loop] User message received with no append system prompt override, using current: ${currentAppendSystemPrompt ? "set" : "none"}`);
|
|
3147
|
+
}
|
|
3148
|
+
let messageAllowedTools = currentAllowedTools;
|
|
3149
|
+
if (message.meta?.hasOwnProperty("allowedTools")) {
|
|
3150
|
+
messageAllowedTools = message.meta.allowedTools || void 0;
|
|
3151
|
+
currentAllowedTools = messageAllowedTools;
|
|
3152
|
+
types$1.logger.debug(`[loop] Allowed tools updated from user message: ${messageAllowedTools ? messageAllowedTools.join(", ") : "reset to none"}`);
|
|
3153
|
+
} else {
|
|
3154
|
+
types$1.logger.debug(`[loop] User message received with no allowed tools override, using current: ${currentAllowedTools ? currentAllowedTools.join(", ") : "none"}`);
|
|
3155
|
+
}
|
|
3156
|
+
let messageDisallowedTools = currentDisallowedTools;
|
|
3157
|
+
if (message.meta?.hasOwnProperty("disallowedTools")) {
|
|
3158
|
+
messageDisallowedTools = message.meta.disallowedTools || void 0;
|
|
3159
|
+
currentDisallowedTools = messageDisallowedTools;
|
|
3160
|
+
types$1.logger.debug(`[loop] Disallowed tools updated from user message: ${messageDisallowedTools ? messageDisallowedTools.join(", ") : "reset to none"}`);
|
|
3161
|
+
} else {
|
|
3162
|
+
types$1.logger.debug(`[loop] User message received with no disallowed tools override, using current: ${currentDisallowedTools ? currentDisallowedTools.join(", ") : "none"}`);
|
|
3163
|
+
}
|
|
3164
|
+
const enhancedMode = {
|
|
3165
|
+
permissionMode: messagePermissionMode || "default",
|
|
3166
|
+
model: messageModel,
|
|
3167
|
+
fallbackModel: messageFallbackModel,
|
|
3168
|
+
customSystemPrompt: messageCustomSystemPrompt,
|
|
3169
|
+
appendSystemPrompt: messageAppendSystemPrompt,
|
|
3170
|
+
allowedTools: messageAllowedTools,
|
|
3171
|
+
disallowedTools: messageDisallowedTools
|
|
3172
|
+
};
|
|
3173
|
+
messageQueue.push(message.content.text, enhancedMode);
|
|
3011
3174
|
types$1.logger.debugLargeJson("User message pushed to queue:", message);
|
|
3012
3175
|
});
|
|
3013
3176
|
await loop({
|
|
@@ -3116,6 +3279,7 @@ class ApiDaemonSession extends node_events.EventEmitter {
|
|
|
3116
3279
|
token;
|
|
3117
3280
|
secret;
|
|
3118
3281
|
spawnedProcesses = /* @__PURE__ */ new Set();
|
|
3282
|
+
machineRegistered = false;
|
|
3119
3283
|
constructor(token, secret, machineIdentity) {
|
|
3120
3284
|
super();
|
|
3121
3285
|
this.token = token;
|
|
@@ -3137,9 +3301,12 @@ class ApiDaemonSession extends node_events.EventEmitter {
|
|
|
3137
3301
|
withCredentials: true,
|
|
3138
3302
|
autoConnect: false
|
|
3139
3303
|
});
|
|
3140
|
-
socket.on("connect", () => {
|
|
3304
|
+
socket.on("connect", async () => {
|
|
3141
3305
|
types$1.logger.debug("[DAEMON SESSION] Socket connected");
|
|
3142
3306
|
types$1.logger.debug(`[DAEMON SESSION] Connected with auth - token: ${this.token.substring(0, 10)}..., machineId: ${this.machineIdentity.machineId}`);
|
|
3307
|
+
if (!this.machineRegistered) {
|
|
3308
|
+
await this.registerMachine();
|
|
3309
|
+
}
|
|
3143
3310
|
const rpcMethod = `${this.machineIdentity.machineId}:spawn-happy-session`;
|
|
3144
3311
|
socket.emit("rpc-register", { method: rpcMethod });
|
|
3145
3312
|
types$1.logger.debug(`[DAEMON SESSION] Emitted RPC registration: ${rpcMethod}`);
|
|
@@ -3166,16 +3333,11 @@ class ApiDaemonSession extends node_events.EventEmitter {
|
|
|
3166
3333
|
args.push("--local");
|
|
3167
3334
|
}
|
|
3168
3335
|
types$1.logger.debug(`[DAEMON SESSION] Spawning happy in directory: ${directory} with args: ${args.join(" ")}`);
|
|
3169
|
-
const
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
spawnArgs = args;
|
|
3175
|
-
} else {
|
|
3176
|
-
executable = "npx";
|
|
3177
|
-
spawnArgs = ["tsx", happyPath, ...args];
|
|
3178
|
-
}
|
|
3336
|
+
const happyBinPath = path.join(projectPath(), "bin", "happy.mjs");
|
|
3337
|
+
types$1.logger.debug(`[DAEMON SESSION] Using happy binary at: ${happyBinPath}`);
|
|
3338
|
+
const executable = happyBinPath;
|
|
3339
|
+
const spawnArgs = args;
|
|
3340
|
+
types$1.logger.debug(`[DAEMON SESSION] Spawn: executable=${executable}, args=${JSON.stringify(spawnArgs)}, cwd=${directory}`);
|
|
3179
3341
|
const happyProcess = child_process.spawn(executable, spawnArgs, {
|
|
3180
3342
|
cwd: directory,
|
|
3181
3343
|
detached: true,
|
|
@@ -3268,7 +3430,7 @@ class ApiDaemonSession extends node_events.EventEmitter {
|
|
|
3268
3430
|
types$1.logger.debug(`[DAEMON SESSION] RPC error: ${JSON.stringify(data)}`);
|
|
3269
3431
|
});
|
|
3270
3432
|
socket.onAny((event, ...args) => {
|
|
3271
|
-
if (!event.startsWith("
|
|
3433
|
+
if (!event.startsWith("session-alive") && event !== "ephemeral") {
|
|
3272
3434
|
types$1.logger.debug(`[DAEMON SESSION] Socket event: ${event}, args: ${JSON.stringify(args)}`);
|
|
3273
3435
|
}
|
|
3274
3436
|
});
|
|
@@ -3291,12 +3453,47 @@ class ApiDaemonSession extends node_events.EventEmitter {
|
|
|
3291
3453
|
});
|
|
3292
3454
|
this.socket = socket;
|
|
3293
3455
|
}
|
|
3456
|
+
async registerMachine() {
|
|
3457
|
+
try {
|
|
3458
|
+
const metadata = {
|
|
3459
|
+
host: this.machineIdentity.machineHost,
|
|
3460
|
+
platform: this.machineIdentity.platform,
|
|
3461
|
+
happyCliVersion: this.machineIdentity.happyCliVersion,
|
|
3462
|
+
happyHomeDirectory: this.machineIdentity.happyHomeDirectory
|
|
3463
|
+
};
|
|
3464
|
+
const encrypted = types$1.encrypt(JSON.stringify(metadata), this.secret);
|
|
3465
|
+
const encryptedMetadata = types$1.encodeBase64(encrypted);
|
|
3466
|
+
const response = await fetch(`${types$1.configuration.serverUrl}/v1/machines`, {
|
|
3467
|
+
method: "POST",
|
|
3468
|
+
headers: {
|
|
3469
|
+
"Authorization": `Bearer ${this.token}`,
|
|
3470
|
+
"Content-Type": "application/json"
|
|
3471
|
+
},
|
|
3472
|
+
body: JSON.stringify({
|
|
3473
|
+
id: this.machineIdentity.machineId,
|
|
3474
|
+
metadata: encryptedMetadata
|
|
3475
|
+
})
|
|
3476
|
+
});
|
|
3477
|
+
if (response.ok) {
|
|
3478
|
+
types$1.logger.debug("[DAEMON SESSION] Machine registered/updated successfully");
|
|
3479
|
+
this.machineRegistered = true;
|
|
3480
|
+
} else {
|
|
3481
|
+
types$1.logger.debug(`[DAEMON SESSION] Failed to register machine: ${response.status}`);
|
|
3482
|
+
}
|
|
3483
|
+
} catch (error) {
|
|
3484
|
+
types$1.logger.debug("[DAEMON SESSION] Failed to register machine:", error);
|
|
3485
|
+
}
|
|
3486
|
+
}
|
|
3294
3487
|
startKeepAlive() {
|
|
3295
3488
|
this.stopKeepAlive();
|
|
3296
3489
|
this.keepAliveInterval = setInterval(() => {
|
|
3297
|
-
|
|
3490
|
+
const payload = {
|
|
3491
|
+
type: "machine-scoped",
|
|
3492
|
+
machineId: this.machineIdentity.machineId,
|
|
3298
3493
|
time: Date.now()
|
|
3299
|
-
}
|
|
3494
|
+
};
|
|
3495
|
+
types$1.logger.debugLargeJson(`[DAEMON SESSION] Emitting session-alive`, payload);
|
|
3496
|
+
this.socket.emit("session-alive", payload);
|
|
3300
3497
|
}, 2e4);
|
|
3301
3498
|
}
|
|
3302
3499
|
stopKeepAlive() {
|
|
@@ -3321,15 +3518,26 @@ class ApiDaemonSession extends node_events.EventEmitter {
|
|
|
3321
3518
|
connect() {
|
|
3322
3519
|
this.socket.connect();
|
|
3323
3520
|
}
|
|
3521
|
+
updateMetadata(updates) {
|
|
3522
|
+
const metadata = {
|
|
3523
|
+
host: this.machineIdentity.machineHost,
|
|
3524
|
+
platform: this.machineIdentity.platform,
|
|
3525
|
+
happyCliVersion: updates.happyCliVersion || this.machineIdentity.happyCliVersion,
|
|
3526
|
+
happyHomeDirectory: updates.happyHomeDirectory || this.machineIdentity.happyHomeDirectory
|
|
3527
|
+
};
|
|
3528
|
+
const encrypted = types$1.encrypt(JSON.stringify(metadata), this.secret);
|
|
3529
|
+
const encryptedMetadata = types$1.encodeBase64(encrypted);
|
|
3530
|
+
this.socket.emit("update-machine-metadata", { metadata: encryptedMetadata });
|
|
3531
|
+
}
|
|
3324
3532
|
shutdown() {
|
|
3325
3533
|
types$1.logger.debug(`[DAEMON SESSION] Shutting down daemon, killing ${this.spawnedProcesses.size} spawned processes`);
|
|
3326
|
-
for (const
|
|
3534
|
+
for (const process of this.spawnedProcesses) {
|
|
3327
3535
|
try {
|
|
3328
|
-
types$1.logger.debug(`[DAEMON SESSION] Killing spawned process with PID: ${
|
|
3329
|
-
|
|
3536
|
+
types$1.logger.debug(`[DAEMON SESSION] Killing spawned process with PID: ${process.pid}`);
|
|
3537
|
+
process.kill("SIGTERM");
|
|
3330
3538
|
setTimeout(() => {
|
|
3331
3539
|
try {
|
|
3332
|
-
|
|
3540
|
+
process.kill("SIGKILL");
|
|
3333
3541
|
} catch (e) {
|
|
3334
3542
|
}
|
|
3335
3543
|
}, 1e3);
|
|
@@ -3405,7 +3613,8 @@ async function startDaemon() {
|
|
|
3405
3613
|
machineId: settings.machineId,
|
|
3406
3614
|
machineHost: settings.machineHost || os$1.hostname(),
|
|
3407
3615
|
platform: process.platform,
|
|
3408
|
-
|
|
3616
|
+
happyCliVersion: packageJson.version,
|
|
3617
|
+
happyHomeDirectory: process.cwd()
|
|
3409
3618
|
};
|
|
3410
3619
|
let credentials = await readCredentials();
|
|
3411
3620
|
if (!credentials) {
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
-
import { l as logger, d as backoff, e as delay, R as RawJSONLinesSchema, c as configuration, f as encodeBase64, A as ApiClient, g as encodeBase64Url, h as decodeBase64, b as initializeConfiguration, i as initLoggerWithGlobalConfiguration } from './types-
|
|
2
|
+
import { l as logger, d as backoff, e as delay, R as RawJSONLinesSchema, c as configuration, f as encodeBase64, A as ApiClient, g as encodeBase64Url, h as decodeBase64, j as encrypt, b as initializeConfiguration, i as initLoggerWithGlobalConfiguration } from './types-DDjn6Ovv.mjs';
|
|
3
3
|
import { randomUUID, randomBytes } from 'node:crypto';
|
|
4
4
|
import { spawn, execSync } from 'node:child_process';
|
|
5
5
|
import { resolve, join, dirname as dirname$1 } from 'node:path';
|
|
@@ -459,6 +459,7 @@ function messageKey(message) {
|
|
|
459
459
|
}
|
|
460
460
|
async function readSessionLog(projectDir, sessionId) {
|
|
461
461
|
const expectedSessionFile = join(projectDir, `${sessionId}.jsonl`);
|
|
462
|
+
logger.debug(`[SESSION_SCANNER] Reading session file: ${expectedSessionFile}`);
|
|
462
463
|
let file;
|
|
463
464
|
try {
|
|
464
465
|
file = await readFile(expectedSessionFile, "utf-8");
|
|
@@ -1231,6 +1232,12 @@ async function claudeRemote(opts) {
|
|
|
1231
1232
|
mcpServers: opts.mcpServers,
|
|
1232
1233
|
permissionPromptToolName: opts.permissionPromptToolName,
|
|
1233
1234
|
permissionMode: opts.permissionMode,
|
|
1235
|
+
model: opts.model,
|
|
1236
|
+
fallbackModel: opts.fallbackModel,
|
|
1237
|
+
customSystemPrompt: opts.customSystemPrompt,
|
|
1238
|
+
appendSystemPrompt: opts.appendSystemPrompt,
|
|
1239
|
+
allowedTools: opts.allowedTools,
|
|
1240
|
+
disallowedTools: opts.disallowedTools,
|
|
1234
1241
|
executable: "node",
|
|
1235
1242
|
abort: opts.signal,
|
|
1236
1243
|
pathToClaudeCodeExecutable: (() => {
|
|
@@ -1240,7 +1247,7 @@ async function claudeRemote(opts) {
|
|
|
1240
1247
|
if (opts.claudeArgs && opts.claudeArgs.length > 0) {
|
|
1241
1248
|
sdkOptions.executableArgs = [...sdkOptions.executableArgs || [], ...opts.claudeArgs];
|
|
1242
1249
|
}
|
|
1243
|
-
logger.debug(`[claudeRemote] Starting query with permission mode: ${opts.permissionMode}`);
|
|
1250
|
+
logger.debug(`[claudeRemote] Starting query with permission mode: ${opts.permissionMode}, model: ${opts.model || "default"}, fallbackModel: ${opts.fallbackModel || "none"}, customSystemPrompt: ${opts.customSystemPrompt ? "set" : "none"}, appendSystemPrompt: ${opts.appendSystemPrompt ? "set" : "none"}, allowedTools: ${opts.allowedTools ? opts.allowedTools.join(",") : "none"}, disallowedTools: ${opts.disallowedTools ? opts.disallowedTools.join(",") : "none"}`);
|
|
1244
1251
|
let message = new PushableAsyncIterable();
|
|
1245
1252
|
message.push({
|
|
1246
1253
|
type: "user",
|
|
@@ -1420,9 +1427,9 @@ async function startPermissionResolver(session) {
|
|
|
1420
1427
|
if (response.approved) {
|
|
1421
1428
|
logger.debug("Plan approved - injecting PLAN_FAKE_RESTART");
|
|
1422
1429
|
if (response.mode && ["default", "acceptEdits", "bypassPermissions"].includes(response.mode)) {
|
|
1423
|
-
session.queue.unshift(PLAN_FAKE_RESTART, response.mode);
|
|
1430
|
+
session.queue.unshift(PLAN_FAKE_RESTART, { permissionMode: response.mode });
|
|
1424
1431
|
} else {
|
|
1425
|
-
session.queue.unshift(PLAN_FAKE_RESTART, "default");
|
|
1432
|
+
session.queue.unshift(PLAN_FAKE_RESTART, { permissionMode: "default" });
|
|
1426
1433
|
}
|
|
1427
1434
|
resolve({ approved: false, reason: PLAN_FAKE_REJECT });
|
|
1428
1435
|
} else {
|
|
@@ -2131,7 +2138,13 @@ async function claudeRemoteLauncher(session) {
|
|
|
2131
2138
|
}
|
|
2132
2139
|
},
|
|
2133
2140
|
permissionPromptToolName: "mcp__permission__" + permissions.server.toolName,
|
|
2134
|
-
permissionMode: messageData.mode,
|
|
2141
|
+
permissionMode: messageData.mode.permissionMode,
|
|
2142
|
+
model: messageData.mode.model,
|
|
2143
|
+
fallbackModel: messageData.mode.fallbackModel,
|
|
2144
|
+
customSystemPrompt: messageData.mode.customSystemPrompt,
|
|
2145
|
+
appendSystemPrompt: messageData.mode.appendSystemPrompt,
|
|
2146
|
+
allowedTools: messageData.mode.allowedTools,
|
|
2147
|
+
disallowedTools: messageData.mode.disallowedTools,
|
|
2135
2148
|
onSessionFound: (sessionId) => {
|
|
2136
2149
|
sdkToLogConverter.updateSessionId(sessionId);
|
|
2137
2150
|
session.onSessionFound(sessionId);
|
|
@@ -2227,7 +2240,7 @@ async function loop(opts) {
|
|
|
2227
2240
|
}
|
|
2228
2241
|
|
|
2229
2242
|
var name = "happy-coder";
|
|
2230
|
-
var version = "0.
|
|
2243
|
+
var version = "0.5.0";
|
|
2231
2244
|
var description = "Claude Code session sharing CLI";
|
|
2232
2245
|
var author = "Kirill Dubovitskiy";
|
|
2233
2246
|
var license = "MIT";
|
|
@@ -2276,13 +2289,13 @@ var scripts = {
|
|
|
2276
2289
|
build: "shx rm -rf dist && tsc --noEmit && pkgroll",
|
|
2277
2290
|
prepublishOnly: "yarn build && yarn test",
|
|
2278
2291
|
typecheck: "tsc --noEmit",
|
|
2279
|
-
dev: "npx tsx --env-file .env.sample src/index.ts",
|
|
2280
|
-
"dev:local-server": "cross-env HANDY_SERVER_URL=http://localhost:3005 tsx --env-file .env.sample src/index.ts",
|
|
2292
|
+
dev: "yarn build && npx tsx --env-file .env.sample src/index.ts",
|
|
2293
|
+
"dev:local-server": "yarn build && cross-env HANDY_SERVER_URL=http://localhost:3005 tsx --env-file .env.sample src/index.ts",
|
|
2281
2294
|
"version:prerelease": "npm version prerelease --preid=beta",
|
|
2282
2295
|
"publish:prerelease": "npm publish --tag beta"
|
|
2283
2296
|
};
|
|
2284
2297
|
var dependencies = {
|
|
2285
|
-
"@anthropic-ai/claude-code": "^1.0.
|
|
2298
|
+
"@anthropic-ai/claude-code": "^1.0.73",
|
|
2286
2299
|
"@anthropic-ai/sdk": "^0.56.0",
|
|
2287
2300
|
"@modelcontextprotocol/sdk": "^1.15.1",
|
|
2288
2301
|
"@stablelib/base64": "^2.0.1",
|
|
@@ -2807,6 +2820,92 @@ class MessageQueue2 {
|
|
|
2807
2820
|
}
|
|
2808
2821
|
}
|
|
2809
2822
|
|
|
2823
|
+
function deterministicStringify(obj, options = {}) {
|
|
2824
|
+
const {
|
|
2825
|
+
undefinedBehavior = "omit",
|
|
2826
|
+
sortArrays = false,
|
|
2827
|
+
replacer,
|
|
2828
|
+
includeSymbols = false
|
|
2829
|
+
} = options;
|
|
2830
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
2831
|
+
function processValue(value, key) {
|
|
2832
|
+
if (replacer && key !== void 0) {
|
|
2833
|
+
value = replacer(key, value);
|
|
2834
|
+
}
|
|
2835
|
+
if (value === null) return null;
|
|
2836
|
+
if (value === void 0) {
|
|
2837
|
+
switch (undefinedBehavior) {
|
|
2838
|
+
case "omit":
|
|
2839
|
+
return void 0;
|
|
2840
|
+
case "null":
|
|
2841
|
+
return null;
|
|
2842
|
+
case "throw":
|
|
2843
|
+
throw new Error(`Undefined value at key: ${key}`);
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
if (typeof value === "boolean" || typeof value === "number" || typeof value === "string") {
|
|
2847
|
+
return value;
|
|
2848
|
+
}
|
|
2849
|
+
if (value instanceof Date) {
|
|
2850
|
+
return value.toISOString();
|
|
2851
|
+
}
|
|
2852
|
+
if (value instanceof RegExp) {
|
|
2853
|
+
return value.toString();
|
|
2854
|
+
}
|
|
2855
|
+
if (typeof value === "function") {
|
|
2856
|
+
return void 0;
|
|
2857
|
+
}
|
|
2858
|
+
if (typeof value === "symbol") {
|
|
2859
|
+
return includeSymbols ? value.toString() : void 0;
|
|
2860
|
+
}
|
|
2861
|
+
if (typeof value === "bigint") {
|
|
2862
|
+
return value.toString() + "n";
|
|
2863
|
+
}
|
|
2864
|
+
if (seen.has(value)) {
|
|
2865
|
+
throw new Error("Circular reference detected");
|
|
2866
|
+
}
|
|
2867
|
+
seen.add(value);
|
|
2868
|
+
if (Array.isArray(value)) {
|
|
2869
|
+
const processed2 = value.map((item, index) => processValue(item, String(index))).filter((item) => item !== void 0);
|
|
2870
|
+
if (sortArrays) {
|
|
2871
|
+
processed2.sort((a, b) => {
|
|
2872
|
+
const aStr = JSON.stringify(processValue(a));
|
|
2873
|
+
const bStr = JSON.stringify(processValue(b));
|
|
2874
|
+
return aStr.localeCompare(bStr);
|
|
2875
|
+
});
|
|
2876
|
+
}
|
|
2877
|
+
seen.delete(value);
|
|
2878
|
+
return processed2;
|
|
2879
|
+
}
|
|
2880
|
+
if (value.constructor === Object || value.constructor === void 0) {
|
|
2881
|
+
const processed2 = {};
|
|
2882
|
+
const keys = Object.keys(value).sort();
|
|
2883
|
+
for (const k of keys) {
|
|
2884
|
+
const processedValue = processValue(value[k], k);
|
|
2885
|
+
if (processedValue !== void 0) {
|
|
2886
|
+
processed2[k] = processedValue;
|
|
2887
|
+
}
|
|
2888
|
+
}
|
|
2889
|
+
seen.delete(value);
|
|
2890
|
+
return processed2;
|
|
2891
|
+
}
|
|
2892
|
+
try {
|
|
2893
|
+
const plain = { ...value };
|
|
2894
|
+
seen.delete(value);
|
|
2895
|
+
return processValue(plain, key);
|
|
2896
|
+
} catch {
|
|
2897
|
+
seen.delete(value);
|
|
2898
|
+
return String(value);
|
|
2899
|
+
}
|
|
2900
|
+
}
|
|
2901
|
+
const processed = processValue(obj);
|
|
2902
|
+
return JSON.stringify(processed);
|
|
2903
|
+
}
|
|
2904
|
+
function hashObject(obj, options, encoding = "hex") {
|
|
2905
|
+
const jsonString = deterministicStringify(obj, options);
|
|
2906
|
+
return createHash("sha256").update(jsonString).digest(encoding);
|
|
2907
|
+
}
|
|
2908
|
+
|
|
2810
2909
|
let caffeinateProcess = null;
|
|
2811
2910
|
function startCaffeinate() {
|
|
2812
2911
|
if (process.platform !== "darwin") {
|
|
@@ -2941,7 +3040,8 @@ async function start(credentials, options = {}) {
|
|
|
2941
3040
|
host: os.hostname(),
|
|
2942
3041
|
version: packageJson.version,
|
|
2943
3042
|
os: os.platform(),
|
|
2944
|
-
machineId: settings.machineId
|
|
3043
|
+
machineId: settings.machineId,
|
|
3044
|
+
homeDir: os.homedir()
|
|
2945
3045
|
};
|
|
2946
3046
|
const response = await api.getOrCreateSession({ tag: sessionTag, metadata, state });
|
|
2947
3047
|
logger.debug(`Session created: ${response.id}`);
|
|
@@ -2969,9 +3069,15 @@ async function start(credentials, options = {}) {
|
|
|
2969
3069
|
if (caffeinateStarted) {
|
|
2970
3070
|
logger.infoDeveloper("Sleep prevention enabled (macOS)");
|
|
2971
3071
|
}
|
|
2972
|
-
const messageQueue = new MessageQueue2((mode) => mode);
|
|
3072
|
+
const messageQueue = new MessageQueue2((mode) => hashObject(mode));
|
|
2973
3073
|
registerHandlers(session);
|
|
2974
3074
|
let currentPermissionMode = options.permissionMode;
|
|
3075
|
+
let currentModel = options.model;
|
|
3076
|
+
let currentFallbackModel = void 0;
|
|
3077
|
+
let currentCustomSystemPrompt = void 0;
|
|
3078
|
+
let currentAppendSystemPrompt = void 0;
|
|
3079
|
+
let currentAllowedTools = void 0;
|
|
3080
|
+
let currentDisallowedTools = void 0;
|
|
2975
3081
|
session.onUserMessage((message) => {
|
|
2976
3082
|
let messagePermissionMode = currentPermissionMode;
|
|
2977
3083
|
if (message.meta?.permissionMode) {
|
|
@@ -2986,7 +3092,64 @@ async function start(credentials, options = {}) {
|
|
|
2986
3092
|
} else {
|
|
2987
3093
|
logger.debug(`[loop] User message received with no permission mode override, using current: ${currentPermissionMode}`);
|
|
2988
3094
|
}
|
|
2989
|
-
|
|
3095
|
+
let messageModel = currentModel;
|
|
3096
|
+
if (message.meta?.hasOwnProperty("model")) {
|
|
3097
|
+
messageModel = message.meta.model || void 0;
|
|
3098
|
+
currentModel = messageModel;
|
|
3099
|
+
logger.debug(`[loop] Model updated from user message: ${messageModel || "reset to default"}`);
|
|
3100
|
+
} else {
|
|
3101
|
+
logger.debug(`[loop] User message received with no model override, using current: ${currentModel || "default"}`);
|
|
3102
|
+
}
|
|
3103
|
+
let messageCustomSystemPrompt = currentCustomSystemPrompt;
|
|
3104
|
+
if (message.meta?.hasOwnProperty("customSystemPrompt")) {
|
|
3105
|
+
messageCustomSystemPrompt = message.meta.customSystemPrompt || void 0;
|
|
3106
|
+
currentCustomSystemPrompt = messageCustomSystemPrompt;
|
|
3107
|
+
logger.debug(`[loop] Custom system prompt updated from user message: ${messageCustomSystemPrompt ? "set" : "reset to none"}`);
|
|
3108
|
+
} else {
|
|
3109
|
+
logger.debug(`[loop] User message received with no custom system prompt override, using current: ${currentCustomSystemPrompt ? "set" : "none"}`);
|
|
3110
|
+
}
|
|
3111
|
+
let messageFallbackModel = currentFallbackModel;
|
|
3112
|
+
if (message.meta?.hasOwnProperty("fallbackModel")) {
|
|
3113
|
+
messageFallbackModel = message.meta.fallbackModel || void 0;
|
|
3114
|
+
currentFallbackModel = messageFallbackModel;
|
|
3115
|
+
logger.debug(`[loop] Fallback model updated from user message: ${messageFallbackModel || "reset to none"}`);
|
|
3116
|
+
} else {
|
|
3117
|
+
logger.debug(`[loop] User message received with no fallback model override, using current: ${currentFallbackModel || "none"}`);
|
|
3118
|
+
}
|
|
3119
|
+
let messageAppendSystemPrompt = currentAppendSystemPrompt;
|
|
3120
|
+
if (message.meta?.hasOwnProperty("appendSystemPrompt")) {
|
|
3121
|
+
messageAppendSystemPrompt = message.meta.appendSystemPrompt || void 0;
|
|
3122
|
+
currentAppendSystemPrompt = messageAppendSystemPrompt;
|
|
3123
|
+
logger.debug(`[loop] Append system prompt updated from user message: ${messageAppendSystemPrompt ? "set" : "reset to none"}`);
|
|
3124
|
+
} else {
|
|
3125
|
+
logger.debug(`[loop] User message received with no append system prompt override, using current: ${currentAppendSystemPrompt ? "set" : "none"}`);
|
|
3126
|
+
}
|
|
3127
|
+
let messageAllowedTools = currentAllowedTools;
|
|
3128
|
+
if (message.meta?.hasOwnProperty("allowedTools")) {
|
|
3129
|
+
messageAllowedTools = message.meta.allowedTools || void 0;
|
|
3130
|
+
currentAllowedTools = messageAllowedTools;
|
|
3131
|
+
logger.debug(`[loop] Allowed tools updated from user message: ${messageAllowedTools ? messageAllowedTools.join(", ") : "reset to none"}`);
|
|
3132
|
+
} else {
|
|
3133
|
+
logger.debug(`[loop] User message received with no allowed tools override, using current: ${currentAllowedTools ? currentAllowedTools.join(", ") : "none"}`);
|
|
3134
|
+
}
|
|
3135
|
+
let messageDisallowedTools = currentDisallowedTools;
|
|
3136
|
+
if (message.meta?.hasOwnProperty("disallowedTools")) {
|
|
3137
|
+
messageDisallowedTools = message.meta.disallowedTools || void 0;
|
|
3138
|
+
currentDisallowedTools = messageDisallowedTools;
|
|
3139
|
+
logger.debug(`[loop] Disallowed tools updated from user message: ${messageDisallowedTools ? messageDisallowedTools.join(", ") : "reset to none"}`);
|
|
3140
|
+
} else {
|
|
3141
|
+
logger.debug(`[loop] User message received with no disallowed tools override, using current: ${currentDisallowedTools ? currentDisallowedTools.join(", ") : "none"}`);
|
|
3142
|
+
}
|
|
3143
|
+
const enhancedMode = {
|
|
3144
|
+
permissionMode: messagePermissionMode || "default",
|
|
3145
|
+
model: messageModel,
|
|
3146
|
+
fallbackModel: messageFallbackModel,
|
|
3147
|
+
customSystemPrompt: messageCustomSystemPrompt,
|
|
3148
|
+
appendSystemPrompt: messageAppendSystemPrompt,
|
|
3149
|
+
allowedTools: messageAllowedTools,
|
|
3150
|
+
disallowedTools: messageDisallowedTools
|
|
3151
|
+
};
|
|
3152
|
+
messageQueue.push(message.content.text, enhancedMode);
|
|
2990
3153
|
logger.debugLargeJson("User message pushed to queue:", message);
|
|
2991
3154
|
});
|
|
2992
3155
|
await loop({
|
|
@@ -3095,6 +3258,7 @@ class ApiDaemonSession extends EventEmitter {
|
|
|
3095
3258
|
token;
|
|
3096
3259
|
secret;
|
|
3097
3260
|
spawnedProcesses = /* @__PURE__ */ new Set();
|
|
3261
|
+
machineRegistered = false;
|
|
3098
3262
|
constructor(token, secret, machineIdentity) {
|
|
3099
3263
|
super();
|
|
3100
3264
|
this.token = token;
|
|
@@ -3116,9 +3280,12 @@ class ApiDaemonSession extends EventEmitter {
|
|
|
3116
3280
|
withCredentials: true,
|
|
3117
3281
|
autoConnect: false
|
|
3118
3282
|
});
|
|
3119
|
-
socket.on("connect", () => {
|
|
3283
|
+
socket.on("connect", async () => {
|
|
3120
3284
|
logger.debug("[DAEMON SESSION] Socket connected");
|
|
3121
3285
|
logger.debug(`[DAEMON SESSION] Connected with auth - token: ${this.token.substring(0, 10)}..., machineId: ${this.machineIdentity.machineId}`);
|
|
3286
|
+
if (!this.machineRegistered) {
|
|
3287
|
+
await this.registerMachine();
|
|
3288
|
+
}
|
|
3122
3289
|
const rpcMethod = `${this.machineIdentity.machineId}:spawn-happy-session`;
|
|
3123
3290
|
socket.emit("rpc-register", { method: rpcMethod });
|
|
3124
3291
|
logger.debug(`[DAEMON SESSION] Emitted RPC registration: ${rpcMethod}`);
|
|
@@ -3145,16 +3312,11 @@ class ApiDaemonSession extends EventEmitter {
|
|
|
3145
3312
|
args.push("--local");
|
|
3146
3313
|
}
|
|
3147
3314
|
logger.debug(`[DAEMON SESSION] Spawning happy in directory: ${directory} with args: ${args.join(" ")}`);
|
|
3148
|
-
const
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
spawnArgs = args;
|
|
3154
|
-
} else {
|
|
3155
|
-
executable = "npx";
|
|
3156
|
-
spawnArgs = ["tsx", happyPath, ...args];
|
|
3157
|
-
}
|
|
3315
|
+
const happyBinPath = join$1(projectPath(), "bin", "happy.mjs");
|
|
3316
|
+
logger.debug(`[DAEMON SESSION] Using happy binary at: ${happyBinPath}`);
|
|
3317
|
+
const executable = happyBinPath;
|
|
3318
|
+
const spawnArgs = args;
|
|
3319
|
+
logger.debug(`[DAEMON SESSION] Spawn: executable=${executable}, args=${JSON.stringify(spawnArgs)}, cwd=${directory}`);
|
|
3158
3320
|
const happyProcess = spawn$1(executable, spawnArgs, {
|
|
3159
3321
|
cwd: directory,
|
|
3160
3322
|
detached: true,
|
|
@@ -3247,7 +3409,7 @@ class ApiDaemonSession extends EventEmitter {
|
|
|
3247
3409
|
logger.debug(`[DAEMON SESSION] RPC error: ${JSON.stringify(data)}`);
|
|
3248
3410
|
});
|
|
3249
3411
|
socket.onAny((event, ...args) => {
|
|
3250
|
-
if (!event.startsWith("
|
|
3412
|
+
if (!event.startsWith("session-alive") && event !== "ephemeral") {
|
|
3251
3413
|
logger.debug(`[DAEMON SESSION] Socket event: ${event}, args: ${JSON.stringify(args)}`);
|
|
3252
3414
|
}
|
|
3253
3415
|
});
|
|
@@ -3270,12 +3432,47 @@ class ApiDaemonSession extends EventEmitter {
|
|
|
3270
3432
|
});
|
|
3271
3433
|
this.socket = socket;
|
|
3272
3434
|
}
|
|
3435
|
+
async registerMachine() {
|
|
3436
|
+
try {
|
|
3437
|
+
const metadata = {
|
|
3438
|
+
host: this.machineIdentity.machineHost,
|
|
3439
|
+
platform: this.machineIdentity.platform,
|
|
3440
|
+
happyCliVersion: this.machineIdentity.happyCliVersion,
|
|
3441
|
+
happyHomeDirectory: this.machineIdentity.happyHomeDirectory
|
|
3442
|
+
};
|
|
3443
|
+
const encrypted = encrypt(JSON.stringify(metadata), this.secret);
|
|
3444
|
+
const encryptedMetadata = encodeBase64(encrypted);
|
|
3445
|
+
const response = await fetch(`${configuration.serverUrl}/v1/machines`, {
|
|
3446
|
+
method: "POST",
|
|
3447
|
+
headers: {
|
|
3448
|
+
"Authorization": `Bearer ${this.token}`,
|
|
3449
|
+
"Content-Type": "application/json"
|
|
3450
|
+
},
|
|
3451
|
+
body: JSON.stringify({
|
|
3452
|
+
id: this.machineIdentity.machineId,
|
|
3453
|
+
metadata: encryptedMetadata
|
|
3454
|
+
})
|
|
3455
|
+
});
|
|
3456
|
+
if (response.ok) {
|
|
3457
|
+
logger.debug("[DAEMON SESSION] Machine registered/updated successfully");
|
|
3458
|
+
this.machineRegistered = true;
|
|
3459
|
+
} else {
|
|
3460
|
+
logger.debug(`[DAEMON SESSION] Failed to register machine: ${response.status}`);
|
|
3461
|
+
}
|
|
3462
|
+
} catch (error) {
|
|
3463
|
+
logger.debug("[DAEMON SESSION] Failed to register machine:", error);
|
|
3464
|
+
}
|
|
3465
|
+
}
|
|
3273
3466
|
startKeepAlive() {
|
|
3274
3467
|
this.stopKeepAlive();
|
|
3275
3468
|
this.keepAliveInterval = setInterval(() => {
|
|
3276
|
-
|
|
3469
|
+
const payload = {
|
|
3470
|
+
type: "machine-scoped",
|
|
3471
|
+
machineId: this.machineIdentity.machineId,
|
|
3277
3472
|
time: Date.now()
|
|
3278
|
-
}
|
|
3473
|
+
};
|
|
3474
|
+
logger.debugLargeJson(`[DAEMON SESSION] Emitting session-alive`, payload);
|
|
3475
|
+
this.socket.emit("session-alive", payload);
|
|
3279
3476
|
}, 2e4);
|
|
3280
3477
|
}
|
|
3281
3478
|
stopKeepAlive() {
|
|
@@ -3300,15 +3497,26 @@ class ApiDaemonSession extends EventEmitter {
|
|
|
3300
3497
|
connect() {
|
|
3301
3498
|
this.socket.connect();
|
|
3302
3499
|
}
|
|
3500
|
+
updateMetadata(updates) {
|
|
3501
|
+
const metadata = {
|
|
3502
|
+
host: this.machineIdentity.machineHost,
|
|
3503
|
+
platform: this.machineIdentity.platform,
|
|
3504
|
+
happyCliVersion: updates.happyCliVersion || this.machineIdentity.happyCliVersion,
|
|
3505
|
+
happyHomeDirectory: updates.happyHomeDirectory || this.machineIdentity.happyHomeDirectory
|
|
3506
|
+
};
|
|
3507
|
+
const encrypted = encrypt(JSON.stringify(metadata), this.secret);
|
|
3508
|
+
const encryptedMetadata = encodeBase64(encrypted);
|
|
3509
|
+
this.socket.emit("update-machine-metadata", { metadata: encryptedMetadata });
|
|
3510
|
+
}
|
|
3303
3511
|
shutdown() {
|
|
3304
3512
|
logger.debug(`[DAEMON SESSION] Shutting down daemon, killing ${this.spawnedProcesses.size} spawned processes`);
|
|
3305
|
-
for (const
|
|
3513
|
+
for (const process of this.spawnedProcesses) {
|
|
3306
3514
|
try {
|
|
3307
|
-
logger.debug(`[DAEMON SESSION] Killing spawned process with PID: ${
|
|
3308
|
-
|
|
3515
|
+
logger.debug(`[DAEMON SESSION] Killing spawned process with PID: ${process.pid}`);
|
|
3516
|
+
process.kill("SIGTERM");
|
|
3309
3517
|
setTimeout(() => {
|
|
3310
3518
|
try {
|
|
3311
|
-
|
|
3519
|
+
process.kill("SIGKILL");
|
|
3312
3520
|
} catch (e) {
|
|
3313
3521
|
}
|
|
3314
3522
|
}, 1e3);
|
|
@@ -3384,7 +3592,8 @@ async function startDaemon() {
|
|
|
3384
3592
|
machineId: settings.machineId,
|
|
3385
3593
|
machineHost: settings.machineHost || hostname(),
|
|
3386
3594
|
platform: process.platform,
|
|
3387
|
-
|
|
3595
|
+
happyCliVersion: packageJson.version,
|
|
3596
|
+
happyHomeDirectory: process.cwd()
|
|
3388
3597
|
};
|
|
3389
3598
|
let credentials = await readCredentials();
|
|
3390
3599
|
if (!credentials) {
|
package/dist/lib.cjs
CHANGED
package/dist/lib.d.cts
CHANGED
|
@@ -339,12 +339,30 @@ declare const UserMessageSchema: z.ZodObject<{
|
|
|
339
339
|
meta: z.ZodOptional<z.ZodObject<{
|
|
340
340
|
sentFrom: z.ZodOptional<z.ZodString>;
|
|
341
341
|
permissionMode: z.ZodOptional<z.ZodString>;
|
|
342
|
+
model: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
343
|
+
fallbackModel: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
344
|
+
customSystemPrompt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
345
|
+
appendSystemPrompt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
346
|
+
allowedTools: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
|
|
347
|
+
disallowedTools: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
|
|
342
348
|
}, "strip", z.ZodTypeAny, {
|
|
343
349
|
sentFrom?: string | undefined;
|
|
344
350
|
permissionMode?: string | undefined;
|
|
351
|
+
model?: string | null | undefined;
|
|
352
|
+
fallbackModel?: string | null | undefined;
|
|
353
|
+
customSystemPrompt?: string | null | undefined;
|
|
354
|
+
appendSystemPrompt?: string | null | undefined;
|
|
355
|
+
allowedTools?: string[] | null | undefined;
|
|
356
|
+
disallowedTools?: string[] | null | undefined;
|
|
345
357
|
}, {
|
|
346
358
|
sentFrom?: string | undefined;
|
|
347
359
|
permissionMode?: string | undefined;
|
|
360
|
+
model?: string | null | undefined;
|
|
361
|
+
fallbackModel?: string | null | undefined;
|
|
362
|
+
customSystemPrompt?: string | null | undefined;
|
|
363
|
+
appendSystemPrompt?: string | null | undefined;
|
|
364
|
+
allowedTools?: string[] | null | undefined;
|
|
365
|
+
disallowedTools?: string[] | null | undefined;
|
|
348
366
|
}>>;
|
|
349
367
|
}, "strip", z.ZodTypeAny, {
|
|
350
368
|
content: {
|
|
@@ -356,6 +374,12 @@ declare const UserMessageSchema: z.ZodObject<{
|
|
|
356
374
|
meta?: {
|
|
357
375
|
sentFrom?: string | undefined;
|
|
358
376
|
permissionMode?: string | undefined;
|
|
377
|
+
model?: string | null | undefined;
|
|
378
|
+
fallbackModel?: string | null | undefined;
|
|
379
|
+
customSystemPrompt?: string | null | undefined;
|
|
380
|
+
appendSystemPrompt?: string | null | undefined;
|
|
381
|
+
allowedTools?: string[] | null | undefined;
|
|
382
|
+
disallowedTools?: string[] | null | undefined;
|
|
359
383
|
} | undefined;
|
|
360
384
|
}, {
|
|
361
385
|
content: {
|
|
@@ -367,6 +391,12 @@ declare const UserMessageSchema: z.ZodObject<{
|
|
|
367
391
|
meta?: {
|
|
368
392
|
sentFrom?: string | undefined;
|
|
369
393
|
permissionMode?: string | undefined;
|
|
394
|
+
model?: string | null | undefined;
|
|
395
|
+
fallbackModel?: string | null | undefined;
|
|
396
|
+
customSystemPrompt?: string | null | undefined;
|
|
397
|
+
appendSystemPrompt?: string | null | undefined;
|
|
398
|
+
allowedTools?: string[] | null | undefined;
|
|
399
|
+
disallowedTools?: string[] | null | undefined;
|
|
370
400
|
} | undefined;
|
|
371
401
|
}>;
|
|
372
402
|
type UserMessage = z.infer<typeof UserMessageSchema>;
|
|
@@ -383,6 +413,7 @@ type Metadata = {
|
|
|
383
413
|
machineId?: string;
|
|
384
414
|
tools?: string[];
|
|
385
415
|
slashCommands?: string[];
|
|
416
|
+
homeDir?: string;
|
|
386
417
|
};
|
|
387
418
|
type AgentState = {
|
|
388
419
|
controlledByUser?: boolean | null | undefined;
|
package/dist/lib.d.mts
CHANGED
|
@@ -339,12 +339,30 @@ declare const UserMessageSchema: z.ZodObject<{
|
|
|
339
339
|
meta: z.ZodOptional<z.ZodObject<{
|
|
340
340
|
sentFrom: z.ZodOptional<z.ZodString>;
|
|
341
341
|
permissionMode: z.ZodOptional<z.ZodString>;
|
|
342
|
+
model: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
343
|
+
fallbackModel: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
344
|
+
customSystemPrompt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
345
|
+
appendSystemPrompt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
346
|
+
allowedTools: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
|
|
347
|
+
disallowedTools: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
|
|
342
348
|
}, "strip", z.ZodTypeAny, {
|
|
343
349
|
sentFrom?: string | undefined;
|
|
344
350
|
permissionMode?: string | undefined;
|
|
351
|
+
model?: string | null | undefined;
|
|
352
|
+
fallbackModel?: string | null | undefined;
|
|
353
|
+
customSystemPrompt?: string | null | undefined;
|
|
354
|
+
appendSystemPrompt?: string | null | undefined;
|
|
355
|
+
allowedTools?: string[] | null | undefined;
|
|
356
|
+
disallowedTools?: string[] | null | undefined;
|
|
345
357
|
}, {
|
|
346
358
|
sentFrom?: string | undefined;
|
|
347
359
|
permissionMode?: string | undefined;
|
|
360
|
+
model?: string | null | undefined;
|
|
361
|
+
fallbackModel?: string | null | undefined;
|
|
362
|
+
customSystemPrompt?: string | null | undefined;
|
|
363
|
+
appendSystemPrompt?: string | null | undefined;
|
|
364
|
+
allowedTools?: string[] | null | undefined;
|
|
365
|
+
disallowedTools?: string[] | null | undefined;
|
|
348
366
|
}>>;
|
|
349
367
|
}, "strip", z.ZodTypeAny, {
|
|
350
368
|
content: {
|
|
@@ -356,6 +374,12 @@ declare const UserMessageSchema: z.ZodObject<{
|
|
|
356
374
|
meta?: {
|
|
357
375
|
sentFrom?: string | undefined;
|
|
358
376
|
permissionMode?: string | undefined;
|
|
377
|
+
model?: string | null | undefined;
|
|
378
|
+
fallbackModel?: string | null | undefined;
|
|
379
|
+
customSystemPrompt?: string | null | undefined;
|
|
380
|
+
appendSystemPrompt?: string | null | undefined;
|
|
381
|
+
allowedTools?: string[] | null | undefined;
|
|
382
|
+
disallowedTools?: string[] | null | undefined;
|
|
359
383
|
} | undefined;
|
|
360
384
|
}, {
|
|
361
385
|
content: {
|
|
@@ -367,6 +391,12 @@ declare const UserMessageSchema: z.ZodObject<{
|
|
|
367
391
|
meta?: {
|
|
368
392
|
sentFrom?: string | undefined;
|
|
369
393
|
permissionMode?: string | undefined;
|
|
394
|
+
model?: string | null | undefined;
|
|
395
|
+
fallbackModel?: string | null | undefined;
|
|
396
|
+
customSystemPrompt?: string | null | undefined;
|
|
397
|
+
appendSystemPrompt?: string | null | undefined;
|
|
398
|
+
allowedTools?: string[] | null | undefined;
|
|
399
|
+
disallowedTools?: string[] | null | undefined;
|
|
370
400
|
} | undefined;
|
|
371
401
|
}>;
|
|
372
402
|
type UserMessage = z.infer<typeof UserMessageSchema>;
|
|
@@ -383,6 +413,7 @@ type Metadata = {
|
|
|
383
413
|
machineId?: string;
|
|
384
414
|
tools?: string[];
|
|
385
415
|
slashCommands?: string[];
|
|
416
|
+
homeDir?: string;
|
|
386
417
|
};
|
|
387
418
|
type AgentState = {
|
|
388
419
|
controlledByUser?: boolean | null | undefined;
|
package/dist/lib.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { A as ApiClient, a as ApiSessionClient, R as RawJSONLinesSchema, c as configuration, i as initLoggerWithGlobalConfiguration, b as initializeConfiguration, l as logger } from './types-
|
|
1
|
+
export { A as ApiClient, a as ApiSessionClient, R as RawJSONLinesSchema, c as configuration, i as initLoggerWithGlobalConfiguration, b as initializeConfiguration, l as logger } from './types-DDjn6Ovv.mjs';
|
|
2
2
|
import 'axios';
|
|
3
3
|
import 'chalk';
|
|
4
4
|
import 'fs';
|
|
@@ -245,8 +245,20 @@ z.z.object({
|
|
|
245
245
|
const MessageMetaSchema = z.z.object({
|
|
246
246
|
sentFrom: z.z.string().optional(),
|
|
247
247
|
// Source identifier
|
|
248
|
-
permissionMode: z.z.string().optional()
|
|
248
|
+
permissionMode: z.z.string().optional(),
|
|
249
249
|
// Permission mode for this message
|
|
250
|
+
model: z.z.string().nullable().optional(),
|
|
251
|
+
// Model name for this message (null = reset)
|
|
252
|
+
fallbackModel: z.z.string().nullable().optional(),
|
|
253
|
+
// Fallback model for this message (null = reset)
|
|
254
|
+
customSystemPrompt: z.z.string().nullable().optional(),
|
|
255
|
+
// Custom system prompt for this message (null = reset)
|
|
256
|
+
appendSystemPrompt: z.z.string().nullable().optional(),
|
|
257
|
+
// Append to system prompt for this message (null = reset)
|
|
258
|
+
allowedTools: z.z.array(z.z.string()).nullable().optional(),
|
|
259
|
+
// Allowed tools for this message (null = reset)
|
|
260
|
+
disallowedTools: z.z.array(z.z.string()).nullable().optional()
|
|
261
|
+
// Disallowed tools for this message (null = reset)
|
|
250
262
|
});
|
|
251
263
|
z.z.object({
|
|
252
264
|
session: z.z.object({
|
|
@@ -534,6 +546,7 @@ class ApiSessionClient extends node_events.EventEmitter {
|
|
|
534
546
|
*/
|
|
535
547
|
keepAlive(thinking, mode) {
|
|
536
548
|
this.socket.volatile.emit("session-alive", {
|
|
549
|
+
type: "session-scoped",
|
|
537
550
|
sid: this.sessionId,
|
|
538
551
|
time: Date.now(),
|
|
539
552
|
thinking,
|
|
@@ -888,5 +901,6 @@ exports.decodeBase64 = decodeBase64;
|
|
|
888
901
|
exports.delay = delay;
|
|
889
902
|
exports.encodeBase64 = encodeBase64;
|
|
890
903
|
exports.encodeBase64Url = encodeBase64Url;
|
|
904
|
+
exports.encrypt = encrypt;
|
|
891
905
|
exports.initLoggerWithGlobalConfiguration = initLoggerWithGlobalConfiguration;
|
|
892
906
|
exports.initializeConfiguration = initializeConfiguration;
|
|
@@ -243,8 +243,20 @@ z.object({
|
|
|
243
243
|
const MessageMetaSchema = z.object({
|
|
244
244
|
sentFrom: z.string().optional(),
|
|
245
245
|
// Source identifier
|
|
246
|
-
permissionMode: z.string().optional()
|
|
246
|
+
permissionMode: z.string().optional(),
|
|
247
247
|
// Permission mode for this message
|
|
248
|
+
model: z.string().nullable().optional(),
|
|
249
|
+
// Model name for this message (null = reset)
|
|
250
|
+
fallbackModel: z.string().nullable().optional(),
|
|
251
|
+
// Fallback model for this message (null = reset)
|
|
252
|
+
customSystemPrompt: z.string().nullable().optional(),
|
|
253
|
+
// Custom system prompt for this message (null = reset)
|
|
254
|
+
appendSystemPrompt: z.string().nullable().optional(),
|
|
255
|
+
// Append to system prompt for this message (null = reset)
|
|
256
|
+
allowedTools: z.array(z.string()).nullable().optional(),
|
|
257
|
+
// Allowed tools for this message (null = reset)
|
|
258
|
+
disallowedTools: z.array(z.string()).nullable().optional()
|
|
259
|
+
// Disallowed tools for this message (null = reset)
|
|
248
260
|
});
|
|
249
261
|
z.object({
|
|
250
262
|
session: z.object({
|
|
@@ -532,6 +544,7 @@ class ApiSessionClient extends EventEmitter {
|
|
|
532
544
|
*/
|
|
533
545
|
keepAlive(thinking, mode) {
|
|
534
546
|
this.socket.volatile.emit("session-alive", {
|
|
547
|
+
type: "session-scoped",
|
|
535
548
|
sid: this.sessionId,
|
|
536
549
|
time: Date.now(),
|
|
537
550
|
thinking,
|
|
@@ -878,4 +891,4 @@ const RawJSONLinesSchema = z.discriminatedUnion("type", [
|
|
|
878
891
|
}).passthrough()
|
|
879
892
|
]);
|
|
880
893
|
|
|
881
|
-
export { ApiClient as A, RawJSONLinesSchema as R, ApiSessionClient as a, initializeConfiguration as b, configuration as c, backoff as d, delay as e, encodeBase64 as f, encodeBase64Url as g, decodeBase64 as h, initLoggerWithGlobalConfiguration as i, logger as l };
|
|
894
|
+
export { ApiClient as A, RawJSONLinesSchema as R, ApiSessionClient as a, initializeConfiguration as b, configuration as c, backoff as d, delay as e, encodeBase64 as f, encodeBase64Url as g, decodeBase64 as h, initLoggerWithGlobalConfiguration as i, encrypt as j, logger as l };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "happy-coder",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Claude Code session sharing CLI",
|
|
5
5
|
"author": "Kirill Dubovitskiy",
|
|
6
6
|
"license": "MIT",
|
|
@@ -49,13 +49,13 @@
|
|
|
49
49
|
"build": "shx rm -rf dist && tsc --noEmit && pkgroll",
|
|
50
50
|
"prepublishOnly": "yarn build && yarn test",
|
|
51
51
|
"typecheck": "tsc --noEmit",
|
|
52
|
-
"dev": "npx tsx --env-file .env.sample src/index.ts",
|
|
53
|
-
"dev:local-server": "cross-env HANDY_SERVER_URL=http://localhost:3005 tsx --env-file .env.sample src/index.ts",
|
|
52
|
+
"dev": "yarn build && npx tsx --env-file .env.sample src/index.ts",
|
|
53
|
+
"dev:local-server": "yarn build && cross-env HANDY_SERVER_URL=http://localhost:3005 tsx --env-file .env.sample src/index.ts",
|
|
54
54
|
"version:prerelease": "npm version prerelease --preid=beta",
|
|
55
55
|
"publish:prerelease": "npm publish --tag beta"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
|
-
"@anthropic-ai/claude-code": "^1.0.
|
|
58
|
+
"@anthropic-ai/claude-code": "^1.0.73",
|
|
59
59
|
"@anthropic-ai/sdk": "^0.56.0",
|
|
60
60
|
"@modelcontextprotocol/sdk": "^1.15.1",
|
|
61
61
|
"@stablelib/base64": "^2.0.1",
|
|
@@ -91,4 +91,4 @@
|
|
|
91
91
|
"overrides": {
|
|
92
92
|
"whatwg-url": "14.2.0"
|
|
93
93
|
}
|
|
94
|
-
}
|
|
94
|
+
}
|