@zhigang1992/happy-cli 0.12.3 → 0.12.4
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-DNeoLdzx.mjs → index-BERBU6rR.mjs} +198 -21
- package/dist/{index-y8CVImEp.cjs → index-CHEjP0zg.cjs} +212 -35
- package/dist/index.cjs +6 -6
- package/dist/index.mjs +6 -6
- package/dist/lib.cjs +1 -1
- package/dist/lib.d.cts +118 -4
- package/dist/lib.d.mts +118 -4
- package/dist/lib.mjs +1 -1
- package/dist/{list-D_NjiLPx.mjs → list-BvtUKVTq.mjs} +1 -1
- package/dist/{list-DiamEbqL.cjs → list-DOsBjFRJ.cjs} +1 -1
- package/dist/{prompt-CJh1Mo2A.mjs → prompt-BbMNN7fl.mjs} +1 -1
- package/dist/{prompt-Cu47wZlI.cjs → prompt-Dh_trad0.cjs} +1 -1
- package/dist/{runCodex-B5ZlUUec.mjs → runCodex-CYkmZphO.mjs} +19 -3
- package/dist/{runCodex-DErgypij.cjs → runCodex-DUqqO-m8.cjs} +19 -3
- package/dist/{types-D4_aCy-H.mjs → types-Cw6y7GyQ.mjs} +124 -6
- package/dist/{types-CllU28mx.cjs → types-Q-euvEmG.cjs} +125 -7
- package/package.json +1 -1
|
@@ -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.
|
|
44
|
+
var version = "0.12.4";
|
|
45
45
|
var description = "Mobile and Web client for Claude Code and Codex";
|
|
46
46
|
var author = "Kirill Dubovitskiy";
|
|
47
47
|
var license = "MIT";
|
|
@@ -332,6 +332,31 @@ function decryptWithDataKey(bundle, dataKey) {
|
|
|
332
332
|
return null;
|
|
333
333
|
}
|
|
334
334
|
}
|
|
335
|
+
function decryptBlobWithDataKey(bundle, dataKey) {
|
|
336
|
+
if (bundle.length < 1) {
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
339
|
+
if (bundle[0] !== 0) {
|
|
340
|
+
return null;
|
|
341
|
+
}
|
|
342
|
+
if (bundle.length < 12 + 16 + 1) {
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
const nonce = bundle.slice(1, 13);
|
|
346
|
+
const authTag = bundle.slice(bundle.length - 16);
|
|
347
|
+
const ciphertext = bundle.slice(13, bundle.length - 16);
|
|
348
|
+
try {
|
|
349
|
+
const decipher = node_crypto.createDecipheriv("aes-256-gcm", dataKey, nonce);
|
|
350
|
+
decipher.setAuthTag(authTag);
|
|
351
|
+
const decrypted = Buffer.concat([
|
|
352
|
+
decipher.update(ciphertext),
|
|
353
|
+
decipher.final()
|
|
354
|
+
]);
|
|
355
|
+
return new Uint8Array(decrypted);
|
|
356
|
+
} catch (error) {
|
|
357
|
+
return null;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
335
360
|
function encrypt(key, variant, data) {
|
|
336
361
|
if (variant === "legacy") {
|
|
337
362
|
return encryptLegacy(data, key);
|
|
@@ -873,12 +898,27 @@ z.z.object({
|
|
|
873
898
|
agentStateVersion: z.z.number()
|
|
874
899
|
})
|
|
875
900
|
});
|
|
901
|
+
const TextContentSchema = z.z.object({
|
|
902
|
+
type: z.z.literal("text"),
|
|
903
|
+
text: z.z.string()
|
|
904
|
+
});
|
|
905
|
+
const ImageRefContentSchema = z.z.object({
|
|
906
|
+
type: z.z.literal("image_ref"),
|
|
907
|
+
blobId: z.z.string(),
|
|
908
|
+
mimeType: z.z.enum(["image/jpeg", "image/png", "image/gif", "image/webp"]),
|
|
909
|
+
width: z.z.number().optional(),
|
|
910
|
+
height: z.z.number().optional()
|
|
911
|
+
});
|
|
912
|
+
const ContentBlockSchema = z.z.union([TextContentSchema, ImageRefContentSchema]);
|
|
913
|
+
const UserMessageContentSchema = z.z.union([
|
|
914
|
+
TextContentSchema,
|
|
915
|
+
// Legacy: single text content
|
|
916
|
+
z.z.array(ContentBlockSchema)
|
|
917
|
+
// New: array of content blocks
|
|
918
|
+
]);
|
|
876
919
|
const UserMessageSchema = z.z.object({
|
|
877
920
|
role: z.z.literal("user"),
|
|
878
|
-
content:
|
|
879
|
-
type: z.z.literal("text"),
|
|
880
|
-
text: z.z.string()
|
|
881
|
-
}),
|
|
921
|
+
content: UserMessageContentSchema,
|
|
882
922
|
localKey: z.z.string().optional(),
|
|
883
923
|
// Mobile messages include this
|
|
884
924
|
meta: MessageMetaSchema.optional()
|
|
@@ -990,12 +1030,29 @@ class RpcHandlerManager {
|
|
|
990
1030
|
encryptionVariant;
|
|
991
1031
|
logger;
|
|
992
1032
|
socket = null;
|
|
1033
|
+
sessionContext = null;
|
|
993
1034
|
constructor(config) {
|
|
994
1035
|
this.scopePrefix = config.scopePrefix;
|
|
995
1036
|
this.encryptionKey = config.encryptionKey;
|
|
996
1037
|
this.encryptionVariant = config.encryptionVariant;
|
|
997
1038
|
this.logger = config.logger || ((msg, data) => logger.debug(msg, data));
|
|
998
1039
|
}
|
|
1040
|
+
/**
|
|
1041
|
+
* Set the session context (path and environment)
|
|
1042
|
+
* This should be called after direnv environment is loaded
|
|
1043
|
+
* @param context - The session context with path and environment
|
|
1044
|
+
*/
|
|
1045
|
+
setSessionContext(context) {
|
|
1046
|
+
this.sessionContext = context;
|
|
1047
|
+
this.logger("[RPC] Session context set", { path: context.path, envVarCount: Object.keys(context.env).length });
|
|
1048
|
+
}
|
|
1049
|
+
/**
|
|
1050
|
+
* Get the current session context
|
|
1051
|
+
* @returns The session context or null if not set
|
|
1052
|
+
*/
|
|
1053
|
+
getSessionContext() {
|
|
1054
|
+
return this.sessionContext;
|
|
1055
|
+
}
|
|
999
1056
|
/**
|
|
1000
1057
|
* Register an RPC handler for a specific method
|
|
1001
1058
|
* @param method - The method name (without prefix)
|
|
@@ -1073,7 +1130,7 @@ class RpcHandlerManager {
|
|
|
1073
1130
|
}
|
|
1074
1131
|
}
|
|
1075
1132
|
|
|
1076
|
-
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-
|
|
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))));
|
|
1077
1134
|
function projectPath() {
|
|
1078
1135
|
const path$1 = path.resolve(__dirname$1, "..");
|
|
1079
1136
|
return path$1;
|
|
@@ -1171,10 +1228,13 @@ function registerCommonHandlers(rpcHandlerManager) {
|
|
|
1171
1228
|
rpcHandlerManager.registerHandler("bash", async (data) => {
|
|
1172
1229
|
logger.debug("Shell command request:", data.command);
|
|
1173
1230
|
try {
|
|
1231
|
+
const sessionContext = rpcHandlerManager.getSessionContext();
|
|
1174
1232
|
const options = {
|
|
1175
1233
|
cwd: data.cwd,
|
|
1176
|
-
timeout: data.timeout || 3e4
|
|
1234
|
+
timeout: data.timeout || 3e4,
|
|
1177
1235
|
// Default 30 seconds timeout
|
|
1236
|
+
// Use session environment if available, otherwise inherit process.env
|
|
1237
|
+
env: sessionContext?.env ?? process.env
|
|
1178
1238
|
};
|
|
1179
1239
|
const { stdout, stderr } = await execAsync(data.command, options);
|
|
1180
1240
|
return {
|
|
@@ -1704,6 +1764,64 @@ class ApiSessionClient extends node_events.EventEmitter {
|
|
|
1704
1764
|
logger.debug("[API] socket.close() called");
|
|
1705
1765
|
this.socket.close();
|
|
1706
1766
|
}
|
|
1767
|
+
/**
|
|
1768
|
+
* Download and decrypt a blob from the server
|
|
1769
|
+
* @param blobId - The blob ID to download
|
|
1770
|
+
* @returns The decrypted binary data and metadata, or null if download/decryption fails
|
|
1771
|
+
*/
|
|
1772
|
+
async downloadBlob(blobId) {
|
|
1773
|
+
try {
|
|
1774
|
+
const response = await axios.get(
|
|
1775
|
+
`${configuration.serverUrl}/v1/sessions/${this.sessionId}/blobs/${blobId}`,
|
|
1776
|
+
{
|
|
1777
|
+
headers: {
|
|
1778
|
+
"Authorization": `Bearer ${this.token}`
|
|
1779
|
+
},
|
|
1780
|
+
responseType: "arraybuffer"
|
|
1781
|
+
}
|
|
1782
|
+
);
|
|
1783
|
+
const encryptedData = new Uint8Array(response.data);
|
|
1784
|
+
const mimeType = response.headers["x-blob-mimetype"];
|
|
1785
|
+
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);
|
|
1791
|
+
if (!decryptedData) {
|
|
1792
|
+
logger.debug("[API] Failed to decrypt blob");
|
|
1793
|
+
return null;
|
|
1794
|
+
}
|
|
1795
|
+
return {
|
|
1796
|
+
data: decryptedData,
|
|
1797
|
+
mimeType,
|
|
1798
|
+
size: originalSize
|
|
1799
|
+
};
|
|
1800
|
+
} catch (error) {
|
|
1801
|
+
logger.debug("[API] Failed to download blob:", error);
|
|
1802
|
+
return null;
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1805
|
+
/**
|
|
1806
|
+
* Convert an image_ref content block to a Claude API image content block
|
|
1807
|
+
* Downloads, decrypts, and base64 encodes the image
|
|
1808
|
+
* @param imageRef - The image reference content block
|
|
1809
|
+
* @returns Claude API image content block, or null if conversion fails
|
|
1810
|
+
*/
|
|
1811
|
+
async resolveImageRef(imageRef) {
|
|
1812
|
+
const blob = await this.downloadBlob(imageRef.blobId);
|
|
1813
|
+
if (!blob) {
|
|
1814
|
+
return null;
|
|
1815
|
+
}
|
|
1816
|
+
return {
|
|
1817
|
+
type: "image",
|
|
1818
|
+
source: {
|
|
1819
|
+
type: "base64",
|
|
1820
|
+
media_type: blob.mimeType,
|
|
1821
|
+
data: Buffer.from(blob.data).toString("base64")
|
|
1822
|
+
}
|
|
1823
|
+
};
|
|
1824
|
+
}
|
|
1707
1825
|
}
|
|
1708
1826
|
|
|
1709
1827
|
class ApiMachineClient {
|