@just-every/manager 0.1.67 → 0.1.68
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 +0 -26
- package/bin/justevery-manager.js +29 -53
- package/package.json +2 -4
- package/lib/queue-cli.js +0 -260
package/README.md
CHANGED
|
@@ -17,29 +17,6 @@ justevery-manager
|
|
|
17
17
|
Use `--download-only` to cache the installer without launching it, and
|
|
18
18
|
`--print-path` to print the cached path.
|
|
19
19
|
|
|
20
|
-
### Queue commands
|
|
21
|
-
|
|
22
|
-
```bash
|
|
23
|
-
justevery-manager queue devices
|
|
24
|
-
|
|
25
|
-
justevery-manager queue start \
|
|
26
|
-
--device dev_123 \
|
|
27
|
-
--message "Start a new session"
|
|
28
|
-
|
|
29
|
-
justevery-manager queue followup \
|
|
30
|
-
--session sess_123 \
|
|
31
|
-
--message "Add tests"
|
|
32
|
-
|
|
33
|
-
justevery-manager queue state --session sess_123
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
Queue commands require a Manager org id and session cookie:
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
export ORG_ID=acct-...
|
|
40
|
-
export SESSION_COOKIE=better-auth.session_token_value
|
|
41
|
-
```
|
|
42
|
-
|
|
43
20
|
On headless Linux, the wrapper will download and run the headless daemon
|
|
44
21
|
(`Every.Manager_*_linux_amd64_headless`) when available.
|
|
45
22
|
|
|
@@ -53,6 +30,3 @@ On headless Linux, the wrapper will download and run the headless daemon
|
|
|
53
30
|
- `JE_AGENT_GITHUB_TOKEN` – optional GitHub token for private releases (also supports `GH_TOKEN` / `GITHUB_TOKEN`).
|
|
54
31
|
- `JE_AGENT_SKIP_DOWNLOAD=1` – skip the postinstall download/caching step.
|
|
55
32
|
- `JE_AGENT_SKIP_LAUNCH=1` – skip launching the installer after download (also supports `JE_MANAGER_SKIP_LAUNCH`).
|
|
56
|
-
- `ORG_ID` – Manager org id for queue commands.
|
|
57
|
-
- `SESSION_COOKIE` – `better-auth.session_token` value for queue commands.
|
|
58
|
-
- `BASE_URL` – Manager base URL (defaults to https://manager.justevery.com).
|
package/bin/justevery-manager.js
CHANGED
|
@@ -3,40 +3,31 @@ import { ensureInstaller, launchInstaller } from '../lib/installer.js';
|
|
|
3
3
|
import { platform as osPlatform } from 'os';
|
|
4
4
|
|
|
5
5
|
const args = process.argv.slice(2);
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (wantsHelp) {
|
|
21
|
-
console.log(`Every Manager CLI
|
|
6
|
+
const wantsHelp = args.includes('--help') || args.includes('-h');
|
|
7
|
+
const skipLaunchEnv = process.env.JE_AGENT_SKIP_LAUNCH === '1' || process.env.JE_MANAGER_SKIP_LAUNCH === '1';
|
|
8
|
+
const forceForeground = args.includes('--foreground') || args.includes('--no-daemon');
|
|
9
|
+
const forceDaemon = args.includes('--daemon');
|
|
10
|
+
const sessionType = (process.env.XDG_SESSION_TYPE || '').toLowerCase();
|
|
11
|
+
const hasDisplay = Boolean(process.env.DISPLAY || process.env.WAYLAND_DISPLAY);
|
|
12
|
+
const hasGuiSession = hasDisplay || (Boolean(sessionType) && sessionType !== 'tty');
|
|
13
|
+
const isHeadlessLinux = osPlatform() === 'linux' && !hasGuiSession;
|
|
14
|
+
const downloadOnly = args.includes('--download-only') || args.includes('--no-open') || skipLaunchEnv;
|
|
15
|
+
const printPath = args.includes('--print-path');
|
|
16
|
+
const launchMode = forceForeground ? 'foreground' : forceDaemon ? 'daemon' : 'auto';
|
|
17
|
+
|
|
18
|
+
if (wantsHelp) {
|
|
19
|
+
console.log(`Every Manager installer helper
|
|
22
20
|
|
|
23
21
|
Usage:
|
|
24
22
|
justevery-manager [--download-only] [--print-path]
|
|
25
|
-
justevery-manager queue <command>
|
|
26
23
|
|
|
27
|
-
|
|
24
|
+
Options:
|
|
28
25
|
--download-only Download the installer but do not launch it.
|
|
29
26
|
--print-path Print the installer path after download.
|
|
30
27
|
--foreground Run the Linux headless daemon in the foreground.
|
|
31
28
|
--daemon Force the Linux headless daemon to run in the background.
|
|
32
29
|
-h, --help Show this help message.
|
|
33
30
|
|
|
34
|
-
Queue Commands:
|
|
35
|
-
queue start Start a new session on a device.
|
|
36
|
-
queue followup Enqueue a follow-up message for a session.
|
|
37
|
-
queue state Show queue state for a session.
|
|
38
|
-
queue devices List available devices.
|
|
39
|
-
|
|
40
31
|
Environment:
|
|
41
32
|
JE_AGENT_VERSION Override the agent version.
|
|
42
33
|
JE_AGENT_RELEASE_TAG Override the GitHub release tag.
|
|
@@ -44,36 +35,21 @@ Environment:
|
|
|
44
35
|
JE_AGENT_FALLBACK_BASE_URL Add fallback base URLs (comma-separated).
|
|
45
36
|
JE_AGENT_ASSET Override the installer filename.
|
|
46
37
|
JE_AGENT_GITHUB_TOKEN Optional GitHub token for private releases.
|
|
47
|
-
ORG_ID Manager org id for queue commands.
|
|
48
|
-
SESSION_COOKIE better-auth.session_token value for queue commands.
|
|
49
|
-
BASE_URL Manager base URL (default https://manager.justevery.com).
|
|
50
38
|
`);
|
|
51
|
-
|
|
52
|
-
|
|
39
|
+
process.exit(0);
|
|
40
|
+
}
|
|
53
41
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
if (!downloadOnly) {
|
|
60
|
-
await launchInstaller(result.path, { mode: launchMode });
|
|
61
|
-
} else if (isHeadlessLinux) {
|
|
62
|
-
console.log('No desktop session detected. Run the installer on a machine with a GUI.');
|
|
63
|
-
}
|
|
64
|
-
} catch (error) {
|
|
65
|
-
console.error(`Failed to prepare installer: ${error.message}`);
|
|
66
|
-
process.exit(1);
|
|
42
|
+
try {
|
|
43
|
+
const result = await ensureInstaller({ allowDownload: true });
|
|
44
|
+
if (printPath || downloadOnly) {
|
|
45
|
+
console.log(result.path);
|
|
67
46
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const { runQueueCommand } = await import('../lib/queue-cli.js');
|
|
73
|
-
await runQueueCommand(args.slice(1));
|
|
74
|
-
return;
|
|
47
|
+
if (!downloadOnly) {
|
|
48
|
+
await launchInstaller(result.path, { mode: launchMode });
|
|
49
|
+
} else if (isHeadlessLinux) {
|
|
50
|
+
console.log('No desktop session detected. Run the installer on a machine with a GUI.');
|
|
75
51
|
}
|
|
76
|
-
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
|
|
52
|
+
} catch (error) {
|
|
53
|
+
console.error(`Failed to prepare installer: ${error.message}`);
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@just-every/manager",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.68",
|
|
4
4
|
"description": "Installer wrapper for Every Manager",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -11,13 +11,11 @@
|
|
|
11
11
|
"files": [
|
|
12
12
|
"bin/justevery-manager.js",
|
|
13
13
|
"lib/installer.js",
|
|
14
|
-
"lib/queue-cli.js",
|
|
15
14
|
"postinstall.js",
|
|
16
15
|
"README.md"
|
|
17
16
|
],
|
|
18
17
|
"scripts": {
|
|
19
|
-
"postinstall": "node postinstall.js"
|
|
20
|
-
"test": "node --test test/cli-routing.test.mjs"
|
|
18
|
+
"postinstall": "node postinstall.js"
|
|
21
19
|
},
|
|
22
20
|
"engines": {
|
|
23
21
|
"node": ">=18"
|
package/lib/queue-cli.js
DELETED
|
@@ -1,260 +0,0 @@
|
|
|
1
|
-
import { parseArgs } from 'node:util';
|
|
2
|
-
|
|
3
|
-
const DEFAULT_BASE_URL = 'https://manager.justevery.com';
|
|
4
|
-
|
|
5
|
-
const USAGE = `
|
|
6
|
-
Every Manager queue commands
|
|
7
|
-
|
|
8
|
-
Usage:
|
|
9
|
-
justevery-manager queue <command> [options]
|
|
10
|
-
|
|
11
|
-
Commands:
|
|
12
|
-
start Start a new session on a device
|
|
13
|
-
followup Enqueue a follow-up message for a session
|
|
14
|
-
state Show queue state for a session
|
|
15
|
-
devices List devices (id, name, run status)
|
|
16
|
-
|
|
17
|
-
Options:
|
|
18
|
-
--org Manager org id (or ORG_ID env)
|
|
19
|
-
--cookie better-auth.session_token value (or SESSION_COOKIE env)
|
|
20
|
-
--base-url Manager base URL (default: https://manager.justevery.com)
|
|
21
|
-
--device Device id
|
|
22
|
-
--session Session id
|
|
23
|
-
--message Message/prompt
|
|
24
|
-
--prompt Alias for --message
|
|
25
|
-
--project Project id
|
|
26
|
-
--cli CLI name (code|codex|claude|gemini|qwen)
|
|
27
|
-
--cwd Working directory
|
|
28
|
-
--action followup action override (resume|new)
|
|
29
|
-
-h, --help Show help
|
|
30
|
-
`;
|
|
31
|
-
|
|
32
|
-
const normalizeCookie = (value) => {
|
|
33
|
-
if (!value) return '';
|
|
34
|
-
if (value.includes('better-auth.session_token=')) return value;
|
|
35
|
-
return `better-auth.session_token=${value}`;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
const resolveBaseUrl = (value) => value || process.env.BASE_URL || process.env.MANAGER_API_BASE || DEFAULT_BASE_URL;
|
|
39
|
-
|
|
40
|
-
const resolveOrgId = (value) => value || process.env.ORG_ID || process.env.MANAGER_ORG_ID || '';
|
|
41
|
-
|
|
42
|
-
const resolveCookie = (value) => value || process.env.SESSION_COOKIE || process.env.MANAGER_SESSION_COOKIE || '';
|
|
43
|
-
|
|
44
|
-
const buildAuthHeaders = (orgId, cookie) => {
|
|
45
|
-
if (!orgId) throw new Error('ORG_ID is required (--org or ORG_ID env)');
|
|
46
|
-
if (!cookie) throw new Error('SESSION_COOKIE is required (--cookie or SESSION_COOKIE env)');
|
|
47
|
-
return {
|
|
48
|
-
'Content-Type': 'application/json',
|
|
49
|
-
'x-manager-org': orgId,
|
|
50
|
-
Cookie: normalizeCookie(cookie),
|
|
51
|
-
};
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const parseResponse = async (response) => {
|
|
55
|
-
const text = await response.text();
|
|
56
|
-
if (!text) return null;
|
|
57
|
-
try {
|
|
58
|
-
return JSON.parse(text);
|
|
59
|
-
} catch {
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
const request = async (baseUrl, path, options = {}) => {
|
|
65
|
-
const url = `${baseUrl}${path}`;
|
|
66
|
-
const response = await fetch(url, options);
|
|
67
|
-
const data = await parseResponse(response);
|
|
68
|
-
if (!response.ok) {
|
|
69
|
-
const detail = data?.error || (data?.message ?? null) || response.statusText || 'Request failed';
|
|
70
|
-
throw new Error(detail);
|
|
71
|
-
}
|
|
72
|
-
return data;
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
const listDevices = async (baseUrl, headers) => {
|
|
76
|
-
const data = await request(baseUrl, '/api/manager/devices', {
|
|
77
|
-
method: 'GET',
|
|
78
|
-
headers,
|
|
79
|
-
});
|
|
80
|
-
return Array.isArray(data?.devices) ? data.devices : [];
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
const printQueueState = (queueState) => {
|
|
84
|
-
if (!queueState) {
|
|
85
|
-
console.log('Queue state unavailable.');
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
const queued = queueState.queuedCount ?? 0;
|
|
89
|
-
const running = queueState.runningCount ?? 0;
|
|
90
|
-
const status = queueState.status || 'unknown';
|
|
91
|
-
console.log(`Queue: ${queued} queued, ${running} running (status=${status}).`);
|
|
92
|
-
if (queueState.error) {
|
|
93
|
-
console.log(`Last error: ${queueState.error}`);
|
|
94
|
-
}
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
const handleStart = async (baseUrl, headers, values) => {
|
|
98
|
-
const deviceId = values.device || '';
|
|
99
|
-
const message = (values.message || values.prompt || '').trim();
|
|
100
|
-
const projectId = values.project || '';
|
|
101
|
-
const cliNameInput = (values.cli || '').trim();
|
|
102
|
-
const cwd = (values.cwd || '').trim();
|
|
103
|
-
|
|
104
|
-
if (!deviceId) throw new Error('device id required (--device)');
|
|
105
|
-
if (!message) throw new Error('message required (--message)');
|
|
106
|
-
|
|
107
|
-
let cliName = cliNameInput;
|
|
108
|
-
let device = null;
|
|
109
|
-
if (!cliName) {
|
|
110
|
-
const devices = await listDevices(baseUrl, headers);
|
|
111
|
-
device = devices.find((entry) => entry.id === deviceId) || null;
|
|
112
|
-
cliName = (device?.cliName || '').trim();
|
|
113
|
-
if (!cliName) {
|
|
114
|
-
throw new Error('CLI name required. Provide --cli or update device metadata.');
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const payload = {
|
|
119
|
-
deviceId,
|
|
120
|
-
message,
|
|
121
|
-
cliName,
|
|
122
|
-
...(projectId ? { projectId } : {}),
|
|
123
|
-
...(cwd ? { workingDirectory: cwd } : {}),
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
const response = await request(baseUrl, '/api/manager/sessions/start', {
|
|
127
|
-
method: 'POST',
|
|
128
|
-
headers,
|
|
129
|
-
body: JSON.stringify(payload),
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
console.log(`Queued start: ${response?.queueItem?.id ?? 'unknown'}`);
|
|
133
|
-
if (!device) {
|
|
134
|
-
const devices = await listDevices(baseUrl, headers);
|
|
135
|
-
device = devices.find((entry) => entry.id === deviceId) || null;
|
|
136
|
-
}
|
|
137
|
-
if (device) {
|
|
138
|
-
console.log(`Device ${device.name || device.deviceName || device.prefix}: ${device.runStatus || 'idle'}`);
|
|
139
|
-
if (device.lastError) {
|
|
140
|
-
console.log(`Device last error: ${device.lastError}`);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
const handleFollowup = async (baseUrl, headers, values) => {
|
|
146
|
-
const sessionId = values.session || '';
|
|
147
|
-
const message = (values.message || values.prompt || '').trim();
|
|
148
|
-
const deviceId = (values.device || '').trim();
|
|
149
|
-
const cliName = (values.cli || '').trim();
|
|
150
|
-
const cwd = (values.cwd || '').trim();
|
|
151
|
-
const action = (values.action || '').trim();
|
|
152
|
-
|
|
153
|
-
if (!sessionId) throw new Error('session id required (--session)');
|
|
154
|
-
if (!message) throw new Error('message required (--message)');
|
|
155
|
-
|
|
156
|
-
const metadata = {};
|
|
157
|
-
if (action) metadata.action = action;
|
|
158
|
-
if (cliName) metadata.cliName = cliName;
|
|
159
|
-
if (cwd) metadata.workingDirectory = cwd;
|
|
160
|
-
|
|
161
|
-
const payload = {
|
|
162
|
-
message,
|
|
163
|
-
...(deviceId ? { deviceId } : {}),
|
|
164
|
-
...(Object.keys(metadata).length ? { metadata } : {}),
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
const response = await request(baseUrl, `/api/manager/sessions/${sessionId}/queue`, {
|
|
168
|
-
method: 'POST',
|
|
169
|
-
headers,
|
|
170
|
-
body: JSON.stringify(payload),
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
console.log(`Queued follow-up: ${response?.queueItem?.id ?? 'unknown'}`);
|
|
174
|
-
printQueueState(response?.queueState);
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
const handleState = async (baseUrl, headers, values) => {
|
|
178
|
-
const sessionId = values.session || '';
|
|
179
|
-
if (!sessionId) throw new Error('session id required (--session)');
|
|
180
|
-
const response = await request(baseUrl, `/api/manager/sessions/${sessionId}/queue`, {
|
|
181
|
-
method: 'GET',
|
|
182
|
-
headers,
|
|
183
|
-
});
|
|
184
|
-
printQueueState(response?.queueState);
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
const handleDevices = async (baseUrl, headers) => {
|
|
188
|
-
const devices = await listDevices(baseUrl, headers);
|
|
189
|
-
if (devices.length === 0) {
|
|
190
|
-
console.log('No devices found.');
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
for (const device of devices) {
|
|
194
|
-
const name = device.name || device.deviceName || device.prefix;
|
|
195
|
-
const cliName = device.cliName ? ` cli=${device.cliName}` : '';
|
|
196
|
-
const status = device.runStatus || 'idle';
|
|
197
|
-
console.log(`${device.id} ${name} ${status}${cliName}`);
|
|
198
|
-
}
|
|
199
|
-
};
|
|
200
|
-
|
|
201
|
-
const printHelp = () => {
|
|
202
|
-
console.log(USAGE.trim());
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
export const runQueueCommand = async (argv = process.argv.slice(2)) => {
|
|
206
|
-
const { values, positionals } = parseArgs({
|
|
207
|
-
args: argv,
|
|
208
|
-
options: {
|
|
209
|
-
help: { type: 'boolean', short: 'h' },
|
|
210
|
-
org: { type: 'string' },
|
|
211
|
-
cookie: { type: 'string' },
|
|
212
|
-
'base-url': { type: 'string' },
|
|
213
|
-
device: { type: 'string' },
|
|
214
|
-
session: { type: 'string' },
|
|
215
|
-
message: { type: 'string' },
|
|
216
|
-
prompt: { type: 'string' },
|
|
217
|
-
project: { type: 'string' },
|
|
218
|
-
cli: { type: 'string' },
|
|
219
|
-
cwd: { type: 'string' },
|
|
220
|
-
action: { type: 'string' },
|
|
221
|
-
},
|
|
222
|
-
allowPositionals: true,
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
const command = positionals[0];
|
|
226
|
-
if (values.help || !command || command === 'help') {
|
|
227
|
-
printHelp();
|
|
228
|
-
return;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
try {
|
|
232
|
-
const baseUrl = resolveBaseUrl(values['base-url']);
|
|
233
|
-
const orgId = resolveOrgId(values.org);
|
|
234
|
-
const cookie = resolveCookie(values.cookie);
|
|
235
|
-
const headers = buildAuthHeaders(orgId, cookie);
|
|
236
|
-
|
|
237
|
-
if (command === 'start') {
|
|
238
|
-
await handleStart(baseUrl, headers, values);
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
if (command === 'followup' || command === 'queue' || command === 'continue') {
|
|
242
|
-
await handleFollowup(baseUrl, headers, values);
|
|
243
|
-
return;
|
|
244
|
-
}
|
|
245
|
-
if (command === 'state') {
|
|
246
|
-
await handleState(baseUrl, headers, values);
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
if (command === 'devices') {
|
|
250
|
-
await handleDevices(baseUrl, headers);
|
|
251
|
-
return;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
printHelp();
|
|
255
|
-
process.exit(1);
|
|
256
|
-
} catch (error) {
|
|
257
|
-
console.error(`Error: ${error instanceof Error ? error.message : error}`);
|
|
258
|
-
process.exit(1);
|
|
259
|
-
}
|
|
260
|
-
};
|