@miruzero/zero-agent 0.3.5 → 0.3.7
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 +31 -22
- package/package.json +6 -3
- package/src/agent.js +193 -158
- package/src/args.js +1 -3
- package/src/autostart.js +44 -68
- package/src/capabilities.js +98 -104
- package/src/chatgpt/auth/index.js +114 -0
- package/src/chatgpt/config/paths.js +25 -0
- package/src/chatgpt/index.js +5 -0
- package/src/chatgpt/session/direct-transport.js +68 -0
- package/src/chatgpt/session/exchange.js +17 -0
- package/src/chatgpt/session/index.js +102 -0
- package/src/chatgpt/session/local-storage.js +106 -0
- package/src/chatgpt/transport/direct/http-client.js +191 -0
- package/src/chatgpt-auth.js +27 -0
- package/src/chatgpt-runtime.js +8 -0
- package/src/chatgpt-session-exchange.js +8 -0
- package/src/chatgpt-session.js +26 -0
- package/src/cli.js +108 -71
- package/src/command/exec.js +34 -0
- package/src/command/filesystem/append-file.js +7 -12
- package/src/command/filesystem/copy-directory.js +8 -12
- package/src/command/filesystem/copy-file.js +8 -13
- package/src/command/filesystem/create-directory.js +7 -11
- package/src/command/filesystem/create-file.js +8 -13
- package/src/command/filesystem/delete-directory.js +7 -11
- package/src/command/filesystem/delete-file.js +8 -12
- package/src/command/filesystem/exists.js +6 -10
- package/src/command/filesystem/get-file-info.js +7 -12
- package/src/command/filesystem/glob-files.js +8 -13
- package/src/command/filesystem/grep-files.js +9 -15
- package/src/command/filesystem/hash-file.js +6 -11
- package/src/command/filesystem/index.js +33 -34
- package/src/command/filesystem/list-directory.js +6 -10
- package/src/command/filesystem/move-directory.js +9 -14
- package/src/command/filesystem/move-file.js +8 -13
- package/src/command/filesystem/path-policy.js +33 -16
- package/src/command/filesystem/read-file.js +7 -11
- package/src/command/filesystem/read-files.js +5 -8
- package/src/command/filesystem/rename-file.js +5 -8
- package/src/command/filesystem/replace-file.js +7 -12
- package/src/command/filesystem/text.js +5 -7
- package/src/command/filesystem/touch-file.js +8 -13
- package/src/command/filesystem/truncate-file.js +6 -10
- package/src/command/filesystem/walk.js +36 -39
- package/src/command/filesystem/write-file.js +8 -13
- package/src/command/index.js +19 -24
- package/src/command/path/index.js +46 -53
- package/src/config.js +21 -33
- package/src/device-paths.js +53 -0
- package/src/enrollment-client.js +19 -0
- package/src/http.js +27 -2
- package/src/identity-state.js +27 -0
- package/src/index.js +2 -4
- package/src/instance.js +85 -0
- package/src/local-server.js +174 -0
- package/src/local-tools.js +205 -205
- package/src/shared-zero/catalog.js +33 -0
- package/src/shared-zero/contract.js +18 -0
- package/src/shared-zero/descriptor.js +25 -0
- package/src/shared-zero/errors.js +12 -0
- package/src/shared-zero/index.js +9 -0
- package/src/shared-zero/runtime.js +14 -0
- package/src/shared-zero/target.js +19 -0
- package/src/shared-zero/tool-id.js +26 -0
- package/src/storage-roots.js +21 -0
- package/src/zero-runtime.js +1 -11
- package/src/zero.js +78 -0
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# Zero Agent
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`zero-agent` is the machine-local execution worker for Miruko Zero OS. It owns target-side execution, local identity/state, filesystem/path policy, capability reporting, and task completion back to Zero Core.
|
|
4
|
+
|
|
5
|
+
It does not own the public MCP endpoint or global device registry authority. The package includes only the machine-local ChatGPT auth/session runtime required by its login flow.
|
|
4
6
|
|
|
5
7
|
## Quick start
|
|
6
8
|
|
|
@@ -8,14 +10,11 @@ Local worker agent for Zero MCP multi-device execution.
|
|
|
8
10
|
npx @miruzero/zero-agent@latest start --once
|
|
9
11
|
```
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
## Commands
|
|
13
|
+
Commands exposed by the package include:
|
|
14
14
|
|
|
15
|
-
```
|
|
16
|
-
zero-agent setup
|
|
17
|
-
zero-agent start --once
|
|
18
|
-
zero-agent start
|
|
15
|
+
```text
|
|
16
|
+
zero-agent setup
|
|
17
|
+
zero-agent start [--once]
|
|
19
18
|
zero-agent status
|
|
20
19
|
zero-agent doctor
|
|
21
20
|
zero-agent providers
|
|
@@ -23,23 +22,33 @@ zero-agent tools
|
|
|
23
22
|
zero-agent capabilities
|
|
24
23
|
```
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
Default state path:
|
|
25
|
+
For source validation:
|
|
29
26
|
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
```powershell
|
|
28
|
+
Set-Location M:\Zero_HOME\source\agent\zero-agent
|
|
29
|
+
npm test
|
|
30
|
+
npm run doctor
|
|
31
|
+
npm pack --dry-run
|
|
34
32
|
```
|
|
33
|
+
## Runtime ownership
|
|
35
34
|
|
|
36
|
-
|
|
35
|
+
Zero Agent owns the machine-local capability boundary. It reports capabilities to Core and executes work only inside local policy/identity constraints.
|
|
37
36
|
|
|
38
|
-
|
|
37
|
+
Shared Zero capabilities should be reached through the module’s Zero root rather than rebuilding dependency ownership in every file. Public capability paths stay stable while implementations may change behind them.
|
|
39
38
|
|
|
40
|
-
##
|
|
39
|
+
## ChatGPT boundary
|
|
41
40
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
Zero Agent owns the ChatGPT auth/session capability required by HOME under `src/chatgpt/`. `src/chatgpt-runtime.js` resolves this package-local implementation only; sibling ChatGPT projects are Supplier / R&D references, never runtime dependencies.
|
|
42
|
+
|
|
43
|
+
The owner can reuse a valid HOME auth context or acquire one from the current machine's local ChatGPT session state. The machine-local handoff reads Chrome Local Storage as input, selects the active personal workspace when available, performs the HOME-owned direct session exchange, persists canonical state under the Agent home, and returns only redacted readiness to Core.
|
|
44
|
+
|
|
45
|
+
There is no Puppeteer/Playwright/CDP browser launcher and no runtime require/import of `M:\Zero_ChatGPT`.
|
|
46
|
+
|
|
47
|
+
## Local instance ownership
|
|
48
|
+
|
|
49
|
+
A current Agent instance acquires local ownership before polling. Replacement/takeover behavior exists to prevent duplicate pollers for the same paired identity. Inspect current tests/source before relying on old PID/process notes.
|
|
50
|
+
|
|
51
|
+
## Secrets
|
|
52
|
+
|
|
53
|
+
Device tokens, machine auth material, ChatGPT session data, cookies and setup tickets are local secrets. Never print, commit, or return them in ordinary diagnostics. Report only redacted status/evidence.
|
|
54
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@miruzero/zero-agent",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
4
|
"description": "MiruZero local worker agent for multi-device tool execution.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"zero-agent": "bin/zero-agent.js"
|
|
12
12
|
},
|
|
13
13
|
"scripts": {
|
|
14
|
-
"test": "node --test",
|
|
14
|
+
"test": "node --test && node ../../ownership/verify.js",
|
|
15
15
|
"start": "node bin/zero-agent.js start",
|
|
16
16
|
"doctor": "node bin/zero-agent.js doctor"
|
|
17
17
|
},
|
|
@@ -25,6 +25,9 @@
|
|
|
25
25
|
},
|
|
26
26
|
"license": "UNLICENSED",
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"
|
|
28
|
+
"classic-level": "^3.0.0"
|
|
29
|
+
},
|
|
30
|
+
"allowScripts": {
|
|
31
|
+
"classic-level@3.0.0": true
|
|
29
32
|
}
|
|
30
33
|
}
|
package/src/agent.js
CHANGED
|
@@ -1,158 +1,193 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if (
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const zero = require('./zero');
|
|
4
|
+
|
|
5
|
+
const nowIso = () => new Date().toISOString();
|
|
6
|
+
|
|
7
|
+
const serverBase = (server) => String(server || 'https://zero.miru.work').replace(/\/$/, '');
|
|
8
|
+
const trace = (env, event, payload = {}) => {
|
|
9
|
+
if (env.ZERO_TRACE !== '1') return;
|
|
10
|
+
console.log(JSON.stringify({ at: nowIso(), event, ...payload }));
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
exports.initDevice = ({ name, server }, env = process.env) => {
|
|
14
|
+
const host = zero.os.hostname();
|
|
15
|
+
const device = {
|
|
16
|
+
name: name || host,
|
|
17
|
+
host,
|
|
18
|
+
server: server || 'https://zero.miru.work',
|
|
19
|
+
device_id: null,
|
|
20
|
+
status: 'initialized',
|
|
21
|
+
created_at: nowIso(),
|
|
22
|
+
updated_at: nowIso()
|
|
23
|
+
};
|
|
24
|
+
const file = zero.config.saveDevice(device, env);
|
|
25
|
+
return { file, device: zero.config.redactedDevice(device) };
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
exports.pairDevice = async ({ name, server, code }, env = process.env) => {
|
|
29
|
+
if (!server) throw Object.assign(new Error('server is required'), { exitCode: 64 });
|
|
30
|
+
if (!code) throw Object.assign(new Error('pairing code is required'), { exitCode: 64 });
|
|
31
|
+
const host = zero.os.hostname();
|
|
32
|
+
const payload = { name: name || host, pairing_code: code, host };
|
|
33
|
+
const result = await zero.http.requestJson(`${serverBase(server)}/devices/register`, {
|
|
34
|
+
method: 'POST',
|
|
35
|
+
body: payload
|
|
36
|
+
});
|
|
37
|
+
if (!result.ok) {
|
|
38
|
+
const error = new Error(`pair failed status=${result.status}`);
|
|
39
|
+
error.response = result.json;
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
const device = {
|
|
43
|
+
name: payload.name,
|
|
44
|
+
host,
|
|
45
|
+
server,
|
|
46
|
+
device_id: result.json.device_id,
|
|
47
|
+
device_token: result.json.device_token,
|
|
48
|
+
status: 'paired',
|
|
49
|
+
paired_at: nowIso(),
|
|
50
|
+
updated_at: nowIso()
|
|
51
|
+
};
|
|
52
|
+
const file = zero.config.saveDevice(device, env);
|
|
53
|
+
return { file, device: zero.config.redactedDevice(device) };
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
exports.getPairedDevice = (env = process.env) => {
|
|
57
|
+
const device = zero.config.loadDevice(env);
|
|
58
|
+
if (!device || !device.device_id || !device.device_token || !device.server) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
return device;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
exports.heartbeatPayload = (device, env = process.env) => {
|
|
65
|
+
const capability = zero.capabilities.buildCapabilities(env);
|
|
66
|
+
return {
|
|
67
|
+
name: device.name,
|
|
68
|
+
status: 'online',
|
|
69
|
+
last_seen: nowIso(),
|
|
70
|
+
agentVersion: zero.pkg.version,
|
|
71
|
+
contractVersion: zero.contract.version,
|
|
72
|
+
platform: process.platform,
|
|
73
|
+
architecture: process.arch,
|
|
74
|
+
capability_hash: capability.capability_hash,
|
|
75
|
+
provider_count: capability.providers.length
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
exports.heartbeatOnce = async (env = process.env) => {
|
|
80
|
+
const device = exports.getPairedDevice(env);
|
|
81
|
+
if (!device) return { ok: false, code: 'NOT_PAIRED', message: 'run zero-agent pair first' };
|
|
82
|
+
const url = `${serverBase(device.server)}/devices/${encodeURIComponent(device.device_id)}/heartbeat`;
|
|
83
|
+
const result = await zero.http.requestJson(url, {
|
|
84
|
+
method: 'POST',
|
|
85
|
+
token: device.device_token,
|
|
86
|
+
body: exports.heartbeatPayload(device, env)
|
|
87
|
+
});
|
|
88
|
+
return { ok: result.ok, status: result.status, body: result.json };
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
exports.syncCapabilitiesOnce = async (env = process.env) => {
|
|
92
|
+
const device = exports.getPairedDevice(env);
|
|
93
|
+
if (!device) return { ok: false, code: 'NOT_PAIRED' };
|
|
94
|
+
const url = `${serverBase(device.server)}/devices/${encodeURIComponent(device.device_id)}/capabilities`;
|
|
95
|
+
const result = await zero.http.requestJson(url, {
|
|
96
|
+
method: 'POST',
|
|
97
|
+
token: device.device_token,
|
|
98
|
+
body: zero.capabilities.buildCapabilities(env)
|
|
99
|
+
});
|
|
100
|
+
return { ok: result.ok, status: result.status, body: result.json };
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
exports.executeTask = (task = {}, env = process.env) => {
|
|
105
|
+
if (task.contractVersion) zero.contract.assertCompatible(task.contractVersion);
|
|
106
|
+
if (task.deadline && Date.parse(task.deadline) <= Date.now()) {
|
|
107
|
+
throw Object.assign(new Error('task deadline exceeded'), { code: 'TASK_DEADLINE_EXCEEDED', retryable: false });
|
|
108
|
+
}
|
|
109
|
+
const tool = String(task.tool || '');
|
|
110
|
+
if (tool === 'zero.chatgpt.auth.check') {
|
|
111
|
+
const status = zero.chatgptAuth.status({ env }).auth || {};
|
|
112
|
+
const auth = ['valid', 'expired', 'missing', 'invalid'].includes(status.status) ? status.status : 'invalid';
|
|
113
|
+
return {
|
|
114
|
+
state: auth === 'valid' ? 'auth_valid' : 'auth_required',
|
|
115
|
+
runtime: 'ready',
|
|
116
|
+
auth,
|
|
117
|
+
redacted: true
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
if (tool === 'zero.device.paths.setAllowedRoots') {
|
|
121
|
+
return zero.devicePaths.saveAllowedRoots(task.arguments?.roots || [], env);
|
|
122
|
+
}
|
|
123
|
+
if (tool.startsWith('zero.command.') || tool === 'readFile' || tool === 'command.readFile') {
|
|
124
|
+
try { return zero.command.callTool(tool, task.arguments || {}, { env }); }
|
|
125
|
+
catch (error) {
|
|
126
|
+
if (error.code !== 'UNKNOWN_TOOL') throw error;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return zero.localTools.execute(tool, task.arguments || {}, env);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
exports.executeTaskAsync = async (task = {}, env = process.env) => {
|
|
133
|
+
if (String(task.tool || '') !== 'zero.chatgpt.auth.ensure') return exports.executeTask(task, env);
|
|
134
|
+
if (task.contractVersion) zero.contract.assertCompatible(task.contractVersion);
|
|
135
|
+
if (task.deadline && Date.parse(task.deadline) <= Date.now()) {
|
|
136
|
+
throw Object.assign(new Error('task deadline exceeded'), { code: 'TASK_DEADLINE_EXCEEDED', retryable: false });
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
await zero.chatgptAuth.ensure({ env });
|
|
140
|
+
return { state: 'auth_valid', runtime: 'ready', auth: 'valid', redacted: true };
|
|
141
|
+
} catch (error) {
|
|
142
|
+
const recoverable = new Set([
|
|
143
|
+
'AUTH_REQUIRED', 'CHATGPT_LOCAL_SESSION_NOT_FOUND', 'CHATGPT_LOCAL_SESSION_AMBIGUOUS',
|
|
144
|
+
'CHATGPT_SESSION_MARKER_MISSING', 'CHATGPT_SESSION_NOT_AUTHENTICATED',
|
|
145
|
+
'CHATGPT_SESSION_FETCH_FAILED', 'CHATGPT_SESSION_BOOTSTRAP_FAILED',
|
|
146
|
+
'CHATGPT_SESSION_BOOTSTRAP_COOKIE_MISSING', 'CHATGPT_SESSION_EXCHANGE_FAILED'
|
|
147
|
+
]);
|
|
148
|
+
if (!recoverable.has(error?.code)) throw error;
|
|
149
|
+
const status = zero.chatgptAuth.status({ env }).auth || {};
|
|
150
|
+
const auth = ['expired', 'missing', 'invalid'].includes(status.status) ? status.status : 'missing';
|
|
151
|
+
return { state: 'auth_required', runtime: 'ready', auth, redacted: true };
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
exports.executeAndPostTask = async (task, device, env = process.env) => {
|
|
155
|
+
const started = Date.now();
|
|
156
|
+
trace(env, 'agent.task.received', { task_id: task.task_id, tool: task.tool, args: task.arguments || {} });
|
|
157
|
+
const resultUrl = serverBase(device.server) + '/devices/' + encodeURIComponent(device.device_id)
|
|
158
|
+
+ '/tasks/' + encodeURIComponent(task.task_id) + '/result';
|
|
159
|
+
try {
|
|
160
|
+
const result = await exports.executeTaskAsync(task, env);
|
|
161
|
+
trace(env, 'agent.task.done', { task_id: task.task_id, ok: true, duration_ms: Date.now() - started });
|
|
162
|
+
const posted = await zero.http.requestJson(resultUrl, { method: 'POST', token: device.device_token, body: { ok: true, result } });
|
|
163
|
+
return { ok: posted.ok, task: posted.json?.task || task, result, posted: { status: posted.status, body: posted.json } };
|
|
164
|
+
} catch (error) {
|
|
165
|
+
const payload = { ok: false, error: { code: error.code || 'AGENT_EXEC_ERROR', message: error.message || String(error) } };
|
|
166
|
+
trace(env, 'agent.task.done', { task_id: task.task_id, ok: false, error: payload.error, duration_ms: Date.now() - started });
|
|
167
|
+
const posted = await zero.http.requestJson(resultUrl, { method: 'POST', token: device.device_token, body: payload });
|
|
168
|
+
return { ok: false, task: posted.json?.task || task, error: payload.error, posted: { status: posted.status, body: posted.json } };
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
exports.listenTaskStreamOnce = async (env = process.env, { signal } = {}) => {
|
|
173
|
+
const device = exports.getPairedDevice(env);
|
|
174
|
+
if (!device) return { ok: false, code: 'NOT_PAIRED' };
|
|
175
|
+
const streamUrl = serverBase(device.server) + '/devices/' + encodeURIComponent(device.device_id) + '/tasks/stream';
|
|
176
|
+
let lastTask = null;
|
|
177
|
+
const stream = await zero.http.consumeEventStream(streamUrl, {
|
|
178
|
+
token: device.device_token,
|
|
179
|
+
signal,
|
|
180
|
+
onEvent: async ({ event, data }) => {
|
|
181
|
+
if (event !== 'task') return;
|
|
182
|
+
const task = JSON.parse(data);
|
|
183
|
+
lastTask = await exports.executeAndPostTask(task, device, env);
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
return { ...stream, task: lastTask?.task || null, result: lastTask?.result || null };
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
exports.listDevices = async (env = process.env) => {
|
|
190
|
+
const device = zero.config.loadDevice(env);
|
|
191
|
+
const result = await zero.http.requestJson(`${serverBase(device?.server)}/devices`);
|
|
192
|
+
return { ok: result.ok, status: result.status, body: result.json };
|
|
193
|
+
};
|
package/src/args.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
exports.parseArgs = (argv = []) => {
|
|
4
4
|
const out = { _: [] };
|
|
5
5
|
for (let index = 0; index < argv.length; index += 1) {
|
|
6
6
|
const item = argv[index];
|
|
@@ -24,5 +24,3 @@ const parseArgs = (argv = []) => {
|
|
|
24
24
|
}
|
|
25
25
|
return out;
|
|
26
26
|
};
|
|
27
|
-
|
|
28
|
-
module.exports = { parseArgs };
|