instar 1.3.1590 → 1.3.1592

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 (72) hide show
  1. package/dashboard/console/console.css +6 -0
  2. package/dashboard/console/machines-model.js +15 -0
  3. package/dashboard/console/machines.js +3 -2
  4. package/dashboard/console/promises.js +3 -1
  5. package/dist/commands/server.d.ts.map +1 -1
  6. package/dist/commands/server.js +76 -0
  7. package/dist/commands/server.js.map +1 -1
  8. package/dist/core/PostUpdateMigrator.d.ts +7 -0
  9. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  10. package/dist/core/PostUpdateMigrator.js +27 -0
  11. package/dist/core/PostUpdateMigrator.js.map +1 -1
  12. package/dist/core/SessionManager.d.ts +1 -1
  13. package/dist/core/SessionManager.d.ts.map +1 -1
  14. package/dist/core/SessionManager.js.map +1 -1
  15. package/dist/core/devGatedFeatures.d.ts.map +1 -1
  16. package/dist/core/devGatedFeatures.js +6 -0
  17. package/dist/core/devGatedFeatures.js.map +1 -1
  18. package/dist/core/types.d.ts +13 -0
  19. package/dist/core/types.d.ts.map +1 -1
  20. package/dist/core/types.js.map +1 -1
  21. package/dist/data/standards-guard-index.json +1 -1
  22. package/dist/data/standards-guard-index.meta.json +2 -2
  23. package/dist/data/standards-registry.meta.json +1 -1
  24. package/dist/monitoring/guardManifest.d.ts.map +1 -1
  25. package/dist/monitoring/guardManifest.js +10 -0
  26. package/dist/monitoring/guardManifest.js.map +1 -1
  27. package/dist/monitoring/machineMaintenance/DrainRehearsal.d.ts +134 -0
  28. package/dist/monitoring/machineMaintenance/DrainRehearsal.d.ts.map +1 -0
  29. package/dist/monitoring/machineMaintenance/DrainRehearsal.js +509 -0
  30. package/dist/monitoring/machineMaintenance/DrainRehearsal.js.map +1 -0
  31. package/dist/monitoring/machineMaintenance/HostMaintenanceStore.d.ts +80 -0
  32. package/dist/monitoring/machineMaintenance/HostMaintenanceStore.d.ts.map +1 -0
  33. package/dist/monitoring/machineMaintenance/HostMaintenanceStore.js +160 -0
  34. package/dist/monitoring/machineMaintenance/HostMaintenanceStore.js.map +1 -0
  35. package/dist/monitoring/machineMaintenance/WorkYieldRegistry.d.ts +69 -0
  36. package/dist/monitoring/machineMaintenance/WorkYieldRegistry.d.ts.map +1 -0
  37. package/dist/monitoring/machineMaintenance/WorkYieldRegistry.js +120 -0
  38. package/dist/monitoring/machineMaintenance/WorkYieldRegistry.js.map +1 -0
  39. package/dist/monitoring/machineMaintenance/planner.d.ts +88 -0
  40. package/dist/monitoring/machineMaintenance/planner.d.ts.map +1 -0
  41. package/dist/monitoring/machineMaintenance/planner.js +154 -0
  42. package/dist/monitoring/machineMaintenance/planner.js.map +1 -0
  43. package/dist/monitoring/machineMaintenance/readings.d.ts +90 -0
  44. package/dist/monitoring/machineMaintenance/readings.d.ts.map +1 -0
  45. package/dist/monitoring/machineMaintenance/readings.js +161 -0
  46. package/dist/monitoring/machineMaintenance/readings.js.map +1 -0
  47. package/dist/native/instar-desktop-host +0 -0
  48. package/dist/scaffold/templates.d.ts.map +1 -1
  49. package/dist/scaffold/templates.js +3 -1
  50. package/dist/scaffold/templates.js.map +1 -1
  51. package/dist/scheduler/JobScheduler.d.ts +2 -0
  52. package/dist/scheduler/JobScheduler.d.ts.map +1 -1
  53. package/dist/scheduler/JobScheduler.js +4 -0
  54. package/dist/scheduler/JobScheduler.js.map +1 -1
  55. package/dist/server/CapabilityIndex.d.ts.map +1 -1
  56. package/dist/server/CapabilityIndex.js +9 -0
  57. package/dist/server/CapabilityIndex.js.map +1 -1
  58. package/dist/server/routes.d.ts.map +1 -1
  59. package/dist/server/routes.js +13 -0
  60. package/dist/server/routes.js.map +1 -1
  61. package/package.json +1 -1
  62. package/src/data/builtin-manifest.json +65 -65
  63. package/src/data/standards-guard-index.json +1 -1
  64. package/src/data/standards-guard-index.meta.json +2 -2
  65. package/src/data/standards-registry.meta.json +1 -1
  66. package/src/data/state-coherence-registry.json +19 -0
  67. package/src/scaffold/templates.ts +3 -1
  68. package/upgrades/1.3.1591.md +27 -0
  69. package/upgrades/1.3.1592.md +22 -0
  70. package/upgrades/side-effects/console-decide-origin.eli16.md +12 -0
  71. package/upgrades/side-effects/console-decide-origin.md +24 -0
  72. package/upgrades/side-effects/machine-self-maintenance-watch-only.md +104 -0
