happy-coder 0.10.0-3 → 0.10.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/README.md +10 -1
- package/dist/{index-DPVbp4Yx.mjs → index-BI37NnoW.mjs} +93 -87
- package/dist/{index-tqOLc1Il.cjs → index-ettJex_e.cjs} +115 -87
- package/dist/index.cjs +3 -2
- package/dist/index.mjs +3 -2
- package/dist/lib.cjs +1 -1
- package/dist/lib.d.cts +44 -110
- package/dist/lib.d.mts +44 -110
- package/dist/lib.mjs +1 -1
- package/dist/{runCodex-C07HQlsW.mjs → runCodex-HlLNepHI.mjs} +47 -6
- package/dist/{runCodex-BxLD6H6G.cjs → runCodex-QdQBx9HK.cjs} +47 -6
- package/dist/{types-xds_c-JJ.mjs → types-8Ad05p3x.mjs} +213 -166
- package/dist/{types-CsJGQvQ3.cjs → types-CQOz_mPp.cjs} +214 -166
- package/package.json +5 -2
|
@@ -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-CQOz_mPp.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;
|
|
@@ -923,7 +943,7 @@ class AbortError extends Error {
|
|
|
923
943
|
}
|
|
924
944
|
}
|
|
925
945
|
|
|
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-
|
|
946
|
+
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-ettJex_e.cjs', document.baseURI).href)));
|
|
927
947
|
const __dirname$1 = node_path.join(__filename$1, "..");
|
|
928
948
|
function getDefaultClaudeCodePath() {
|
|
929
949
|
return node_path.join(__dirname$1, "..", "..", "..", "node_modules", "@anthropic-ai", "claude-code", "cli.js");
|
|
@@ -3684,7 +3704,7 @@ function displayQRCode(url) {
|
|
|
3684
3704
|
|
|
3685
3705
|
function generateWebAuthUrl(publicKey) {
|
|
3686
3706
|
const publicKeyBase64 = types.encodeBase64(publicKey, "base64url");
|
|
3687
|
-
return
|
|
3707
|
+
return `${types.configuration.webappUrl}/terminal/connect#key=${publicKeyBase64}`;
|
|
3688
3708
|
}
|
|
3689
3709
|
|
|
3690
3710
|
async function openBrowser(url) {
|
|
@@ -3751,7 +3771,8 @@ async function doAuth() {
|
|
|
3751
3771
|
console.log(`[AUTH DEBUG] Sending auth request to: ${types.configuration.serverUrl}/v1/auth/request`);
|
|
3752
3772
|
console.log(`[AUTH DEBUG] Public key: ${types.encodeBase64(keypair.publicKey).substring(0, 20)}...`);
|
|
3753
3773
|
await axios.post(`${types.configuration.serverUrl}/v1/auth/request`, {
|
|
3754
|
-
publicKey: types.encodeBase64(keypair.publicKey)
|
|
3774
|
+
publicKey: types.encodeBase64(keypair.publicKey),
|
|
3775
|
+
supportsV2: true
|
|
3755
3776
|
});
|
|
3756
3777
|
console.log(`[AUTH DEBUG] Auth request sent successfully`);
|
|
3757
3778
|
} catch (error) {
|
|
@@ -3830,20 +3851,50 @@ async function waitForAuthentication(keypair) {
|
|
|
3830
3851
|
while (!cancelled) {
|
|
3831
3852
|
try {
|
|
3832
3853
|
const response = await axios.post(`${types.configuration.serverUrl}/v1/auth/request`, {
|
|
3833
|
-
publicKey: types.encodeBase64(keypair.publicKey)
|
|
3854
|
+
publicKey: types.encodeBase64(keypair.publicKey),
|
|
3855
|
+
supportsV2: true
|
|
3834
3856
|
});
|
|
3835
3857
|
if (response.data.state === "authorized") {
|
|
3836
3858
|
let token = response.data.token;
|
|
3837
3859
|
let r = types.decodeBase64(response.data.response);
|
|
3838
3860
|
let decrypted = decryptWithEphemeralKey(r, keypair.secretKey);
|
|
3839
3861
|
if (decrypted) {
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
|
|
3843
|
-
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
|
|
3862
|
+
if (decrypted.length === 32) {
|
|
3863
|
+
const credentials = {
|
|
3864
|
+
secret: decrypted,
|
|
3865
|
+
token
|
|
3866
|
+
};
|
|
3867
|
+
await types.writeCredentialsLegacy(credentials);
|
|
3868
|
+
console.log("\n\n\u2713 Authentication successful\n");
|
|
3869
|
+
return {
|
|
3870
|
+
encryption: {
|
|
3871
|
+
type: "legacy",
|
|
3872
|
+
secret: decrypted
|
|
3873
|
+
},
|
|
3874
|
+
token
|
|
3875
|
+
};
|
|
3876
|
+
} else {
|
|
3877
|
+
if (decrypted[0] === 0) {
|
|
3878
|
+
const credentials = {
|
|
3879
|
+
publicKey: decrypted.slice(1, 33),
|
|
3880
|
+
machineKey: node_crypto.randomBytes(32),
|
|
3881
|
+
token
|
|
3882
|
+
};
|
|
3883
|
+
await types.writeCredentialsDataKey(credentials);
|
|
3884
|
+
console.log("\n\n\u2713 Authentication successful\n");
|
|
3885
|
+
return {
|
|
3886
|
+
encryption: {
|
|
3887
|
+
type: "dataKey",
|
|
3888
|
+
publicKey: credentials.publicKey,
|
|
3889
|
+
machineKey: credentials.machineKey
|
|
3890
|
+
},
|
|
3891
|
+
token
|
|
3892
|
+
};
|
|
3893
|
+
} else {
|
|
3894
|
+
console.log("\n\nFailed to decrypt response. Please try again.");
|
|
3895
|
+
return null;
|
|
3896
|
+
}
|
|
3897
|
+
}
|
|
3847
3898
|
} else {
|
|
3848
3899
|
console.log("\n\nFailed to decrypt response. Please try again.");
|
|
3849
3900
|
return null;
|
|
@@ -3875,6 +3926,7 @@ function decryptWithEphemeralKey(encryptedBundle, recipientSecretKey) {
|
|
|
3875
3926
|
async function authAndSetupMachineIfNeeded() {
|
|
3876
3927
|
types.logger.debug("[AUTH] Starting auth and machine setup...");
|
|
3877
3928
|
let credentials = await types.readCredentials();
|
|
3929
|
+
let newAuth = false;
|
|
3878
3930
|
if (!credentials) {
|
|
3879
3931
|
types.logger.debug("[AUTH] No credentials found, starting authentication flow...");
|
|
3880
3932
|
const authResult = await doAuth();
|
|
@@ -3882,13 +3934,12 @@ async function authAndSetupMachineIfNeeded() {
|
|
|
3882
3934
|
throw new Error("Authentication failed or was cancelled");
|
|
3883
3935
|
}
|
|
3884
3936
|
credentials = authResult;
|
|
3937
|
+
newAuth = true;
|
|
3885
3938
|
} else {
|
|
3886
3939
|
types.logger.debug("[AUTH] Using existing credentials");
|
|
3887
3940
|
}
|
|
3888
3941
|
const settings = await types.updateSettings(async (s) => {
|
|
3889
|
-
if (!s.machineId) {
|
|
3890
|
-
const newMachineId = node_crypto.randomUUID();
|
|
3891
|
-
types.logger.debug(`[AUTH] No machine ID found, generating new one: ${newMachineId}; We will not create machine on startup since we don't have api client intialized`);
|
|
3942
|
+
if (newAuth || !s.machineId) {
|
|
3892
3943
|
return {
|
|
3893
3944
|
...s,
|
|
3894
3945
|
machineId: node_crypto.randomUUID()
|
|
@@ -4237,7 +4288,22 @@ async function startDaemon() {
|
|
|
4237
4288
|
}
|
|
4238
4289
|
}
|
|
4239
4290
|
try {
|
|
4291
|
+
let extraEnv = {};
|
|
4292
|
+
if (options.token) {
|
|
4293
|
+
if (options.agent === "codex") {
|
|
4294
|
+
const codexHomeDir = tmp__namespace.dirSync();
|
|
4295
|
+
fs$1.writeFile(path.join(codexHomeDir.name, "auth.json"), options.token);
|
|
4296
|
+
extraEnv = {
|
|
4297
|
+
CODEX_HOME: codexHomeDir.name
|
|
4298
|
+
};
|
|
4299
|
+
} else {
|
|
4300
|
+
extraEnv = {
|
|
4301
|
+
CLAUDE_CODE_OAUTH_TOKEN: options.token
|
|
4302
|
+
};
|
|
4303
|
+
}
|
|
4304
|
+
}
|
|
4240
4305
|
const args = [
|
|
4306
|
+
options.agent === "claude" ? "claude" : "codex",
|
|
4241
4307
|
"--happy-starting-mode",
|
|
4242
4308
|
"remote",
|
|
4243
4309
|
"--started-by",
|
|
@@ -4247,9 +4313,12 @@ async function startDaemon() {
|
|
|
4247
4313
|
cwd: directory,
|
|
4248
4314
|
detached: true,
|
|
4249
4315
|
// Sessions stay alive when daemon stops
|
|
4250
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
4316
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
4251
4317
|
// Capture stdout/stderr for debugging
|
|
4252
|
-
|
|
4318
|
+
env: {
|
|
4319
|
+
...process.env,
|
|
4320
|
+
...extraEnv
|
|
4321
|
+
}
|
|
4253
4322
|
});
|
|
4254
4323
|
if (process.env.DEBUG) {
|
|
4255
4324
|
happyProcess.stdout?.on("data", (data) => {
|
|
@@ -4368,7 +4437,7 @@ async function startDaemon() {
|
|
|
4368
4437
|
httpPort: controlPort,
|
|
4369
4438
|
startedAt: Date.now()
|
|
4370
4439
|
};
|
|
4371
|
-
const api =
|
|
4440
|
+
const api = await types.ApiClient.create(credentials);
|
|
4372
4441
|
const machine = await api.getOrCreateMachine({
|
|
4373
4442
|
machineId,
|
|
4374
4443
|
metadata: initialMachineMetadata,
|
|
@@ -4572,7 +4641,7 @@ async function runClaude(credentials, options = {}) {
|
|
|
4572
4641
|
types.logger.debug("Daemon spawn requested with local mode - forcing remote mode");
|
|
4573
4642
|
options.startingMode = "remote";
|
|
4574
4643
|
}
|
|
4575
|
-
const api =
|
|
4644
|
+
const api = await types.ApiClient.create(credentials);
|
|
4576
4645
|
let state = {};
|
|
4577
4646
|
const settings = await types.readSettings();
|
|
4578
4647
|
let machineId = settings?.machineId;
|
|
@@ -4600,7 +4669,8 @@ async function runClaude(credentials, options = {}) {
|
|
|
4600
4669
|
startedBy: options.startedBy || "terminal",
|
|
4601
4670
|
// Initialize lifecycle state
|
|
4602
4671
|
lifecycleState: "running",
|
|
4603
|
-
lifecycleStateSince: Date.now()
|
|
4672
|
+
lifecycleStateSince: Date.now(),
|
|
4673
|
+
flavor: "claude"
|
|
4604
4674
|
};
|
|
4605
4675
|
const response = await api.getOrCreateSession({ tag: sessionTag, metadata, state });
|
|
4606
4676
|
types.logger.debug(`Session created: ${response.id}`);
|
|
@@ -4942,33 +5012,6 @@ async function uninstall() {
|
|
|
4942
5012
|
await uninstall$1();
|
|
4943
5013
|
}
|
|
4944
5014
|
|
|
4945
|
-
const BASE32_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
|
4946
|
-
function bytesToBase32(bytes) {
|
|
4947
|
-
let result = "";
|
|
4948
|
-
let buffer = 0;
|
|
4949
|
-
let bufferLength = 0;
|
|
4950
|
-
for (const byte of bytes) {
|
|
4951
|
-
buffer = buffer << 8 | byte;
|
|
4952
|
-
bufferLength += 8;
|
|
4953
|
-
while (bufferLength >= 5) {
|
|
4954
|
-
bufferLength -= 5;
|
|
4955
|
-
result += BASE32_ALPHABET[buffer >> bufferLength & 31];
|
|
4956
|
-
}
|
|
4957
|
-
}
|
|
4958
|
-
if (bufferLength > 0) {
|
|
4959
|
-
result += BASE32_ALPHABET[buffer << 5 - bufferLength & 31];
|
|
4960
|
-
}
|
|
4961
|
-
return result;
|
|
4962
|
-
}
|
|
4963
|
-
function formatSecretKeyForBackup(secretBytes) {
|
|
4964
|
-
const base32 = bytesToBase32(secretBytes);
|
|
4965
|
-
const groups = [];
|
|
4966
|
-
for (let i = 0; i < base32.length; i += 5) {
|
|
4967
|
-
groups.push(base32.slice(i, i + 5));
|
|
4968
|
-
}
|
|
4969
|
-
return groups.join("-");
|
|
4970
|
-
}
|
|
4971
|
-
|
|
4972
5015
|
async function handleAuthCommand(args) {
|
|
4973
5016
|
const subcommand = args[0];
|
|
4974
5017
|
if (!subcommand || subcommand === "help" || subcommand === "--help" || subcommand === "-h") {
|
|
@@ -4982,9 +5025,9 @@ async function handleAuthCommand(args) {
|
|
|
4982
5025
|
case "logout":
|
|
4983
5026
|
await handleAuthLogout();
|
|
4984
5027
|
break;
|
|
4985
|
-
case
|
|
4986
|
-
|
|
4987
|
-
|
|
5028
|
+
// case 'backup':
|
|
5029
|
+
// await handleAuthShowBackup();
|
|
5030
|
+
// break;
|
|
4988
5031
|
case "status":
|
|
4989
5032
|
await handleAuthStatus();
|
|
4990
5033
|
break;
|
|
@@ -5007,11 +5050,6 @@ ${chalk.bold("Usage:")}
|
|
|
5007
5050
|
|
|
5008
5051
|
${chalk.bold("Options:")}
|
|
5009
5052
|
--force Clear credentials, machine ID, and stop daemon before re-auth
|
|
5010
|
-
|
|
5011
|
-
${chalk.bold("Notes:")}
|
|
5012
|
-
\u2022 Use 'auth login --force' when you need to re-register your machine
|
|
5013
|
-
\u2022 'auth show-backup' displays the key format expected by mobile/web clients
|
|
5014
|
-
\u2022 The backup key allows linking multiple devices to the same account
|
|
5015
5053
|
`);
|
|
5016
5054
|
}
|
|
5017
5055
|
async function handleAuthLogin(args) {
|
|
@@ -5096,31 +5134,6 @@ async function handleAuthLogout() {
|
|
|
5096
5134
|
console.log(chalk.blue("Logout cancelled"));
|
|
5097
5135
|
}
|
|
5098
5136
|
}
|
|
5099
|
-
async function handleAuthShowBackup() {
|
|
5100
|
-
const credentials = await types.readCredentials();
|
|
5101
|
-
const settings = await types.readSettings();
|
|
5102
|
-
if (!credentials) {
|
|
5103
|
-
console.log(chalk.yellow("Not authenticated"));
|
|
5104
|
-
console.log(chalk.gray('Run "happy auth login" to authenticate first'));
|
|
5105
|
-
return;
|
|
5106
|
-
}
|
|
5107
|
-
const formattedBackupKey = formatSecretKeyForBackup(credentials.secret);
|
|
5108
|
-
console.log(chalk.bold("\n\u{1F4F1} Backup Key\n"));
|
|
5109
|
-
console.log(chalk.cyan("Your backup key:"));
|
|
5110
|
-
console.log(chalk.bold(formattedBackupKey));
|
|
5111
|
-
console.log("");
|
|
5112
|
-
console.log(chalk.cyan("Machine Information:"));
|
|
5113
|
-
console.log(` Machine ID: ${settings?.machineId || "not set"}`);
|
|
5114
|
-
console.log(` Host: ${os.hostname()}`);
|
|
5115
|
-
console.log("");
|
|
5116
|
-
console.log(chalk.bold("How to use this backup key:"));
|
|
5117
|
-
console.log(chalk.gray("\u2022 In Happy mobile app: Go to restore/link device and enter this key"));
|
|
5118
|
-
console.log(chalk.gray("\u2022 This key format matches what the mobile app expects"));
|
|
5119
|
-
console.log(chalk.gray("\u2022 You can type it with or without dashes - the app will normalize it"));
|
|
5120
|
-
console.log(chalk.gray("\u2022 Common typos (0\u2192O, 1\u2192I) are automatically corrected"));
|
|
5121
|
-
console.log("");
|
|
5122
|
-
console.log(chalk.yellow("\u26A0\uFE0F Keep this key secure - it provides full access to your account"));
|
|
5123
|
-
}
|
|
5124
5137
|
async function handleAuthStatus() {
|
|
5125
5138
|
const credentials = await types.readCredentials();
|
|
5126
5139
|
const settings = await types.readSettings();
|
|
@@ -5657,7 +5670,7 @@ ${chalk.bold("happy connect")} - Connect AI vendor API keys to Happy cloud
|
|
|
5657
5670
|
|
|
5658
5671
|
${chalk.bold("Usage:")}
|
|
5659
5672
|
happy connect codex Store your Codex API key in Happy cloud
|
|
5660
|
-
happy connect
|
|
5673
|
+
happy connect claude Store your Anthropic API key in Happy cloud
|
|
5661
5674
|
happy connect gemini Store your Gemini API key in Happy cloud
|
|
5662
5675
|
happy connect help Show this help message
|
|
5663
5676
|
|
|
@@ -5668,7 +5681,7 @@ ${chalk.bold("Description:")}
|
|
|
5668
5681
|
|
|
5669
5682
|
${chalk.bold("Examples:")}
|
|
5670
5683
|
happy connect codex
|
|
5671
|
-
happy connect
|
|
5684
|
+
happy connect claude
|
|
5672
5685
|
happy connect gemini
|
|
5673
5686
|
|
|
5674
5687
|
${chalk.bold("Notes:")}
|
|
@@ -5687,7 +5700,7 @@ async function handleConnectVendor(vendor, displayName) {
|
|
|
5687
5700
|
console.log(chalk.gray(' Please run "happy auth login" first'));
|
|
5688
5701
|
process.exit(1);
|
|
5689
5702
|
}
|
|
5690
|
-
const api =
|
|
5703
|
+
const api = await types.ApiClient.create(credentials);
|
|
5691
5704
|
if (vendor === "codex") {
|
|
5692
5705
|
console.log("\u{1F680} Registering Codex token with server");
|
|
5693
5706
|
const codexAuthTokens = await authenticateCodex();
|
|
@@ -5752,11 +5765,17 @@ async function handleConnectVendor(vendor, displayName) {
|
|
|
5752
5765
|
return;
|
|
5753
5766
|
} else if (subcommand === "codex") {
|
|
5754
5767
|
try {
|
|
5755
|
-
const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex-
|
|
5768
|
+
const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex-QdQBx9HK.cjs'); });
|
|
5769
|
+
let startedBy = void 0;
|
|
5770
|
+
for (let i = 1; i < args.length; i++) {
|
|
5771
|
+
if (args[i] === "--started-by") {
|
|
5772
|
+
startedBy = args[++i];
|
|
5773
|
+
}
|
|
5774
|
+
}
|
|
5756
5775
|
const {
|
|
5757
5776
|
credentials
|
|
5758
5777
|
} = await authAndSetupMachineIfNeeded();
|
|
5759
|
-
await runCodex(credentials);
|
|
5778
|
+
await runCodex({ credentials, startedBy });
|
|
5760
5779
|
} catch (error) {
|
|
5761
5780
|
console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
|
|
5762
5781
|
if (process.env.DEBUG) {
|
|
@@ -5889,6 +5908,9 @@ ${chalk.bold("To clean up runaway processes:")} Use ${chalk.cyan("happy doctor c
|
|
|
5889
5908
|
}
|
|
5890
5909
|
return;
|
|
5891
5910
|
} else {
|
|
5911
|
+
if (args.length > 0 && args[0] === "claude") {
|
|
5912
|
+
args.shift();
|
|
5913
|
+
}
|
|
5892
5914
|
const options = {};
|
|
5893
5915
|
let showHelp = false;
|
|
5894
5916
|
let showVersion = false;
|
|
@@ -5924,6 +5946,9 @@ ${chalk.bold("happy")} - Claude Code On the Go
|
|
|
5924
5946
|
${chalk.bold("Usage:")}
|
|
5925
5947
|
happy [options] Start Claude with mobile control
|
|
5926
5948
|
happy auth Manage authentication
|
|
5949
|
+
happy codex Start Codex mode
|
|
5950
|
+
happy connect Connect AI vendor API keys
|
|
5951
|
+
happy notify Send push notification
|
|
5927
5952
|
happy daemon Manage background service that allows
|
|
5928
5953
|
to spawn new sessions away from your computer
|
|
5929
5954
|
happy doctor System diagnostics & troubleshooting
|
|
@@ -6022,12 +6047,12 @@ ${chalk.bold("Examples:")}
|
|
|
6022
6047
|
}
|
|
6023
6048
|
let credentials = await types.readCredentials();
|
|
6024
6049
|
if (!credentials) {
|
|
6025
|
-
console.error(chalk.red('Error: Not authenticated. Please run "happy
|
|
6050
|
+
console.error(chalk.red('Error: Not authenticated. Please run "happy auth login" first.'));
|
|
6026
6051
|
process.exit(1);
|
|
6027
6052
|
}
|
|
6028
6053
|
console.log(chalk.blue("\u{1F4F1} Sending push notification..."));
|
|
6029
6054
|
try {
|
|
6030
|
-
const api =
|
|
6055
|
+
const api = await types.ApiClient.create(credentials);
|
|
6031
6056
|
const notificationTitle = title || "Happy";
|
|
6032
6057
|
api.push().sendToAllDevices(
|
|
6033
6058
|
notificationTitle,
|
|
@@ -6052,5 +6077,8 @@ exports.MessageBuffer = MessageBuffer;
|
|
|
6052
6077
|
exports.MessageQueue2 = MessageQueue2;
|
|
6053
6078
|
exports.hashObject = hashObject;
|
|
6054
6079
|
exports.initialMachineMetadata = initialMachineMetadata;
|
|
6080
|
+
exports.notifyDaemonSessionStarted = notifyDaemonSessionStarted;
|
|
6081
|
+
exports.registerKillSessionHandler = registerKillSessionHandler;
|
|
6055
6082
|
exports.startHappyServer = startHappyServer;
|
|
6083
|
+
exports.stopCaffeinate = stopCaffeinate;
|
|
6056
6084
|
exports.trimIdent = trimIdent;
|
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-ettJex_e.cjs');
|
|
5
|
+
require('./types-CQOz_mPp.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-BI37NnoW.mjs';
|
|
3
|
+
import './types-8Ad05p3x.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
|
@@ -308,11 +308,9 @@ interface RpcRequest {
|
|
|
308
308
|
* Configuration for RPC handler manager
|
|
309
309
|
*/
|
|
310
310
|
interface RpcHandlerConfig {
|
|
311
|
-
/** Prefix to add to all method names (e.g., sessionId or machineId) */
|
|
312
311
|
scopePrefix: string;
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
/** Logger function for debugging */
|
|
312
|
+
encryptionKey: Uint8Array;
|
|
313
|
+
encryptionVariant: 'legacy' | 'dataKey';
|
|
316
314
|
logger?: (message: string, data?: any) => void;
|
|
317
315
|
}
|
|
318
316
|
|
|
@@ -324,7 +322,8 @@ interface RpcHandlerConfig {
|
|
|
324
322
|
declare class RpcHandlerManager {
|
|
325
323
|
private handlers;
|
|
326
324
|
private readonly scopePrefix;
|
|
327
|
-
private readonly
|
|
325
|
+
private readonly encryptionKey;
|
|
326
|
+
private readonly encryptionVariant;
|
|
328
327
|
private readonly logger;
|
|
329
328
|
private socket;
|
|
330
329
|
constructor(config: RpcHandlerConfig);
|
|
@@ -364,7 +363,6 @@ declare class RpcHandlerManager {
|
|
|
364
363
|
|
|
365
364
|
declare class ApiSessionClient extends EventEmitter {
|
|
366
365
|
private readonly token;
|
|
367
|
-
private readonly secret;
|
|
368
366
|
readonly sessionId: string;
|
|
369
367
|
private metadata;
|
|
370
368
|
private metadataVersion;
|
|
@@ -376,7 +374,9 @@ declare class ApiSessionClient extends EventEmitter {
|
|
|
376
374
|
readonly rpcHandlerManager: RpcHandlerManager;
|
|
377
375
|
private agentStateLock;
|
|
378
376
|
private metadataLock;
|
|
379
|
-
|
|
377
|
+
private encryptionKey;
|
|
378
|
+
private encryptionVariant;
|
|
379
|
+
constructor(token: string, session: Session);
|
|
380
380
|
onUserMessage(callback: (data: UserMessage) => void): void;
|
|
381
381
|
/**
|
|
382
382
|
* Send message to session
|
|
@@ -434,53 +434,16 @@ type Usage = z.infer<typeof UsageSchema>;
|
|
|
434
434
|
/**
|
|
435
435
|
* Session information
|
|
436
436
|
*/
|
|
437
|
-
|
|
438
|
-
createdAt: z.ZodNumber;
|
|
439
|
-
id: z.ZodString;
|
|
440
|
-
seq: z.ZodNumber;
|
|
441
|
-
updatedAt: z.ZodNumber;
|
|
442
|
-
metadata: z.ZodAny;
|
|
443
|
-
metadataVersion: z.ZodNumber;
|
|
444
|
-
agentState: z.ZodNullable<z.ZodAny>;
|
|
445
|
-
agentStateVersion: z.ZodNumber;
|
|
446
|
-
connectivityStatus: z.ZodOptional<z.ZodUnion<[z.ZodEnum<["neverConnected", "online", "offline"]>, z.ZodString]>>;
|
|
447
|
-
connectivityStatusSince: z.ZodOptional<z.ZodNumber>;
|
|
448
|
-
connectivityStatusReason: z.ZodOptional<z.ZodString>;
|
|
449
|
-
state: z.ZodOptional<z.ZodUnion<[z.ZodEnum<["running", "archiveRequested", "archived"]>, z.ZodString]>>;
|
|
450
|
-
stateSince: z.ZodOptional<z.ZodNumber>;
|
|
451
|
-
stateReason: z.ZodOptional<z.ZodString>;
|
|
452
|
-
}, "strip", z.ZodTypeAny, {
|
|
453
|
-
id: string;
|
|
454
|
-
seq: number;
|
|
455
|
-
createdAt: number;
|
|
456
|
-
updatedAt: number;
|
|
457
|
-
metadataVersion: number;
|
|
458
|
-
agentStateVersion: number;
|
|
459
|
-
metadata?: any;
|
|
460
|
-
agentState?: any;
|
|
461
|
-
connectivityStatus?: string | undefined;
|
|
462
|
-
connectivityStatusSince?: number | undefined;
|
|
463
|
-
connectivityStatusReason?: string | undefined;
|
|
464
|
-
state?: string | undefined;
|
|
465
|
-
stateSince?: number | undefined;
|
|
466
|
-
stateReason?: string | undefined;
|
|
467
|
-
}, {
|
|
437
|
+
type Session = {
|
|
468
438
|
id: string;
|
|
469
439
|
seq: number;
|
|
470
|
-
|
|
471
|
-
|
|
440
|
+
encryptionKey: Uint8Array;
|
|
441
|
+
encryptionVariant: 'legacy' | 'dataKey';
|
|
442
|
+
metadata: Metadata;
|
|
472
443
|
metadataVersion: number;
|
|
444
|
+
agentState: AgentState | null;
|
|
473
445
|
agentStateVersion: number;
|
|
474
|
-
|
|
475
|
-
agentState?: any;
|
|
476
|
-
connectivityStatus?: string | undefined;
|
|
477
|
-
connectivityStatusSince?: number | undefined;
|
|
478
|
-
connectivityStatusReason?: string | undefined;
|
|
479
|
-
state?: string | undefined;
|
|
480
|
-
stateSince?: number | undefined;
|
|
481
|
-
stateReason?: string | undefined;
|
|
482
|
-
}>;
|
|
483
|
-
type Session = z.infer<typeof SessionSchema>;
|
|
446
|
+
};
|
|
484
447
|
/**
|
|
485
448
|
* Machine metadata - static information (rarely changes)
|
|
486
449
|
*/
|
|
@@ -533,59 +496,15 @@ declare const DaemonStateSchema: z.ZodObject<{
|
|
|
533
496
|
shutdownSource?: string | undefined;
|
|
534
497
|
}>;
|
|
535
498
|
type DaemonState = z.infer<typeof DaemonStateSchema>;
|
|
536
|
-
|
|
537
|
-
* Machine information - similar to Session
|
|
538
|
-
*/
|
|
539
|
-
declare const MachineSchema: z.ZodObject<{
|
|
540
|
-
id: z.ZodString;
|
|
541
|
-
metadata: z.ZodAny;
|
|
542
|
-
metadataVersion: z.ZodNumber;
|
|
543
|
-
daemonState: z.ZodNullable<z.ZodAny>;
|
|
544
|
-
daemonStateVersion: z.ZodNumber;
|
|
545
|
-
active: z.ZodBoolean;
|
|
546
|
-
activeAt: z.ZodNumber;
|
|
547
|
-
createdAt: z.ZodNumber;
|
|
548
|
-
updatedAt: z.ZodNumber;
|
|
549
|
-
connectivityStatus: z.ZodOptional<z.ZodUnion<[z.ZodEnum<["neverConnected", "online", "offline"]>, z.ZodString]>>;
|
|
550
|
-
connectivityStatusSince: z.ZodOptional<z.ZodNumber>;
|
|
551
|
-
connectivityStatusReason: z.ZodOptional<z.ZodString>;
|
|
552
|
-
state: z.ZodOptional<z.ZodUnion<[z.ZodEnum<["running", "archiveRequested", "archived"]>, z.ZodString]>>;
|
|
553
|
-
stateSince: z.ZodOptional<z.ZodNumber>;
|
|
554
|
-
stateReason: z.ZodOptional<z.ZodString>;
|
|
555
|
-
}, "strip", z.ZodTypeAny, {
|
|
556
|
-
id: string;
|
|
557
|
-
createdAt: number;
|
|
558
|
-
updatedAt: number;
|
|
559
|
-
metadataVersion: number;
|
|
560
|
-
daemonStateVersion: number;
|
|
561
|
-
active: boolean;
|
|
562
|
-
activeAt: number;
|
|
563
|
-
metadata?: any;
|
|
564
|
-
daemonState?: any;
|
|
565
|
-
connectivityStatus?: string | undefined;
|
|
566
|
-
connectivityStatusSince?: number | undefined;
|
|
567
|
-
connectivityStatusReason?: string | undefined;
|
|
568
|
-
state?: string | undefined;
|
|
569
|
-
stateSince?: number | undefined;
|
|
570
|
-
stateReason?: string | undefined;
|
|
571
|
-
}, {
|
|
499
|
+
type Machine = {
|
|
572
500
|
id: string;
|
|
573
|
-
|
|
574
|
-
|
|
501
|
+
encryptionKey: Uint8Array;
|
|
502
|
+
encryptionVariant: 'legacy' | 'dataKey';
|
|
503
|
+
metadata: MachineMetadata;
|
|
575
504
|
metadataVersion: number;
|
|
505
|
+
daemonState: DaemonState | null;
|
|
576
506
|
daemonStateVersion: number;
|
|
577
|
-
|
|
578
|
-
activeAt: number;
|
|
579
|
-
metadata?: any;
|
|
580
|
-
daemonState?: any;
|
|
581
|
-
connectivityStatus?: string | undefined;
|
|
582
|
-
connectivityStatusSince?: number | undefined;
|
|
583
|
-
connectivityStatusReason?: string | undefined;
|
|
584
|
-
state?: string | undefined;
|
|
585
|
-
stateSince?: number | undefined;
|
|
586
|
-
stateReason?: string | undefined;
|
|
587
|
-
}>;
|
|
588
|
-
type Machine = z.infer<typeof MachineSchema>;
|
|
507
|
+
};
|
|
589
508
|
declare const UserMessageSchema: z.ZodObject<{
|
|
590
509
|
role: z.ZodLiteral<"user">;
|
|
591
510
|
content: z.ZodObject<{
|
|
@@ -719,6 +638,8 @@ interface SpawnSessionOptions {
|
|
|
719
638
|
directory: string;
|
|
720
639
|
sessionId?: string;
|
|
721
640
|
approvedNewDirectoryCreation?: boolean;
|
|
641
|
+
agent?: 'claude' | 'codex';
|
|
642
|
+
token?: string;
|
|
722
643
|
}
|
|
723
644
|
type SpawnSessionResult = {
|
|
724
645
|
type: 'success';
|
|
@@ -743,12 +664,11 @@ type MachineRpcHandlers = {
|
|
|
743
664
|
};
|
|
744
665
|
declare class ApiMachineClient {
|
|
745
666
|
private token;
|
|
746
|
-
private secret;
|
|
747
667
|
private machine;
|
|
748
668
|
private socket;
|
|
749
669
|
private keepAliveInterval;
|
|
750
670
|
private rpcHandlerManager;
|
|
751
|
-
constructor(token: string,
|
|
671
|
+
constructor(token: string, machine: Machine);
|
|
752
672
|
setRPCHandlers({ spawnSession, stopSession, requestShutdown }: MachineRpcHandlers): void;
|
|
753
673
|
/**
|
|
754
674
|
* Update machine metadata
|
|
@@ -796,11 +716,29 @@ declare class PushNotificationClient {
|
|
|
796
716
|
sendToAllDevices(title: string, body: string, data?: Record<string, any>): void;
|
|
797
717
|
}
|
|
798
718
|
|
|
719
|
+
/**
|
|
720
|
+
* Minimal persistence functions for happy CLI
|
|
721
|
+
*
|
|
722
|
+
* Handles settings and private key storage in ~/.happy/ or local .happy/
|
|
723
|
+
*/
|
|
724
|
+
|
|
725
|
+
type Credentials = {
|
|
726
|
+
token: string;
|
|
727
|
+
encryption: {
|
|
728
|
+
type: 'legacy';
|
|
729
|
+
secret: Uint8Array;
|
|
730
|
+
} | {
|
|
731
|
+
type: 'dataKey';
|
|
732
|
+
publicKey: Uint8Array;
|
|
733
|
+
machineKey: Uint8Array;
|
|
734
|
+
};
|
|
735
|
+
};
|
|
736
|
+
|
|
799
737
|
declare class ApiClient {
|
|
800
|
-
|
|
801
|
-
private readonly
|
|
738
|
+
static create(credential: Credentials): Promise<ApiClient>;
|
|
739
|
+
private readonly credential;
|
|
802
740
|
private readonly pushClient;
|
|
803
|
-
constructor(
|
|
741
|
+
private constructor();
|
|
804
742
|
/**
|
|
805
743
|
* Create a new session or load existing one with the given tag
|
|
806
744
|
*/
|
|
@@ -809,11 +747,6 @@ declare class ApiClient {
|
|
|
809
747
|
metadata: Metadata;
|
|
810
748
|
state: AgentState | null;
|
|
811
749
|
}): Promise<Session>;
|
|
812
|
-
/**
|
|
813
|
-
* Get machine by ID from the server
|
|
814
|
-
* Returns the current machine state from the server with decrypted metadata and daemonState
|
|
815
|
-
*/
|
|
816
|
-
getMachine(machineId: string): Promise<Machine | null>;
|
|
817
750
|
/**
|
|
818
751
|
* Register or update machine with the server
|
|
819
752
|
* Returns the current machine state from the server with decrypted metadata and daemonState
|
|
@@ -864,6 +797,7 @@ declare let logger: Logger;
|
|
|
864
797
|
*/
|
|
865
798
|
declare class Configuration {
|
|
866
799
|
readonly serverUrl: string;
|
|
800
|
+
readonly webappUrl: string;
|
|
867
801
|
readonly isDaemonProcess: boolean;
|
|
868
802
|
readonly happyHomeDir: string;
|
|
869
803
|
readonly logsDir: string;
|