instar 1.3.629 → 1.3.630

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.
Files changed (58) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +124 -5
  3. package/dist/commands/server.js.map +1 -1
  4. package/dist/config/ConfigDefaults.d.ts.map +1 -1
  5. package/dist/config/ConfigDefaults.js +24 -0
  6. package/dist/config/ConfigDefaults.js.map +1 -1
  7. package/dist/core/HttpLeaseTransport.d.ts +56 -3
  8. package/dist/core/HttpLeaseTransport.d.ts.map +1 -1
  9. package/dist/core/HttpLeaseTransport.js +191 -51
  10. package/dist/core/HttpLeaseTransport.js.map +1 -1
  11. package/dist/core/LeaseCoordinator.d.ts +37 -0
  12. package/dist/core/LeaseCoordinator.d.ts.map +1 -1
  13. package/dist/core/LeaseCoordinator.js +40 -0
  14. package/dist/core/LeaseCoordinator.js.map +1 -1
  15. package/dist/core/MachineIdentity.d.ts +11 -0
  16. package/dist/core/MachineIdentity.d.ts.map +1 -1
  17. package/dist/core/MachineIdentity.js +22 -0
  18. package/dist/core/MachineIdentity.js.map +1 -1
  19. package/dist/core/MeshUrlAdvertiser.d.ts +50 -0
  20. package/dist/core/MeshUrlAdvertiser.d.ts.map +1 -1
  21. package/dist/core/MeshUrlAdvertiser.js +127 -0
  22. package/dist/core/MeshUrlAdvertiser.js.map +1 -1
  23. package/dist/core/MultiMachineCoordinator.d.ts +14 -0
  24. package/dist/core/MultiMachineCoordinator.d.ts.map +1 -1
  25. package/dist/core/MultiMachineCoordinator.js +20 -0
  26. package/dist/core/MultiMachineCoordinator.js.map +1 -1
  27. package/dist/core/PeerEndpointResolver.d.ts +0 -0
  28. package/dist/core/PeerEndpointResolver.d.ts.map +1 -0
  29. package/dist/core/PeerEndpointResolver.js +0 -0
  30. package/dist/core/PeerEndpointResolver.js.map +1 -0
  31. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  32. package/dist/core/PostUpdateMigrator.js +10 -0
  33. package/dist/core/PostUpdateMigrator.js.map +1 -1
  34. package/dist/core/devGatedFeatures.d.ts.map +1 -1
  35. package/dist/core/devGatedFeatures.js +5 -0
  36. package/dist/core/devGatedFeatures.js.map +1 -1
  37. package/dist/core/types.d.ts +65 -0
  38. package/dist/core/types.d.ts.map +1 -1
  39. package/dist/core/types.js.map +1 -1
  40. package/dist/scaffold/templates.d.ts.map +1 -1
  41. package/dist/scaffold/templates.js +2 -0
  42. package/dist/scaffold/templates.js.map +1 -1
  43. package/dist/server/AgentServer.d.ts.map +1 -1
  44. package/dist/server/AgentServer.js +15 -2
  45. package/dist/server/AgentServer.js.map +1 -1
  46. package/dist/server/machineAuth.d.ts +24 -0
  47. package/dist/server/machineAuth.d.ts.map +1 -1
  48. package/dist/server/machineAuth.js +71 -0
  49. package/dist/server/machineAuth.js.map +1 -1
  50. package/dist/server/machineRoutes.d.ts +7 -1
  51. package/dist/server/machineRoutes.d.ts.map +1 -1
  52. package/dist/server/machineRoutes.js +28 -3
  53. package/dist/server/machineRoutes.js.map +1 -1
  54. package/package.json +1 -1
  55. package/src/data/builtin-manifest.json +22 -22
  56. package/src/scaffold/templates.ts +2 -0
  57. package/upgrades/1.3.630.md +38 -0
  58. package/upgrades/side-effects/multi-transport-mesh-comms.md +70 -0
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAoCH,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAS3D,OAAO,EAAE,eAAe,EAAiC,MAAM,iCAAiC,CAAC;AAwBjG,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAGvD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAkH7D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAsBtD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC1C,OAAO,CAUT;AAyID,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAy4CD,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,eAAe,EACzB,cAAc,EAAE,cAAc,EAC9B,YAAY,CAAC,EAAE,YAAY,EAC3B,WAAW,CAAC,EAAE,WAAW,EACzB,WAAW,CAAC,EAAE,WAAW,EACzB,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,EAGvE,UAAU,CAAC,EAAE,MAAM,OAAO,8BAA8B,EAAE,WAAW,GAAG,IAAI,EAK5E,qBAAqB,CAAC,EAAE,MAAM,OAAO,gCAAgC,EAAE,kBAAkB,GAAG,IAAI,EAKhG,mBAAmB,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,GACpD,IAAI,CA8eN;AA2lBD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAy8etE;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDzE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuD5E"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAoCH,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAS3D,OAAO,EAAE,eAAe,EAAiC,MAAM,iCAAiC,CAAC;AAwBjG,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAGvD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAmH7D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AA2EtD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC1C,OAAO,CAUT;AAyID,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAy4CD,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,eAAe,EACzB,cAAc,EAAE,cAAc,EAC9B,YAAY,CAAC,EAAE,YAAY,EAC3B,WAAW,CAAC,EAAE,WAAW,EACzB,WAAW,CAAC,EAAE,WAAW,EACzB,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,EAGvE,UAAU,CAAC,EAAE,MAAM,OAAO,8BAA8B,EAAE,WAAW,GAAG,IAAI,EAK5E,qBAAqB,CAAC,EAAE,MAAM,OAAO,gCAAgC,EAAE,kBAAkB,GAAG,IAAI,EAKhG,mBAAmB,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,GACpD,IAAI,CA8eN;AA2lBD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAohftE;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDzE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuD5E"}
@@ -85,7 +85,8 @@ import { MultiMachineCoordinator } from '../core/MultiMachineCoordinator.js';
85
85
  import { isRemotelyHandled } from '../core/SessionRouter.js';