@@ -992,6 +992,12 @@ button.run-mark:focus-visible { outline: 2px solid var(--accent); outline-offset
992
992
  /* A column flex box squeezes its children to fit; history items must keep their own height
993
993
  and let the box scroll (tool lines clip their overflow, so without this they shrink to 0). */
994
994
  .sess-history > * { flex-shrink: 0; }
995
+ /* Long tool lines never wrap, so their min-content width is the whole line: without these
996
+ the open session (and the page's grid column) grew to fit it, wider than a phone. */
997
+ .main, .sess-view, .sess-open, .sess-term-wrap, .sess-composer { min-width: 0; }
998
+ .sess-input { min-width: 0; width: 100%; }
999
+ /* History has no live stream to return to: never float "Back to live" over it. */
1000
+ .sess-history:not([hidden]) ~ .sess-resume { display: none; }
995
1001
  .sess-history-note { margin: 0; text-align: center; font-size: 13px; color: var(--text-muted); }
996
1002
  .sess-h { max-width: 92%; }
997
1003
  .sess-h-user { align-self: flex-end; background: var(--accent-wash); border: 1px solid var(--hairline); border-radius: var(--r-md); padding: var(--s-2) var(--s-3); }
@@ -133,3 +133,18 @@ export function usageOf(res, sessionNames = {}) {
133
133
  ].filter(Boolean),
134
134
  };
135
135
  }
136
+
137
+ /** One line for this machine's care status. Watch-only, so it never implies a restart will happen. */
138
+ export function machineCareLine(r) {
139
+ if (!r || !r.ok || !r.data) return null;
140
+ const d = r.data;
141
+ const uptime = typeof d.uptimeDays === 'number' ? `Up ${d.uptimeDays} days` : 'Uptime unread';
142
+ const held = (Array.isArray(d.safetyHolds) ? d.safetyHolds : []).filter((h) => h.active).map((h) => h.label);
143
+ const night = d.lastRehearsal;
144
+ const last = !night ? 'No practice run yet'
145
+ : night.outcome === 'would-restart' ? 'Last practice run: would have restarted'
146
+ : night.outcome === 'would-roll' ? 'Last practice run: would have waited a night'
147
+ : night.outcome === 'would-hold' ? 'Last practice run: would have been held'
148
+ : 'Last practice run: outcome unknown';
149
+ return [`Restart care is watching only, nothing restarts.`, uptime, last, held.length ? `Holding now: ${held.join(', ')}` : null].filter(Boolean).join(' · ');
150
+ }
@@ -2,7 +2,7 @@
2
2
  // Reads only; the one frequent write is Rename (bearer). Identity reviews stay in
3
3
  // the legacy tab until their PIN sheet is rebuilt (the plan's first cut).
4
4
 
5
- import { buildMachinesPage, ropesFor, healthOf, usageOf } from './machines-model.js';
5
+ import { buildMachinesPage, ropesFor, healthOf, usageOf, machineCareLine } from './machines-model.js';
6
6
  import { el, setKids, pageHead, sheet, closeSheet, story, note, cantTell } from './ui.js';
7
7
  import { legacyHref } from './nav-model.js';
8
8
 
