@ours.network/install 1.2.1-nightly.37 → 1.2.1-nightly.38

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
@@ -637,7 +637,7 @@ Existing installation records keep their ports and identities. A listener acquir
637
637
  by another process after preflight still causes startup to fail safely; no foreign
638
638
  process is stopped and no retained installation is silently moved.
639
639
 
640
- Workspace setup pins Fleet `1.2.0-nightly.49` with its recorded registry integrity. This release includes first-time Fleet setup through the host API for the account App, direct App access to the workspace services with the device credential, v2 positional one-use grants and automatic QR/connection-code output from `ours-fleet setup-tunnel`, optional private file/stdin inputs for legacy v1 payloads, a separate `ours-fleet link-device` command for additional devices, host prerequisite checks before the one-time workspace proof (`setup-tunnel --check`), `setup-tunnel --resume` to finish a setup that stopped after the host saved its private pending setup record (not when the proof's answer was lost, or after the setup window expired with an unconfirmed non-default port), and persists the available Fleet loopback port used by the workspace tunnel. It also accepts a setup-generated configuration left behind after the host enrollment state was removed, runs the host Codex when it is at least as new as the packaged one, offers only the Codex models the signed-in account can use, and removes the temporary setup contact after confirmation. Fleet serves no pages and opens no browser: every screen is in the App. Fleet also serves the workspace notification routes, produces notifications through the server gateway with the imported producer credential, accepts the App's device credential on the notification presence socket so an open App receives no push, and defaults agent wakes to `monitor.interrupt: after_tool` (Hermes: no interrupt; role snapshots saved before this default keep no interrupt). Existing installation identities and configured ports remain retained; a retained-port collision fails safely.
640
+ Workspace setup pins Fleet `1.2.0-nightly.50` with its recorded registry integrity. This release includes first-time Fleet setup through the host API for the account App, direct App access to the workspace services with the device credential, v2 positional one-use grants and automatic QR/connection-code output from `ours-fleet setup-tunnel`, optional private file/stdin inputs for legacy v1 payloads, a separate `ours-fleet link-device` command for additional devices, host prerequisite checks before the one-time workspace proof (`setup-tunnel --check`), `setup-tunnel --resume` to finish a setup that stopped after the host saved its private pending setup record (not when the proof's answer was lost, or after the setup window expired with an unconfirmed non-default port), and persists the available Fleet loopback port used by the workspace tunnel. It also accepts a setup-generated configuration left behind after the host enrollment state was removed, runs the host Codex when it is at least as new as the packaged one, offers only the Codex models the signed-in account can use, and removes the temporary setup contact after confirmation. Fleet serves no pages and opens no browser: every screen is in the App. Fleet also serves the workspace notification routes, produces notifications through the server gateway with the imported producer credential, accepts the App's device credential on the notification presence socket so an open App receives no push, and defaults agent wakes to `monitor.interrupt: after_tool` (Hermes: no interrupt; role snapshots saved before this default keep no interrupt). Existing installation identities and configured ports remain retained; a retained-port collision fails safely.
641
641
 
642
642
  ### App tunnel setup prerelease sequencing
643
643
 
@@ -654,7 +654,7 @@ connection code automatically; the App checks readiness and opens the code field
654
654
  Private `--file`/`--stdin` transports remain optional and are the only transports
655
655
  for legacy v1 payloads with long-lived credentials.
656
656
 
657
- The nightly installer release manifest selects published Fleet `1.2.0-nightly.49`
657
+ The nightly installer release manifest selects published Fleet `1.2.0-nightly.50`
658
658
  and its actual registry integrity through the normal release manifest/source-policy
659
659
  generators. This release includes v2 argument and private-input support. The former
660
660
  nightly.41 selection predates this capability. Merge and publish the repinned
@@ -13,7 +13,7 @@
13
13
  "@ours.network/codex": "1.2.0-nightly.12",
14
14
  "@ours.network/cowork": "1.3.3-nightly.20261005.f549477",
15
15
  "@ours.network/daemon": "3.8.1-nightly.9",
16
- "@ours.network/fleet": "1.2.0-nightly.49",
16
+ "@ours.network/fleet": "1.2.0-nightly.50",
17
17
  "@ours.network/mcp": "1.2.0-nightly.12",
18
18
  "@ours.network/messenger-server": "1.0.31-nightly.17",
19
19
  "@ours.network/notifications": "0.3.1-nightly.2",
@@ -1002,9 +1002,9 @@
1002
1002
  }
1003
1003
  },
