happy-coder 0.10.0-4 → 0.10.1
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-67rskwL7.cjs → index-B_nemqpL.cjs} +99 -10
- package/dist/{index-Dw96QD4T.mjs → index-Cp1f1oto.mjs} +77 -10
- package/dist/index.cjs +3 -2
- package/dist/index.mjs +3 -2
- package/dist/lib.cjs +1 -1
- package/dist/lib.d.cts +2 -0
- package/dist/lib.d.mts +2 -0
- package/dist/lib.mjs +1 -1
- package/dist/{runCodex-BLNf5zb1.cjs → runCodex-BjT2Vmcd.cjs} +94 -14
- package/dist/{runCodex-BNH8w4O9.mjs → runCodex-CHAghw9e.mjs} +94 -14
- package/dist/{types-2wHnX7UW.mjs → types-CYZG1S69.mjs} +8 -5
- package/dist/{types-BcDnTXMg.cjs → types-DOKP_I5s.cjs} +9 -6
- package/package.json +5 -3
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
var chalk = require('chalk');
|
|
4
4
|
var os = require('node:os');
|
|
5
5
|
var node_crypto = require('node:crypto');
|
|
6
|
-
var types = require('./types-
|
|
6
|
+
var types = require('./types-DOKP_I5s.cjs');
|
|
7
7
|
var node_child_process = require('node:child_process');
|
|
8
8
|
var node_path = require('node:path');
|
|
9
9
|
var node_readline = require('node:readline');
|
|
@@ -25,6 +25,7 @@ var path = require('path');
|
|
|
25
25
|
var psList = require('ps-list');
|
|
26
26
|
var spawn = require('cross-spawn');
|
|
27
27
|
var os$1 = require('os');
|
|
28
|
+
var tmp = require('tmp');
|
|
28
29
|
var qrcode = require('qrcode-terminal');
|
|
29
30
|
var open = require('open');
|
|
30
31
|
var fastify = require('fastify');
|
|
@@ -37,6 +38,25 @@ var http = require('http');
|
|
|
37
38
|
var util = require('util');
|
|
38
39
|
|
|
39
40
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
41
|
+
function _interopNamespaceDefault(e) {
|
|
42
|
+
var n = Object.create(null);
|
|
43
|
+
if (e) {
|
|
44
|
+
Object.keys(e).forEach(function (k) {
|
|
45
|
+
if (k !== 'default') {
|
|
46
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
47
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
48
|
+
enumerable: true,
|
|
49
|
+
get: function () { return e[k]; }
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
n.default = e;
|
|
55
|
+
return Object.freeze(n);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
var tmp__namespace = /*#__PURE__*/_interopNamespaceDefault(tmp);
|
|
59
|
+
|
|
40
60
|
class Session {
|
|
41
61
|
path;
|
|
42
62
|
logPath;
|
|
@@ -166,9 +186,39 @@ function trimIdent(text) {
|
|
|
166
186
|
return trimmedLines.join("\n");
|
|
167
187
|
}
|
|
168
188
|
|
|
169
|
-
|
|
170
|
-
|
|
189
|
+
function getClaudeSettingsPath() {
|
|
190
|
+
const claudeConfigDir = process.env.CLAUDE_CONFIG_DIR || node_path.join(os.homedir(), ".claude");
|
|
191
|
+
return node_path.join(claudeConfigDir, "settings.json");
|
|
192
|
+
}
|
|
193
|
+
function readClaudeSettings() {
|
|
194
|
+
try {
|
|
195
|
+
const settingsPath = getClaudeSettingsPath();
|
|
196
|
+
if (!fs.existsSync(settingsPath)) {
|
|
197
|
+
types.logger.debug(`[ClaudeSettings] No Claude settings file found at ${settingsPath}`);
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
const settingsContent = fs.readFileSync(settingsPath, "utf-8");
|
|
201
|
+
const settings = JSON.parse(settingsContent);
|
|
202
|
+
types.logger.debug(`[ClaudeSettings] Successfully read Claude settings from ${settingsPath}`);
|
|
203
|
+
types.logger.debug(`[ClaudeSettings] includeCoAuthoredBy: ${settings.includeCoAuthoredBy}`);
|
|
204
|
+
return settings;
|
|
205
|
+
} catch (error) {
|
|
206
|
+
types.logger.debug(`[ClaudeSettings] Error reading Claude settings: ${error}`);
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
function shouldIncludeCoAuthoredBy() {
|
|
211
|
+
const settings = readClaudeSettings();
|
|
212
|
+
if (!settings || settings.includeCoAuthoredBy === void 0) {
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
return settings.includeCoAuthoredBy;
|
|
216
|
+
}
|
|
171
217
|
|
|
218
|
+
const BASE_SYSTEM_PROMPT = (() => trimIdent(`
|
|
219
|
+
ALWAYS when you start a new chat - you must call a tool "mcp__happy__change_title" to set a chat title. When you think chat title is not relevant anymore - call the tool again to change it. When chat name is too generic and you have a change to make it more specific - call the tool again to change it. This title is needed to easily find the chat in the future. Help human.
|
|
220
|
+
`))();
|
|
221
|
+
const CO_AUTHORED_CREDITS = (() => trimIdent(`
|
|
172
222
|
When making commit messages, instead of just giving co-credit to Claude, also give credit to Happy like so:
|
|
173
223
|
|
|
174
224
|
<main commit message>
|
|
@@ -178,7 +228,15 @@ const systemPrompt = trimIdent(`
|
|
|
178
228
|
|
|
179
229
|
Co-Authored-By: Claude <noreply@anthropic.com>
|
|
180
230
|
Co-Authored-By: Happy <yesreply@happy.engineering>
|
|
181
|
-
`);
|
|
231
|
+
`))();
|
|
232
|
+
const systemPrompt = (() => {
|
|
233
|
+
const includeCoAuthored = shouldIncludeCoAuthoredBy();
|
|
234
|
+
if (includeCoAuthored) {
|
|
235
|
+
return BASE_SYSTEM_PROMPT + "\n\n" + CO_AUTHORED_CREDITS;
|
|
236
|
+
} else {
|
|
237
|
+
return BASE_SYSTEM_PROMPT;
|
|
238
|
+
}
|
|
239
|
+
})();
|
|
182
240
|
|
|
183
241
|
const claudeCliPath = node_path.resolve(node_path.join(types.projectPath(), "scripts", "claude_local_launcher.cjs"));
|
|
184
242
|
async function claudeLocal(opts) {
|
|
@@ -923,7 +981,7 @@ class AbortError extends Error {
|
|
|
923
981
|
}
|
|
924
982
|
}
|
|
925
983
|
|
|
926
|
-
const __filename$1 = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-
|
|
984
|
+
const __filename$1 = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-B_nemqpL.cjs', document.baseURI).href)));
|
|
927
985
|
const __dirname$1 = node_path.join(__filename$1, "..");
|
|
928
986
|
function getDefaultClaudeCodePath() {
|
|
929
987
|
return node_path.join(__dirname$1, "..", "..", "..", "node_modules", "@anthropic-ai", "claude-code", "cli.js");
|
|
@@ -4268,7 +4326,22 @@ async function startDaemon() {
|
|
|
4268
4326
|
}
|
|
4269
4327
|
}
|
|
4270
4328
|
try {
|
|
4329
|
+
let extraEnv = {};
|
|
4330
|
+
if (options.token) {
|
|
4331
|
+
if (options.agent === "codex") {
|
|
4332
|
+
const codexHomeDir = tmp__namespace.dirSync();
|
|
4333
|
+
fs$1.writeFile(path.join(codexHomeDir.name, "auth.json"), options.token);
|
|
4334
|
+
extraEnv = {
|
|
4335
|
+
CODEX_HOME: codexHomeDir.name
|
|
4336
|
+
};
|
|
4337
|
+
} else {
|
|
4338
|
+
extraEnv = {
|
|
4339
|
+
CLAUDE_CODE_OAUTH_TOKEN: options.token
|
|
4340
|
+
};
|
|
4341
|
+
}
|
|
4342
|
+
}
|
|
4271
4343
|
const args = [
|
|
4344
|
+
options.agent === "claude" ? "claude" : "codex",
|
|
4272
4345
|
"--happy-starting-mode",
|
|
4273
4346
|
"remote",
|
|
4274
4347
|
"--started-by",
|
|
@@ -4278,9 +4351,12 @@ async function startDaemon() {
|
|
|
4278
4351
|
cwd: directory,
|
|
4279
4352
|
detached: true,
|
|
4280
4353
|
// Sessions stay alive when daemon stops
|
|
4281
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
4354
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
4282
4355
|
// Capture stdout/stderr for debugging
|
|
4283
|
-
|
|
4356
|
+
env: {
|
|
4357
|
+
...process.env,
|
|
4358
|
+
...extraEnv
|
|
4359
|
+
}
|
|
4284
4360
|
});
|
|
4285
4361
|
if (process.env.DEBUG) {
|
|
4286
4362
|
happyProcess.stdout?.on("data", (data) => {
|
|
@@ -4631,7 +4707,8 @@ async function runClaude(credentials, options = {}) {
|
|
|
4631
4707
|
startedBy: options.startedBy || "terminal",
|
|
4632
4708
|
// Initialize lifecycle state
|
|
4633
4709
|
lifecycleState: "running",
|
|
4634
|
-
lifecycleStateSince: Date.now()
|
|
4710
|
+
lifecycleStateSince: Date.now(),
|
|
4711
|
+
flavor: "claude"
|
|
4635
4712
|
};
|
|
4636
4713
|
const response = await api.getOrCreateSession({ tag: sessionTag, metadata, state });
|
|
4637
4714
|
types.logger.debug(`Session created: ${response.id}`);
|
|
@@ -5726,11 +5803,17 @@ async function handleConnectVendor(vendor, displayName) {
|
|
|
5726
5803
|
return;
|
|
5727
5804
|
} else if (subcommand === "codex") {
|
|
5728
5805
|
try {
|
|
5729
|
-
const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex-
|
|
5806
|
+
const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex-BjT2Vmcd.cjs'); });
|
|
5807
|
+
let startedBy = void 0;
|
|
5808
|
+
for (let i = 1; i < args.length; i++) {
|
|
5809
|
+
if (args[i] === "--started-by") {
|
|
5810
|
+
startedBy = args[++i];
|
|
5811
|
+
}
|
|
5812
|
+
}
|
|
5730
5813
|
const {
|
|
5731
5814
|
credentials
|
|
5732
5815
|
} = await authAndSetupMachineIfNeeded();
|
|
5733
|
-
await runCodex({ credentials });
|
|
5816
|
+
await runCodex({ credentials, startedBy });
|
|
5734
5817
|
} catch (error) {
|
|
5735
5818
|
console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
|
|
5736
5819
|
if (process.env.DEBUG) {
|
|
@@ -5863,6 +5946,9 @@ ${chalk.bold("To clean up runaway processes:")} Use ${chalk.cyan("happy doctor c
|
|
|
5863
5946
|
}
|
|
5864
5947
|
return;
|
|
5865
5948
|
} else {
|
|
5949
|
+
if (args.length > 0 && args[0] === "claude") {
|
|
5950
|
+
args.shift();
|
|
5951
|
+
}
|
|
5866
5952
|
const options = {};
|
|
5867
5953
|
let showHelp = false;
|
|
5868
5954
|
let showVersion = false;
|
|
@@ -6029,5 +6115,8 @@ exports.MessageBuffer = MessageBuffer;
|
|
|
6029
6115
|
exports.MessageQueue2 = MessageQueue2;
|
|
6030
6116
|
exports.hashObject = hashObject;
|
|
6031
6117
|
exports.initialMachineMetadata = initialMachineMetadata;
|
|
6118
|
+
exports.notifyDaemonSessionStarted = notifyDaemonSessionStarted;
|
|
6119
|
+
exports.registerKillSessionHandler = registerKillSessionHandler;
|
|
6032
6120
|
exports.startHappyServer = startHappyServer;
|
|
6121
|
+
exports.stopCaffeinate = stopCaffeinate;
|
|
6033
6122
|
exports.trimIdent = trimIdent;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import os$1, { homedir } from 'node:os';
|
|
3
3
|
import { randomUUID, randomBytes } from 'node:crypto';
|
|
4
|
-
import { l as logger, p as projectPath, d as backoff, e as delay, R as RawJSONLinesSchema, f as AsyncLock, g as readDaemonState, h as clearDaemonState, b as packageJson, c as configuration, r as readSettings, i as readCredentials, j as encodeBase64, u as updateSettings, k as encodeBase64Url, m as decodeBase64, w as writeCredentialsLegacy, n as writeCredentialsDataKey, o as acquireDaemonLock, q as writeDaemonState, A as ApiClient, s as releaseDaemonLock, t as clearCredentials, v as clearMachineId, x as getLatestDaemonLog } from './types-
|
|
4
|
+
import { l as logger, p as projectPath, d as backoff, e as delay, R as RawJSONLinesSchema, f as AsyncLock, g as readDaemonState, h as clearDaemonState, b as packageJson, c as configuration, r as readSettings, i as readCredentials, j as encodeBase64, u as updateSettings, k as encodeBase64Url, m as decodeBase64, w as writeCredentialsLegacy, n as writeCredentialsDataKey, o as acquireDaemonLock, q as writeDaemonState, A as ApiClient, s as releaseDaemonLock, t as clearCredentials, v as clearMachineId, x as getLatestDaemonLog } from './types-CYZG1S69.mjs';
|
|
5
5
|
import { spawn, execSync, execFileSync } from 'node:child_process';
|
|
6
6
|
import { resolve, join } from 'node:path';
|
|
7
7
|
import { createInterface } from 'node:readline';
|
|
@@ -23,6 +23,7 @@ import { join as join$1 } from 'path';
|
|
|
23
23
|
import psList from 'ps-list';
|
|
24
24
|
import spawn$2 from 'cross-spawn';
|
|
25
25
|
import os from 'os';
|
|
26
|
+
import * as tmp from 'tmp';
|
|
26
27
|
import qrcode from 'qrcode-terminal';
|
|
27
28
|
import open from 'open';
|
|
28
29
|
import fastify from 'fastify';
|
|
@@ -163,9 +164,39 @@ function trimIdent(text) {
|
|
|
163
164
|
return trimmedLines.join("\n");
|
|
164
165
|
}
|
|
165
166
|
|
|
166
|
-
|
|
167
|
-
|
|
167
|
+
function getClaudeSettingsPath() {
|
|
168
|
+
const claudeConfigDir = process.env.CLAUDE_CONFIG_DIR || join(homedir(), ".claude");
|
|
169
|
+
return join(claudeConfigDir, "settings.json");
|
|
170
|
+
}
|
|
171
|
+
function readClaudeSettings() {
|
|
172
|
+
try {
|
|
173
|
+
const settingsPath = getClaudeSettingsPath();
|
|
174
|
+
if (!existsSync(settingsPath)) {
|
|
175
|
+
logger.debug(`[ClaudeSettings] No Claude settings file found at ${settingsPath}`);
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
const settingsContent = readFileSync(settingsPath, "utf-8");
|
|
179
|
+
const settings = JSON.parse(settingsContent);
|
|
180
|
+
logger.debug(`[ClaudeSettings] Successfully read Claude settings from ${settingsPath}`);
|
|
181
|
+
logger.debug(`[ClaudeSettings] includeCoAuthoredBy: ${settings.includeCoAuthoredBy}`);
|
|
182
|
+
return settings;
|
|
183
|
+
} catch (error) {
|
|
184
|
+
logger.debug(`[ClaudeSettings] Error reading Claude settings: ${error}`);
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
function shouldIncludeCoAuthoredBy() {
|
|
189
|
+
const settings = readClaudeSettings();
|
|
190
|
+
if (!settings || settings.includeCoAuthoredBy === void 0) {
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
return settings.includeCoAuthoredBy;
|
|
194
|
+
}
|
|
168
195
|
|
|
196
|
+
const BASE_SYSTEM_PROMPT = (() => trimIdent(`
|
|
197
|
+
ALWAYS when you start a new chat - you must call a tool "mcp__happy__change_title" to set a chat title. When you think chat title is not relevant anymore - call the tool again to change it. When chat name is too generic and you have a change to make it more specific - call the tool again to change it. This title is needed to easily find the chat in the future. Help human.
|
|
198
|
+
`))();
|
|
199
|
+
const CO_AUTHORED_CREDITS = (() => trimIdent(`
|
|
169
200
|
When making commit messages, instead of just giving co-credit to Claude, also give credit to Happy like so:
|
|
170
201
|
|
|
171
202
|
<main commit message>
|
|
@@ -175,7 +206,15 @@ const systemPrompt = trimIdent(`
|
|
|
175
206
|
|
|
176
207
|
Co-Authored-By: Claude <noreply@anthropic.com>
|
|
177
208
|
Co-Authored-By: Happy <yesreply@happy.engineering>
|
|
178
|
-
`);
|
|
209
|
+
`))();
|
|
210
|
+
const systemPrompt = (() => {
|
|
211
|
+
const includeCoAuthored = shouldIncludeCoAuthoredBy();
|
|
212
|
+
if (includeCoAuthored) {
|
|
213
|
+
return BASE_SYSTEM_PROMPT + "\n\n" + CO_AUTHORED_CREDITS;
|
|
214
|
+
} else {
|
|
215
|
+
return BASE_SYSTEM_PROMPT;
|
|
216
|
+
}
|
|
217
|
+
})();
|
|
179
218
|
|
|
180
219
|
const claudeCliPath = resolve(join(projectPath(), "scripts", "claude_local_launcher.cjs"));
|
|
181
220
|
async function claudeLocal(opts) {
|
|
@@ -4265,7 +4304,22 @@ async function startDaemon() {
|
|
|
4265
4304
|
}
|
|
4266
4305
|
}
|
|
4267
4306
|
try {
|
|
4307
|
+
let extraEnv = {};
|
|
4308
|
+
if (options.token) {
|
|
4309
|
+
if (options.agent === "codex") {
|
|
4310
|
+
const codexHomeDir = tmp.dirSync();
|
|
4311
|
+
fs.writeFile(join$1(codexHomeDir.name, "auth.json"), options.token);
|
|
4312
|
+
extraEnv = {
|
|
4313
|
+
CODEX_HOME: codexHomeDir.name
|
|
4314
|
+
};
|
|
4315
|
+
} else {
|
|
4316
|
+
extraEnv = {
|
|
4317
|
+
CLAUDE_CODE_OAUTH_TOKEN: options.token
|
|
4318
|
+
};
|
|
4319
|
+
}
|
|
4320
|
+
}
|
|
4268
4321
|
const args = [
|
|
4322
|
+
options.agent === "claude" ? "claude" : "codex",
|
|
4269
4323
|
"--happy-starting-mode",
|
|
4270
4324
|
"remote",
|
|
4271
4325
|
"--started-by",
|
|
@@ -4275,9 +4329,12 @@ async function startDaemon() {
|
|
|
4275
4329
|
cwd: directory,
|
|
4276
4330
|
detached: true,
|
|
4277
4331
|
// Sessions stay alive when daemon stops
|
|
4278
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
4332
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
4279
4333
|
// Capture stdout/stderr for debugging
|
|
4280
|
-
|
|
4334
|
+
env: {
|
|
4335
|
+
...process.env,
|
|
4336
|
+
...extraEnv
|
|
4337
|
+
}
|
|
4281
4338
|
});
|
|
4282
4339
|
if (process.env.DEBUG) {
|
|
4283
4340
|
happyProcess.stdout?.on("data", (data) => {
|
|
@@ -4628,7 +4685,8 @@ async function runClaude(credentials, options = {}) {
|
|
|
4628
4685
|
startedBy: options.startedBy || "terminal",
|
|
4629
4686
|
// Initialize lifecycle state
|
|
4630
4687
|
lifecycleState: "running",
|
|
4631
|
-
lifecycleStateSince: Date.now()
|
|
4688
|
+
lifecycleStateSince: Date.now(),
|
|
4689
|
+
flavor: "claude"
|
|
4632
4690
|
};
|
|
4633
4691
|
const response = await api.getOrCreateSession({ tag: sessionTag, metadata, state });
|
|
4634
4692
|
logger.debug(`Session created: ${response.id}`);
|
|
@@ -5723,11 +5781,17 @@ async function handleConnectVendor(vendor, displayName) {
|
|
|
5723
5781
|
return;
|
|
5724
5782
|
} else if (subcommand === "codex") {
|
|
5725
5783
|
try {
|
|
5726
|
-
const { runCodex } = await import('./runCodex-
|
|
5784
|
+
const { runCodex } = await import('./runCodex-CHAghw9e.mjs');
|
|
5785
|
+
let startedBy = void 0;
|
|
5786
|
+
for (let i = 1; i < args.length; i++) {
|
|
5787
|
+
if (args[i] === "--started-by") {
|
|
5788
|
+
startedBy = args[++i];
|
|
5789
|
+
}
|
|
5790
|
+
}
|
|
5727
5791
|
const {
|
|
5728
5792
|
credentials
|
|
5729
5793
|
} = await authAndSetupMachineIfNeeded();
|
|
5730
|
-
await runCodex({ credentials });
|
|
5794
|
+
await runCodex({ credentials, startedBy });
|
|
5731
5795
|
} catch (error) {
|
|
5732
5796
|
console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
|
|
5733
5797
|
if (process.env.DEBUG) {
|
|
@@ -5860,6 +5924,9 @@ ${chalk.bold("To clean up runaway processes:")} Use ${chalk.cyan("happy doctor c
|
|
|
5860
5924
|
}
|
|
5861
5925
|
return;
|
|
5862
5926
|
} else {
|
|
5927
|
+
if (args.length > 0 && args[0] === "claude") {
|
|
5928
|
+
args.shift();
|
|
5929
|
+
}
|
|
5863
5930
|
const options = {};
|
|
5864
5931
|
let showHelp = false;
|
|
5865
5932
|
let showVersion = false;
|
|
@@ -6022,4 +6089,4 @@ ${chalk.bold("Examples:")}
|
|
|
6022
6089
|
}
|
|
6023
6090
|
}
|
|
6024
6091
|
|
|
6025
|
-
export { MessageQueue2 as M, MessageBuffer as a, hashObject as h, initialMachineMetadata as i, startHappyServer as s, trimIdent as t };
|
|
6092
|
+
export { MessageQueue2 as M, MessageBuffer as a, stopCaffeinate as b, hashObject as h, initialMachineMetadata as i, notifyDaemonSessionStarted as n, registerKillSessionHandler as r, startHappyServer as s, trimIdent as t };
|
package/dist/index.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
require('chalk');
|
|
4
|
-
require('./index-
|
|
5
|
-
require('./types-
|
|
4
|
+
require('./index-B_nemqpL.cjs');
|
|
5
|
+
require('./types-DOKP_I5s.cjs');
|
|
6
6
|
require('zod');
|
|
7
7
|
require('node:child_process');
|
|
8
8
|
require('node:os');
|
|
@@ -27,6 +27,7 @@ require('path');
|
|
|
27
27
|
require('ps-list');
|
|
28
28
|
require('cross-spawn');
|
|
29
29
|
require('os');
|
|
30
|
+
require('tmp');
|
|
30
31
|
require('qrcode-terminal');
|
|
31
32
|
require('open');
|
|
32
33
|
require('fastify');
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import 'chalk';
|
|
2
|
-
import './index-
|
|
3
|
-
import './types-
|
|
2
|
+
import './index-Cp1f1oto.mjs';
|
|
3
|
+
import './types-CYZG1S69.mjs';
|
|
4
4
|
import 'zod';
|
|
5
5
|
import 'node:child_process';
|
|
6
6
|
import 'node:os';
|
|
@@ -25,6 +25,7 @@ import 'path';
|
|
|
25
25
|
import 'ps-list';
|
|
26
26
|
import 'cross-spawn';
|
|
27
27
|
import 'os';
|
|
28
|
+
import 'tmp';
|
|
28
29
|
import 'qrcode-terminal';
|
|
29
30
|
import 'open';
|
|
30
31
|
import 'fastify';
|
package/dist/lib.cjs
CHANGED
package/dist/lib.d.cts
CHANGED
package/dist/lib.d.mts
CHANGED
package/dist/lib.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { A as ApiClient, a as ApiSessionClient, R as RawJSONLinesSchema, c as configuration, l as logger } from './types-
|
|
1
|
+
export { A as ApiClient, a as ApiSessionClient, R as RawJSONLinesSchema, c as configuration, l as logger } from './types-CYZG1S69.mjs';
|
|
2
2
|
import 'axios';
|
|
3
3
|
import 'chalk';
|
|
4
4
|
import 'fs';
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
var ink = require('ink');
|
|
4
4
|
var React = require('react');
|
|
5
|
-
var types = require('./types-
|
|
5
|
+
var types = require('./types-DOKP_I5s.cjs');
|
|
6
6
|
var index_js = require('@modelcontextprotocol/sdk/client/index.js');
|
|
7
7
|
var stdio_js = require('@modelcontextprotocol/sdk/client/stdio.js');
|
|
8
8
|
var z = require('zod');
|
|
9
9
|
var types_js = require('@modelcontextprotocol/sdk/types.js');
|
|
10
10
|
var node_crypto = require('node:crypto');
|
|
11
|
-
var index = require('./index-
|
|
11
|
+
var index = require('./index-B_nemqpL.cjs');
|
|
12
12
|
var os = require('node:os');
|
|
13
13
|
var node_path = require('node:path');
|
|
14
14
|
var fs = require('node:fs');
|
|
@@ -32,6 +32,7 @@ require('node:readline');
|
|
|
32
32
|
require('node:url');
|
|
33
33
|
require('ps-list');
|
|
34
34
|
require('cross-spawn');
|
|
35
|
+
require('tmp');
|
|
35
36
|
require('qrcode-terminal');
|
|
36
37
|
require('open');
|
|
37
38
|
require('fastify');
|
|
@@ -182,8 +183,16 @@ class CodexMcpClient {
|
|
|
182
183
|
return this.sessionId !== null;
|
|
183
184
|
}
|
|
184
185
|
clearSession() {
|
|
186
|
+
const previousSessionId = this.sessionId;
|
|
185
187
|
this.sessionId = null;
|
|
186
|
-
types.logger.debug("[CodexMCP] Session cleared");
|
|
188
|
+
types.logger.debug("[CodexMCP] Session cleared, previous sessionId:", previousSessionId);
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Store the current session ID without clearing it, useful for abort handling
|
|
192
|
+
*/
|
|
193
|
+
storeSessionForResume() {
|
|
194
|
+
types.logger.debug("[CodexMCP] Storing session for potential resume:", this.sessionId);
|
|
195
|
+
return this.sessionId;
|
|
187
196
|
}
|
|
188
197
|
async disconnect() {
|
|
189
198
|
if (!this.connected) return;
|
|
@@ -681,6 +690,7 @@ const CodexDisplay = ({ messageBuffer, logPath, onExit }) => {
|
|
|
681
690
|
async function runCodex(opts) {
|
|
682
691
|
const sessionTag = node_crypto.randomUUID();
|
|
683
692
|
const api = await types.ApiClient.create(opts.credentials);
|
|
693
|
+
types.logger.debug(`[codex] Starting with options: startedBy=${opts.startedBy || "terminal"}`);
|
|
684
694
|
const settings = await types.readSettings();
|
|
685
695
|
let machineId = settings?.machineId;
|
|
686
696
|
if (!machineId) {
|
|
@@ -705,9 +715,9 @@ async function runCodex(opts) {
|
|
|
705
715
|
happyHomeDir: types.configuration.happyHomeDir,
|
|
706
716
|
happyLibDir: types.projectPath(),
|
|
707
717
|
happyToolsDir: node_path.resolve(types.projectPath(), "tools", "unpacked"),
|
|
708
|
-
startedFromDaemon:
|
|
718
|
+
startedFromDaemon: opts.startedBy === "daemon",
|
|
709
719
|
hostPid: process.pid,
|
|
710
|
-
startedBy: "terminal",
|
|
720
|
+
startedBy: opts.startedBy || "terminal",
|
|
711
721
|
// Initialize lifecycle state
|
|
712
722
|
lifecycleState: "running",
|
|
713
723
|
lifecycleStateSince: Date.now(),
|
|
@@ -715,6 +725,17 @@ async function runCodex(opts) {
|
|
|
715
725
|
};
|
|
716
726
|
const response = await api.getOrCreateSession({ tag: sessionTag, metadata, state });
|
|
717
727
|
const session = api.sessionSyncClient(response);
|
|
728
|
+
try {
|
|
729
|
+
types.logger.debug(`[START] Reporting session ${response.id} to daemon`);
|
|
730
|
+
const result = await index.notifyDaemonSessionStarted(response.id, metadata);
|
|
731
|
+
if (result.error) {
|
|
732
|
+
types.logger.debug(`[START] Failed to report to daemon (may not be running):`, result.error);
|
|
733
|
+
} else {
|
|
734
|
+
types.logger.debug(`[START] Reported session ${response.id} to daemon`);
|
|
735
|
+
}
|
|
736
|
+
} catch (error) {
|
|
737
|
+
types.logger.debug("[START] Failed to report to daemon (may not be running):", error);
|
|
738
|
+
}
|
|
718
739
|
const messageQueue = new index.MessageQueue2((mode) => index.hashObject({
|
|
719
740
|
permissionMode: mode.permissionMode,
|
|
720
741
|
model: mode.model
|
|
@@ -768,22 +789,54 @@ async function runCodex(opts) {
|
|
|
768
789
|
}
|
|
769
790
|
let abortController = new AbortController();
|
|
770
791
|
let shouldExit = false;
|
|
792
|
+
let storedSessionIdForResume = null;
|
|
771
793
|
async function handleAbort() {
|
|
772
|
-
types.logger.debug("[Codex] Abort requested");
|
|
794
|
+
types.logger.debug("[Codex] Abort requested - stopping current task");
|
|
773
795
|
try {
|
|
796
|
+
if (client.hasActiveSession()) {
|
|
797
|
+
storedSessionIdForResume = client.storeSessionForResume();
|
|
798
|
+
types.logger.debug("[Codex] Stored session for resume:", storedSessionIdForResume);
|
|
799
|
+
}
|
|
774
800
|
abortController.abort();
|
|
775
801
|
messageQueue.reset();
|
|
776
802
|
permissionHandler.reset();
|
|
777
803
|
reasoningProcessor.abort();
|
|
778
804
|
diffProcessor.reset();
|
|
779
|
-
types.logger.debug("[Codex] Abort completed");
|
|
805
|
+
types.logger.debug("[Codex] Abort completed - session remains active");
|
|
780
806
|
} catch (error) {
|
|
781
807
|
types.logger.debug("[Codex] Error during abort:", error);
|
|
782
808
|
} finally {
|
|
783
809
|
abortController = new AbortController();
|
|
784
810
|
}
|
|
785
811
|
}
|
|
812
|
+
const handleKillSession = async () => {
|
|
813
|
+
types.logger.debug("[Codex] Kill session requested - terminating process");
|
|
814
|
+
await handleAbort();
|
|
815
|
+
types.logger.debug("[Codex] Abort completed, proceeding with termination");
|
|
816
|
+
try {
|
|
817
|
+
if (session) {
|
|
818
|
+
session.updateMetadata((currentMetadata) => ({
|
|
819
|
+
...currentMetadata,
|
|
820
|
+
lifecycleState: "archived",
|
|
821
|
+
lifecycleStateSince: Date.now(),
|
|
822
|
+
archivedBy: "cli",
|
|
823
|
+
archiveReason: "User terminated"
|
|
824
|
+
}));
|
|
825
|
+
session.sendSessionDeath();
|
|
826
|
+
await session.flush();
|
|
827
|
+
await session.close();
|
|
828
|
+
}
|
|
829
|
+
index.stopCaffeinate();
|
|
830
|
+
happyServer.stop();
|
|
831
|
+
types.logger.debug("[Codex] Session termination complete, exiting");
|
|
832
|
+
process.exit(0);
|
|
833
|
+
} catch (error) {
|
|
834
|
+
types.logger.debug("[Codex] Error during session termination:", error);
|
|
835
|
+
process.exit(1);
|
|
836
|
+
}
|
|
837
|
+
};
|
|
786
838
|
session.rpcHandlerManager.registerHandler("abort", handleAbort);
|
|
839
|
+
index.registerKillSessionHandler(session.rpcHandlerManager, handleKillSession);
|
|
787
840
|
const messageBuffer = new index.MessageBuffer();
|
|
788
841
|
const hasTTY = process.stdout.isTTY && process.stdin.isTTY;
|
|
789
842
|
let inkInstance = null;
|
|
@@ -831,7 +884,8 @@ async function runCodex(opts) {
|
|
|
831
884
|
return acc;
|
|
832
885
|
};
|
|
833
886
|
var collectFilesRecursive = collectFilesRecursive2;
|
|
834
|
-
const
|
|
887
|
+
const codexHomeDir = process.env.CODEX_HOME || node_path.join(os.homedir(), ".codex");
|
|
888
|
+
const rootDir = node_path.join(codexHomeDir, "sessions");
|
|
835
889
|
const candidates = collectFilesRecursive2(rootDir).filter((full) => full.endsWith(`-${sessionId}.jsonl`)).filter((full) => {
|
|
836
890
|
try {
|
|
837
891
|
return fs.statSync(full).isFile();
|
|
@@ -998,8 +1052,13 @@ async function runCodex(opts) {
|
|
|
998
1052
|
let message = pending;
|
|
999
1053
|
pending = null;
|
|
1000
1054
|
if (!message) {
|
|
1001
|
-
const
|
|
1002
|
-
|
|
1055
|
+
const waitSignal = abortController.signal;
|
|
1056
|
+
const batch = await messageQueue.waitForMessagesAndGetAsString(waitSignal);
|
|
1057
|
+
if (!batch) {
|
|
1058
|
+
if (waitSignal.aborted && !shouldExit) {
|
|
1059
|
+
types.logger.debug("[codex]: Wait aborted while idle; ignoring and continuing");
|
|
1060
|
+
continue;
|
|
1061
|
+
}
|
|
1003
1062
|
types.logger.debug(`[codex]: batch=${!!batch}, shouldExit=${shouldExit}`);
|
|
1004
1063
|
break;
|
|
1005
1064
|
}
|
|
@@ -1072,9 +1131,22 @@ async function runCodex(opts) {
|
|
|
1072
1131
|
if (message.mode.model) {
|
|
1073
1132
|
startConfig.model = message.mode.model;
|
|
1074
1133
|
}
|
|
1134
|
+
let resumeFile = null;
|
|
1075
1135
|
if (nextExperimentalResume) {
|
|
1076
|
-
|
|
1136
|
+
resumeFile = nextExperimentalResume;
|
|
1077
1137
|
nextExperimentalResume = null;
|
|
1138
|
+
types.logger.debug("[Codex] Using resume file from mode change:", resumeFile);
|
|
1139
|
+
} else if (storedSessionIdForResume) {
|
|
1140
|
+
const abortResumeFile = findCodexResumeFile(storedSessionIdForResume);
|
|
1141
|
+
if (abortResumeFile) {
|
|
1142
|
+
resumeFile = abortResumeFile;
|
|
1143
|
+
types.logger.debug("[Codex] Using resume file from aborted session:", resumeFile);
|
|
1144
|
+
messageBuffer.addMessage("Resuming from aborted session...", "status");
|
|
1145
|
+
}
|
|
1146
|
+
storedSessionIdForResume = null;
|
|
1147
|
+
}
|
|
1148
|
+
if (resumeFile) {
|
|
1149
|
+
startConfig.config.experimental_resume = resumeFile;
|
|
1078
1150
|
}
|
|
1079
1151
|
await client.startSession(
|
|
1080
1152
|
startConfig,
|
|
@@ -1090,12 +1162,20 @@ async function runCodex(opts) {
|
|
|
1090
1162
|
}
|
|
1091
1163
|
} catch (error) {
|
|
1092
1164
|
types.logger.warn("Error in codex session:", error);
|
|
1093
|
-
|
|
1165
|
+
const isAbortError = error instanceof Error && error.name === "AbortError";
|
|
1166
|
+
if (isAbortError) {
|
|
1094
1167
|
messageBuffer.addMessage("Aborted by user", "status");
|
|
1095
1168
|
session.sendSessionEvent({ type: "message", message: "Aborted by user" });
|
|
1169
|
+
wasCreated = false;
|
|
1170
|
+
currentModeHash = null;
|
|
1171
|
+
types.logger.debug("[Codex] Marked session as not created after abort for proper resume");
|
|
1096
1172
|
} else {
|
|
1097
1173
|
messageBuffer.addMessage("Process exited unexpectedly", "status");
|
|
1098
1174
|
session.sendSessionEvent({ type: "message", message: "Process exited unexpectedly" });
|
|
1175
|
+
if (client.hasActiveSession()) {
|
|
1176
|
+
storedSessionIdForResume = client.storeSessionForResume();
|
|
1177
|
+
types.logger.debug("[Codex] Stored session after unexpected error:", storedSessionIdForResume);
|
|
1178
|
+
}
|
|
1099
1179
|
}
|
|
1100
1180
|
} finally {
|
|
1101
1181
|
permissionHandler.reset();
|
|
@@ -1107,7 +1187,7 @@ async function runCodex(opts) {
|
|
|
1107
1187
|
}
|
|
1108
1188
|
}
|
|
1109
1189
|
} finally {
|
|
1110
|
-
types.logger.debug("[codex]:
|
|
1190
|
+
types.logger.debug("[codex]: Final cleanup start");
|
|
1111
1191
|
logActiveHandles("cleanup-start");
|
|
1112
1192
|
try {
|
|
1113
1193
|
types.logger.debug("[codex]: sendSessionDeath");
|
|
@@ -1148,7 +1228,7 @@ async function runCodex(opts) {
|
|
|
1148
1228
|
}
|
|
1149
1229
|
messageBuffer.clear();
|
|
1150
1230
|
logActiveHandles("cleanup-end");
|
|
1151
|
-
types.logger.debug("[codex]:
|
|
1231
|
+
types.logger.debug("[codex]: Final cleanup completed");
|
|
1152
1232
|
}
|
|
1153
1233
|
}
|
|
1154
1234
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { useStdout, useInput, Box, Text, render } from 'ink';
|
|
2
2
|
import React, { useState, useRef, useEffect, useCallback } from 'react';
|
|
3
|
-
import { l as logger, A as ApiClient, r as readSettings, p as projectPath, c as configuration, b as packageJson } from './types-
|
|
3
|
+
import { l as logger, A as ApiClient, r as readSettings, p as projectPath, c as configuration, b as packageJson } from './types-CYZG1S69.mjs';
|
|
4
4
|
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
5
5
|
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
6
6
|
import { z } from 'zod';
|
|
7
7
|
import { ElicitRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
8
8
|
import { randomUUID } from 'node:crypto';
|
|
9
|
-
import { i as initialMachineMetadata, M as MessageQueue2, h as hashObject, a as MessageBuffer, s as startHappyServer, t as trimIdent } from './index-
|
|
9
|
+
import { i as initialMachineMetadata, n as notifyDaemonSessionStarted, M as MessageQueue2, h as hashObject, r as registerKillSessionHandler, a as MessageBuffer, s as startHappyServer, t as trimIdent, b as stopCaffeinate } from './index-Cp1f1oto.mjs';
|
|
10
10
|
import os from 'node:os';
|
|
11
11
|
import { resolve, join } from 'node:path';
|
|
12
12
|
import fs from 'node:fs';
|
|
@@ -30,6 +30,7 @@ import 'node:readline';
|
|
|
30
30
|
import 'node:url';
|
|
31
31
|
import 'ps-list';
|
|
32
32
|
import 'cross-spawn';
|
|
33
|
+
import 'tmp';
|
|
33
34
|
import 'qrcode-terminal';
|
|
34
35
|
import 'open';
|
|
35
36
|
import 'fastify';
|
|
@@ -180,8 +181,16 @@ class CodexMcpClient {
|
|
|
180
181
|
return this.sessionId !== null;
|
|
181
182
|
}
|
|
182
183
|
clearSession() {
|
|
184
|
+
const previousSessionId = this.sessionId;
|
|
183
185
|
this.sessionId = null;
|
|
184
|
-
logger.debug("[CodexMCP] Session cleared");
|
|
186
|
+
logger.debug("[CodexMCP] Session cleared, previous sessionId:", previousSessionId);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Store the current session ID without clearing it, useful for abort handling
|
|
190
|
+
*/
|
|
191
|
+
storeSessionForResume() {
|
|
192
|
+
logger.debug("[CodexMCP] Storing session for potential resume:", this.sessionId);
|
|
193
|
+
return this.sessionId;
|
|
185
194
|
}
|
|
186
195
|
async disconnect() {
|
|
187
196
|
if (!this.connected) return;
|
|
@@ -679,6 +688,7 @@ const CodexDisplay = ({ messageBuffer, logPath, onExit }) => {
|
|
|
679
688
|
async function runCodex(opts) {
|
|
680
689
|
const sessionTag = randomUUID();
|
|
681
690
|
const api = await ApiClient.create(opts.credentials);
|
|
691
|
+
logger.debug(`[codex] Starting with options: startedBy=${opts.startedBy || "terminal"}`);
|
|
682
692
|
const settings = await readSettings();
|
|
683
693
|
let machineId = settings?.machineId;
|
|
684
694
|
if (!machineId) {
|
|
@@ -703,9 +713,9 @@ async function runCodex(opts) {
|
|
|
703
713
|
happyHomeDir: configuration.happyHomeDir,
|
|
704
714
|
happyLibDir: projectPath(),
|
|
705
715
|
happyToolsDir: resolve(projectPath(), "tools", "unpacked"),
|
|
706
|
-
startedFromDaemon:
|
|
716
|
+
startedFromDaemon: opts.startedBy === "daemon",
|
|
707
717
|
hostPid: process.pid,
|
|
708
|
-
startedBy: "terminal",
|
|
718
|
+
startedBy: opts.startedBy || "terminal",
|
|
709
719
|
// Initialize lifecycle state
|
|
710
720
|
lifecycleState: "running",
|
|
711
721
|
lifecycleStateSince: Date.now(),
|
|
@@ -713,6 +723,17 @@ async function runCodex(opts) {
|
|
|
713
723
|
};
|
|
714
724
|
const response = await api.getOrCreateSession({ tag: sessionTag, metadata, state });
|
|
715
725
|
const session = api.sessionSyncClient(response);
|
|
726
|
+
try {
|
|
727
|
+
logger.debug(`[START] Reporting session ${response.id} to daemon`);
|
|
728
|
+
const result = await notifyDaemonSessionStarted(response.id, metadata);
|
|
729
|
+
if (result.error) {
|
|
730
|
+
logger.debug(`[START] Failed to report to daemon (may not be running):`, result.error);
|
|
731
|
+
} else {
|
|
732
|
+
logger.debug(`[START] Reported session ${response.id} to daemon`);
|
|
733
|
+
}
|
|
734
|
+
} catch (error) {
|
|
735
|
+
logger.debug("[START] Failed to report to daemon (may not be running):", error);
|
|
736
|
+
}
|
|
716
737
|
const messageQueue = new MessageQueue2((mode) => hashObject({
|
|
717
738
|
permissionMode: mode.permissionMode,
|
|
718
739
|
model: mode.model
|
|
@@ -766,22 +787,54 @@ async function runCodex(opts) {
|
|
|
766
787
|
}
|
|
767
788
|
let abortController = new AbortController();
|
|
768
789
|
let shouldExit = false;
|
|
790
|
+
let storedSessionIdForResume = null;
|
|
769
791
|
async function handleAbort() {
|
|
770
|
-
logger.debug("[Codex] Abort requested");
|
|
792
|
+
logger.debug("[Codex] Abort requested - stopping current task");
|
|
771
793
|
try {
|
|
794
|
+
if (client.hasActiveSession()) {
|
|
795
|
+
storedSessionIdForResume = client.storeSessionForResume();
|
|
796
|
+
logger.debug("[Codex] Stored session for resume:", storedSessionIdForResume);
|
|
797
|
+
}
|
|
772
798
|
abortController.abort();
|
|
773
799
|
messageQueue.reset();
|
|
774
800
|
permissionHandler.reset();
|
|
775
801
|
reasoningProcessor.abort();
|
|
776
802
|
diffProcessor.reset();
|
|
777
|
-
logger.debug("[Codex] Abort completed");
|
|
803
|
+
logger.debug("[Codex] Abort completed - session remains active");
|
|
778
804
|
} catch (error) {
|
|
779
805
|
logger.debug("[Codex] Error during abort:", error);
|
|
780
806
|
} finally {
|
|
781
807
|
abortController = new AbortController();
|
|
782
808
|
}
|
|
783
809
|
}
|
|
810
|
+
const handleKillSession = async () => {
|
|
811
|
+
logger.debug("[Codex] Kill session requested - terminating process");
|
|
812
|
+
await handleAbort();
|
|
813
|
+
logger.debug("[Codex] Abort completed, proceeding with termination");
|
|
814
|
+
try {
|
|
815
|
+
if (session) {
|
|
816
|
+
session.updateMetadata((currentMetadata) => ({
|
|
817
|
+
...currentMetadata,
|
|
818
|
+
lifecycleState: "archived",
|
|
819
|
+
lifecycleStateSince: Date.now(),
|
|
820
|
+
archivedBy: "cli",
|
|
821
|
+
archiveReason: "User terminated"
|
|
822
|
+
}));
|
|
823
|
+
session.sendSessionDeath();
|
|
824
|
+
await session.flush();
|
|
825
|
+
await session.close();
|
|
826
|
+
}
|
|
827
|
+
stopCaffeinate();
|
|
828
|
+
happyServer.stop();
|
|
829
|
+
logger.debug("[Codex] Session termination complete, exiting");
|
|
830
|
+
process.exit(0);
|
|
831
|
+
} catch (error) {
|
|
832
|
+
logger.debug("[Codex] Error during session termination:", error);
|
|
833
|
+
process.exit(1);
|
|
834
|
+
}
|
|
835
|
+
};
|
|
784
836
|
session.rpcHandlerManager.registerHandler("abort", handleAbort);
|
|
837
|
+
registerKillSessionHandler(session.rpcHandlerManager, handleKillSession);
|
|
785
838
|
const messageBuffer = new MessageBuffer();
|
|
786
839
|
const hasTTY = process.stdout.isTTY && process.stdin.isTTY;
|
|
787
840
|
let inkInstance = null;
|
|
@@ -829,7 +882,8 @@ async function runCodex(opts) {
|
|
|
829
882
|
return acc;
|
|
830
883
|
};
|
|
831
884
|
var collectFilesRecursive = collectFilesRecursive2;
|
|
832
|
-
const
|
|
885
|
+
const codexHomeDir = process.env.CODEX_HOME || join(os.homedir(), ".codex");
|
|
886
|
+
const rootDir = join(codexHomeDir, "sessions");
|
|
833
887
|
const candidates = collectFilesRecursive2(rootDir).filter((full) => full.endsWith(`-${sessionId}.jsonl`)).filter((full) => {
|
|
834
888
|
try {
|
|
835
889
|
return fs.statSync(full).isFile();
|
|
@@ -996,8 +1050,13 @@ async function runCodex(opts) {
|
|
|
996
1050
|
let message = pending;
|
|
997
1051
|
pending = null;
|
|
998
1052
|
if (!message) {
|
|
999
|
-
const
|
|
1000
|
-
|
|
1053
|
+
const waitSignal = abortController.signal;
|
|
1054
|
+
const batch = await messageQueue.waitForMessagesAndGetAsString(waitSignal);
|
|
1055
|
+
if (!batch) {
|
|
1056
|
+
if (waitSignal.aborted && !shouldExit) {
|
|
1057
|
+
logger.debug("[codex]: Wait aborted while idle; ignoring and continuing");
|
|
1058
|
+
continue;
|
|
1059
|
+
}
|
|
1001
1060
|
logger.debug(`[codex]: batch=${!!batch}, shouldExit=${shouldExit}`);
|
|
1002
1061
|
break;
|
|
1003
1062
|
}
|
|
@@ -1070,9 +1129,22 @@ async function runCodex(opts) {
|
|
|
1070
1129
|
if (message.mode.model) {
|
|
1071
1130
|
startConfig.model = message.mode.model;
|
|
1072
1131
|
}
|
|
1132
|
+
let resumeFile = null;
|
|
1073
1133
|
if (nextExperimentalResume) {
|
|
1074
|
-
|
|
1134
|
+
resumeFile = nextExperimentalResume;
|
|
1075
1135
|
nextExperimentalResume = null;
|
|
1136
|
+
logger.debug("[Codex] Using resume file from mode change:", resumeFile);
|
|
1137
|
+
} else if (storedSessionIdForResume) {
|
|
1138
|
+
const abortResumeFile = findCodexResumeFile(storedSessionIdForResume);
|
|
1139
|
+
if (abortResumeFile) {
|
|
1140
|
+
resumeFile = abortResumeFile;
|
|
1141
|
+
logger.debug("[Codex] Using resume file from aborted session:", resumeFile);
|
|
1142
|
+
messageBuffer.addMessage("Resuming from aborted session...", "status");
|
|
1143
|
+
}
|
|
1144
|
+
storedSessionIdForResume = null;
|
|
1145
|
+
}
|
|
1146
|
+
if (resumeFile) {
|
|
1147
|
+
startConfig.config.experimental_resume = resumeFile;
|
|
1076
1148
|
}
|
|
1077
1149
|
await client.startSession(
|
|
1078
1150
|
startConfig,
|
|
@@ -1088,12 +1160,20 @@ async function runCodex(opts) {
|
|
|
1088
1160
|
}
|
|
1089
1161
|
} catch (error) {
|
|
1090
1162
|
logger.warn("Error in codex session:", error);
|
|
1091
|
-
|
|
1163
|
+
const isAbortError = error instanceof Error && error.name === "AbortError";
|
|
1164
|
+
if (isAbortError) {
|
|
1092
1165
|
messageBuffer.addMessage("Aborted by user", "status");
|
|
1093
1166
|
session.sendSessionEvent({ type: "message", message: "Aborted by user" });
|
|
1167
|
+
wasCreated = false;
|
|
1168
|
+
currentModeHash = null;
|
|
1169
|
+
logger.debug("[Codex] Marked session as not created after abort for proper resume");
|
|
1094
1170
|
} else {
|
|
1095
1171
|
messageBuffer.addMessage("Process exited unexpectedly", "status");
|
|
1096
1172
|
session.sendSessionEvent({ type: "message", message: "Process exited unexpectedly" });
|
|
1173
|
+
if (client.hasActiveSession()) {
|
|
1174
|
+
storedSessionIdForResume = client.storeSessionForResume();
|
|
1175
|
+
logger.debug("[Codex] Stored session after unexpected error:", storedSessionIdForResume);
|
|
1176
|
+
}
|
|
1097
1177
|
}
|
|
1098
1178
|
} finally {
|
|
1099
1179
|
permissionHandler.reset();
|
|
@@ -1105,7 +1185,7 @@ async function runCodex(opts) {
|
|
|
1105
1185
|
}
|
|
1106
1186
|
}
|
|
1107
1187
|
} finally {
|
|
1108
|
-
logger.debug("[codex]:
|
|
1188
|
+
logger.debug("[codex]: Final cleanup start");
|
|
1109
1189
|
logActiveHandles("cleanup-start");
|
|
1110
1190
|
try {
|
|
1111
1191
|
logger.debug("[codex]: sendSessionDeath");
|
|
@@ -1146,7 +1226,7 @@ async function runCodex(opts) {
|
|
|
1146
1226
|
}
|
|
1147
1227
|
messageBuffer.clear();
|
|
1148
1228
|
logActiveHandles("cleanup-end");
|
|
1149
|
-
logger.debug("[codex]:
|
|
1229
|
+
logger.debug("[codex]: Final cleanup completed");
|
|
1150
1230
|
}
|
|
1151
1231
|
}
|
|
1152
1232
|
|
|
@@ -21,7 +21,7 @@ import { platform } from 'os';
|
|
|
21
21
|
import { Expo } from 'expo-server-sdk';
|
|
22
22
|
|
|
23
23
|
var name = "happy-coder";
|
|
24
|
-
var version = "0.10.
|
|
24
|
+
var version = "0.10.1";
|
|
25
25
|
var description = "Mobile and Web client for Claude Code and Codex";
|
|
26
26
|
var author = "Kirill Dubovitskiy";
|
|
27
27
|
var license = "MIT";
|
|
@@ -89,8 +89,8 @@ var scripts = {
|
|
|
89
89
|
postinstall: "node scripts/unpack-tools.cjs"
|
|
90
90
|
};
|
|
91
91
|
var dependencies = {
|
|
92
|
-
"@anthropic-ai/claude-code": "
|
|
93
|
-
"@anthropic-ai/sdk": "
|
|
92
|
+
"@anthropic-ai/claude-code": "1.0.120",
|
|
93
|
+
"@anthropic-ai/sdk": "0.56.0",
|
|
94
94
|
"@modelcontextprotocol/sdk": "^1.15.1",
|
|
95
95
|
"@stablelib/base64": "^2.0.1",
|
|
96
96
|
"@stablelib/hex": "^2.0.1",
|
|
@@ -99,6 +99,7 @@ var dependencies = {
|
|
|
99
99
|
"@types/ps-list": "^6.2.1",
|
|
100
100
|
"@types/qrcode-terminal": "^0.12.2",
|
|
101
101
|
"@types/react": "^19.1.9",
|
|
102
|
+
"@types/tmp": "^0.2.6",
|
|
102
103
|
axios: "^1.10.0",
|
|
103
104
|
chalk: "^5.4.1",
|
|
104
105
|
"cross-spawn": "^7.0.6",
|
|
@@ -114,6 +115,7 @@ var dependencies = {
|
|
|
114
115
|
react: "^19.1.1",
|
|
115
116
|
"socket.io-client": "^4.8.1",
|
|
116
117
|
tar: "^7.4.3",
|
|
118
|
+
tmp: "^0.2.5",
|
|
117
119
|
tweetnacl: "^1.0.3",
|
|
118
120
|
zod: "^3.23.8"
|
|
119
121
|
};
|
|
@@ -1627,11 +1629,12 @@ class ApiMachineClient {
|
|
|
1627
1629
|
requestShutdown
|
|
1628
1630
|
}) {
|
|
1629
1631
|
this.rpcHandlerManager.registerHandler("spawn-happy-session", async (params) => {
|
|
1630
|
-
const { directory, sessionId, machineId, approvedNewDirectoryCreation } = params || {};
|
|
1632
|
+
const { directory, sessionId, machineId, approvedNewDirectoryCreation, agent, token } = params || {};
|
|
1633
|
+
logger.debug(`[API MACHINE] Spawning session with params: ${JSON.stringify(params)}`);
|
|
1631
1634
|
if (!directory) {
|
|
1632
1635
|
throw new Error("Directory is required");
|
|
1633
1636
|
}
|
|
1634
|
-
const result = await spawnSession({ directory, sessionId, machineId, approvedNewDirectoryCreation });
|
|
1637
|
+
const result = await spawnSession({ directory, sessionId, machineId, approvedNewDirectoryCreation, agent, token });
|
|
1635
1638
|
switch (result.type) {
|
|
1636
1639
|
case "success":
|
|
1637
1640
|
logger.debug(`[API MACHINE] Spawned session ${result.sessionId}`);
|
|
@@ -42,7 +42,7 @@ function _interopNamespaceDefault(e) {
|
|
|
42
42
|
var z__namespace = /*#__PURE__*/_interopNamespaceDefault(z);
|
|
43
43
|
|
|
44
44
|
var name = "happy-coder";
|
|
45
|
-
var version = "0.10.
|
|
45
|
+
var version = "0.10.1";
|
|
46
46
|
var description = "Mobile and Web client for Claude Code and Codex";
|
|
47
47
|
var author = "Kirill Dubovitskiy";
|
|
48
48
|
var license = "MIT";
|
|
@@ -110,8 +110,8 @@ var scripts = {
|
|
|
110
110
|
postinstall: "node scripts/unpack-tools.cjs"
|
|
111
111
|
};
|
|
112
112
|
var dependencies = {
|
|
113
|
-
"@anthropic-ai/claude-code": "
|
|
114
|
-
"@anthropic-ai/sdk": "
|
|
113
|
+
"@anthropic-ai/claude-code": "1.0.120",
|
|
114
|
+
"@anthropic-ai/sdk": "0.56.0",
|
|
115
115
|
"@modelcontextprotocol/sdk": "^1.15.1",
|
|
116
116
|
"@stablelib/base64": "^2.0.1",
|
|
117
117
|
"@stablelib/hex": "^2.0.1",
|
|
@@ -120,6 +120,7 @@ var dependencies = {
|
|
|
120
120
|
"@types/ps-list": "^6.2.1",
|
|
121
121
|
"@types/qrcode-terminal": "^0.12.2",
|
|
122
122
|
"@types/react": "^19.1.9",
|
|
123
|
+
"@types/tmp": "^0.2.6",
|
|
123
124
|
axios: "^1.10.0",
|
|
124
125
|
chalk: "^5.4.1",
|
|
125
126
|
"cross-spawn": "^7.0.6",
|
|
@@ -135,6 +136,7 @@ var dependencies = {
|
|
|
135
136
|
react: "^19.1.1",
|
|
136
137
|
"socket.io-client": "^4.8.1",
|
|
137
138
|
tar: "^7.4.3",
|
|
139
|
+
tmp: "^0.2.5",
|
|
138
140
|
tweetnacl: "^1.0.3",
|
|
139
141
|
zod: "^3.23.8"
|
|
140
142
|
};
|
|
@@ -1015,7 +1017,7 @@ class RpcHandlerManager {
|
|
|
1015
1017
|
}
|
|
1016
1018
|
}
|
|
1017
1019
|
|
|
1018
|
-
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-
|
|
1020
|
+
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-DOKP_I5s.cjs', document.baseURI).href))));
|
|
1019
1021
|
function projectPath() {
|
|
1020
1022
|
const path$1 = path.resolve(__dirname$1, "..");
|
|
1021
1023
|
return path$1;
|
|
@@ -1648,11 +1650,12 @@ class ApiMachineClient {
|
|
|
1648
1650
|
requestShutdown
|
|
1649
1651
|
}) {
|
|
1650
1652
|
this.rpcHandlerManager.registerHandler("spawn-happy-session", async (params) => {
|
|
1651
|
-
const { directory, sessionId, machineId, approvedNewDirectoryCreation } = params || {};
|
|
1653
|
+
const { directory, sessionId, machineId, approvedNewDirectoryCreation, agent, token } = params || {};
|
|
1654
|
+
logger.debug(`[API MACHINE] Spawning session with params: ${JSON.stringify(params)}`);
|
|
1652
1655
|
if (!directory) {
|
|
1653
1656
|
throw new Error("Directory is required");
|
|
1654
1657
|
}
|
|
1655
|
-
const result = await spawnSession({ directory, sessionId, machineId, approvedNewDirectoryCreation });
|
|
1658
|
+
const result = await spawnSession({ directory, sessionId, machineId, approvedNewDirectoryCreation, agent, token });
|
|
1656
1659
|
switch (result.type) {
|
|
1657
1660
|
case "success":
|
|
1658
1661
|
logger.debug(`[API MACHINE] Spawned session ${result.sessionId}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "happy-coder",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"description": "Mobile and Web client for Claude Code and Codex",
|
|
5
5
|
"author": "Kirill Dubovitskiy",
|
|
6
6
|
"license": "MIT",
|
|
@@ -68,8 +68,8 @@
|
|
|
68
68
|
"postinstall": "node scripts/unpack-tools.cjs"
|
|
69
69
|
},
|
|
70
70
|
"dependencies": {
|
|
71
|
-
"@anthropic-ai/claude-code": "
|
|
72
|
-
"@anthropic-ai/sdk": "
|
|
71
|
+
"@anthropic-ai/claude-code": "1.0.120",
|
|
72
|
+
"@anthropic-ai/sdk": "0.56.0",
|
|
73
73
|
"@modelcontextprotocol/sdk": "^1.15.1",
|
|
74
74
|
"@stablelib/base64": "^2.0.1",
|
|
75
75
|
"@stablelib/hex": "^2.0.1",
|
|
@@ -78,6 +78,7 @@
|
|
|
78
78
|
"@types/ps-list": "^6.2.1",
|
|
79
79
|
"@types/qrcode-terminal": "^0.12.2",
|
|
80
80
|
"@types/react": "^19.1.9",
|
|
81
|
+
"@types/tmp": "^0.2.6",
|
|
81
82
|
"axios": "^1.10.0",
|
|
82
83
|
"chalk": "^5.4.1",
|
|
83
84
|
"cross-spawn": "^7.0.6",
|
|
@@ -93,6 +94,7 @@
|
|
|
93
94
|
"react": "^19.1.1",
|
|
94
95
|
"socket.io-client": "^4.8.1",
|
|
95
96
|
"tar": "^7.4.3",
|
|
97
|
+
"tmp": "^0.2.5",
|
|
96
98
|
"tweetnacl": "^1.0.3",
|
|
97
99
|
"zod": "^3.23.8"
|
|
98
100
|
},
|