@zhigang1992/happy-cli 0.12.4 → 0.12.6

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.
@@ -29,10 +29,7 @@ async function main() {
29
29
  let httpClient = null;
30
30
  async function ensureHttpClient() {
31
31
  if (httpClient) return httpClient;
32
- const client = new index_js.Client(
33
- { name: "happy-stdio-bridge", version: "1.0.0" },
34
- { capabilities: { tools: {} } }
35
- );
32
+ const client = new index_js.Client({ name: "happy-stdio-bridge", version: "1.0.0" });
36
33
  const transport = new streamableHttp_js.StreamableHTTPClientTransport(new URL(baseUrl));
37
34
  await client.connect(transport);
38
35
  httpClient = client;
@@ -41,7 +38,7 @@ async function main() {
41
38
  const server = new mcp_js.McpServer({
42
39
  name: "Happy MCP Bridge",
43
40
  version: "1.0.0",
44
- description: "STDIO bridge forwarding to Happy HTTP MCP"
41
+ title: "STDIO bridge forwarding to Happy HTTP MCP"
45
42
  });
46
43
  server.registerTool(
47
44
  "change_title",
@@ -27,10 +27,7 @@ async function main() {
27
27
  let httpClient = null;
28
28
  async function ensureHttpClient() {
29
29
  if (httpClient) return httpClient;
30
- const client = new Client(
31
- { name: "happy-stdio-bridge", version: "1.0.0" },
32
- { capabilities: { tools: {} } }
33
- );
30
+ const client = new Client({ name: "happy-stdio-bridge", version: "1.0.0" });
34
31
  const transport = new StreamableHTTPClientTransport(new URL(baseUrl));
35
32
  await client.connect(transport);
36
33
  httpClient = client;
@@ -39,7 +36,7 @@ async function main() {
39
36
  const server = new McpServer({
40
37
  name: "Happy MCP Bridge",
41
38
  version: "1.0.0",
42
- description: "STDIO bridge forwarding to Happy HTTP MCP"
39
+ title: "STDIO bridge forwarding to Happy HTTP MCP"
43
40
  });
44
41
  server.registerTool(
45
42
  "change_title",
@@ -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-Q-euvEmG.cjs');
6
+ var types = require('./types-Bd_EJ8VV.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');
@@ -1082,7 +1082,7 @@ class AbortError extends Error {
1082
1082
  }
1083
1083
  }
1084
1084
 
1085
- 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-CHEjP0zg.cjs', document.baseURI).href)));
1085
+ 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-BkDVLUcE.cjs', document.baseURI).href)));
1086
1086
  const __dirname$1 = node_path.join(__filename$1, "..");
1087
1087
  function getDefaultClaudeCodePath() {
1088
1088
  return node_path.join(__dirname$1, "..", "..", "..", "node_modules", "@anthropic-ai", "claude-code", "cli.js");
@@ -4902,7 +4902,7 @@ async function startHappyServer(client) {
4902
4902
  const mcp = new mcp_js.McpServer({
4903
4903
  name: "Happy MCP",
4904
4904
  version: "1.0.0",
4905
- description: "Happy CLI MCP server with chat session management tools"
4905
+ title: "Happy CLI MCP Server"
4906
4906
  });
4907
4907
  mcp.registerTool("change_title", {
4908
4908
  description: "Change the title of the current chat session",
@@ -6393,7 +6393,7 @@ async function handleConnectVendor(vendor, displayName) {
6393
6393
  return;
6394
6394
  } else if (subcommand === "codex") {
6395
6395
  try {
6396
- const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex-DUqqO-m8.cjs'); });
6396
+ const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex-uPJ1h0J4.cjs'); });
6397
6397
  let startedBy = void 0;
6398
6398
  for (let i = 1; i < args.length; i++) {
6399
6399
  if (args[i] === "--started-by") {
@@ -6438,7 +6438,7 @@ async function handleConnectVendor(vendor, displayName) {
6438
6438
  } else if (subcommand === "list") {
6439
6439
  try {
6440
6440
  const { credentials } = await authAndSetupMachineIfNeeded();
6441
- const { listSessions } = await Promise.resolve().then(function () { return require('./list-DOsBjFRJ.cjs'); });
6441
+ const { listSessions } = await Promise.resolve().then(function () { return require('./list-LCFlAICJ.cjs'); });
6442
6442
  let sessionId;
6443
6443
  let titleFilter;
6444
6444
  let recentMsgs;
@@ -6540,7 +6540,7 @@ Examples:
6540
6540
  process.exit(1);
6541
6541
  }
6542
6542
  const { credentials } = await authAndSetupMachineIfNeeded();
6543
- const { promptSession } = await Promise.resolve().then(function () { return require('./prompt-Dh_trad0.cjs'); });
6543
+ const { promptSession } = await Promise.resolve().then(function () { return require('./prompt-B0ezty5F.cjs'); });
6544
6544
  await promptSession(credentials, sessionId, promptText, timeoutMinutes ?? void 0);
6545
6545
  } catch (error) {
6546
6546
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
@@ -1,7 +1,7 @@
1
1
  import chalk from 'chalk';
2
2
  import os$1, { homedir } from 'node:os';
3
3
  import { randomUUID, randomBytes, createHmac } from 'node:crypto';
4
- import { l as logger, p as projectPath, j as backoff, k as delay, R as RawJSONLinesSchema, m as AsyncLock, c as configuration, n as readDaemonState, o as clearDaemonState, i as packageJson, r as readSettings, q as readCredentials, g as encodeBase64, u as updateSettings, s as encodeBase64Url, d as decodeBase64, w as writeCredentialsLegacy, t as writeCredentialsDataKey, v as acquireDaemonLock, x as writeDaemonState, A as ApiClient, y as releaseDaemonLock, z as authChallenge, B as clearCredentials, C as clearMachineId, D as getLatestDaemonLog } from './types-Cw6y7GyQ.mjs';
4
+ import { l as logger, p as projectPath, j as backoff, k as delay, R as RawJSONLinesSchema, m as AsyncLock, c as configuration, n as readDaemonState, o as clearDaemonState, i as packageJson, r as readSettings, q as readCredentials, g as encodeBase64, u as updateSettings, s as encodeBase64Url, d as decodeBase64, w as writeCredentialsLegacy, t as writeCredentialsDataKey, v as acquireDaemonLock, x as writeDaemonState, A as ApiClient, y as releaseDaemonLock, z as authChallenge, B as clearCredentials, C as clearMachineId, D as getLatestDaemonLog } from './types-Cn6qSxMP.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';
@@ -1059,10 +1059,10 @@ class AbortError extends Error {
1059
1059
  }
1060
1060
  }
1061
1061
 
1062
- const __filename = fileURLToPath(import.meta.url);
1063
- const __dirname = join(__filename, "..");
1062
+ const __filename$1 = fileURLToPath(import.meta.url);
1063
+ const __dirname$1 = join(__filename$1, "..");
1064
1064
  function getDefaultClaudeCodePath() {
1065
- return join(__dirname, "..", "..", "..", "node_modules", "@anthropic-ai", "claude-code", "cli.js");
1065
+ return join(__dirname$1, "..", "..", "..", "node_modules", "@anthropic-ai", "claude-code", "cli.js");
1066
1066
  }
1067
1067
  function logDebug(message) {
1068
1068
  if (process.env.DEBUG) {
@@ -4879,7 +4879,7 @@ async function startHappyServer(client) {
4879
4879
  const mcp = new McpServer({
4880
4880
  name: "Happy MCP",
4881
4881
  version: "1.0.0",
4882
- description: "Happy CLI MCP server with chat session management tools"
4882
+ title: "Happy CLI MCP Server"
4883
4883
  });
4884
4884
  mcp.registerTool("change_title", {
4885
4885
  description: "Change the title of the current chat session",
@@ -6370,7 +6370,7 @@ async function handleConnectVendor(vendor, displayName) {
6370
6370
  return;
6371
6371
  } else if (subcommand === "codex") {
6372
6372
  try {
6373
- const { runCodex } = await import('./runCodex-CYkmZphO.mjs');
6373
+ const { runCodex } = await import('./runCodex-BarDBoPV.mjs');
6374
6374
  let startedBy = void 0;
6375
6375
  for (let i = 1; i < args.length; i++) {
6376
6376
  if (args[i] === "--started-by") {
@@ -6415,7 +6415,7 @@ async function handleConnectVendor(vendor, displayName) {
6415
6415
  } else if (subcommand === "list") {
6416
6416
  try {
6417
6417
  const { credentials } = await authAndSetupMachineIfNeeded();
6418
- const { listSessions } = await import('./list-BvtUKVTq.mjs');
6418
+ const { listSessions } = await import('./list-BJBPeYMn.mjs');
6419
6419
  let sessionId;
6420
6420
  let titleFilter;
6421
6421
  let recentMsgs;
@@ -6517,7 +6517,7 @@ Examples:
6517
6517
  process.exit(1);
6518
6518
  }
6519
6519
  const { credentials } = await authAndSetupMachineIfNeeded();
6520
- const { promptSession } = await import('./prompt-BbMNN7fl.mjs');
6520
+ const { promptSession } = await import('./prompt-B35fwI-i.mjs');
6521
6521
  await promptSession(credentials, sessionId, promptText, timeoutMinutes ?? void 0);
6522
6522
  } catch (error) {
6523
6523
  console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
package/dist/index.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  require('chalk');
4
- require('./index-CHEjP0zg.cjs');
5
- require('./types-Q-euvEmG.cjs');
4
+ require('./index-BkDVLUcE.cjs');
5
+ require('./types-Bd_EJ8VV.cjs');
6
6
  require('zod');
7
7
  require('node:child_process');
8
8
  require('node:os');
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import 'chalk';
2
- import './index-BERBU6rR.mjs';
3
- import './types-Cw6y7GyQ.mjs';
2
+ import './index-h3SrsKqR.mjs';
3
+ import './types-Cn6qSxMP.mjs';
4
4
  import 'zod';
5
5
  import 'node:child_process';
6
6
  import 'node:os';
package/dist/lib.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var types = require('./types-Q-euvEmG.cjs');
3
+ var types = require('./types-Bd_EJ8VV.cjs');
4
4
  require('axios');
5
5
  require('chalk');
6
6
  require('fs');
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-Cw6y7GyQ.mjs';
1
+ export { A as ApiClient, a as ApiSessionClient, R as RawJSONLinesSchema, c as configuration, l as logger } from './types-Cn6qSxMP.mjs';
2
2
  import 'axios';
3
3
  import 'chalk';
4
4
  import 'fs';
@@ -1,4 +1,4 @@
1
- import { c as configuration, l as logger, d as decodeBase64, b as decrypt, f as formatTimeAgo, e as libsodiumDecryptFromPublicKey } from './types-Cw6y7GyQ.mjs';
1
+ import { c as configuration, l as logger, d as decodeBase64, b as decrypt, f as formatTimeAgo, e as libsodiumDecryptFromPublicKey } from './types-Cn6qSxMP.mjs';
2
2
  import axios from 'axios';
3
3
  import { existsSync, readdirSync, statSync, readFileSync } from 'fs';
4
4
  import { join } from 'path';
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var types = require('./types-Q-euvEmG.cjs');
3
+ var types = require('./types-Bd_EJ8VV.cjs');
4
4
  var axios = require('axios');
5
5
  var fs = require('fs');
6
6
  var path = require('path');
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var types = require('./types-Q-euvEmG.cjs');
3
+ var types = require('./types-Bd_EJ8VV.cjs');
4
4
  var axios = require('axios');
5
5
  var socket_ioClient = require('socket.io-client');
6
6
  require('chalk');
@@ -1,4 +1,4 @@
1
- import { c as configuration, b as decrypt, d as decodeBase64, l as logger, g as encodeBase64, h as encrypt } from './types-Cw6y7GyQ.mjs';
1
+ import { c as configuration, b as decrypt, d as decodeBase64, l as logger, g as encodeBase64, h as encrypt } from './types-Cn6qSxMP.mjs';
2
2
  import axios from 'axios';
3
3
  import { io } from 'socket.io-client';
4
4
  import 'chalk';
@@ -1,16 +1,17 @@
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, i as packageJson } from './types-Cw6y7GyQ.mjs';
3
+ import { l as logger, A as ApiClient, r as readSettings, p as projectPath, c as configuration, i as packageJson } from './types-Cn6qSxMP.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 { execSync } from 'child_process';
9
9
  import { randomUUID } from 'node:crypto';
10
- 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-BERBU6rR.mjs';
10
+ 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-h3SrsKqR.mjs';
11
11
  import os from 'node:os';
12
12
  import { resolve, join } from 'node:path';
13
13
  import fs from 'node:fs';
14
+ import { parse } from '@iarna/toml';
14
15
  import 'axios';
15
16
  import 'chalk';
16
17
  import 'fs';
@@ -74,7 +75,7 @@ class CodexMcpClient {
74
75
  constructor() {
75
76
  this.client = new Client(
76
77
  { name: "happy-codex-client", version: "1.0.0" },
77
- { capabilities: { tools: {}, elicitation: {} } }
78
+ { capabilities: { elicitation: {} } }
78
79
  );
79
80
  this.client.setNotificationHandler(z.object({
80
81
  method: z.literal("codex/event"),
@@ -1139,13 +1140,39 @@ async function runCodex(opts) {
1139
1140
  }
1140
1141
  }
1141
1142
  });
1143
+ let existingMcpServers = {};
1144
+ try {
1145
+ const codexConfigPath = join(os.homedir(), ".codex", "config.toml");
1146
+ if (fs.existsSync(codexConfigPath)) {
1147
+ const configContents = fs.readFileSync(codexConfigPath, "utf8");
1148
+ const parsedConfig = parse(configContents);
1149
+ const parsedServers = parsedConfig?.mcp_servers;
1150
+ if (parsedServers && typeof parsedServers === "object") {
1151
+ for (const [name, rawConfig] of Object.entries(parsedServers)) {
1152
+ if (!rawConfig || typeof rawConfig !== "object") {
1153
+ continue;
1154
+ }
1155
+ const command = rawConfig.command;
1156
+ if (typeof command !== "string") {
1157
+ logger.debug(`[codex] Skipping MCP server "${name}" because command is missing`);
1158
+ continue;
1159
+ }
1160
+ existingMcpServers[name] = rawConfig;
1161
+ }
1162
+ }
1163
+ }
1164
+ } catch (error) {
1165
+ const message = error instanceof Error ? error.message : String(error);
1166
+ logger.debug(`[codex] Error reading Codex config: ${message}`);
1167
+ }
1142
1168
  const happyServer = await startHappyServer(session);
1143
1169
  const bridgeCommand = join(projectPath(), "bin", "happy-mcp.mjs");
1144
1170
  const mcpServers = {
1145
1171
  happy: {
1146
1172
  command: bridgeCommand,
1147
1173
  args: ["--url", happyServer.url]
1148
- }
1174
+ },
1175
+ ...existingMcpServers
1149
1176
  };
1150
1177
  let first = true;
1151
1178
  try {
@@ -2,17 +2,18 @@
2
2
 
3
3
  var ink = require('ink');
4
4
  var React = require('react');
5
- var types = require('./types-Q-euvEmG.cjs');
5
+ var types = require('./types-Bd_EJ8VV.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 child_process = require('child_process');
11
11
  var node_crypto = require('node:crypto');
12
- var index = require('./index-CHEjP0zg.cjs');
12
+ var index = require('./index-BkDVLUcE.cjs');
13
13
  var os = require('node:os');
14
14
  var node_path = require('node:path');
15
15
  var fs = require('node:fs');
16
+ var toml = require('@iarna/toml');
16
17
  require('axios');
17
18
  require('chalk');
18
19
  require('fs');
@@ -76,7 +77,7 @@ class CodexMcpClient {
76
77
  constructor() {
77
78
  this.client = new index_js.Client(
78
79
  { name: "happy-codex-client", version: "1.0.0" },
79
- { capabilities: { tools: {}, elicitation: {} } }
80
+ { capabilities: { elicitation: {} } }
80
81
  );
81
82
  this.client.setNotificationHandler(z.z.object({
82
83
  method: z.z.literal("codex/event"),
@@ -1141,13 +1142,39 @@ async function runCodex(opts) {
1141
1142
  }
1142
1143
  }
1143
1144
  });
1145
+ let existingMcpServers = {};
1146
+ try {
1147
+ const codexConfigPath = node_path.join(os.homedir(), ".codex", "config.toml");
1148
+ if (fs.existsSync(codexConfigPath)) {
1149
+ const configContents = fs.readFileSync(codexConfigPath, "utf8");
1150
+ const parsedConfig = toml.parse(configContents);
1151
+ const parsedServers = parsedConfig?.mcp_servers;
1152
+ if (parsedServers && typeof parsedServers === "object") {
1153
+ for (const [name, rawConfig] of Object.entries(parsedServers)) {
1154
+ if (!rawConfig || typeof rawConfig !== "object") {
1155
+ continue;
1156
+ }
1157
+ const command = rawConfig.command;
1158
+ if (typeof command !== "string") {
1159
+ types.logger.debug(`[codex] Skipping MCP server "${name}" because command is missing`);
1160
+ continue;
1161
+ }
1162
+ existingMcpServers[name] = rawConfig;
1163
+ }
1164
+ }
1165
+ }
1166
+ } catch (error) {
1167
+ const message = error instanceof Error ? error.message : String(error);
1168
+ types.logger.debug(`[codex] Error reading Codex config: ${message}`);
1169
+ }
1144
1170
  const happyServer = await index.startHappyServer(session);
1145
1171
  const bridgeCommand = node_path.join(types.projectPath(), "bin", "happy-mcp.mjs");
1146
1172
  const mcpServers = {
1147
1173
  happy: {
1148
1174
  command: bridgeCommand,
1149
1175
  args: ["--url", happyServer.url]
1150
- }
1176
+ },
1177
+ ...existingMcpServers
1151
1178
  };
1152
1179
  let first = true;
1153
1180
  try {
@@ -41,7 +41,7 @@ function _interopNamespaceDefault(e) {
41
41
  var z__namespace = /*#__PURE__*/_interopNamespaceDefault(z);
42
42
 
43
43
  var name = "@zhigang1992/happy-cli";
44
- var version = "0.12.4";
44
+ var version = "0.12.6";
45
45
  var description = "Mobile and Web client for Claude Code and Codex";
46
46
  var author = "Kirill Dubovitskiy";
47
47
  var license = "MIT";
@@ -98,18 +98,19 @@ var scripts = {
98
98
  "why do we need to build before running tests / dev?": "We need the binary to be built so we run daemon commands which directly run the binary - we don't want them to go out of sync or have custom spawn logic depending how we started happy",
99
99
  typecheck: "tsc --noEmit",
100
100
  build: "shx rm -rf dist && npx tsc --noEmit && pkgroll",
101
- test: "yarn build && tsx --env-file .env.integration-test node_modules/.bin/vitest run",
102
- start: "yarn build && ./bin/happy.mjs",
101
+ test: "bun run build && tsx --env-file .env.integration-test node_modules/.bin/vitest run",
102
+ start: "bun run build && ./bin/happy.mjs",
103
103
  dev: "tsx src/index.ts",
104
- "dev:local-server": "yarn build && tsx --env-file .env.dev-local-server src/index.ts",
105
- "dev:integration-test-env": "yarn build && tsx --env-file .env.integration-test src/index.ts",
106
- prepublishOnly: "yarn build && yarn test",
104
+ "dev:local-server": "bun run build && tsx --env-file .env.dev-local-server src/index.ts",
105
+ "dev:integration-test-env": "bun run build && tsx --env-file .env.integration-test src/index.ts",
106
+ prepublishOnly: "bun run build && bun test",
107
107
  release: "release-it"
108
108
  };
109
109
  var dependencies = {
110
110
  "@anthropic-ai/claude-code": "2.0.55",
111
111
  "@anthropic-ai/sdk": "0.65.0",
112
112
  "@elevenlabs/elevenlabs-js": "^2.25.1",
113
+ "@iarna/toml": "^3.0.0",
113
114
  "@modelcontextprotocol/sdk": "^1.15.1",
114
115
  "@stablelib/base64": "^2.0.1",
115
116
  "@stablelib/hex": "^2.0.1",
@@ -161,7 +162,7 @@ var resolutions = {
161
162
  var publishConfig = {
162
163
  registry: "https://registry.npmjs.org"
163
164
  };
164
- var packageManager = "yarn@1.22.22";
165
+ var packageManager = "bun@1.3.3";
165
166
  var packageJson = {
166
167
  name: name,
167
168
  version: version,
@@ -357,6 +358,18 @@ function decryptBlobWithDataKey(bundle, dataKey) {
357
358
  return null;
358
359
  }
359
360
  }
361
+ function decryptBlobWithSecretBox(bundle, secret) {
362
+ if (bundle.length < 1 + tweetnacl.secretbox.nonceLength) {
363
+ return null;
364
+ }
365
+ if (bundle[0] !== 0) {
366
+ return null;
367
+ }
368
+ const nonce = bundle.slice(1, 1 + tweetnacl.secretbox.nonceLength);
369
+ const ciphertext = bundle.slice(1 + tweetnacl.secretbox.nonceLength);
370
+ const decrypted = tweetnacl.secretbox.open(ciphertext, nonce, secret);
371
+ return decrypted || null;
372
+ }
360
373
  function encrypt(key, variant, data) {
361
374
  if (variant === "legacy") {
362
375
  return encryptLegacy(data, key);
@@ -371,6 +384,13 @@ function decrypt(key, variant, data) {
371
384
  return decryptWithDataKey(data, key);
372
385
  }
373
386
  }
387
+ function decryptBlob(key, variant, bundle) {
388
+ if (variant === "legacy") {
389
+ return decryptBlobWithSecretBox(bundle, key);
390
+ } else {
391
+ return decryptBlobWithDataKey(bundle, key);
392
+ }
393
+ }
374
394
  function authChallenge(secret) {
375
395
  const keypair = tweetnacl.sign.keyPair.fromSeed(secret);
376
396
  const challenge = getRandomBytes(32);
@@ -1130,7 +1150,7 @@ class RpcHandlerManager {
1130
1150
  }
1131
1151
  }
1132
1152
 
1133
- 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-Q-euvEmG.cjs', document.baseURI).href))));
1153
+ 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-Bd_EJ8VV.cjs', document.baseURI).href))));
1134
1154
  function projectPath() {
1135
1155
  const path$1 = path.resolve(__dirname$1, "..");
1136
1156
  return path$1;
@@ -1783,11 +1803,7 @@ class ApiSessionClient extends node_events.EventEmitter {
1783
1803
  const encryptedData = new Uint8Array(response.data);
1784
1804
  const mimeType = response.headers["x-blob-mimetype"];
1785
1805
  const originalSize = parseInt(response.headers["x-blob-size"], 10);
1786
- if (this.encryptionVariant !== "dataKey") {
1787
- logger.debug("[API] Cannot decrypt blob: session uses legacy encryption");
1788
- return null;
1789
- }
1790
- const decryptedData = decryptBlobWithDataKey(encryptedData, this.encryptionKey);
1806
+ const decryptedData = decryptBlob(this.encryptionKey, this.encryptionVariant, encryptedData);
1791
1807
  if (!decryptedData) {
1792
1808
  logger.debug("[API] Failed to decrypt blob");
1793
1809
  return null;
@@ -20,7 +20,7 @@ import { fileURLToPath } from 'url';
20
20
  import { Expo } from 'expo-server-sdk';
21
21
 
22
22
  var name = "@zhigang1992/happy-cli";
23
- var version = "0.12.4";
23
+ var version = "0.12.6";
24
24
  var description = "Mobile and Web client for Claude Code and Codex";
25
25
  var author = "Kirill Dubovitskiy";
26
26
  var license = "MIT";
@@ -33,9 +33,9 @@ var bin = {
33
33
  "happy-mcp": "./bin/happy-mcp.mjs"
34
34
  };
35
35
  var main = "./dist/index.cjs";
36
- var module = "./dist/index.mjs";
36
+ var module$1 = "./dist/index.mjs";
37
37
  var types = "./dist/index.d.cts";
38
- var exports = {
38
+ var exports$1 = {
39
39
  ".": {
40
40
  require: {
41
41
  types: "./dist/index.d.cts",
@@ -77,18 +77,19 @@ var scripts = {
77
77
  "why do we need to build before running tests / dev?": "We need the binary to be built so we run daemon commands which directly run the binary - we don't want them to go out of sync or have custom spawn logic depending how we started happy",
78
78
  typecheck: "tsc --noEmit",
79
79
  build: "shx rm -rf dist && npx tsc --noEmit && pkgroll",
80
- test: "yarn build && tsx --env-file .env.integration-test node_modules/.bin/vitest run",
81
- start: "yarn build && ./bin/happy.mjs",
80
+ test: "bun run build && tsx --env-file .env.integration-test node_modules/.bin/vitest run",
81
+ start: "bun run build && ./bin/happy.mjs",
82
82
  dev: "tsx src/index.ts",
83
- "dev:local-server": "yarn build && tsx --env-file .env.dev-local-server src/index.ts",
84
- "dev:integration-test-env": "yarn build && tsx --env-file .env.integration-test src/index.ts",
85
- prepublishOnly: "yarn build && yarn test",
83
+ "dev:local-server": "bun run build && tsx --env-file .env.dev-local-server src/index.ts",
84
+ "dev:integration-test-env": "bun run build && tsx --env-file .env.integration-test src/index.ts",
85
+ prepublishOnly: "bun run build && bun test",
86
86
  release: "release-it"
87
87
  };
88
88
  var dependencies = {
89
89
  "@anthropic-ai/claude-code": "2.0.55",
90
90
  "@anthropic-ai/sdk": "0.65.0",
91
91
  "@elevenlabs/elevenlabs-js": "^2.25.1",
92
+ "@iarna/toml": "^3.0.0",
92
93
  "@modelcontextprotocol/sdk": "^1.15.1",
93
94
  "@stablelib/base64": "^2.0.1",
94
95
  "@stablelib/hex": "^2.0.1",
@@ -140,7 +141,7 @@ var resolutions = {
140
141
  var publishConfig = {
141
142
  registry: "https://registry.npmjs.org"
142
143
  };
143
- var packageManager = "yarn@1.22.22";
144
+ var packageManager = "bun@1.3.3";
144
145
  var packageJson = {
145
146
  name: name,
146
147
  version: version,
@@ -153,9 +154,9 @@ var packageJson = {
153
154
  repository: repository,
154
155
  bin: bin,
155
156
  main: main,
156
- module: module,
157
+ module: module$1,
157
158
  types: types,
158
- exports: exports,
159
+ exports: exports$1,
159
160
  files: files,
160
161
  scripts: scripts,
161
162
  dependencies: dependencies,
@@ -336,6 +337,18 @@ function decryptBlobWithDataKey(bundle, dataKey) {
336
337
  return null;
337
338
  }
338
339
  }
340
+ function decryptBlobWithSecretBox(bundle, secret) {
341
+ if (bundle.length < 1 + tweetnacl.secretbox.nonceLength) {
342
+ return null;
343
+ }
344
+ if (bundle[0] !== 0) {
345
+ return null;
346
+ }
347
+ const nonce = bundle.slice(1, 1 + tweetnacl.secretbox.nonceLength);
348
+ const ciphertext = bundle.slice(1 + tweetnacl.secretbox.nonceLength);
349
+ const decrypted = tweetnacl.secretbox.open(ciphertext, nonce, secret);
350
+ return decrypted || null;
351
+ }
339
352
  function encrypt(key, variant, data) {
340
353
  if (variant === "legacy") {
341
354
  return encryptLegacy(data, key);
@@ -350,6 +363,13 @@ function decrypt(key, variant, data) {
350
363
  return decryptWithDataKey(data, key);
351
364
  }
352
365
  }
366
+ function decryptBlob(key, variant, bundle) {
367
+ if (variant === "legacy") {
368
+ return decryptBlobWithSecretBox(bundle, key);
369
+ } else {
370
+ return decryptBlobWithDataKey(bundle, key);
371
+ }
372
+ }
353
373
  function authChallenge(secret) {
354
374
  const keypair = tweetnacl.sign.keyPair.fromSeed(secret);
355
375
  const challenge = getRandomBytes(32);
@@ -1109,9 +1129,9 @@ class RpcHandlerManager {
1109
1129
  }
1110
1130
  }
1111
1131
 
1112
- const __dirname = dirname(fileURLToPath(import.meta.url));
1132
+ const __dirname$1 = dirname(fileURLToPath(import.meta.url));
1113
1133
  function projectPath() {
1114
- const path = resolve(__dirname, "..");
1134
+ const path = resolve(__dirname$1, "..");
1115
1135
  return path;
1116
1136
  }
1117
1137
 
@@ -1762,11 +1782,7 @@ class ApiSessionClient extends EventEmitter {
1762
1782
  const encryptedData = new Uint8Array(response.data);
1763
1783
  const mimeType = response.headers["x-blob-mimetype"];
1764
1784
  const originalSize = parseInt(response.headers["x-blob-size"], 10);
1765
- if (this.encryptionVariant !== "dataKey") {
1766
- logger.debug("[API] Cannot decrypt blob: session uses legacy encryption");
1767
- return null;
1768
- }
1769
- const decryptedData = decryptBlobWithDataKey(encryptedData, this.encryptionKey);
1785
+ const decryptedData = decryptBlob(this.encryptionKey, this.encryptionVariant, encryptedData);
1770
1786
  if (!decryptedData) {
1771
1787
  logger.debug("[API] Failed to decrypt blob");
1772
1788
  return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhigang1992/happy-cli",
3
- "version": "0.12.4",
3
+ "version": "0.12.6",
4
4
  "description": "Mobile and Web client for Claude Code and Codex",
5
5
  "author": "Kirill Dubovitskiy",
6
6
  "license": "MIT",
@@ -57,18 +57,19 @@
57
57
  "why do we need to build before running tests / dev?": "We need the binary to be built so we run daemon commands which directly run the binary - we don't want them to go out of sync or have custom spawn logic depending how we started happy",
58
58
  "typecheck": "tsc --noEmit",
59
59
  "build": "shx rm -rf dist && npx tsc --noEmit && pkgroll",
60
- "test": "yarn build && tsx --env-file .env.integration-test node_modules/.bin/vitest run",
61
- "start": "yarn build && ./bin/happy.mjs",
60
+ "test": "bun run build && tsx --env-file .env.integration-test node_modules/.bin/vitest run",
61
+ "start": "bun run build && ./bin/happy.mjs",
62
62
  "dev": "tsx src/index.ts",
63
- "dev:local-server": "yarn build && tsx --env-file .env.dev-local-server src/index.ts",
64
- "dev:integration-test-env": "yarn build && tsx --env-file .env.integration-test src/index.ts",
65
- "prepublishOnly": "yarn build && yarn test",
63
+ "dev:local-server": "bun run build && tsx --env-file .env.dev-local-server src/index.ts",
64
+ "dev:integration-test-env": "bun run build && tsx --env-file .env.integration-test src/index.ts",
65
+ "prepublishOnly": "bun run build && bun test",
66
66
  "release": "release-it"
67
67
  },
68
68
  "dependencies": {
69
69
  "@anthropic-ai/claude-code": "2.0.55",
70
70
  "@anthropic-ai/sdk": "0.65.0",
71
71
  "@elevenlabs/elevenlabs-js": "^2.25.1",
72
+ "@iarna/toml": "^3.0.0",
72
73
  "@modelcontextprotocol/sdk": "^1.15.1",
73
74
  "@stablelib/base64": "^2.0.1",
74
75
  "@stablelib/hex": "^2.0.1",
@@ -120,5 +121,5 @@
120
121
  "publishConfig": {
121
122
  "registry": "https://registry.npmjs.org"
122
123
  },
123
- "packageManager": "yarn@1.22.22"
124
+ "packageManager": "bun@1.3.3"
124
125
  }