@@ -11,7 +11,7 @@ const STATE_DOT = { ok: 'dot live', attn: 'dot attn', bad: 'dot bad', stale: 'do
11
11
  export async function renderMachines(main, ctx) {
12
12
  const { get } = ctx;
13
13
  if (!main.querySelector('.machine-cards')) setKids(main, el('section', { class: 'hero page-hero' }, el('div', { class: 'eyebrow', text: 'Capacity · Machines' }), el('h1', { class: 'page-title skeleton', text: 'Loading machines' })));
14
- const [pool, health, guards, sessions] = await Promise.all([get('/pool'), get('/health'), get('/guards'), get('/sessions?scope=pool', 8000)]);
14
+ const [pool, health, guards, sessions, care] = await Promise.all([get('/pool'), get('/health'), get('/guards'), get('/sessions?scope=pool', 8000), get('/machine-maintenance')]);
15
15
  const live = sessions.ok && Array.isArray(sessions.data && sessions.data.sessions) ? sessions.data.sessions.filter((s) => s.status === 'running' || s.status === 'starting') : [];
16
16
  const byMachine = {};
17
17
  const names = {};
@@ -38,6 +38,7 @@ export async function renderMachines(main, ctx) {
38
38
  setKids(main,
39
39
  pageHead({ eyebrow: 'Capacity · Machines', headline: page.headline, sub: page.sub, tone: page.tone, facts: page.facts }),
40
40
  !sessions.ok ? note(`Couldn't count sessions: ${sessions.reason}.`) : null,
41
+ machineCareLine(care) ? note(machineCareLine(care)) : null,
41
42
  cards,
42
43
  legacyLink(),
43
44
  );
@@ -143,7 +143,9 @@ function openPromise(r, { post, chatId, names, refresh }) {
143
143
  else if (fallback) fallback.querySelector('p').textContent = 'Copying is unavailable here. Select this question and paste it in the conversation:';
144
144
  } : undefined }));
145
145
  }
146
- const q = r.replica && r.origin ? `?origin=${encodeURIComponent(r.origin)}` : '';
146
+ // Always name the machine that holds it: the same promise id can exist on several
147
+ // machines (ids are per machine), and a bare id is refused as ambiguous.
148
+ const q = r.origin ? `?origin=${encodeURIComponent(r.origin)}` : '';
147
149
  const id = encodeURIComponent(c.id);
148
150
  const result = async (path, body) => {
149
151
  const x = await post(`/commitments/${id}/${path}${q}`, body);
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"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"}
@@ -22755,6 +22755,82 @@ export async function startServer(options) {
22755
22755
  console.log(pc.dim(` [work-admission] self-help notice failed: ${err instanceof Error ? err.message : String(err)}`));
22756
22756
  }
22757
22757
  }
