@jian-ai/remote-control 0.8.0 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -1
- package/bin/computer-linux.mjs +537 -0
- package/bin/computer-macos.mjs +255 -59
- package/bin/computer-shared.mjs +61 -0
- package/bin/computer-windows.mjs +516 -0
- package/bin/computer.mjs +63 -0
- package/bin/jian-remote.mjs +44 -27
- package/linux/computer-helper.py +694 -0
- package/macos/build-helper.sh +46 -0
- package/macos/computer-helper +0 -0
- package/macos/computer-helper.swift +300 -131
- package/package.json +3 -1
- package/windows/computer-helper.ps1 +500 -0
package/bin/jian-remote.mjs
CHANGED
|
@@ -21,7 +21,7 @@ const option = (name) => {
|
|
|
21
21
|
* Stamped to the release tag on npm publish and when the gateway serves this script.
|
|
22
22
|
* Compatibility with the gateway requires the same major.minor (see versionsCompatible).
|
|
23
23
|
*/
|
|
24
|
-
export const PACKAGE_VERSION = '0.8.
|
|
24
|
+
export const PACKAGE_VERSION = '0.8.2';
|
|
25
25
|
|
|
26
26
|
/** Soft stdout/stderr caps while capturing a command (chars). Gateway schema matches these. */
|
|
27
27
|
const STDOUT_CAP = 400_000;
|
|
@@ -136,6 +136,9 @@ export function buildMacosAppInfoPlist() {
|
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
export function buildLaunchAgentPlist({ label, executable, script, logPath }) {
|
|
139
|
+
// ProcessType=Interactive opts the worker out of App Nap. Without it, macOS can freeze the
|
|
140
|
+
// Node poll loop while the screen is locked or idle; lastSeenAt ages out and the gateway
|
|
141
|
+
// shows Offline even though the process is still "running".
|
|
139
142
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
140
143
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
141
144
|
<plist version="1.0"><dict>
|
|
@@ -148,6 +151,7 @@ export function buildLaunchAgentPlist({ label, executable, script, logPath }) {
|
|
|
148
151
|
<string>${xmlEscape(script)}</string>
|
|
149
152
|
<string>run</string>
|
|
150
153
|
</array>
|
|
154
|
+
<key>ProcessType</key><string>Interactive</string>
|
|
151
155
|
<key>RunAtLoad</key><true/>
|
|
152
156
|
<key>KeepAlive</key><true/>
|
|
153
157
|
<key>StandardOutPath</key><string>${xmlEscape(logPath)}</string>
|
|
@@ -486,19 +490,26 @@ async function materializeWorkerScript(sourceBytes) {
|
|
|
486
490
|
if (source !== installedScript) await copyFile(source, installedScript);
|
|
487
491
|
}
|
|
488
492
|
if (process.platform !== 'win32') await chmod(installedScript, 0o700);
|
|
489
|
-
// Companion modules +
|
|
493
|
+
// Companion modules + OS helpers (computer use). Best-effort beside the worker.
|
|
490
494
|
try {
|
|
491
495
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
492
|
-
const
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
496
|
+
const companions = [
|
|
497
|
+
'computer.mjs',
|
|
498
|
+
'computer-shared.mjs',
|
|
499
|
+
'computer-macos.mjs',
|
|
500
|
+
'computer-linux.mjs',
|
|
501
|
+
'computer-windows.mjs',
|
|
502
|
+
];
|
|
503
|
+
for (const name of companions) {
|
|
504
|
+
const src = join(here, name);
|
|
505
|
+
const dest = join(configDir, name);
|
|
506
|
+
if (existsSync(src) && src !== dest) {
|
|
507
|
+
await copyFile(src, dest);
|
|
508
|
+
if (process.platform !== 'win32') await chmod(dest, 0o700);
|
|
509
|
+
}
|
|
501
510
|
}
|
|
511
|
+
const { materializeComputerHelperSources } = await import('./computer.mjs');
|
|
512
|
+
await materializeComputerHelperSources(configDir);
|
|
502
513
|
} catch {
|
|
503
514
|
// Install still succeeds; computer-use probe will explain if the helper is missing.
|
|
504
515
|
}
|
|
@@ -816,17 +827,7 @@ async function executeShell(task) {
|
|
|
816
827
|
|
|
817
828
|
async function execute(task) {
|
|
818
829
|
if (task.kind === 'computer') {
|
|
819
|
-
|
|
820
|
-
return {
|
|
821
|
-
taskId: task.id,
|
|
822
|
-
exitCode: 1,
|
|
823
|
-
stdout: '',
|
|
824
|
-
stderr: 'Computer use is supported on macOS Jian Remote only.',
|
|
825
|
-
timedOut: false,
|
|
826
|
-
computer: { ok: false, error: 'Computer use is supported on macOS Jian Remote only.' },
|
|
827
|
-
};
|
|
828
|
-
}
|
|
829
|
-
const { executeComputerTask } = await import('./computer-macos.mjs');
|
|
830
|
+
const { executeComputerTask } = await import('./computer.mjs');
|
|
830
831
|
return executeComputerTask(task);
|
|
831
832
|
}
|
|
832
833
|
return executeShell(task);
|
|
@@ -940,20 +941,35 @@ async function postResult(base, headers, result) {
|
|
|
940
941
|
async function run() {
|
|
941
942
|
const config = await loadConfig();
|
|
942
943
|
const capabilities = [];
|
|
944
|
+
let probeMacUiState = () => 'unknown';
|
|
945
|
+
try {
|
|
946
|
+
const { probeComputerCapability, computerCapabilityName } = await import('./computer.mjs');
|
|
947
|
+
const name = computerCapabilityName();
|
|
948
|
+
if (name && (await probeComputerCapability())) capabilities.push(name);
|
|
949
|
+
} catch {
|
|
950
|
+
// Computer use unavailable until helper is ready; shell tasks still work.
|
|
951
|
+
}
|
|
943
952
|
if (process.platform === 'darwin') {
|
|
944
953
|
try {
|
|
945
|
-
const
|
|
946
|
-
|
|
954
|
+
const mac = await import('./computer-macos.mjs');
|
|
955
|
+
mac.startWorkerIdleAssertion(process.pid);
|
|
956
|
+
probeMacUiState = () => mac.probeMacUiState();
|
|
957
|
+
for (const signal of ['SIGINT', 'SIGTERM']) {
|
|
958
|
+
process.once(signal, () => {
|
|
959
|
+
mac.stopWorkerIdleAssertion();
|
|
960
|
+
});
|
|
961
|
+
}
|
|
947
962
|
} catch {
|
|
948
|
-
//
|
|
963
|
+
// Idle assertion / uiState probe optional; shell still works.
|
|
949
964
|
}
|
|
950
965
|
}
|
|
951
|
-
const
|
|
966
|
+
const pollHeaders = () => ({
|
|
952
967
|
authorization: `Bearer ${config.token}`,
|
|
953
968
|
'x-jian-platform': `${process.platform}-${process.arch}`,
|
|
954
969
|
'x-jian-remote-version': PACKAGE_VERSION,
|
|
970
|
+
'x-jian-remote-ui-state': probeMacUiState(),
|
|
955
971
|
...(capabilities.length ? { 'x-jian-remote-capabilities': capabilities.join(',') } : {}),
|
|
956
|
-
};
|
|
972
|
+
});
|
|
957
973
|
const base = `${config.gateway}/v1/remote/worker/${config.machineId}`;
|
|
958
974
|
// Fail fast before the poll loop so an incompatible build does not look "online then stuck".
|
|
959
975
|
const gatewayVersion = await assertCompatibleWithGateway(config.gateway);
|
|
@@ -978,6 +994,7 @@ async function run() {
|
|
|
978
994
|
};
|
|
979
995
|
while (true) {
|
|
980
996
|
try {
|
|
997
|
+
const headers = pollHeaders();
|
|
981
998
|
if (Date.now() >= nextUpdateCheck) {
|
|
982
999
|
await ensureCompatible();
|
|
983
1000
|
await updateIfNeeded(base, headers);
|