@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 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, guides installation of
47
- the Aglit AI Chrome extension, and enables Anywhere Access. Team selection and
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 requires a two-factor security code by default; an explicit off preference is preserved. In CLI headless mode, 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.
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 opens the published Aglit AI Chrome Web Store
136
- listing. Choose Add to Chrome and approve Chrome’s prompt. Setup waits until the
137
- Store extension is installed and enabled in Chrome’s selected profile; it never
138
- changes a disabled extension setting or browser policy. Installation detection is
139
- separate from browser-control connectivity.
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aglit-ai/cli",
3
- "version": "1.0.17197",
3
+ "version": "1.0.17300",
4
4
  "description": "Install and manage Aglit Computer Use",
5
5
  "license": "UNLICENSED",
6
6
  "type": "commonjs",
@@ -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};
@@ -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=,comm='], {encoding: 'utf8', timeout: 15000, maxBuffer: 8 * 1024 ** 2});
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 };