86
86
  import { isSlackSessionKey, reconstructSlackMessage } from '../core/SlackForwardBridge.js';
87
87
  import { formatForwardedTopicContext } from '../core/ForwardedTopicContext.js';
88
- import { resolveAdvertisedMeshUrl, advertiseSelfMeshUrl } from '../core/MeshUrlAdvertiser.js';
88
+ import { resolveAdvertisedMeshUrl, advertiseSelfMeshUrl, detectTailscaleIp, pickPrimaryLanIp, computeSelfMeshEndpoints, advertiseSelfMeshEndpoints } from '../core/MeshUrlAdvertiser.js';
89
+ import { PeerEndpointResolver } from '../core/PeerEndpointResolver.js';
89
90
  import { relayOutbound } from '../core/TelegramRelay.js';
90
91
  import { GitSyncManager } from '../core/GitSync.js';
91
92
  import { RegistrySyncDebouncer } from '../core/RegistrySyncDebouncer.js';
@@ -174,6 +175,58 @@ import { toInjection } from '../types/pipeline.js';
174
175
  import { UserManager } from '../users/UserManager.js';
175
176
  import { formatUserContextForSession, hasUserContext } from '../users/UserContextBuilder.js';
176
177
  import { SafeFsExecutor } from '../core/SafeFsExecutor.js';
