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.
@@ -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-CsJGQvQ3.cjs');
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-tqOLc1Il.cjs', document.baseURI).href)));
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 `https://app.happy.engineering/terminal/connect#key=${publicKeyBase64}`;
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
- const credentials = {
3841
- secret: decrypted,
3842
- token
3843
- };
3844
- await types.writeCredentials(credentials);
3845
- console.log("\n\n\u2713 Authentication successful\n");
3846
- return credentials;
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
- // env is inherited automatically from parent process
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 = new types.ApiClient(credentials.token, credentials.secret);
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 = new types.ApiClient(credentials.token, credentials.secret);
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 "show-backup":
4986
- await handleAuthShowBackup();
4987
- break;
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 anthropic Store your Anthropic API key in Happy cloud
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 anthropic
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 = new types.ApiClient(credentials.token, credentials.secret);
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-BxLD6H6G.cjs'); });
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 --auth" first.'));
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 = new types.ApiClient(credentials.token, credentials.secret);
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-tqOLc1Il.cjs');
5
- require('./types-CsJGQvQ3.cjs');
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-DPVbp4Yx.mjs';
3
- import './types-xds_c-JJ.mjs';
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
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var types = require('./types-CsJGQvQ3.cjs');
3
+ var types = require('./types-CQOz_mPp.cjs');
4
4
  require('axios');
5
5
  require('chalk');
6
6
  require('fs');
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
- /** Secret key for encryption/decryption */
314
- secret: Uint8Array;
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 secret;
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
- constructor(token: string, secret: Uint8Array, session: Session);
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
- declare const SessionSchema: z.ZodObject<{
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
- createdAt: number;
471
- updatedAt: number;
440
+ encryptionKey: Uint8Array;
441
+ encryptionVariant: 'legacy' | 'dataKey';
442
+ metadata: Metadata;
472
443
  metadataVersion: number;
444
+ agentState: AgentState | null;
473
445
  agentStateVersion: number;
474
- metadata?: any;
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
- createdAt: number;
574
- updatedAt: number;
501
+ encryptionKey: Uint8Array;
502
+ encryptionVariant: 'legacy' | 'dataKey';
503
+ metadata: MachineMetadata;
575
504
  metadataVersion: number;
505
+ daemonState: DaemonState | null;
576
506
  daemonStateVersion: number;
577
- active: boolean;
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, secret: Uint8Array, machine: Machine);
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
- private readonly token;
801
- private readonly secret;
738
+ static create(credential: Credentials): Promise<ApiClient>;
739
+ private readonly credential;
802
740
  private readonly pushClient;
803
- constructor(token: string, secret: Uint8Array);
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;