22758
+ // ── Machine self-maintenance, watch-only (docs/specs/machine-self-maintenance.md) ──
22759
+ // Every dep below is a read: this build cannot restart a machine or stop work.
22760
+ // A throwaway agent never runs it, whatever the gate says.
22761
+ try {
22762
+ const mmEnabled = () => resolveDevAgentGate(liveConfig.get('machineMaintenance.enabled', undefined), config);
22763
+ const projectDir = path.dirname(config.stateDir);
22764
+ const { classifyLocation, readThrowawayRecord } = await import('../core/ThrowawayAgentGuard.js');
22765
+ const throwaway = classifyLocation({ projectDir, record: readThrowawayRecord(projectDir) }).throwaway;
22766
+ if (mmEnabled() && !throwaway) {
22767
+ const { DrainRehearsal, readHostCensus, setActiveDrainRehearsal } = await import('../monitoring/machineMaintenance/DrainRehearsal.js');
22768
+ const { HostMaintenanceStore } = await import('../monitoring/machineMaintenance/HostMaintenanceStore.js');
22769
+ const { normalizeSettings } = await import('../monitoring/machineMaintenance/planner.js');
22770
+ const { makeReadOnlyRunner, readMachineSignals } = await import('../monitoring/machineMaintenance/readings.js');
22771
+ const { activeAutonomousJobs } = await import('../core/AutonomousSessions.js');
22772
+ const { getHostTestRunnerSemaphore } = await import('../core/hostTestRunnerSemaphore.js');
22773
+ const { IDLE_PROMPT_PATTERNS } = await import('../core/SessionManager.js');
22774
+ const atBoundary = async (tmux) => {
22775
+ // Async, so a slow pane cannot hold the event loop. tmux returns the whole
22776
+ // pane plus history here, and only the bottom says what the session is doing.
22777
+ const output = await sessionManager.captureOutputAsync(tmux, 12);
22778
+ if (output === null)
22779
+ return null;
22780
+ const tail = output.trimEnd().split('\n').slice(-12).join('\n');
22781
+ // Claude Code shows its prompt box while working too, so the working marker decides first.
22782
+ if (/esc to interrupt/i.test(tail))
22783
+ return false;
22784
+ return IDLE_PROMPT_PATTERNS.some((p) => tail.includes(p));
22785
+ };
22786
+ const rehearsal = new DrainRehearsal({
22787
+ agentName: config.projectName,
22788
+ version: startupVersion,
22789
+ stateDir: config.stateDir,
22790
+ logPath: path.join(config.stateDir, '..', 'logs', 'machine-drain.jsonl'),
22791
+ store: new HostMaintenanceStore(),
22792
+ enabled: mmEnabled,
22793
+ settings: () => normalizeSettings(liveConfig.get('machineMaintenance', undefined)),
22794
+ readSignals: () => readMachineSignals(makeReadOnlyRunner(config.sessions.tmuxPath)),
22795
+ census: async ({ readBoundaries }) => {
22796
+ const limiter = getHostTestRunnerSemaphore().status();
22797
+ const snapshot = localVerifyService?.snapshot();
22798
+ const sessions = [];
22799
+ for (const s of sessionManager.getCachedRunningSessions().sessions) {
22800
+ sessions.push({
22801
+ name: s.name, tmuxSession: s.tmuxSession, topicId: s.telegramTopicId, jobSlug: s.jobSlug,
22802
+ slackRoutingKey: _slackAdapter?.getChannelForSession(s.tmuxSession) ?? undefined,
22803
+ atBoundary: readBoundaries ? await atBoundary(s.tmuxSession) : null,
22804
+ });
22805
+ }
22806
+ return {
22807
+ sessions,
22808
+ autonomousRuns: activeAutonomousJobs(config.stateDir).map((j) => ({ topic: j.topic ?? 'legacy' })),
22809
+ localVerifyRunning: snapshot?.inFlight ? [snapshot.inFlight] : [],
22810
+ localVerifyQueued: (snapshot?.queue ?? []).map((e) => ({ pr: e.pr, headSha: e.headSha })),
22811
+ testRuns: [
22812
+ ...limiter.liveHolders.map((h) => ({ pid: h.pid, acquiredAt: h.acquiredAt, lane: 'suite' })),
22813
+ ...limiter.targetedHolders.map((h) => ({ pid: h.pid, acquiredAt: h.acquiredAt, lane: 'targeted' })),
22814
+ ],
22815
+ scriptRuns: scheduler?.getActiveScriptRunIds() ?? [],
22816
+ };
22817
+ },
22818
+ resumeQueue: () => {
22819
+ const q = resumeQueue?.snapshot();
22820
+ return q ? { disabled: q.disabled, paused: q.paused, dryRun: q.dryRun, entries: q.entries.length } : null;
22821
+ },
22822
+ coResidentAgents: () => readHostCensus(path.join(os.homedir(), '.instar', 'registry.json'), Date.now()),
22823
+ holdsLease: () => (coordinator.enabled ? coordinator.holdsLease() : null),
22824
+ ownUser: os.userInfo().username,
22825
+ log: (line) => console.log(pc.yellow(` [machine-maintenance] ${line}`)),
22826
+ });
22827
+ setActiveDrainRehearsal(rehearsal);
22828
+ rehearsal.start();
22829
+ }
22830
+ }
22831
+ catch (err) {
22832
+ console.warn(` [machine-maintenance] not started: ${err instanceof Error ? err.message : err}`);
22833
+ }
22758
22834
  // ── Overload admission (trustworthy-machine-load Part C) ──
22759
22835
  // Each machine protects its own resources: closed to new AUTOMATIC work while
22760
22836
  // its own load verdict is saturated/impaired, one host-wide recovery slot for an