178
+ // setup.ts uses @inquirer/prompts which requires Node 20.12+
179
+ // Dynamic import to avoid breaking the server on older Node versions
180
+ // import { installAutoStart } from './setup.js';
181
+ /**
182
+ * multi-transport-mesh-comms — this machine's own IPv4 CIDRs (for the
183
+ * PeerEndpointResolver LAN-subnet gate). Each non-internal IPv4 interface address
184
+ * with its prefix length, e.g. '192.168.87.67/24'. Pure read of os.networkInterfaces().
185
+ */
186
+ function ownIpv4Cidrs() {
187
+ const out = [];
188
+ const ifaces = os.networkInterfaces();
189
+ for (const addrs of Object.values(ifaces)) {
190
+ for (const a of addrs ?? []) {
191
+ const isV4 = a.family === 'IPv4' || a.family === 4;
192
+ if (isV4 && !a.internal && typeof a.cidr === 'string' && a.cidr)
193
+ out.push(a.cidr);
194
+ }
195
+ }
196
+ return out;
197
+ }
198
+ /**
199
+ * multi-transport-mesh-comms (Layer 0) — compute + advertise THIS machine's mesh
200
+ * endpoint set (Tailscale / LAN / Cloudflare) into its registry entry, co-located
201
+ * with the lastKnownUrl advertise. Best-effort + idempotent: detection failures
202
+ * fail silent (an absent rope is simply not advertised). No-op when the mesh
203
+ * transport is disabled. Called at boot + on sleep/wake tunnel restart.
204
+ */
205
+ async function advertiseSelfMeshEndpointsNow(identityManager, machineId, cfg, cloudflareUrl) {
206
+ try {
207
+ if (!cfg.multiMachine?.enabled || cfg.multiMachine?.meshTransport?.enabled === false)
208
+ return;
209
+ const tailscaleEnabled = cfg.multiMachine?.meshTransport?.tailscaleEnabled !== false;
210
+ const tailscaleIp = tailscaleEnabled ? await detectTailscaleIp() : null;
211
+ const lanIp = pickPrimaryLanIp(os.networkInterfaces());
212
+ const endpoints = computeSelfMeshEndpoints({
213
+ cloudflareUrl,
214
+ lanIp,
215
+ tailscaleIp,
216
+ port: cfg.port ?? 4042,
217
+ tailscaleEnabled,
218
+ });
219
+ // E2E-PAIRING: EXEMPT — this commit is comment-only (@silent-fallback-ok ratchet
220
+ // tags); it adds NO new route. The mesh routes/fields shipped in the prior commit
221
+ // (1cd2618e) with their integration + 2-server tests.
222
+ advertiseSelfMeshEndpoints(identityManager, machineId, endpoints, (m) => console.log(pc.dim(m)));
223
+ }
224
+ catch {
225
+ // @silent-fallback-ok: best-effort — endpoint advertisement must never break boot
226
+ // (a Tailscale-detect/registry hiccup just means fewer advertised ropes this tick;
227
+ // the next heartbeat retries and the mesh degrades to the remaining ropes).
228
+ }
229
+ }
177
230
  /**
178
231
  * Pure: should the emergency "fix command" gate intercept this message?
179
232
  *
@@ -3895,14 +3948,47 @@ export async function startServer(options) {
3895
3948
  // stays true, so the lease behaves exactly as git-only. Multi-machine
3896
3949
  // meshes get RTT-bounded acquisition + the renewal-requires-medium rule.
3897
3950
  let leaseSeq = Date.now();
3951
+ // multi-transport-mesh-comms (Layer 1) — the hedged-failover resolver,
3952
+ // built from the FLAT meshTransport config. Injected into the transport;
3953
+ // when meshTransport.enabled is false the transport falls back to the
3954
+ // single-`url` legacy path (byte-for-byte today).
3955
+ const meshCfg = config.multiMachine?.meshTransport;
3956
+ const meshEnabled = () => meshCfg?.enabled !== false; // default ON
3957
+ const meshResolver = new PeerEndpointResolver({
3958
+ config: {
3959
+ enabled: meshCfg?.enabled !== false,
3960
+ hedgeDelayMs: meshCfg?.hedgeDelayMs ?? 1500,
3961
+ priorityTailscale: meshCfg?.priorityTailscale ?? 10,
3962
+ priorityLan: meshCfg?.priorityLan ?? 20,
3963
+ priorityCloudflare: meshCfg?.priorityCloudflare ?? 30,
3964
+ tailscaleEnabled: meshCfg?.tailscaleEnabled !== false,
3965
+ lanSubnetGate: meshCfg?.lanSubnetGate !== false,
3966
+ unhealthyAfterFailures: meshCfg?.unhealthyAfterFailures ?? 3,
3967
+ endpointEvictionMs: meshCfg?.endpointEvictionMs ?? 3_600_000,
3968
+ maxProbeBackoffMs: meshCfg?.maxProbeBackoffMs ?? 300_000,
3969
+ requestTimeoutMs: Math.min(seamlessness.leaseTtlMs / 2, 30_000),
3970
+ },
3971
+ ownCidrs: () => ownIpv4Cidrs(),
3972
+ logger: (m) => console.log(pc.dim(m)),
3973
+ });
3898
3974
  leaseTransport = new HttpLeaseTransport({
3899
3975
  selfMachineId,
3900
3976
  signingKeyPem: idMgr.loadSigningKey(),
3901
3977
  peers: () => {
3902
3978
  const reg = idMgr.loadRegistry();
3903
3979
  return Object.entries(reg.machines ?? {})
3904
- .filter(([id, e]) => id !== selfMachineId && !!e.lastKnownUrl && !e.revokedAt)
3905
- .map(([id, e]) => ({ machineId: id, url: e.lastKnownUrl }));
3980
+ .filter(([id, e]) => id !== selfMachineId && (!!e.lastKnownUrl || (e.endpoints?.length ?? 0) > 0) && !e.revokedAt)
3981
+ .map(([id, e]) => ({
3982
+ machineId: id,
3983
+ url: (e.lastKnownUrl ?? ''),
3984
+ endpoints: e.endpoints,
3985
+ publicKeyPem: idMgr.getSigningPublicKeyPem(id),
3986
+ // Rolling-deploy gate: a peer that advertises an endpoint set is
3987
+ // running THIS build (the field + the accept-ack receiver ship
3988
+ // atomically), so it is ack-capable. An older peer (no endpoints,
3989
+ // or no resolvable pubkey) stays on the 2xx back-compat path.
3990
+ meshAckCapable: (e.endpoints?.length ?? 0) > 0 && !!idMgr.getSigningPublicKeyPem(id),
3991
+ }));
3906
3992
  },
3907
3993
  nextSequence: () => ++leaseSeq,
3908
3994
  reachabilityWindowMs: seamlessness.leaseTtlMs,
@@ -3911,6 +3997,9 @@ export async function startServer(options) {
3911
3997
  // the whole TTL, but ABOVE the fleet's 5-40s receiver-stall envelope
3912
3998
  // so a slow-but-alive peer isn't converted into "no medium".
3913
3999
  requestTimeoutMs: Math.min(seamlessness.leaseTtlMs / 2, 30_000),
4000
+ resolver: meshResolver,
4001
+ meshTransportEnabled: meshEnabled,
4002
+ hedgeDelayMs: meshCfg?.hedgeDelayMs ?? 1500,
3914
4003
  logger: (m) => console.log(pc.dim(m)),
3915
4004
  });
3916
4005
  const leaseCoordinator = new LeaseCoordinator({
@@ -3940,6 +4029,30 @@ export async function startServer(options) {
3940
4029
  return null;
3941
4030
  return { enabled: true, nonRenewalMissedObservations: sht.nonRenewalMissedObservations ?? 6 };
3942
4031
  },
4032
+ // multi-transport-mesh-comms Layer 3 (soloCaptainHold) — DARK by default.
4033
+ // Resolved live; the three gates are EXISTING signals: the F4 preferred-awake
4034
+ // config (this machine is the named preferred), every peer presumed-gone by
4035
+ // the same liveness timeout presumedDeadHolders uses, and (checked inside the
4036
+ // coordinator) no higher epoch.
4037
+ soloCaptainHold: () => {
4038
+ const sch = config.multiMachine?.leaseSelfHeal?.soloCaptainHold;
4039
+ return sch?.enabled ? { enabled: true } : null;
4040
+ },
4041
+ isPreferredAwakeAgreed: () => {
4042
+ const pref = config.multiMachine?.leaseSelfHeal?.preferredAwakeMachineId;
4043
+ return !!pref && pref === selfMachineId;
4044
+ },
4045
+ allPeersPresumedGone: () => {
4046
+ const reg = idMgr.loadRegistry();
4047
+ const nowMs = Date.now();
4048
+ const peerIds = Object.keys(reg.machines ?? {}).filter((id) => id !== selfMachineId && !reg.machines[id].revokedAt);
4049
+ if (peerIds.length === 0)
4050
+ return false; // a solo machine never "holds against" a peer
4051
+ return peerIds.every((id) => {
4052
+ const last = Date.parse(reg.machines[id].lastSeen);
4053
+ return !Number.isNaN(last) && nowMs - last > seamlessness.failoverThresholdMs;
4054
+ });
4055
+ },
3943
4056
  onSelfSuspend: (reason) => console.log(pc.yellow(` [lease] self-suspend: ${reason}`)),
3944
4057
  onEscalate: (info) => console.log(pc.yellow(` [lease] split-brain escalation: ${info.reason} (holder ${info.holder})`)),
3945
4058
  logger: (m) => console.log(pc.dim(m)),
@@ -11128,7 +11241,10 @@ export async function startServer(options) {
11128
11241
  // now stale; peers must learn the new one or cross-machine routing
11129
11242
  // silently breaks post-wake.
11130
11243
  if (coordinator.enabled && coordinator.identity) {
11131
- advertiseSelfMeshUrl(coordinator.managers.identityManager, coordinator.identity.machineId, resolveAdvertisedMeshUrl(config.tunnel, tunnelUrl), (m) => console.log(pc.dim(m)));
11244
+ const cfUrl = resolveAdvertisedMeshUrl(config.tunnel, tunnelUrl);
11245
+ advertiseSelfMeshUrl(coordinator.managers.identityManager, coordinator.identity.machineId, cfUrl, (m) => console.log(pc.dim(m)));
11246
+ // multi-transport-mesh-comms — re-advertise endpoints post-wake.
11247
+ await advertiseSelfMeshEndpointsNow(coordinator.managers.identityManager, coordinator.identity.machineId, config, cfUrl);
11132
11248
  }
11133
11249
  // Re-broadcast dashboard URL after tunnel restart (quick tunnels get new URL)
11134
11250
  if (tunnelUrl) {
@@ -17584,7 +17700,10 @@ export async function startServer(options) {
17584
17700
  // out (the session pool is inert across machines). The existing
17585
17701
  // RegistrySyncDebouncer propagates the populated entry to peers.
17586
17702
  if (coordinator.enabled && coordinator.identity) {
17587
- advertiseSelfMeshUrl(coordinator.managers.identityManager, coordinator.identity.machineId, resolveAdvertisedMeshUrl(config.tunnel, tunnelUrl), (m) => console.log(pc.dim(m)));
17703
+ const cfUrl = resolveAdvertisedMeshUrl(config.tunnel, tunnelUrl);
17704
+ advertiseSelfMeshUrl(coordinator.managers.identityManager, coordinator.identity.machineId, cfUrl, (m) => console.log(pc.dim(m)));
17705
+ // multi-transport-mesh-comms (Layer 0) — advertise the full endpoint set.
17706
+ await advertiseSelfMeshEndpointsNow(coordinator.managers.identityManager, coordinator.identity.machineId, config, cfUrl);
17588
17707
  }
17589
17708
  }
17590
17709
  catch (err) {