infinicode 2.5.1 → 2.6.1

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.
@@ -4,6 +4,7 @@ import { PeerMesh } from './peer-mesh.js';
4
4
  import { EventBridge } from './event-bridge.js';
5
5
  import { ConfigSync } from './config-sync.js';
6
6
  import { AutoUpdate } from './auto-update.js';
7
+ import { performSelfUpdate } from './self-update.js';
7
8
  import { ComputeRouter } from './compute-router.js';
8
9
  import { TelemetryCollector, loadFromSnapshot, selfNodeStatus, nodeStatusFromPeer } from './telemetry.js';
9
10
  import { buildManifest } from './node-identity.js';
@@ -58,6 +59,17 @@ export class Federation {
58
59
  version: deps.options.version,
59
60
  logger: deps.logger,
60
61
  enabled: deps.options.autoUpdate,
62
+ // Apply the announced update (npm install + supervised restart). Only ever
63
+ // reached for announces from a hub/relay with auto-update enabled — see
64
+ // AutoUpdate.onAnnounce. Supervision is read from INFINICODE_SUPERVISED.
65
+ applyUpdate: async (announce) => {
66
+ await performSelfUpdate({
67
+ version: announce.version,
68
+ channel: announce.channel === 'git' ? 'git' : 'npm',
69
+ currentVersion: deps.options.version,
70
+ logger: deps.logger,
71
+ });
72
+ },
61
73
  });
62
74
  }
63
75
  get identity() {
@@ -0,0 +1,26 @@
1
+ import type { Logger } from '../types.js';
2
+ export interface SelfUpdateOptions {
3
+ /** Target version — 'latest' or a semver like '2.6.1'. Default 'latest'. */
4
+ version?: string;
5
+ /** npm package to install. Default 'infinicode' (override via INFINICODE_UPDATE_PKG). */
6
+ pkg?: string;
7
+ channel?: 'npm' | 'git' | 'manual';
8
+ /** The version currently running, for the from→to report. */
9
+ currentVersion?: string;
10
+ /** Node runs under a supervisor → safe to exit-for-restart. Falls back to
11
+ * INFINICODE_SUPERVISED=1. */
12
+ supervised?: boolean;
13
+ /** Schedule a restart after a successful install. Defaults to `supervised`. */
14
+ restart?: boolean;
15
+ /** Delay before exiting so the command reply flushes back over the mesh. */
16
+ restartDelayMs?: number;
17
+ logger?: Logger;
18
+ }
19
+ export interface SelfUpdateResult {
20
+ ok: boolean;
21
+ from?: string;
22
+ to: string;
23
+ restarting: boolean;
24
+ message: string;
25
+ }
26
+ export declare function performSelfUpdate(opts?: SelfUpdateOptions): Promise<SelfUpdateResult>;
@@ -0,0 +1,68 @@
1
+ /**
2
+ * OpenKernel — Self Update
3
+ *
4
+ * The apply side of mesh updates: install a newer npm release of this package
5
+ * globally, then (if the node runs under a process supervisor) exit so the
6
+ * supervisor relaunches it on the new version. Isolated here so the shell-out
7
+ * lives in exactly one place — the `/update` command and the AutoUpdate gossip
8
+ * path both call this, nothing else shells out for updates.
9
+ *
10
+ * Restart policy is deliberately conservative: a node only exits-for-restart
11
+ * when it is explicitly marked supervised (`serve --supervised`, which sets
12
+ * INFINICODE_SUPERVISED=1). An unsupervised node still installs the new version
13
+ * on disk but stays up on the old one, and says so — killing a hand-started
14
+ * process would just take the node offline with nothing to bring it back.
15
+ */
16
+ import { execa } from 'execa';
17
+ const SAFE_VERSION = /^[A-Za-z0-9._-]+$/; // 'latest', '2.6.1', 'next' — never a shell metachar
18
+ const SAFE_PKG = /^[@A-Za-z0-9._/-]+$/;
19
+ export async function performSelfUpdate(opts = {}) {
20
+ const version = (opts.version ?? 'latest').trim();
21
+ const pkg = (opts.pkg ?? process.env.INFINICODE_UPDATE_PKG ?? 'infinicode').trim();
22
+ const channel = opts.channel ?? 'npm';
23
+ const supervised = opts.supervised ?? process.env.INFINICODE_SUPERVISED === '1';
24
+ const restart = opts.restart ?? supervised;
25
+ const info = (m) => (opts.logger ? opts.logger.info(m) : console.log(' ' + m));
26
+ const warn = (m) => (opts.logger ? opts.logger.warn(m) : console.log(' ' + m));
27
+ if (channel !== 'npm') {
28
+ return { ok: false, to: version, restarting: false, message: `channel "${channel}" is not supported for self-update yet (npm only).` };
29
+ }
30
+ if (!SAFE_VERSION.test(version) || !SAFE_PKG.test(pkg)) {
31
+ return { ok: false, to: version, restarting: false, message: `refused: unsafe update spec "${pkg}@${version}".` };
32
+ }
33
+ const spec = `${pkg}@${version}`;
34
+ info(`[update] installing ${spec} (global)…`);
35
+ try {
36
+ // Use npm.cmd on Windows so we never need a shell (no injection surface).
37
+ const bin = process.platform === 'win32' ? 'npm.cmd' : 'npm';
38
+ const res = await execa(bin, ['install', '-g', spec], { all: true, timeout: 300_000 });
39
+ const tail = String(res.all ?? res.stdout ?? '').split('\n').filter(Boolean).slice(-2).join(' ').trim();
40
+ info(`[update] installed ${spec}${tail ? ' — ' + tail : ''}`);
41
+ }
42
+ catch (err) {
43
+ const detail = err;
44
+ const message = (detail.all || detail.shortMessage || detail.message || String(err)).replace(/\s+/g, ' ').slice(0, 300);
45
+ warn(`[update] npm install failed: ${message}`);
46
+ return { ok: false, from: opts.currentVersion, to: version, restarting: false, message: `npm install -g ${spec} failed: ${message}` };
47
+ }
48
+ let restarting = false;
49
+ if (restart && supervised) {
50
+ restarting = true;
51
+ const delay = opts.restartDelayMs ?? 2000;
52
+ info(`[update] restarting in ${delay}ms for the supervisor to relaunch on ${version}…`);
53
+ const timer = setTimeout(() => process.exit(0), delay);
54
+ timer.unref?.();
55
+ }
56
+ else if (restart && !supervised) {
57
+ warn('[update] installed but NOT restarting — node is not marked supervised (start serve with --supervised). Restart it to activate.');
58
+ }
59
+ return {
60
+ ok: true,
61
+ from: opts.currentVersion,
62
+ to: version,
63
+ restarting,
64
+ message: restarting
65
+ ? `updated to ${spec} — restarting now; the supervisor will relaunch on the new version.`
66
+ : `updated to ${spec} on disk — restart the node to activate${supervised ? '' : ' (not supervised, so no auto-restart)'}.`,
67
+ };
68
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "infinicode",
3
- "version": "2.5.1",
3
+ "version": "2.6.1",
4
4
  "description": "OpenKernel — provider-agnostic AI execution kernel. Native coding agent + mission-driven execution runtime.",
5
5
  "type": "module",
6
6
  "main": "./dist/kernel/index.js",