@aglit-ai/cli 1.0.17197 → 1.0.17300
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 +10 -8
- package/bin/aglit.cjs +11 -18
- package/package.json +1 -1
- package/src/browser-setup.cjs +27 -0
- package/src/installation.cjs +19 -3
package/README.md
CHANGED
|
@@ -43,8 +43,8 @@ aglit invite USER_EMAIL --team TEAM_ID
|
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
Setup registers a Personal computer with your signed-in account. It asks for its
|
|
46
|
-
name and AI provider, requests the required OS permissions,
|
|
47
|
-
the Aglit AI Chrome extension
|
|
46
|
+
name and AI provider, requests the required OS permissions, enables Anywhere
|
|
47
|
+
Access, then offers the Aglit AI Chrome extension. Team selection and
|
|
48
48
|
pipeline discovery are separate from setup.
|
|
49
49
|
Use `aglit team --name "My team"` to associate this computer with a team on your account. The CLI derives its installed workspace; no server-side workspace record or private-key provisioning is required. Manage invitations at teams.aglit.ai.
|
|
50
50
|
Use `aglit teams` to inspect memberships and `aglit pipelines --open` to open the
|
|
@@ -130,13 +130,15 @@ Google currently rejects this proposed callback with `redirect_uri_mismatch`.
|
|
|
130
130
|
No port change has shipped; provider registration and native acceptance remain
|
|
131
131
|
required before qualifying coexistence.
|
|
132
132
|
|
|
133
|
-
Anywhere Access
|
|
133
|
+
Anywhere Access defaults to no two-factor security code; an explicit on preference is preserved. When enabled, incoming connection requests display the code in a native window without opening the full app. This requires a logged-in graphical desktop session; an SSH-only/server environment cannot display the prompt. Codes are not printed to the terminal.
|
|
134
134
|
|
|
135
|
-
After computer-use permissions, setup
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
135
|
+
After computer-use permissions, setup enables Anywhere Access before offering
|
|
136
|
+
the Aglit AI Chrome extension. Browser setup failures do not undo computer
|
|
137
|
+
registration. Run `aglit browser setup` to retry, or `aglit browser status --json`
|
|
138
|
+
to inspect it separately. Interactive browser setup waits for installation;
|
|
139
|
+
unattended setup returns the current browser status without waiting for a person.
|
|
140
|
+
It never changes a disabled extension setting or browser policy. Installation
|
|
141
|
+
detection is separate from browser-control connectivity.
|
|
140
142
|
|
|
141
143
|
This release supports Apple Silicon Macs. Windows publication is deferred until its signed native runtime is available.
|
|
142
144
|
|
package/bin/aglit.cjs
CHANGED
|
@@ -31,6 +31,7 @@ const help = `Aglit Computer Use
|
|
|
31
31
|
aglit teams [--open]
|
|
32
32
|
aglit team --name "Team name" [--team TEAM_ID] [--workspace WORKSPACE_ID]
|
|
33
33
|
aglit pipelines [--open]
|
|
34
|
+
aglit browser setup|status [--json]
|
|
34
35
|
aglit providers
|
|
35
36
|
aglit models list | choose
|
|
36
37
|
aglit models login copilot [--reauth] [--json]
|
|
@@ -79,12 +80,13 @@ async function main() {
|
|
|
79
80
|
const options = {
|
|
80
81
|
models: ['device','fingerprint','name','json','challenge','code','connection','connections','model','harness','attempt','reauth'],
|
|
81
82
|
install: ['json', 'channel'], init: ['name', 'provider', 'account', 'json', 'channel', 'headed', 'headless'],
|
|
82
|
-
start: ['json', 'channel', 'headed', 'headless'], ui: ['json'], status: ['json'], update: ['check', 'channel', 'json'], updates: ['json'], enable: ['two-factor'], disable: [], rename: ['name', 'json'], console: ['json'], teams: ['json', 'open'], team: ['name', 'team', 'workspace', 'json'], pipelines: ['open', 'json'], providers: ['json'], invite: ['team'], uninstall: [],
|
|
83
|
+
start: ['json', 'channel', 'headed', 'headless'], ui: ['json'], status: ['json'], update: ['check', 'channel', 'json'], updates: ['json'], enable: ['two-factor'], disable: [], rename: ['name', 'json'], console: ['json'], teams: ['json', 'open'], team: ['name', 'team', 'workspace', 'json'], pipelines: ['open', 'json'], browser: ['json'], providers: ['json'], invite: ['team'], uninstall: [],
|
|
83
84
|
};
|
|
84
|
-
if (!Object.hasOwn(options, command) || Object.keys(values).some(key => !options[command].includes(key)) || positionals.length > (command === 'models' ? 3 : ['invite', 'updates'].includes(command) ? 2 : 1)) throw Error('Invalid command or options. Run aglit --help.');
|
|
85
|
+
if (!Object.hasOwn(options, command) || Object.keys(values).some(key => !options[command].includes(key)) || positionals.length > (command === 'models' ? 3 : ['invite', 'updates', 'browser'].includes(command) ? 2 : 1)) throw Error('Invalid command or options. Run aglit --help.');
|
|
85
86
|
if (values['two-factor'] !== undefined && !['on', 'off'].includes(values['two-factor']))
|
|
86
87
|
throw Error('Choose --two-factor on or off.');
|
|
87
|
-
if (installation.development && !['models','status','init','providers','enable','disable','ui','start'].includes(command)) throw Error('Source profile supports model/setup, access and window commands; installed runtime management is separate');
|
|
88
|
+
if (installation.development && !['models','status','init','providers','enable','disable','ui','start','browser'].includes(command)) throw Error('Source profile supports model/setup, access and window commands; installed runtime management is separate');
|
|
89
|
+
if (command === 'browser' && !['setup','status'].includes(email)) throw Error('Use aglit browser setup|status');
|
|
88
90
|
if (command === 'updates' && !['on', 'off', 'status'].includes(email)) throw Error('Use aglit updates on|off|status');
|
|
89
91
|
if (values.channel !== undefined && !['latest', 'canary', 'embedded'].includes(values.channel)) throw Error('Update channel must be latest, canary or embedded');
|
|
90
92
|
if (values.team && !/^[A-Za-z0-9._:-]{1,128}$/.test(values.team)) throw Error('Invalid team ID');
|
|
@@ -182,6 +184,10 @@ async function main() {
|
|
|
182
184
|
ui.finish('Model connections'); return;
|
|
183
185
|
}
|
|
184
186
|
if (command === 'status') { ui.result(state); ui.finish('Computer status'); return; }
|
|
187
|
+
if (command === 'browser') {
|
|
188
|
+
ui.result(email === 'status' ? await control('browser-status') : await require('../src/browser-setup.cjs').setupBrowser(control, ui, interactive));
|
|
189
|
+
ui.finish('Browser extension'); return;
|
|
190
|
+
}
|
|
185
191
|
if (command === 'console') { ui.result({ url: state.consoleUrl }); ui.finish('Console'); return; }
|
|
186
192
|
if (command === 'rename') {
|
|
187
193
|
if (!values.name) throw Error('Provide --name to rename this computer');
|
|
@@ -248,28 +254,15 @@ async function main() {
|
|
|
248
254
|
if (!interactive) ui.result(permissions);
|
|
249
255
|
if (permissions.permissions?.supported && (permissions.permissions.screenRecording !== 'granted' || permissions.permissions.accessibility !== 'granted'))
|
|
250
256
|
throw Error('Grant Screen Recording and Accessibility in System Settings, then rerun aglit init. Anywhere Access has not been enabled.');
|
|
251
|
-
let browser = await ui.step('Check Aglit AI browser extension', () => control('browser-status'));
|
|
252
|
-
if (!browser.enabled) {
|
|
253
|
-
const prepared = await ui.step('Set up Aglit AI browser extension', () => control('browser-setup'));
|
|
254
|
-
ui.browserExtension(prepared);
|
|
255
|
-
browser = await ui.step('Waiting for Chrome extension installation', async () => {
|
|
256
|
-
const deadline = Date.now() + 180000;
|
|
257
|
-
do {
|
|
258
|
-
const current = await control('browser-status');
|
|
259
|
-
if (current.installed && current.enabled) return current;
|
|
260
|
-
await delay(1500);
|
|
261
|
-
} while (Date.now() < deadline);
|
|
262
|
-
throw Error('Add or enable the Aglit AI Chrome extension, then rerun aglit init.');
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
257
|
state = await ui.step('Connect this computer to your account', async () => {
|
|
266
258
|
await control('enable');
|
|
267
259
|
return control('status');
|
|
268
260
|
});
|
|
269
261
|
if (!installation.development) updates.rememberStatus(state);
|
|
270
262
|
if (typeof state.deviceId !== 'string' || !state.deviceId) throw Error('Registration returned no device ID. Check aglit status before retrying.');
|
|
263
|
+
const browser = await require('../src/browser-setup.cjs').setupOptionalBrowser(control, ui, interactive);
|
|
271
264
|
state = { ...state, ...await control('window', { mode }) };
|
|
272
|
-
state = { ...state, employeeUrl: new URL(`/employees/${encodeURIComponent(state.deviceId)}`, state.consoleUrl).href };
|
|
265
|
+
state = { ...state, browser, employeeUrl: new URL(`/employees/${encodeURIComponent(state.deviceId)}`, state.consoleUrl).href };
|
|
273
266
|
ui.result(state); ui.finish('Anywhere Access enabled'); return;
|
|
274
267
|
}
|
|
275
268
|
if (command === 'invite') { ui.result(await control('invite', { teamId: values.team, email })); ui.finish('Invitation sent'); return; }
|
package/package.json
CHANGED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
|
|
3
|
+
async function setupBrowser(control, ui, interactive) {
|
|
4
|
+
let browser = await ui.step('Check Aglit AI browser extension', () => control('browser-status'));
|
|
5
|
+
if (browser.enabled) return browser;
|
|
6
|
+
const prepared = await ui.step('Set up Aglit AI browser extension', () => control('browser-setup'));
|
|
7
|
+
ui.browserExtension(prepared);
|
|
8
|
+
if (!interactive) return control('browser-status');
|
|
9
|
+
return ui.step('Waiting for Chrome extension installation', async () => {
|
|
10
|
+
const deadline = Date.now() + 180000;
|
|
11
|
+
do {
|
|
12
|
+
browser = await control('browser-status');
|
|
13
|
+
if (browser.installed && browser.enabled) return browser;
|
|
14
|
+
await delay(1500);
|
|
15
|
+
} while (Date.now() < deadline);
|
|
16
|
+
throw Error('Add or enable the Aglit AI Chrome extension, then run aglit browser setup.');
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
async function setupOptionalBrowser(control, ui, interactive) {
|
|
20
|
+
try { return await setupBrowser(control, ui, interactive); }
|
|
21
|
+
catch (error) {
|
|
22
|
+
if (error.cancelled) throw error;
|
|
23
|
+
ui.info('Browser setup is incomplete: ' + error.message + '\nRetry with aglit browser setup. Anywhere Access remains enabled.');
|
|
24
|
+
return { installed: false, enabled: false, setupRequired: true };
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
module.exports = {setupBrowser, setupOptionalBrowser};
|
package/src/installation.cjs
CHANGED
|
@@ -195,6 +195,21 @@ async function install(channel) {
|
|
|
195
195
|
if (bootstrap) require('./updates.cjs').adoptBootstrap(bootstrap);
|
|
196
196
|
return { installed: true, ...receipt };
|
|
197
197
|
}
|
|
198
|
+
function runtimePorts() {
|
|
199
|
+
const file = path.join(root, 'runtime-ports.json');
|
|
200
|
+
if (fs.existsSync(file)) {
|
|
201
|
+
const stat = fs.lstatSync(file);
|
|
202
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.nlink !== 1 || stat.size > 1024 ||
|
|
203
|
+
process.platform !== 'win32' && (stat.uid !== process.getuid() || stat.mode & 0o077)) throw Error('Private runtime ports required');
|
|
204
|
+
const ports = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
205
|
+
if (!Array.isArray(ports) || ports.length !== 5 || new Set(ports).size !== 5 || ports.some(port => !Number.isInteger(port) || port < 1024 || port > 65535)) throw Error('Runtime ports differ');
|
|
206
|
+
return ports;
|
|
207
|
+
}
|
|
208
|
+
const probe = `const net=require('node:net');(async()=>{for(let base=49117;base<50117;base+=10){const servers=[];try{for(let i=0;i<5;i++){const server=net.createServer();servers.push(server);await new Promise((resolve,reject)=>{server.once('error',reject);server.listen(base+i,'127.0.0.1',resolve);});}console.log(JSON.stringify(servers.map(server=>server.address().port)));return;}catch{}finally{for(const server of servers)server.close();}}process.exitCode=1;})()`;
|
|
209
|
+
const ports = JSON.parse(run(process.execPath, ['-e', probe]));
|
|
210
|
+
fs.writeFileSync(file, JSON.stringify(ports) + '\n', {flag:'wx',mode:0o600});
|
|
211
|
+
return ports;
|
|
212
|
+
}
|
|
198
213
|
function start() {
|
|
199
214
|
if (development) throw Error('Start the source runtime with scripts/dev/run-computer-use.cjs before invoking this CLI');
|
|
200
215
|
if (fs.existsSync(path.join(root, 'uninstalling.json'))) throw Error('Computer Use is uninstalling. Run aglit uninstall to finish cleanup.');
|
|
@@ -202,6 +217,7 @@ function start() {
|
|
|
202
217
|
'$p=[Security.Principal.WindowsPrincipal]::new([Security.Principal.WindowsIdentity]::GetCurrent()); if($p.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)){throw "Run aglit init from a non-elevated interactive user terminal"}']);
|
|
203
218
|
const installed = readInstallation();
|
|
204
219
|
verifyPublisher(installed.executable);
|
|
220
|
+
runtimePorts();
|
|
205
221
|
const log = fs.openSync(path.join(root, 'runtime.log'), 'a', 0o600);
|
|
206
222
|
const env = { ...process.env };
|
|
207
223
|
// Do not let an operator's guest/development environment adopt another identity.
|
|
@@ -222,10 +238,10 @@ function start() {
|
|
|
222
238
|
// Bind the result to the exact installed executable and current OS user.
|
|
223
239
|
const deadline = Date.now() + 10000;
|
|
224
240
|
do {
|
|
225
|
-
const rows = execFileSync('/bin/ps', ['-axo', 'pid=,uid=,
|
|
241
|
+
const rows = execFileSync('/bin/ps', ['-axo', 'pid=,uid=,args='], {encoding: 'utf8', timeout: 15000, maxBuffer: 8 * 1024 ** 2});
|
|
226
242
|
const matches = rows.split('\n').flatMap(line => {
|
|
227
243
|
const row = /^\s*(\d+)\s+(\d+)\s+(.+)$/.exec(line);
|
|
228
|
-
return row && Number(row[2]) === process.getuid() && row[3].trim() === installed.executable ? [Number(row[1])] : [];
|
|
244
|
+
return row && Number(row[2]) === process.getuid() && row[3].trim() === installed.executable + ' --computer-use' ? [Number(row[1])] : [];
|
|
229
245
|
});
|
|
230
246
|
if (matches.length > 1) throw Error('Multiple installed Desktop processes; activation remains pending');
|
|
231
247
|
if (matches.length === 1) return { pid: matches[0] };
|
|
@@ -278,4 +294,4 @@ function readUninstall() {
|
|
|
278
294
|
!Number.isSafeInteger(receipt.pid) || receipt.pid <= 0) throw Error('Invalid uninstall receipt');
|
|
279
295
|
return receipt;
|
|
280
296
|
}
|
|
281
|
-
module.exports = { development, root, profile, readInstallation, install, start, purge, purgeIncomplete, readUninstall, privateRoot, canonical, verifyPublisher, embeddedRelease, copyArchive, stageRuntime, verifyRuntime };
|
|
297
|
+
module.exports = { runtimePorts, development, root, profile, readInstallation, install, start, purge, purgeIncomplete, readUninstall, privateRoot, canonical, verifyPublisher, embeddedRelease, copyArchive, stageRuntime, verifyRuntime };
|