1004
1004
  "node_modules/@ours.network/fleet": {
1005
- "version": "1.2.0-nightly.49",
1006
- "resolved": "https://registry.npmjs.org/@ours.network/fleet/-/fleet-1.2.0-nightly.49.tgz",
1007
- "integrity": "sha512-CbhqgskezARmx8IpH8097geE5UVbrABKR5CK10iX4nR4wf0oRZSMNEV5xNPvm2R20n7dZ5ZWd/mxp4aORZU9Xw==",
1005
+ "version": "1.2.0-nightly.50",
1006
+ "resolved": "https://registry.npmjs.org/@ours.network/fleet/-/fleet-1.2.0-nightly.50.tgz",
1007
+ "integrity": "sha512-5hotA7c/I29Fj6KM3jjDxwmtlt1H5nKCCOWir4G37CqHcYIvMDuTwJKiL7RHR0OYjCdoS3zHj2hEKlwA+06M+A==",
1008
1008
  "license": "FSL-1.1-Apache-2.0",
1009
1009
  "dependencies": {
1010
1010
  "@agentclientprotocol/sdk": "^1.3.0",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schema": 1,
3
3
  "channel": "nightly",
4
- "installerVersion": "1.2.1-nightly.37",
4
+ "installerVersion": "1.2.1-nightly.38",
5
5
  "packages": {
6
6
  "@ours.network/sdk": {
7
7
  "version": "3.8.1-nightly.17",
@@ -28,8 +28,8 @@
28
28
  "integrity": "sha512-OjnrJ8ZuOfKYT4KAmiRLU7czfiuacs6rShwOvvqxqBaUKcs1UwjsYwHARNb6erMxG4am3xxcE0ItahL+d2vt4A=="
29
29
  },
30
30
  "@ours.network/fleet": {
31
- "version": "1.2.0-nightly.49",
32
- "integrity": "sha512-CbhqgskezARmx8IpH8097geE5UVbrABKR5CK10iX4nR4wf0oRZSMNEV5xNPvm2R20n7dZ5ZWd/mxp4aORZU9Xw=="
31
+ "version": "1.2.0-nightly.50",
32
+ "integrity": "sha512-5hotA7c/I29Fj6KM3jjDxwmtlt1H5nKCCOWir4G37CqHcYIvMDuTwJKiL7RHR0OYjCdoS3zHj2hEKlwA+06M+A=="
33
33
  },
34
34
  "@ours.network/mcp": {
35
35
  "version": "1.2.0-nightly.12",
@@ -6,14 +6,14 @@ import { readFileSync, statSync } from 'node:fs';
6
6
  const BROWSER = ['cookie', 'origin', 'sec-fetch-site', 'sec-fetch-mode', 'sec-fetch-dest', 'sec-fetch-user'];
7
7
  const SERVER_CREDENTIAL = 'x-ours-api-token', PRODUCER = 'x-ours-notifications-producer';
8
8
 
9
- /** Ask the daemon, exactly like the gateway's auth_request, whether a server API credential is valid. */
9
+ /** true: accepted; false: explicitly denied; null: the daemon could not decide. */
10
10
  export function daemonCredentialCheck(daemonUrl) {
11
11
  return token => new Promise(resolve => {
12
12
  const req = request(new URL('/identities', daemonUrl), { method: 'GET', headers: { [SERVER_CREDENTIAL]: token }, timeout: 5000 }, res => {
13
- res.resume(); resolve(res.statusCode >= 200 && res.statusCode < 300);
13
+ res.resume(); resolve(res.statusCode >= 200 && res.statusCode < 300 ? true : [401,403].includes(res.statusCode) ? false : null);
14
14
  });
15
15
  req.on('timeout', () => req.destroy());
16
- req.on('error', () => resolve(false));
16
+ req.on('error', () => resolve(null));
17
17
  req.end();
18
18
  });
19
19
  }
@@ -30,23 +30,31 @@ export function createNotificationsAdapter({ service, userToken, verifyServerCre
30
30
  for (const name of BROWSER) delete req.headers[name];
31
31
  const credential = req.headers[SERVER_CREDENTIAL], producer = req.headers[PRODUCER];
32
32
  delete req.headers[SERVER_CREDENTIAL]; delete req.headers[PRODUCER];
33
- if (credential === undefined) return producer === undefined;
34
- if (typeof credential !== 'string' || !credential || !await verifyServerCredential(credential)) return false;
33
+ if (credential === undefined) return producer === undefined ? 200 : 401;
34
+ if (typeof credential !== 'string' || !credential) return 401;
35
+ let verified;
36
+ try { verified = await verifyServerCredential(credential); } catch { return 503; }
37
+ if (verified !== true) return verified === false ? 401 : 503;
35
38
  const path = new URL(req.url ?? '/', 'http://localhost').pathname;
36
- if (producer !== undefined && !(req.method === 'POST' && ['/api/v1/send', '/api/v1/delete-target'].includes(path))) return false;
39
+ if (producer !== undefined && !(req.method === 'POST' && ['/api/v1/send', '/api/v1/delete-target'].includes(path))) return 401;
37
40
  req.headers.authorization = `Bearer ${producer ?? userToken}`;
38
- return true;
41
+ return 200;
39
42
  };
40
43
  const server = createServer(async (req, res) => {
41
44
  if (req.url === '/healthz' && req.method === 'GET') { res.writeHead(200, { 'content-type': 'application/json' }); res.end('{"ok":true}'); return; }
42
- if (!await authorize(req)) { res.writeHead(401, { 'content-type': 'application/json', 'cache-control': 'no-store' }); res.end('{"error":"authentication required"}'); return; }
45
+ const status = await authorize(req);
46
+ if (status !== 200) {
47
+ res.writeHead(status, { 'content-type': 'application/json', 'cache-control': 'no-store', ...(status === 503 ? { 'retry-after': '1' } : {}) });
48
+ res.end(status === 503 ? '{"error":{"code":"authentication_unavailable","message":"Server authentication is temporarily unavailable"}}' : '{"error":"authentication required"}'); return;
49
+ }
43
50
  service.server.emit('request', req, res);
44
51
  });
45
52
  // Upgraded connections leave the HTTP server's connection tracking, so shutdown ends them itself.
46
53
  const upgraded = new Set();
47
54
  server.on('upgrade', async (req, socket, head) => {
48
55
  upgraded.add(socket); socket.once('close', () => upgraded.delete(socket));
49
- if (!await authorize(req)) { socket.end('HTTP/1.1 401 Unauthorized\r\nConnection: close\r\nContent-Length: 0\r\n\r\n'); return; }
56
+ const status = await authorize(req);
57
+ if (status !== 200) { socket.end(`HTTP/1.1 ${status} ${status === 503 ? 'Service Unavailable' : 'Unauthorized'}\r\nConnection: close\r\n${status === 503 ? 'Retry-After: 1\r\n' : ''}Content-Length: 0\r\n\r\n`); return; }
50
58
  service.server.emit('upgrade', req, socket, head);
51
59
  });
52
60
  return { server, async close() {
@@ -2,7 +2,7 @@
2
2
  "release": {
3
3
  "schema": 1,
4
4
  "channel": "nightly",
5
- "installerVersion": "1.2.1-nightly.37",
5
+ "installerVersion": "1.2.1-nightly.38",
6
6
  "packages": {
7
7
  "@ours.network/sdk": {
8
8
  "version": "3.8.1-nightly.17",
@@ -29,8 +29,8 @@
29
29
  "integrity": "sha512-OjnrJ8ZuOfKYT4KAmiRLU7czfiuacs6rShwOvvqxqBaUKcs1UwjsYwHARNb6erMxG4am3xxcE0ItahL+d2vt4A=="
30
30
  },
31
31
  "@ours.network/fleet": {
32
- "version": "1.2.0-nightly.49",
33
- "integrity": "sha512-CbhqgskezARmx8IpH8097geE5UVbrABKR5CK10iX4nR4wf0oRZSMNEV5xNPvm2R20n7dZ5ZWd/mxp4aORZU9Xw=="
32
+ "version": "1.2.0-nightly.50",
33
+ "integrity": "sha512-5hotA7c/I29Fj6KM3jjDxwmtlt1H5nKCCOWir4G37CqHcYIvMDuTwJKiL7RHR0OYjCdoS3zHj2hEKlwA+06M+A=="
34
34
  },
35
35
  "@ours.network/mcp": {
36
36
  "version": "1.2.0-nightly.12",
@@ -87,7 +87,7 @@
87
87
  },
88
88
  "@ours.network/fleet": {
89
89
  "type": "npm",
90
- "version": "1.2.0-nightly.49"
90
+ "version": "1.2.0-nightly.50"
91
91
  },
92
92
  "@ours.network/mcp": {
93
93
  "type": "npm",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ours.network/install",
3
- "version": "1.2.1-nightly.37",
3
+ "version": "1.2.1-nightly.38",
4
4
  "private": false,
5
5
  "description": "The all-in-one ours.network installer: one shared daemon, MCP, cowork, Telegram, Fleet initialization, harness plugins, Human identity, progress UI, and guided next steps.",
6
6
  "type": "module",