@ours.network/install 1.2.1-nightly.20 → 1.2.1-nightly.21

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schema": 1,
3
3
  "channel": "nightly",
4
- "installerVersion": "1.2.1-nightly.20",
4
+ "installerVersion": "1.2.1-nightly.21",
5
5
  "packages": {
6
6
  "@ours.network/sdk": {
7
7
  "version": "3.8.1-nightly.15",
@@ -2,7 +2,7 @@
2
2
  "release": {
3
3
  "schema": 1,
4
4
  "channel": "nightly",
5
- "installerVersion": "1.2.1-nightly.20",
5
+ "installerVersion": "1.2.1-nightly.21",
6
6
  "packages": {
7
7
  "@ours.network/sdk": {
8
8
  "version": "3.8.1-nightly.15",
package/lib/effects.mjs CHANGED
@@ -782,21 +782,30 @@ export function networkEffects(effects) {
782
782
  async removeGatewayContainer(record) { await compose(record, ['rm', '-f', 'gateway']); },
783
783
  async verifyGateway(record) {
784
784
  const { prefix } = gatewayAddress(record);
785
- const script = `const fs=require('node:fs');(async()=>{
785
+ const script = `const fs=require('node:fs');let stage='selection';(async()=>{
786
786
  const base=${JSON.stringify('http://gateway:8080' + prefix)};
787
787
  const get=async(path,options={})=>{const r=await fetch(base+path,{...options,redirect:'error',signal:AbortSignal.timeout(5000)});if(!r.ok)throw Error('Gateway readiness HTTP '+r.status);return r.json();};
788
788
  const selection=await get('/daemon/selection');
789
789
  if(selection.instanceId!==${JSON.stringify(record.instanceId)})throw Error('Gateway daemon instance mismatch');
790
+ stage='unauthenticated-management';
790
791
  const denied=await fetch(base+'/cowork/management/rpc',{method:'POST',redirect:'error',signal:AbortSignal.timeout(5000),headers:{'content-type':'application/json'},body:'{}'});
791
792
  await denied.body?.cancel();if(denied.status!==401)throw Error('Gateway management does not reject unauthenticated requests');
793
+ stage='credential';
792
794
  const token=fs.readFileSync('/var/lib/ours/daemon-token','utf8').trim();
793
795
  const headers={'x-ours-api-token':token,'content-type':'application/json'};
796
+ stage='authenticated-daemon';
794
797
  const identities=await get('/daemon/identities',{headers});
795
798
  if(!Array.isArray(identities.identities))throw Error('Gateway daemon API invalid');
799
+ stage='authenticated-management';
796
800
  const result=await get('/cowork/management/rpc',{method:'POST',headers,body:JSON.stringify({version:1,id:'installer-readiness',method:'room.list',params:{}})});
797
801
  if(result.version!==1||result.id!=='installer-readiness'||!Array.isArray(result.result)||result.error)throw Error('Gateway Cowork management unavailable');
798
- })().catch(()=>{console.error('Authenticated gateway readiness failed');process.exitCode=1;});`;
799
- await compose(record, ['exec', '-T', 'daemon', 'node', '-e', script], { sensitive: true });
802
+ })().catch(error=>{const code=error.cause?.code;process.stdout.write('gateway-readiness:'+stage+':'+(['EAI_AGAIN','ENOTFOUND','ECONNREFUSED','ETIMEDOUT'].includes(code)?code:'CHECK_FAILED'));process.exitCode=1;});`;
803
+ const result = await compose(record, ['exec', '-T', 'daemon', 'node', '-e', script], { sensitive: true, allowCodes: [1] });
804
+ if (result.code === 1) {
805
+ const match = /^gateway-readiness:(selection|unauthenticated-management|credential|authenticated-daemon|authenticated-management):(EAI_AGAIN|ENOTFOUND|ECONNREFUSED|ETIMEDOUT|CHECK_FAILED)$/.exec(result.stdout.trim());
806
+ const detail = match ? ` (${match[1]}, ${match[2]})` : '';
807
+ throw new Error(`Gateway readiness failed${detail}. Keep installation state intact; check the managed gateway startup and network connection, then retry setup.`);
808
+ }
800
809
  },
801
810
  async qualifyGatewayRuntime(record) {
802
811
  for (const [name, args, capability] of [
@@ -1244,7 +1253,9 @@ export function networkEffects(effects) {
1244
1253
  }
1245
1254
  const start = async service => {
1246
1255
  effects.out(`Starting ${service}; waiting for readiness...`);
1247
- try { await compose(record, ['up', '-d', '--no-build', '--no-deps', '--wait', service]); }
1256
+ // Gateway has no persistent state. Recreate its network endpoint on each
1257
+ // managed start, including retries after an interrupted/failed bind.
1258
+ try { await compose(record, ['up', '-d', '--no-build', '--no-deps', ...(service === 'gateway' ? ['--force-recreate'] : []), '--wait', service]); }
1248
1259
  catch (cause) { throw await dockerStartupError(record, service, cause); }
1249
1260
  effects.out(`${service} is ready.`);
1250
1261
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ours.network/install",
3
- "version": "1.2.1-nightly.20",
3
+ "version": "1.2.1-nightly.21",
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",