@zonease/happy 0.6.39 → 0.6.41
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/bin/happy.mjs +10 -0
- package/dist/{api-CIZKyfSn.mjs → api-K2-jr9ar.mjs} +86 -6
- package/dist/{api-CwOCQeLH.cjs → api-XeHlmApX.cjs} +87 -7
- package/dist/{auth-BIleVCw0.cjs → auth-BQvEuSs5.cjs} +2 -2
- package/dist/{auth-Cas9DR3b.cjs → auth-BbvPcnkY.cjs} +4 -4
- package/dist/{auth-0VnlXT9f.mjs → auth-CjLkoM3m.mjs} +4 -4
- package/dist/{auth-BE8dD20T.mjs → auth-DS8fzlin.mjs} +2 -2
- package/dist/{browser-Dll5hxOV.mjs → browser-C05Ak6RL.mjs} +1 -1
- package/dist/{browser-Cc08m7of.cjs → browser-C05SP_Tt.cjs} +1 -1
- package/dist/{claudeLocal-WkgLbl1a.cjs → claudeLocal-CpDhLCcZ.cjs} +1 -1
- package/dist/{claudeLocal-CPT3zcIU.mjs → claudeLocal-DJNRlHIC.mjs} +1 -1
- package/dist/{config-Draa-5XC.cjs → config-B0mns9fF.cjs} +1 -1
- package/dist/{config-rTT4qTU5.mjs → config-DWWtjKQx.mjs} +1 -1
- package/dist/{connect-CJZ73syK.cjs → connect-BxCScVNX.cjs} +4 -4
- package/dist/{connect-BfC1tYP_.mjs → connect-DXQC1CJe.mjs} +4 -4
- package/dist/{controlClient-DZMIsKsT.cjs → controlClient-DgELDZgM.cjs} +10 -1
- package/dist/{controlClient-CM_QcJnB.mjs → controlClient-DgjVRN8D.mjs} +10 -2
- package/dist/deviceKeys-BpIAWz13.cjs +182 -0
- package/dist/deviceKeys-CejCdWpw.mjs +175 -0
- package/dist/{doctor-DZYB6IVc.mjs → doctor-B-LCMVN9.mjs} +3 -3
- package/dist/{doctor-Cya9YSA0.cjs → doctor-DznasgP3.cjs} +3 -3
- package/dist/{downloadImage-MQMrUUxS.cjs → downloadImage-B_ygLAXY.cjs} +5 -5
- package/dist/{downloadImage-DfSFLb-h.mjs → downloadImage-ia5SzlCV.mjs} +3 -3
- package/dist/{enroll-BxlbVftP.cjs → enroll-BvfpRUGJ.cjs} +3 -3
- package/dist/{enroll-C52x8oly.mjs → enroll-HjUqyGnD.mjs} +3 -3
- package/dist/{evidence-Ccd9iYcj.mjs → evidence-BEQd1dCh.mjs} +1 -1
- package/dist/{evidence-CjWBG5rX.cjs → evidence-CVgTjBrq.cjs} +1 -1
- package/dist/{formatImageMessage-DbyG8c2j.cjs → formatImageMessage-CmJTP_hU.cjs} +1 -1
- package/dist/{formatImageMessage-B4lSxlk2.mjs → formatImageMessage-DVs57t3x.mjs} +1 -1
- package/dist/index.cjs +58 -43
- package/dist/index.mjs +58 -43
- package/dist/{install-C_cp8b2-.cjs → install-2Yl_L582.cjs} +2 -2
- package/dist/{install-oRAjVLjP.mjs → install-B3mMGISS.mjs} +1 -1
- package/dist/{install-BokHRgFW.cjs → install-Ck22tYHP.cjs} +1 -1
- package/dist/{install-DAeCn8ae.mjs → install-UTz_vYvB.mjs} +2 -2
- package/dist/lib.cjs +3 -3
- package/dist/lib.d.cts +77 -0
- package/dist/lib.d.mts +77 -0
- package/dist/lib.mjs +3 -3
- package/dist/{loadableToolOutput-Cuygmd4K.mjs → loadableToolOutput-4EvraaNY.mjs} +3 -3
- package/dist/{loadableToolOutput-DDCJjywt.cjs → loadableToolOutput-BZYlaqHn.cjs} +3 -3
- package/dist/{persistence-BFjvtUad.mjs → persistence-CIUFyOwz.mjs} +2 -2
- package/dist/{persistence-JLUn_Nou.cjs → persistence-DrfN7TzY.cjs} +1 -1
- package/dist/push-CCOXCcM_.cjs +80 -0
- package/dist/push-USXj_pv0.mjs +78 -0
- package/dist/{run-BDn2aE3Q.cjs → run-D3CopmEb.cjs} +45 -9
- package/dist/{run-DBZqN6Kn.mjs → run-Dy6KX6m-.mjs} +45 -9
- package/dist/{runClaude-DNHvERX0.mjs → runClaude-CWux2RDq.mjs} +14 -14
- package/dist/{runClaude-uaKxPZPm.cjs → runClaude-aHzvx6Ha.cjs} +15 -15
- package/dist/{runCodex-C-RTM0wA.mjs → runCodex-D0ZxSj3O.mjs} +13 -13
- package/dist/{runCodex-82UrZLme.cjs → runCodex-G-Aq531U.cjs} +13 -13
- package/dist/{runGemini-Bm6-4Xm2.mjs → runGemini-DZC2i6vA.mjs} +15 -15
- package/dist/{runGemini-CXMr4Jwb.cjs → runGemini-DxGgDAIM.cjs} +15 -15
- package/dist/{runOneShot-1B6RMYT7.cjs → runOneShot-BgT-JNMA.cjs} +2 -2
- package/dist/{runOneShot-ioARRHrx.mjs → runOneShot-cxlk7VKA.mjs} +2 -2
- package/dist/{serve-CwibwU6N.mjs → serve-CKyvJNs0.mjs} +6 -6
- package/dist/{serve-BtdAhkIE.cjs → serve-Dr3wPrtK.cjs} +6 -6
- package/dist/{session-D--F87zL.cjs → session-dYzbOo_W.cjs} +5 -5
- package/dist/{session-2sU4Bu1R.mjs → session-vf2ZjFto.mjs} +5 -5
- package/dist/{sessionKeyCache-D2BwO91C.mjs → sessionKeyCache-D2u3JUys.mjs} +1 -1
- package/dist/{sessionKeyCache-4Tp8pJ3N.cjs → sessionKeyCache-dDquDzn0.cjs} +1 -1
- package/dist/{sessionList-BCSw3qYt.mjs → sessionList-C1k2PNg_.mjs} +2 -2
- package/dist/{sessionList-ICJsjNtJ.cjs → sessionList-DmmtC7uR.cjs} +2 -2
- package/dist/{sessionSummary-lHGBWQSb.mjs → sessionSummary-5a1QtFVS.mjs} +3 -3
- package/dist/{sessionSummary-Bkz52BPh.cjs → sessionSummary-DGLoVOxd.cjs} +3 -3
- package/dist/{spawnHappyCLI-D_V-AAoP.cjs → spawnHappyCLI-CarRI4GM.cjs} +1 -1
- package/dist/{spawnHappyCLI-CoORX0YW.mjs → spawnHappyCLI-D3EkTFIn.mjs} +1 -1
- package/dist/{ssh-DL_AkRAD.mjs → ssh-B0hvEYIl.mjs} +137 -103
- package/dist/{ssh-BTOlhhxi.cjs → ssh-CBgVwKsB.cjs} +142 -106
- package/dist/{task-CSpaC9HX.cjs → task-CMunPKCV.cjs} +6 -6
- package/dist/{task-CQzrHRZe.mjs → task-CRo6W-3_.mjs} +6 -6
- package/dist/{uninstall-nFMFGUVM.mjs → uninstall-BALE2up0.mjs} +2 -2
- package/dist/{uninstall-BiKyRAb1.cjs → uninstall-BJ3eEGM4.cjs} +2 -2
- package/dist/{update-Dw8pgsAT.cjs → update-Bb3iijy8.cjs} +3 -3
- package/dist/{update-BcqRHXf2.mjs → update-BfjtLrhO.mjs} +3 -3
- package/package.json +1 -1
- package/dist/deviceExec-CU1R9CRb.cjs +0 -84
- package/dist/deviceExec-D93AOVV4.mjs +0 -81
package/dist/lib.d.cts
CHANGED
|
@@ -1606,6 +1606,80 @@ type SpawnSessionResult = {
|
|
|
1606
1606
|
* Similar to ApiSessionClient but for machine-scoped connections
|
|
1607
1607
|
*/
|
|
1608
1608
|
|
|
1609
|
+
interface ServerToDaemonEvents {
|
|
1610
|
+
update: (data: Update) => void;
|
|
1611
|
+
'rpc-request': (data: {
|
|
1612
|
+
method: string;
|
|
1613
|
+
params: string;
|
|
1614
|
+
}, callback: (response: string) => void) => void;
|
|
1615
|
+
'rpc-registered': (data: {
|
|
1616
|
+
method: string;
|
|
1617
|
+
}) => void;
|
|
1618
|
+
'rpc-unregistered': (data: {
|
|
1619
|
+
method: string;
|
|
1620
|
+
}) => void;
|
|
1621
|
+
'rpc-error': (data: {
|
|
1622
|
+
type: string;
|
|
1623
|
+
error: string;
|
|
1624
|
+
}) => void;
|
|
1625
|
+
auth: (data: {
|
|
1626
|
+
success: boolean;
|
|
1627
|
+
user: string;
|
|
1628
|
+
}) => void;
|
|
1629
|
+
error: (data: {
|
|
1630
|
+
message: string;
|
|
1631
|
+
}) => void;
|
|
1632
|
+
}
|
|
1633
|
+
interface DaemonToServerEvents {
|
|
1634
|
+
'machine-alive': (data: {
|
|
1635
|
+
machineId: string;
|
|
1636
|
+
time: number;
|
|
1637
|
+
}) => void;
|
|
1638
|
+
'machine-update-metadata': (data: {
|
|
1639
|
+
machineId: string;
|
|
1640
|
+
metadata: string;
|
|
1641
|
+
expectedVersion: number;
|
|
1642
|
+
}, cb: (answer: {
|
|
1643
|
+
result: 'error';
|
|
1644
|
+
} | {
|
|
1645
|
+
result: 'version-mismatch';
|
|
1646
|
+
version: number;
|
|
1647
|
+
metadata: string;
|
|
1648
|
+
} | {
|
|
1649
|
+
result: 'success';
|
|
1650
|
+
version: number;
|
|
1651
|
+
metadata: string;
|
|
1652
|
+
}) => void) => void;
|
|
1653
|
+
'machine-update-state': (data: {
|
|
1654
|
+
machineId: string;
|
|
1655
|
+
daemonState: string;
|
|
1656
|
+
expectedVersion: number;
|
|
1657
|
+
}, cb: (answer: {
|
|
1658
|
+
result: 'error';
|
|
1659
|
+
} | {
|
|
1660
|
+
result: 'version-mismatch';
|
|
1661
|
+
version: number;
|
|
1662
|
+
daemonState: string;
|
|
1663
|
+
} | {
|
|
1664
|
+
result: 'success';
|
|
1665
|
+
version: number;
|
|
1666
|
+
daemonState: string;
|
|
1667
|
+
}) => void) => void;
|
|
1668
|
+
'rpc-register': (data: {
|
|
1669
|
+
method: string;
|
|
1670
|
+
}) => void;
|
|
1671
|
+
'rpc-unregister': (data: {
|
|
1672
|
+
method: string;
|
|
1673
|
+
}) => void;
|
|
1674
|
+
'rpc-call': (data: {
|
|
1675
|
+
method: string;
|
|
1676
|
+
params: any;
|
|
1677
|
+
}, callback: (response: {
|
|
1678
|
+
ok: boolean;
|
|
1679
|
+
result?: any;
|
|
1680
|
+
error?: string;
|
|
1681
|
+
}) => void) => void;
|
|
1682
|
+
}
|
|
1609
1683
|
type MachineRpcHandlers = {
|
|
1610
1684
|
spawnSession: (options: SpawnSessionOptions) => Promise<SpawnSessionResult>;
|
|
1611
1685
|
stopSession: (sessionId: string) => boolean;
|
|
@@ -1641,6 +1715,9 @@ declare class ApiMachineClient {
|
|
|
1641
1715
|
private machine;
|
|
1642
1716
|
private currentRuntimeDaemonState?;
|
|
1643
1717
|
private socket;
|
|
1718
|
+
/** The daemon's live connection. Reused for device RPC so a CLI command does
|
|
1719
|
+
* not spend ~500ms building its own TLS + WebSocket handshake. */
|
|
1720
|
+
get rpcSocket(): Socket<ServerToDaemonEvents, DaemonToServerEvents>;
|
|
1644
1721
|
private keepAliveInterval;
|
|
1645
1722
|
private rpcHandlerManager;
|
|
1646
1723
|
private claudeCache;
|
package/dist/lib.d.mts
CHANGED
|
@@ -1606,6 +1606,80 @@ type SpawnSessionResult = {
|
|
|
1606
1606
|
* Similar to ApiSessionClient but for machine-scoped connections
|
|
1607
1607
|
*/
|
|
1608
1608
|
|
|
1609
|
+
interface ServerToDaemonEvents {
|
|
1610
|
+
update: (data: Update) => void;
|
|
1611
|
+
'rpc-request': (data: {
|
|
1612
|
+
method: string;
|
|
1613
|
+
params: string;
|
|
1614
|
+
}, callback: (response: string) => void) => void;
|
|
1615
|
+
'rpc-registered': (data: {
|
|
1616
|
+
method: string;
|
|
1617
|
+
}) => void;
|
|
1618
|
+
'rpc-unregistered': (data: {
|
|
1619
|
+
method: string;
|
|
1620
|
+
}) => void;
|
|
1621
|
+
'rpc-error': (data: {
|
|
1622
|
+
type: string;
|
|
1623
|
+
error: string;
|
|
1624
|
+
}) => void;
|
|
1625
|
+
auth: (data: {
|
|
1626
|
+
success: boolean;
|
|
1627
|
+
user: string;
|
|
1628
|
+
}) => void;
|
|
1629
|
+
error: (data: {
|
|
1630
|
+
message: string;
|
|
1631
|
+
}) => void;
|
|
1632
|
+
}
|
|
1633
|
+
interface DaemonToServerEvents {
|
|
1634
|
+
'machine-alive': (data: {
|
|
1635
|
+
machineId: string;
|
|
1636
|
+
time: number;
|
|
1637
|
+
}) => void;
|
|
1638
|
+
'machine-update-metadata': (data: {
|
|
1639
|
+
machineId: string;
|
|
1640
|
+
metadata: string;
|
|
1641
|
+
expectedVersion: number;
|
|
1642
|
+
}, cb: (answer: {
|
|
1643
|
+
result: 'error';
|
|
1644
|
+
} | {
|
|
1645
|
+
result: 'version-mismatch';
|
|
1646
|
+
version: number;
|
|
1647
|
+
metadata: string;
|
|
1648
|
+
} | {
|
|
1649
|
+
result: 'success';
|
|
1650
|
+
version: number;
|
|
1651
|
+
metadata: string;
|
|
1652
|
+
}) => void) => void;
|
|
1653
|
+
'machine-update-state': (data: {
|
|
1654
|
+
machineId: string;
|
|
1655
|
+
daemonState: string;
|
|
1656
|
+
expectedVersion: number;
|
|
1657
|
+
}, cb: (answer: {
|
|
1658
|
+
result: 'error';
|
|
1659
|
+
} | {
|
|
1660
|
+
result: 'version-mismatch';
|
|
1661
|
+
version: number;
|
|
1662
|
+
daemonState: string;
|
|
1663
|
+
} | {
|
|
1664
|
+
result: 'success';
|
|
1665
|
+
version: number;
|
|
1666
|
+
daemonState: string;
|
|
1667
|
+
}) => void) => void;
|
|
1668
|
+
'rpc-register': (data: {
|
|
1669
|
+
method: string;
|
|
1670
|
+
}) => void;
|
|
1671
|
+
'rpc-unregister': (data: {
|
|
1672
|
+
method: string;
|
|
1673
|
+
}) => void;
|
|
1674
|
+
'rpc-call': (data: {
|
|
1675
|
+
method: string;
|
|
1676
|
+
params: any;
|
|
1677
|
+
}, callback: (response: {
|
|
1678
|
+
ok: boolean;
|
|
1679
|
+
result?: any;
|
|
1680
|
+
error?: string;
|
|
1681
|
+
}) => void) => void;
|
|
1682
|
+
}
|
|
1609
1683
|
type MachineRpcHandlers = {
|
|
1610
1684
|
spawnSession: (options: SpawnSessionOptions) => Promise<SpawnSessionResult>;
|
|
1611
1685
|
stopSession: (sessionId: string) => boolean;
|
|
@@ -1641,6 +1715,9 @@ declare class ApiMachineClient {
|
|
|
1641
1715
|
private machine;
|
|
1642
1716
|
private currentRuntimeDaemonState?;
|
|
1643
1717
|
private socket;
|
|
1718
|
+
/** The daemon's live connection. Reused for device RPC so a CLI command does
|
|
1719
|
+
* not spend ~500ms building its own TLS + WebSocket handshake. */
|
|
1720
|
+
get rpcSocket(): Socket<ServerToDaemonEvents, DaemonToServerEvents>;
|
|
1644
1721
|
private keepAliveInterval;
|
|
1645
1722
|
private rpcHandlerManager;
|
|
1646
1723
|
private claudeCache;
|
package/dist/lib.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { A as ApiClient, a as ApiSessionClient } from './api-
|
|
2
|
-
export { c as configuration, l as logger } from './persistence-
|
|
1
|
+
export { A as ApiClient, a as ApiSessionClient } from './api-K2-jr9ar.mjs';
|
|
2
|
+
export { c as configuration, l as logger } from './persistence-CIUFyOwz.mjs';
|
|
3
3
|
export { R as RawJSONLinesSchema } from './types-BoJh4Qfv.mjs';
|
|
4
4
|
import 'axios';
|
|
5
5
|
import 'node:events';
|
|
@@ -28,6 +28,6 @@ import 'tweetnacl';
|
|
|
28
28
|
import '@stablelib/base64';
|
|
29
29
|
import 'node:readline';
|
|
30
30
|
import 'expo-server-sdk';
|
|
31
|
-
import './sessionKeyCache-
|
|
31
|
+
import './sessionKeyCache-D2u3JUys.mjs';
|
|
32
32
|
import 'chalk';
|
|
33
33
|
import 'fs';
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { l as logger, c as configuration, p as packageJson } from './persistence-
|
|
1
|
+
import { l as logger, c as configuration, p as packageJson } from './persistence-CIUFyOwz.mjs';
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
3
|
import { readFileSync, existsSync, readdirSync } from 'node:fs';
|
|
4
4
|
import os, { homedir } from 'node:os';
|
|
5
5
|
import { join, basename, dirname } from 'node:path';
|
|
6
6
|
import { p as projectPath } from './projectPath-BTBIMB57.mjs';
|
|
7
|
-
import { r as resolveToolsDir, s as startOfflineReconnection, b as saveToolOutputRecord } from './api-
|
|
8
|
-
import { a as detectGitWorktree } from './downloadImage-
|
|
7
|
+
import { r as resolveToolsDir, s as startOfflineReconnection, b as saveToolOutputRecord } from './api-K2-jr9ar.mjs';
|
|
8
|
+
import { a as detectGitWorktree } from './downloadImage-ia5SzlCV.mjs';
|
|
9
9
|
|
|
10
10
|
class BasePermissionHandler {
|
|
11
11
|
pendingRequests = /* @__PURE__ */ new Map();
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var logger = require('./persistence-
|
|
3
|
+
var logger = require('./persistence-DrfN7TzY.cjs');
|
|
4
4
|
var node_crypto = require('node:crypto');
|
|
5
5
|
var fs = require('node:fs');
|
|
6
6
|
var os = require('node:os');
|
|
7
7
|
var path = require('node:path');
|
|
8
8
|
var projectPath = require('./projectPath-ChLhdOyt.cjs');
|
|
9
|
-
var api = require('./api-
|
|
10
|
-
var downloadImage = require('./downloadImage-
|
|
9
|
+
var api = require('./api-XeHlmApX.cjs');
|
|
10
|
+
var downloadImage = require('./downloadImage-B_ygLAXY.cjs');
|
|
11
11
|
|
|
12
12
|
class BasePermissionHandler {
|
|
13
13
|
pendingRequests = /* @__PURE__ */ new Map();
|
|
@@ -14,7 +14,7 @@ function isDebug() {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
var name = "@zonease/happy";
|
|
17
|
-
var version = "0.6.
|
|
17
|
+
var version = "0.6.41";
|
|
18
18
|
var description = "Mobile and Web client for Claude Code, Codex, and Gemini";
|
|
19
19
|
var author = "ZonEaseTech";
|
|
20
20
|
var license = "MIT";
|
|
@@ -941,4 +941,4 @@ var persistence = /*#__PURE__*/Object.freeze({
|
|
|
941
941
|
writeDaemonState: writeDaemonState
|
|
942
942
|
});
|
|
943
943
|
|
|
944
|
-
export { getProfileEnvironmentVariables as A, encryptLegacy as B, getRandomBytes as C, libsodiumEncryptForPublicKey as D, logger$1 as E, persistence as F, readSettings as a, clearCredentials as b, configuration as c, clearMachineId as d,
|
|
944
|
+
export { getProfileEnvironmentVariables as A, encryptLegacy as B, getRandomBytes as C, libsodiumEncryptForPublicKey as D, logger$1 as E, persistence as F, readSettings as a, clearCredentials as b, configuration as c, clearMachineId as d, encodeBase64 as e, encrypt as f, decrypt as g, decodeBase64 as h, isDebug as i, encryptWithDataKey as j, decryptWithDataKey as k, logger as l, readDaemonState as m, clearDaemonState as n, libsodiumPublicKeyFromSecretKey as o, packageJson as p, decryptLegacy as q, readCredentials as r, encodeBase64Url as s, writeCredentialsLegacy as t, updateSettings as u, acquireDaemonLock as v, writeCredentialsDataKey as w, writeDaemonState as x, releaseDaemonLock as y, validateProfileForAgent as z };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var promises = require('node:fs/promises');
|
|
4
|
+
var socket_ioClient = require('socket.io-client');
|
|
5
|
+
var logger = require('./persistence-DrfN7TzY.cjs');
|
|
6
|
+
var ssh = require('./ssh-CBgVwKsB.cjs');
|
|
7
|
+
require('node:fs');
|
|
8
|
+
require('node:os');
|
|
9
|
+
require('node:path');
|
|
10
|
+
require('zod');
|
|
11
|
+
require('node:crypto');
|
|
12
|
+
require('tweetnacl');
|
|
13
|
+
require('chalk');
|
|
14
|
+
require('fs');
|
|
15
|
+
require('./deviceKeys-BpIAWz13.cjs');
|
|
16
|
+
require('axios');
|
|
17
|
+
require('./auth-BQvEuSs5.cjs');
|
|
18
|
+
require('qrcode-terminal');
|
|
19
|
+
require('./time-Bj2HRkKH.cjs');
|
|
20
|
+
require('./browser-C05SP_Tt.cjs');
|
|
21
|
+
require('open');
|
|
22
|
+
require('react');
|
|
23
|
+
require('ink');
|
|
24
|
+
require('./controlClient-DgELDZgM.cjs');
|
|
25
|
+
require('./projectPath-ChLhdOyt.cjs');
|
|
26
|
+
require('path');
|
|
27
|
+
require('url');
|
|
28
|
+
|
|
29
|
+
const CHUNK_BYTES = 8 * 1024 * 1024;
|
|
30
|
+
async function pushToDevice(credentials, query, localPath, remotePath) {
|
|
31
|
+
const resolved = await ssh.resolveDeviceForCommand(credentials, query);
|
|
32
|
+
if (!resolved) return 1;
|
|
33
|
+
const { device, key, variant } = resolved;
|
|
34
|
+
const info = await promises.stat(localPath).catch(() => null);
|
|
35
|
+
if (!info?.isFile()) {
|
|
36
|
+
console.error(`Not a file: ${localPath}`);
|
|
37
|
+
return 1;
|
|
38
|
+
}
|
|
39
|
+
const contents = await promises.readFile(localPath);
|
|
40
|
+
const socket = socket_ioClient.io(logger.configuration.serverUrl, {
|
|
41
|
+
auth: { token: credentials.token, clientType: "user-scoped" },
|
|
42
|
+
path: "/v1/updates",
|
|
43
|
+
transports: ["websocket"]
|
|
44
|
+
});
|
|
45
|
+
await new Promise((resolve, reject) => {
|
|
46
|
+
socket.once("connect", () => resolve());
|
|
47
|
+
socket.once("connect_error", reject);
|
|
48
|
+
});
|
|
49
|
+
const writeChunk = async (path, chunk) => {
|
|
50
|
+
const answer = await socket.timeout(12e4).emitWithAck("rpc-call", {
|
|
51
|
+
method: `${device.id}:writeFile`,
|
|
52
|
+
params: logger.encodeBase64(logger.encrypt(key, variant, { path, content: chunk.toString("base64") }))
|
|
53
|
+
});
|
|
54
|
+
if (!answer?.ok) throw new Error(answer?.error || "writeFile failed");
|
|
55
|
+
const result = logger.decrypt(key, variant, logger.decodeBase64(answer.result));
|
|
56
|
+
if (!result?.success) throw new Error(result?.error || "Device refused the write");
|
|
57
|
+
};
|
|
58
|
+
try {
|
|
59
|
+
if (contents.length <= CHUNK_BYTES) {
|
|
60
|
+
await writeChunk(remotePath, contents);
|
|
61
|
+
console.error(`pushed ${contents.length} bytes to ${device.name}:${remotePath}`);
|
|
62
|
+
return 0;
|
|
63
|
+
}
|
|
64
|
+
const parts = Math.ceil(contents.length / CHUNK_BYTES);
|
|
65
|
+
for (let i = 0; i < parts; i++) {
|
|
66
|
+
await writeChunk(`${remotePath}.part-${i}`, contents.subarray(i * CHUNK_BYTES, (i + 1) * CHUNK_BYTES));
|
|
67
|
+
console.error(` part ${i + 1}/${parts}`);
|
|
68
|
+
}
|
|
69
|
+
console.error(`pushed ${contents.length} bytes to ${device.name}:${remotePath}.part-0..${parts - 1}`);
|
|
70
|
+
console.error(`join with: cat '${remotePath}'.part-* > '${remotePath}' && rm -f '${remotePath}'.part-*`);
|
|
71
|
+
return 0;
|
|
72
|
+
} catch (error) {
|
|
73
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
74
|
+
return 1;
|
|
75
|
+
} finally {
|
|
76
|
+
socket.close();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
exports.pushToDevice = pushToDevice;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { stat, readFile } from 'node:fs/promises';
|
|
2
|
+
import { io } from 'socket.io-client';
|
|
3
|
+
import { c as configuration, e as encodeBase64, f as encrypt, g as decrypt, h as decodeBase64 } from './persistence-CIUFyOwz.mjs';
|
|
4
|
+
import { resolveDeviceForCommand } from './ssh-B0hvEYIl.mjs';
|
|
5
|
+
import 'node:fs';
|
|
6
|
+
import 'node:os';
|
|
7
|
+
import 'node:path';
|
|
8
|
+
import 'zod';
|
|
9
|
+
import 'node:crypto';
|
|
10
|
+
import 'tweetnacl';
|
|
11
|
+
import 'chalk';
|
|
12
|
+
import 'fs';
|
|
13
|
+
import './deviceKeys-CejCdWpw.mjs';
|
|
14
|
+
import 'axios';
|
|
15
|
+
import './auth-DS8fzlin.mjs';
|
|
16
|
+
import 'qrcode-terminal';
|
|
17
|
+
import './time-DgsBLJA_.mjs';
|
|
18
|
+
import './browser-C05Ak6RL.mjs';
|
|
19
|
+
import 'open';
|
|
20
|
+
import 'react';
|
|
21
|
+
import 'ink';
|
|
22
|
+
import './controlClient-DgjVRN8D.mjs';
|
|
23
|
+
import './projectPath-BTBIMB57.mjs';
|
|
24
|
+
import 'path';
|
|
25
|
+
import 'url';
|
|
26
|
+
|
|
27
|
+
const CHUNK_BYTES = 8 * 1024 * 1024;
|
|
28
|
+
async function pushToDevice(credentials, query, localPath, remotePath) {
|
|
29
|
+
const resolved = await resolveDeviceForCommand(credentials, query);
|
|
30
|
+
if (!resolved) return 1;
|
|
31
|
+
const { device, key, variant } = resolved;
|
|
32
|
+
const info = await stat(localPath).catch(() => null);
|
|
33
|
+
if (!info?.isFile()) {
|
|
34
|
+
console.error(`Not a file: ${localPath}`);
|
|
35
|
+
return 1;
|
|
36
|
+
}
|
|
37
|
+
const contents = await readFile(localPath);
|
|
38
|
+
const socket = io(configuration.serverUrl, {
|
|
39
|
+
auth: { token: credentials.token, clientType: "user-scoped" },
|
|
40
|
+
path: "/v1/updates",
|
|
41
|
+
transports: ["websocket"]
|
|
42
|
+
});
|
|
43
|
+
await new Promise((resolve, reject) => {
|
|
44
|
+
socket.once("connect", () => resolve());
|
|
45
|
+
socket.once("connect_error", reject);
|
|
46
|
+
});
|
|
47
|
+
const writeChunk = async (path, chunk) => {
|
|
48
|
+
const answer = await socket.timeout(12e4).emitWithAck("rpc-call", {
|
|
49
|
+
method: `${device.id}:writeFile`,
|
|
50
|
+
params: encodeBase64(encrypt(key, variant, { path, content: chunk.toString("base64") }))
|
|
51
|
+
});
|
|
52
|
+
if (!answer?.ok) throw new Error(answer?.error || "writeFile failed");
|
|
53
|
+
const result = decrypt(key, variant, decodeBase64(answer.result));
|
|
54
|
+
if (!result?.success) throw new Error(result?.error || "Device refused the write");
|
|
55
|
+
};
|
|
56
|
+
try {
|
|
57
|
+
if (contents.length <= CHUNK_BYTES) {
|
|
58
|
+
await writeChunk(remotePath, contents);
|
|
59
|
+
console.error(`pushed ${contents.length} bytes to ${device.name}:${remotePath}`);
|
|
60
|
+
return 0;
|
|
61
|
+
}
|
|
62
|
+
const parts = Math.ceil(contents.length / CHUNK_BYTES);
|
|
63
|
+
for (let i = 0; i < parts; i++) {
|
|
64
|
+
await writeChunk(`${remotePath}.part-${i}`, contents.subarray(i * CHUNK_BYTES, (i + 1) * CHUNK_BYTES));
|
|
65
|
+
console.error(` part ${i + 1}/${parts}`);
|
|
66
|
+
}
|
|
67
|
+
console.error(`pushed ${contents.length} bytes to ${device.name}:${remotePath}.part-0..${parts - 1}`);
|
|
68
|
+
console.error(`join with: cat '${remotePath}'.part-* > '${remotePath}' && rm -f '${remotePath}'.part-*`);
|
|
69
|
+
return 0;
|
|
70
|
+
} catch (error) {
|
|
71
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
72
|
+
return 1;
|
|
73
|
+
} finally {
|
|
74
|
+
socket.close();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export { pushToDevice };
|
|
@@ -3,14 +3,15 @@
|
|
|
3
3
|
var fs$1 = require('fs/promises');
|
|
4
4
|
var os = require('os');
|
|
5
5
|
var tmp = require('tmp');
|
|
6
|
-
var api = require('./api-
|
|
7
|
-
var logger = require('./persistence-
|
|
8
|
-
var auth = require('./auth-
|
|
6
|
+
var api = require('./api-XeHlmApX.cjs');
|
|
7
|
+
var logger = require('./persistence-DrfN7TzY.cjs');
|
|
8
|
+
var auth = require('./auth-BQvEuSs5.cjs');
|
|
9
9
|
var child_process = require('child_process');
|
|
10
|
-
var doctor = require('./doctor-
|
|
11
|
-
var spawnHappyCLI = require('./spawnHappyCLI-
|
|
12
|
-
var controlClient = require('./controlClient-
|
|
13
|
-
var
|
|
10
|
+
var doctor = require('./doctor-DznasgP3.cjs');
|
|
11
|
+
var spawnHappyCLI = require('./spawnHappyCLI-CarRI4GM.cjs');
|
|
12
|
+
var controlClient = require('./controlClient-DgELDZgM.cjs');
|
|
13
|
+
var deviceKeys = require('./deviceKeys-BpIAWz13.cjs');
|
|
14
|
+
var install = require('./install-Ck22tYHP.cjs');
|
|
14
15
|
var fastify = require('fastify');
|
|
15
16
|
var fs = require('node:fs');
|
|
16
17
|
var promises = require('node:fs/promises');
|
|
@@ -182,7 +183,8 @@ function startDaemonControlServer({
|
|
|
182
183
|
stopSession,
|
|
183
184
|
spawnSession,
|
|
184
185
|
requestShutdown,
|
|
185
|
-
onHappySessionWebhook
|
|
186
|
+
onHappySessionWebhook,
|
|
187
|
+
execOnDevice
|
|
186
188
|
}) {
|
|
187
189
|
return new Promise((resolve) => {
|
|
188
190
|
const app = fastify({
|
|
@@ -288,6 +290,23 @@ function startDaemonControlServer({
|
|
|
288
290
|
}))
|
|
289
291
|
};
|
|
290
292
|
});
|
|
293
|
+
typed.post("/device-exec", {
|
|
294
|
+
schema: {
|
|
295
|
+
body: z.z.object({
|
|
296
|
+
deviceId: z.z.string(),
|
|
297
|
+
command: z.z.string(),
|
|
298
|
+
timeoutMs: z.z.number().optional()
|
|
299
|
+
})
|
|
300
|
+
}
|
|
301
|
+
}, async (request, reply) => {
|
|
302
|
+
const { deviceId, command, timeoutMs } = request.body;
|
|
303
|
+
logger.logger.debug(`[CONTROL SERVER] Device exec request for ${deviceId}`);
|
|
304
|
+
try {
|
|
305
|
+
return { ok: true, result: await execOnDevice(deviceId, command, timeoutMs ?? 3e5) };
|
|
306
|
+
} catch (error) {
|
|
307
|
+
return reply.code(200).send({ ok: false, error: error instanceof Error ? error.message : String(error) });
|
|
308
|
+
}
|
|
309
|
+
});
|
|
291
310
|
typed.post("/stop-session", {
|
|
292
311
|
schema: {
|
|
293
312
|
body: z.z.object({
|
|
@@ -1996,12 +2015,28 @@ ${error.message}
|
|
|
1996
2015
|
}
|
|
1997
2016
|
pidToTrackedSession.delete(pid);
|
|
1998
2017
|
};
|
|
2018
|
+
let connectedMachine = null;
|
|
1999
2019
|
const { port: controlPort, stop: stopControlServer } = await startDaemonControlServer({
|
|
2000
2020
|
getChildren: getCurrentChildren,
|
|
2001
2021
|
stopSession,
|
|
2002
2022
|
spawnSession,
|
|
2003
2023
|
requestShutdown: () => requestShutdown("happy-cli"),
|
|
2004
|
-
onHappySessionWebhook
|
|
2024
|
+
onHappySessionWebhook,
|
|
2025
|
+
execOnDevice: async (deviceId, command, timeoutMs) => {
|
|
2026
|
+
if (!connectedMachine) {
|
|
2027
|
+
throw new Error("Daemon is not connected yet");
|
|
2028
|
+
}
|
|
2029
|
+
const material = await deviceKeys.readCachedDeviceKey(deviceId);
|
|
2030
|
+
if (!material) {
|
|
2031
|
+
throw new Error(`No cached key for device ${deviceId}`);
|
|
2032
|
+
}
|
|
2033
|
+
return await deviceKeys.deviceExec(connectedMachine.rpcSocket, credentials, deviceId, command, {
|
|
2034
|
+
deviceKeyBase64: logger.encodeBase64(material.key),
|
|
2035
|
+
deviceKeyVariant: material.variant,
|
|
2036
|
+
timeout: timeoutMs,
|
|
2037
|
+
skipMachineLookup: true
|
|
2038
|
+
});
|
|
2039
|
+
}
|
|
2005
2040
|
});
|
|
2006
2041
|
const fileState = {
|
|
2007
2042
|
pid: process.pid,
|
|
@@ -2035,6 +2070,7 @@ ${error.message}
|
|
|
2035
2070
|
orchestratorCancel: handleOrchestratorCancel
|
|
2036
2071
|
});
|
|
2037
2072
|
apiMachine.connect();
|
|
2073
|
+
connectedMachine = apiMachine;
|
|
2038
2074
|
apiMachine.updateMachineMetadata((current) => ({ ...current, ...machineMetadata })).catch((error) => {
|
|
2039
2075
|
logger.logger.debug("[DAEMON RUN] Failed to update machine metadata", error);
|
|
2040
2076
|
});
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import fs from 'fs/promises';
|
|
2
2
|
import os from 'os';
|
|
3
3
|
import * as tmp from 'tmp';
|
|
4
|
-
import { A as ApiClient } from './api-
|
|
5
|
-
import { c as configuration, l as logger, p as packageJson, v as acquireDaemonLock, a as readSettings, i as isDebug, x as writeDaemonState,
|
|
6
|
-
import { authAndSetupMachineIfNeeded } from './auth-
|
|
4
|
+
import { A as ApiClient } from './api-K2-jr9ar.mjs';
|
|
5
|
+
import { c as configuration, l as logger, p as packageJson, v as acquireDaemonLock, a as readSettings, i as isDebug, e as encodeBase64, x as writeDaemonState, m as readDaemonState, y as releaseDaemonLock, z as validateProfileForAgent, A as getProfileEnvironmentVariables } from './persistence-CIUFyOwz.mjs';
|
|
6
|
+
import { authAndSetupMachineIfNeeded } from './auth-DS8fzlin.mjs';
|
|
7
7
|
import { spawn, execSync, exec } from 'child_process';
|
|
8
|
-
import { getEnvironmentInfo } from './doctor-
|
|
9
|
-
import { s as spawnHappyCLI } from './spawnHappyCLI-
|
|
10
|
-
import { isDaemonRunningCurrentlyInstalledHappyVersion, stopDaemon, cleanupDaemonState } from './controlClient-
|
|
11
|
-
import {
|
|
8
|
+
import { getEnvironmentInfo } from './doctor-B-LCMVN9.mjs';
|
|
9
|
+
import { s as spawnHappyCLI } from './spawnHappyCLI-D3EkTFIn.mjs';
|
|
10
|
+
import { isDaemonRunningCurrentlyInstalledHappyVersion, stopDaemon, cleanupDaemonState } from './controlClient-DgjVRN8D.mjs';
|
|
11
|
+
import { a as readCachedDeviceKey, d as deviceExec } from './deviceKeys-CejCdWpw.mjs';
|
|
12
|
+
import { P as PLIST_LABEL } from './install-B3mMGISS.mjs';
|
|
12
13
|
import fastify from 'fastify';
|
|
13
14
|
import { createReadStream } from 'node:fs';
|
|
14
15
|
import { stat } from 'node:fs/promises';
|
|
@@ -161,7 +162,8 @@ function startDaemonControlServer({
|
|
|
161
162
|
stopSession,
|
|
162
163
|
spawnSession,
|
|
163
164
|
requestShutdown,
|
|
164
|
-
onHappySessionWebhook
|
|
165
|
+
onHappySessionWebhook,
|
|
166
|
+
execOnDevice
|
|
165
167
|
}) {
|
|
166
168
|
return new Promise((resolve) => {
|
|
167
169
|
const app = fastify({
|
|
@@ -267,6 +269,23 @@ function startDaemonControlServer({
|
|
|
267
269
|
}))
|
|
268
270
|
};
|
|
269
271
|
});
|
|
272
|
+
typed.post("/device-exec", {
|
|
273
|
+
schema: {
|
|
274
|
+
body: z.object({
|
|
275
|
+
deviceId: z.string(),
|
|
276
|
+
command: z.string(),
|
|
277
|
+
timeoutMs: z.number().optional()
|
|
278
|
+
})
|
|
279
|
+
}
|
|
280
|
+
}, async (request, reply) => {
|
|
281
|
+
const { deviceId, command, timeoutMs } = request.body;
|
|
282
|
+
logger.debug(`[CONTROL SERVER] Device exec request for ${deviceId}`);
|
|
283
|
+
try {
|
|
284
|
+
return { ok: true, result: await execOnDevice(deviceId, command, timeoutMs ?? 3e5) };
|
|
285
|
+
} catch (error) {
|
|
286
|
+
return reply.code(200).send({ ok: false, error: error instanceof Error ? error.message : String(error) });
|
|
287
|
+
}
|
|
288
|
+
});
|
|
270
289
|
typed.post("/stop-session", {
|
|
271
290
|
schema: {
|
|
272
291
|
body: z.object({
|
|
@@ -1975,12 +1994,28 @@ ${error.message}
|
|
|
1975
1994
|
}
|
|
1976
1995
|
pidToTrackedSession.delete(pid);
|
|
1977
1996
|
};
|
|
1997
|
+
let connectedMachine = null;
|
|
1978
1998
|
const { port: controlPort, stop: stopControlServer } = await startDaemonControlServer({
|
|
1979
1999
|
getChildren: getCurrentChildren,
|
|
1980
2000
|
stopSession,
|
|
1981
2001
|
spawnSession,
|
|
1982
2002
|
requestShutdown: () => requestShutdown("happy-cli"),
|
|
1983
|
-
onHappySessionWebhook
|
|
2003
|
+
onHappySessionWebhook,
|
|
2004
|
+
execOnDevice: async (deviceId, command, timeoutMs) => {
|
|
2005
|
+
if (!connectedMachine) {
|
|
2006
|
+
throw new Error("Daemon is not connected yet");
|
|
2007
|
+
}
|
|
2008
|
+
const material = await readCachedDeviceKey(deviceId);
|
|
2009
|
+
if (!material) {
|
|
2010
|
+
throw new Error(`No cached key for device ${deviceId}`);
|
|
2011
|
+
}
|
|
2012
|
+
return await deviceExec(connectedMachine.rpcSocket, credentials, deviceId, command, {
|
|
2013
|
+
deviceKeyBase64: encodeBase64(material.key),
|
|
2014
|
+
deviceKeyVariant: material.variant,
|
|
2015
|
+
timeout: timeoutMs,
|
|
2016
|
+
skipMachineLookup: true
|
|
2017
|
+
});
|
|
2018
|
+
}
|
|
1984
2019
|
});
|
|
1985
2020
|
const fileState = {
|
|
1986
2021
|
pid: process.pid,
|
|
@@ -2014,6 +2049,7 @@ ${error.message}
|
|
|
2014
2049
|
orchestratorCancel: handleOrchestratorCancel
|
|
2015
2050
|
});
|
|
2016
2051
|
apiMachine.connect();
|
|
2052
|
+
connectedMachine = apiMachine;
|
|
2017
2053
|
apiMachine.updateMachineMetadata((current) => ({ ...current, ...machineMetadata })).catch((error) => {
|
|
2018
2054
|
logger.debug("[DAEMON RUN] Failed to update machine metadata", error);
|
|
2019
2055
|
});
|