instar 1.3.1601 → 1.3.1602

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 (62) hide show
  1. package/dist/commands/init.d.ts +7 -0
  2. package/dist/commands/init.d.ts.map +1 -1
  3. package/dist/commands/init.js +8 -1
  4. package/dist/commands/init.js.map +1 -1
  5. package/dist/commands/server.d.ts.map +1 -1
  6. package/dist/commands/server.js +38 -0
  7. package/dist/commands/server.js.map +1 -1
  8. package/dist/core/BrowserCareProbes.d.ts +15 -0
  9. package/dist/core/BrowserCareProbes.d.ts.map +1 -0
  10. package/dist/core/BrowserCareProbes.js +78 -0
  11. package/dist/core/BrowserCareProbes.js.map +1 -0
  12. package/dist/core/MachineLockStateReader.d.ts +34 -0
  13. package/dist/core/MachineLockStateReader.d.ts.map +1 -0
  14. package/dist/core/MachineLockStateReader.js +114 -0
  15. package/dist/core/MachineLockStateReader.js.map +1 -0
  16. package/dist/core/PostUpdateMigrator.d.ts +6 -0
  17. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  18. package/dist/core/PostUpdateMigrator.js +25 -0
  19. package/dist/core/PostUpdateMigrator.js.map +1 -1
  20. package/dist/core/types.d.ts +10 -0
  21. package/dist/core/types.d.ts.map +1 -1
  22. package/dist/core/types.js.map +1 -1
  23. package/dist/data/standards-guard-index.json +1 -1
  24. package/dist/data/standards-guard-index.meta.json +2 -2
  25. package/dist/data/standards-registry.meta.json +1 -1
  26. package/dist/monitoring/machineMaintenance/BrowserCare.d.ts +166 -0
  27. package/dist/monitoring/machineMaintenance/BrowserCare.d.ts.map +1 -0
  28. package/dist/monitoring/machineMaintenance/BrowserCare.js +334 -0
  29. package/dist/monitoring/machineMaintenance/BrowserCare.js.map +1 -0
  30. package/dist/monitoring/machineMaintenance/lockState.d.ts +34 -0
  31. package/dist/monitoring/machineMaintenance/lockState.d.ts.map +1 -0
  32. package/dist/monitoring/machineMaintenance/lockState.js +53 -0
  33. package/dist/monitoring/machineMaintenance/lockState.js.map +1 -0
  34. package/dist/monitoring/machineMaintenance/readings.d.ts +4 -0
  35. package/dist/monitoring/machineMaintenance/readings.d.ts.map +1 -1
  36. package/dist/monitoring/machineMaintenance/readings.js +2 -1
  37. package/dist/monitoring/machineMaintenance/readings.js.map +1 -1
  38. package/dist/native/instar-desktop-host +0 -0
  39. package/dist/scaffold/templates.d.ts.map +1 -1
  40. package/dist/scaffold/templates.js +2 -1
  41. package/dist/scaffold/templates.js.map +1 -1
  42. package/dist/server/CapabilityIndex.js +2 -2
  43. package/dist/server/CapabilityIndex.js.map +1 -1
  44. package/dist/server/routes.d.ts.map +1 -1
  45. package/dist/server/routes.js +19 -1
  46. package/dist/server/routes.js.map +1 -1
  47. package/package.json +1 -1
  48. package/scripts/blocking-decision-surfaces-baseline.json +22 -2
  49. package/src/data/builtin-manifest.json +63 -63
  50. package/src/data/standards-guard-index.json +1 -1
  51. package/src/data/standards-guard-index.meta.json +2 -2
  52. package/src/data/standards-registry.meta.json +1 -1
  53. package/src/data/state-coherence-registry.json +37 -0
  54. package/src/scaffold/templates.ts +2 -1
  55. package/src/templates/scripts/browser/chrome-close.sh +97 -0
  56. package/src/templates/scripts/browser/chrome-js.sh +2 -0
  57. package/src/templates/scripts/browser/chrome-launch.sh +16 -3
  58. package/src/templates/scripts/browser/chrome-ledger.sh +49 -0
  59. package/src/templates/scripts/browser/chrome-renew.sh +38 -0
  60. package/src/templates/scripts/browser/chrome-unsaved.sh +83 -0
  61. package/upgrades/1.3.1602.md +24 -0
  62. package/upgrades/side-effects/machine-self-maintenance-browser-care-lock-reading.md +98 -0
@@ -2,7 +2,7 @@
2
2
  "schemaVersion": 1,
3
3
  "generatedFrom": "source-tree",
4
4
  "registrySha256": "db01d9f92c6aa26ca903702896b41be53722982ed07d27633237bb254c214290",
5
- "packageVersion": "1.3.1601",
5
+ "packageVersion": "1.3.1602",
6
6
  "guards": [
7
7
  {
8
8
  "ref": "docs/audits/phase-b/f10-triage.md",
@@ -1,5 +1,5 @@
1
1
  {
2
- "sha256": "4378fdb6ce78ccb6de9436ef9d3fc24352e055fe90667bb84243b19da8432d0c",
2
+ "sha256": "c80fc45becd1fa7131aadde7c0e03b87c2a37f73896352375c2db356e4956b3f",
3
3
  "registrySha256": "db01d9f92c6aa26ca903702896b41be53722982ed07d27633237bb254c214290",
4
- "packageVersion": "1.3.1601"
4
+ "packageVersion": "1.3.1602"
5
5
  }
@@ -2,5 +2,5 @@
2
2
  "sha256": "db01d9f92c6aa26ca903702896b41be53722982ed07d27633237bb254c214290",
3
3
  "articleCount": 93,
4
4
  "generatedFrom": "docs/STANDARDS-REGISTRY.md",
5
- "packageVersion": "1.3.1601"
5
+ "packageVersion": "1.3.1602"
6
6
  }
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Browser and window care, watch-only (docs/specs/machine-self-maintenance.md, Part B).
3
+ *
4
+ * The ledger of the normal-Chrome browsers this agent opened, and a 15-minute sweep
5
+ * that decides, by the spec's rules, which of them it WOULD close. This build closes
6
+ * nothing: it has no way to signal a process, and
7
+ * `tests/unit/machine-maintenance-watch-only.test.ts` holds that. Every verdict is
8
+ * written to `logs/browser-care.jsonl` so seven days of would-close rows can show the
9
+ * rule never picks a browser that is still in use before any later build may act.
10
+ *
11
+ * Who may be closed: only a Chrome main process whose `--user-data-dir` is inside this
12
+ * agent's own `.instar/state/playwright-profiles/`. The operator's own Chrome has no
13
+ * such flag and can never match. An owned process with no ledger entry is adopted.
14
+ *
15
+ * A close needs one of: a completion signal (`completedAt`), an expired declared
16
+ * lifetime (`ttlDeclared`), an adopted instance's expired lease, or a confirmed absent
17
+ * owner (idle past `idleMinutes` and the owning tmux session gone on a fresh read).
18
+ * Then it must pass the keep checks: no operator input in the last 5 minutes, no open
19
+ * sign-in repair, no download growing, and every tab read as holding no unsaved input.
20
+ * Any unreadable answer keeps the instance and says so.
21
+ */
22
+ export declare const SWEEP_INTERVAL_MS: number;
23
+ export declare const OPERATOR_ACTIVE_MS: number;
24
+ export declare const DOWNLOAD_FRESH_MS: number;
25
+ /** At most this many instances get the per-tab check in one pass. */
26
+ export declare const MAX_CHECKS_PER_PASS = 5;
27
+ export interface BrowserCareSettings {
28
+ enabled: boolean;
29
+ /** Always true in this build: there is no close path. Reported so a reader sees it. */
30
+ dryRun: boolean;
31
+ maxPerAgent: number;
32
+ maxPerHost: number;
33
+ idleMinutes: number;
34
+ ttlMinutes: number;
35
+ /** Profile ids (folder names under playwright-profiles) the sweep never picks. */
36
+ keepProfiles: string[];
37
+ }
38
+ export declare const DEFAULT_BROWSER_CARE: BrowserCareSettings;
39
+ export declare function normalizeBrowserCare(raw: unknown): BrowserCareSettings;
40
+ /** One file per instance, written by `chrome-launch.sh` and kept current by the other helpers. */
41
+ export interface BrowserInstanceEntry {
42
+ userDataDir: string;
43
+ pid: number | null;
44
+ processStartTime: string | null;
45
+ agent: string | null;
46
+ sessionName: string | null;
47
+ topicId: string | null;
48
+ purpose: string | null;
49
+ openedAt: string;
50
+ lastUsedAt: string;
51
+ ttlMinutes: number;
52
+ ttlDeclared: boolean;
53
+ leaseUntil: string;
54
+ completedAt: string | null;
55
+ }
56
+ /** A Chrome browser main process: no `--type=`, with a `--user-data-dir=`. */
57
+ export interface ChromeProcess {
58
+ pid: number;
59
+ startTime: string;
60
+ userDataDir: string;
61
+ }
62
+ /** The file name the helper scripts use too: the first 16 hex of SHA-256 of the directory. */
63
+ export declare function ledgerFileName(userDataDir: string): string;
64
+ /**
65
+ * Parses `ps -axo pid=,lstart=,args=`. `lstart` is five fields ("Mon Nov 2 10:00:00 2026").
66
+ * Only the real Chrome app's main process counts; helpers carry `--type=`, and an automation-driven
67
+ * browser (Playwright, Chrome for Testing) is never counted.
68
+ */
69
+ export declare function parseChromeProcesses(psOutput: string): ChromeProcess[];
70
+ export type BrowserCloseGround = 'completed' | 'declared-lifetime-expired' | 'adopted-lease-expired' | 'owner-absent';
71
+ export type BrowserKeepReason = 'allowlisted' | 'in-use' | 'lease-expired-owner-alive' | 'owner-unreadable' | 'declared-lifetime-running' | 'operator-active' | 'operator-unreadable' | 'sign-in-repair-open' | 'sign-in-repair-unreadable' | 'download-active' | 'download-unreadable' | 'unsaved-input' | 'unreadable-tabs' | 'check-budget';
72
+ export interface BrowserVerdict {
73
+ verdict: 'would-close' | 'keep';
74
+ ground: BrowserCloseGround | null;
75
+ reason: BrowserKeepReason | null;
76
+ }
77
+ /** Step one: does any close ground apply? Owner reads are fresh from the caller. */
78
+ export declare function closeGround(entry: BrowserInstanceEntry, nowMs: number, idleMinutes: number, ownerAlive: boolean | null): BrowserVerdict;
79
+ export type TabCheck = 'no' | 'yes' | 'unreadable';
80
+ export interface BrowserCareDeps {
81
+ agentName: string;
82
+ /** The agent home; profiles live under `<home>/.instar/state/playwright-profiles/`. */
83
+ agentHome: string;
84
+ operatorChromeDir: string;
85
+ ledgerDir: string;
86
+ logPath: string;
87
+ settings: () => BrowserCareSettings;
88
+ /** Chrome main processes on this host, or null when the process table is unreadable. */
89
+ listChrome: () => Promise<ChromeProcess[] | null>;
90
+ /** Names of live tmux sessions, or null when unreadable. */
91
+ tmuxSessions: () => Promise<string[] | null>;
92
+ /** Milliseconds since the last console input, or null. */
93
+ inputIdleMs: () => Promise<number | null>;
94
+ /** True when a sign-in repair is open on this machine; null when unreadable. */
95
+ signInRepairOpen: () => boolean | null;
96
+ /** True when a download in this profile grew recently; null when unreadable. */
97
+ downloadActive: (userDataDir: string) => Promise<boolean | null>;
98
+ /** Read-only per-tab unsaved-input check for one instance. Every tab, or `unreadable`. */
99
+ checkTabs: (userDataDir: string) => Promise<TabCheck[] | 'unreadable'>;
100
+ now?: () => number;
101
+ log?: (line: string) => void;
102
+ }
103
+ export interface InstanceReport {
104
+ profile: string;
105
+ pid: number | null;
106
+ purpose: string | null;
107
+ sessionName: string | null;
108
+ openedAt: string;
109
+ lastUsedAt: string;
110
+ leaseUntil: string;
111
+ ttlDeclared: boolean;
112
+ verdict: BrowserVerdict['verdict'];
113
+ ground: BrowserCloseGround | null;
114
+ reason: BrowserKeepReason | null;
115
+ }
116
+ export interface BrowserCareStatus {
117
+ enabled: boolean;
118
+ dryRun: true;
119
+ canClose: false;
120
+ lastSweepAt: string | null;
121
+ lastError: string | null;
122
+ breakerUntil: string | null;
123
+ owned: number;
124
+ adopted: number;
125
+ hostTotal: number | null;
126
+ maxPerAgent: number;
127
+ maxPerHost: number;
128
+ overAgentCap: boolean;
129
+ overHostCap: boolean;
130
+ wouldClose: number;
131
+ keptUnsaved: number;
132
+ keptUnreadable: number;
133
+ instances: InstanceReport[];
134
+ }
135
+ export declare class BrowserCareSweep {
136
+ private readonly deps;
137
+ private readonly now;
138
+ private readonly profilesRoot;
139
+ private timer;
140
+ private running;
141
+ private failures;
142
+ private breakerUntil;
143
+ private lastSweepAt;
144
+ private lastError;
145
+ private hostTotal;
146
+ private reports;
147
+ /** Last verdict per instance, so the audit records changes, not every pass. */
148
+ private readonly lastKey;
149
+ constructor(deps: BrowserCareDeps);
150
+ start(): void;
151
+ stop(): void;
152
+ /** Owned: inside this agent's profiles folder and never the operator's own Chrome. */
153
+ isOwned(dir: string): boolean;
154
+ readLedger(): BrowserInstanceEntry[];
155
+ private write;
156
+ private remove;
157
+ private audit;
158
+ private profile;
159
+ sweep(): Promise<void>;
160
+ private pass;
161
+ private keepChecks;
162
+ status(): BrowserCareStatus;
163
+ }
164
+ export declare function setActiveBrowserCare(sweep: BrowserCareSweep | null): void;
165
+ export declare function getActiveBrowserCare(): BrowserCareSweep | null;
166
+ //# sourceMappingURL=BrowserCare.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BrowserCare.d.ts","sourceRoot":"","sources":["../../../src/monitoring/machineMaintenance/BrowserCare.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,334 @@
1
+ /**
2
+ * Browser and window care, watch-only (docs/specs/machine-self-maintenance.md, Part B).
3
+ *
4
+ * The ledger of the normal-Chrome browsers this agent opened, and a 15-minute sweep
5
+ * that decides, by the spec's rules, which of them it WOULD close. This build closes
6
+ * nothing: it has no way to signal a process, and
7
+ * `tests/unit/machine-maintenance-watch-only.test.ts` holds that. Every verdict is
8
+ * written to `logs/browser-care.jsonl` so seven days of would-close rows can show the
9
+ * rule never picks a browser that is still in use before any later build may act.
10
+ *
11
+ * Who may be closed: only a Chrome main process whose `--user-data-dir` is inside this
12
+ * agent's own `.instar/state/playwright-profiles/`. The operator's own Chrome has no
13
+ * such flag and can never match. An owned process with no ledger entry is adopted.
14
+ *
15
+ * A close needs one of: a completion signal (`completedAt`), an expired declared
16
+ * lifetime (`ttlDeclared`), an adopted instance's expired lease, or a confirmed absent
17
+ * owner (idle past `idleMinutes` and the owning tmux session gone on a fresh read).
18
+ * Then it must pass the keep checks: no operator input in the last 5 minutes, no open
19
+ * sign-in repair, no download growing, and every tab read as holding no unsaved input.
20
+ * Any unreadable answer keeps the instance and says so.
21
+ */
22
+ import crypto from 'node:crypto';
23
+ import fs from 'node:fs';
24
+ import path from 'node:path';
25
+ import { atomicWriteFileSync } from '../../core/hostSemaphoreCore.js';
26
+ import { SafeFsExecutor } from '../../core/SafeFsExecutor.js';
27
+ const MIN = 60_000;
28
+ export const SWEEP_INTERVAL_MS = 15 * MIN;
29
+ export const OPERATOR_ACTIVE_MS = 5 * MIN;
30
+ export const DOWNLOAD_FRESH_MS = 5 * MIN;
31
+ /** At most this many instances get the per-tab check in one pass. */
32
+ export const MAX_CHECKS_PER_PASS = 5;
33
+ const BREAKER_FAILURES = 3;
34
+ const BREAKER_PAUSE_MS = 24 * 60 * MIN;
35
+ const MAX_LOG_BYTES = 2 * 1024 * 1024;
36
+ export const DEFAULT_BROWSER_CARE = {
37
+ enabled: true, dryRun: true, maxPerAgent: 4, maxPerHost: 8, idleMinutes: 30, ttlMinutes: 120, keepProfiles: [],
38
+ };
39
+ const posInt = (v, d, min = 1, max = 10_000) => typeof v === 'number' && Number.isFinite(v) && v >= min && v <= max ? Math.floor(v) : d;
40
+ export function normalizeBrowserCare(raw) {
41
+ const r = raw && typeof raw === 'object' ? raw : {};
42
+ return {
43
+ enabled: r.enabled !== false,
44
+ dryRun: true,
45
+ maxPerAgent: posInt(r.maxPerAgent, DEFAULT_BROWSER_CARE.maxPerAgent, 1, 100),
46
+ maxPerHost: posInt(r.maxPerHost, DEFAULT_BROWSER_CARE.maxPerHost, 1, 200),
47
+ idleMinutes: posInt(r.idleMinutes, DEFAULT_BROWSER_CARE.idleMinutes, 5, 7 * 24 * 60),
48
+ ttlMinutes: posInt(r.ttlMinutes, DEFAULT_BROWSER_CARE.ttlMinutes, 5, 30 * 24 * 60),
49
+ keepProfiles: Array.isArray(r.keepProfiles) ? r.keepProfiles.filter((p) => typeof p === 'string' && p.length > 0).slice(0, 100) : [],
50
+ };
51
+ }
52
+ /** The file name the helper scripts use too: the first 16 hex of SHA-256 of the directory. */
53
+ export function ledgerFileName(userDataDir) {
54
+ return `${crypto.createHash('sha256').update(userDataDir).digest('hex').slice(0, 16)}.json`;
55
+ }
56
+ /** The macOS Chrome app binary, exactly. `Google Chrome for Testing.app` does not match. */
57
+ const NORMAL_CHROME_MAIN = /\/Google Chrome\.app\/Contents\/MacOS\/Google Chrome( |$)/;
58
+ /** Flags an automation-driven browser carries; chrome-launch.sh adds no flags at all. */
59
+ const AUTOMATION_FLAGS = /--remote-debugging-(port|pipe)|--enable-automation|--test-type/;
60
+ /**
61
+ * Parses `ps -axo pid=,lstart=,args=`. `lstart` is five fields ("Mon Nov 2 10:00:00 2026").
62
+ * Only the real Chrome app's main process counts; helpers carry `--type=`, and an automation-driven
63
+ * browser (Playwright, Chrome for Testing) is never counted.
64
+ */
65
+ export function parseChromeProcesses(psOutput) {
66
+ const out = [];
67
+ for (const line of psOutput.split('\n')) {
68
+ const m = /^\s*(\d+)\s+(\w{3}\s+\w{3}\s+\d{1,2}\s+\d{1,2}:\d{2}:\d{2}\s+\d{4})\s+(.*)$/.exec(line);
69
+ if (!m)
70
+ continue;
71
+ const args = m[3];
72
+ // The real Chrome app only: not "Google Chrome for Testing" or a Chromium, and not a browser
73
+ // started for automation (the Playwright MCP's), which the normal-Chrome launcher never is.
74
+ if (!NORMAL_CHROME_MAIN.test(args) || /--type=/.test(args) || AUTOMATION_FLAGS.test(args))
75
+ continue;
76
+ const dir = /--user-data-dir=(\S+)/.exec(args);
77
+ if (!dir)
78
+ continue;
79
+ out.push({ pid: Number(m[1]), startTime: m[2].replace(/\s+/g, ' '), userDataDir: dir[1] });
80
+ }
81
+ return out;
82
+ }
83
+ function isInside(dir, root) {
84
+ const rel = path.relative(root, dir);
85
+ return rel !== '' && !rel.startsWith('..') && !path.isAbsolute(rel);
86
+ }
87
+ /** Step one: does any close ground apply? Owner reads are fresh from the caller. */
88
+ export function closeGround(entry, nowMs, idleMinutes, ownerAlive) {
89
+ const keep = (reason) => ({ verdict: 'keep', ground: null, reason });
90
+ const ground = (g) => ({ verdict: 'would-close', ground: g, reason: null });
91
+ if (entry.completedAt)
92
+ return ground('completed');
93
+ const leaseOver = Date.parse(entry.leaseUntil) < nowMs;
94
+ const idle = nowMs - Date.parse(entry.lastUsedAt) > idleMinutes * MIN;
95
+ if (entry.ttlDeclared)
96
+ return leaseOver ? ground('declared-lifetime-expired') : keep('declared-lifetime-running');
97
+ if (entry.purpose === 'adopted')
98
+ return leaseOver ? ground('adopted-lease-expired') : keep('in-use');
99
+ if (!idle && !leaseOver)
100
+ return keep('in-use');
101
+ if (!idle)
102
+ return keep('lease-expired-owner-alive');
103
+ if (!entry.sessionName || ownerAlive === null)
104
+ return keep('owner-unreadable');
105
+ if (ownerAlive)
106
+ return keep(leaseOver ? 'lease-expired-owner-alive' : 'in-use');
107
+ return ground('owner-absent');
108
+ }
109
+ export class BrowserCareSweep {
110
+ deps;
111
+ now;
112
+ profilesRoot;
113
+ timer = null;
114
+ running = false;
115
+ failures = 0;
116
+ breakerUntil = 0;
117
+ lastSweepAt = null;
118
+ lastError = null;
119
+ hostTotal = null;
120
+ reports = [];
121
+ /** Last verdict per instance, so the audit records changes, not every pass. */
122
+ lastKey = new Map();
123
+ constructor(deps) {
124
+ this.deps = deps;
125
+ this.now = deps.now ?? Date.now;
126
+ this.profilesRoot = path.join(deps.agentHome, '.instar', 'state', 'playwright-profiles');
127
+ }
128
+ start() {
129
+ if (this.timer)
130
+ return;
131
+ this.timer = setInterval(() => { void this.sweep(); }, SWEEP_INTERVAL_MS);
132
+ this.timer.unref?.();
133
+ setTimeout(() => { void this.sweep(); }, 60_000).unref?.();
134
+ }
135
+ stop() {
136
+ if (this.timer)
137
+ clearInterval(this.timer);
138
+ this.timer = null;
139
+ }
140
+ /** Owned: inside this agent's profiles folder and never the operator's own Chrome. */
141
+ isOwned(dir) {
142
+ return isInside(dir, this.profilesRoot) && !isInside(dir, this.deps.operatorChromeDir) && dir !== this.deps.operatorChromeDir;
143
+ }
144
+ readLedger() {
145
+ let names;
146
+ try {
147
+ names = fs.readdirSync(this.deps.ledgerDir).filter((n) => n.endsWith('.json'));
148
+ }
149
+ catch {
150
+ return [];
151
+ } // @silent-fallback-ok — no ledger folder is an empty ledger; adoption fills it.
152
+ const out = [];
153
+ for (const name of names) {
154
+ try {
155
+ const e = JSON.parse(fs.readFileSync(path.join(this.deps.ledgerDir, name), 'utf-8'));
156
+ if (typeof e.userDataDir === 'string' && typeof e.openedAt === 'string' && typeof e.lastUsedAt === 'string' && typeof e.leaseUntil === 'string')
157
+ out.push(e);
158
+ }
159
+ catch { /* @silent-fallback-ok — a half-written or foreign file is skipped; adoption rewrites it. */ }
160
+ }
161
+ return out;
162
+ }
163
+ write(entry) {
164
+ fs.mkdirSync(this.deps.ledgerDir, { recursive: true });
165
+ atomicWriteFileSync(path.join(this.deps.ledgerDir, ledgerFileName(entry.userDataDir)), JSON.stringify(entry, null, 2), { mode: 0o600, operation: 'BrowserCareSweep.writeLedger' });
166
+ }
167
+ remove(entry) {
168
+ try {
169
+ SafeFsExecutor.safeUnlinkSync(path.join(this.deps.ledgerDir, ledgerFileName(entry.userDataDir)), { operation: 'browser-care: ledger entry for an instance that has exited' });
170
+ }
171
+ catch { /* @silent-fallback-ok — a stale entry is removed on the next pass. */ }
172
+ }
173
+ audit(row) {
174
+ try {
175
+ fs.mkdirSync(path.dirname(this.deps.logPath), { recursive: true });
176
+ try {
177
+ if (fs.statSync(this.deps.logPath).size > MAX_LOG_BYTES)
178
+ fs.renameSync(this.deps.logPath, `${this.deps.logPath}.1`);
179
+ }
180
+ catch { /* @silent-fallback-ok — no log yet. */ }
181
+ fs.appendFileSync(this.deps.logPath, `${JSON.stringify({ ts: new Date(this.now()).toISOString(), agent: this.deps.agentName, dryRun: true, ...row })}\n`);
182
+ }
183
+ catch (err) {
184
+ this.deps.log?.(`browser-care audit write failed: ${err instanceof Error ? err.message : String(err)}`);
185
+ }
186
+ }
187
+ profile(dir) {
188
+ return path.relative(this.deps.agentHome, dir);
189
+ }
190
+ async sweep() {
191
+ const settings = this.deps.settings();
192
+ if (!settings.enabled || this.running || this.now() < this.breakerUntil)
193
+ return;
194
+ this.running = true;
195
+ try {
196
+ await this.pass(settings);
197
+ this.failures = 0;
198
+ this.lastError = null;
199
+ }
200
+ catch (err) {
201
+ this.failures++;
202
+ this.lastError = err instanceof Error ? err.message : String(err);
203
+ if (this.failures >= BREAKER_FAILURES) {
204
+ this.breakerUntil = this.now() + BREAKER_PAUSE_MS;
205
+ this.audit({ event: 'breaker-open', failures: this.failures, error: this.lastError });
206
+ this.failures = 0;
207
+ }
208
+ }
209
+ finally {
210
+ this.running = false;
211
+ }
212
+ }
213
+ async pass(settings) {
214
+ const now = this.now();
215
+ const procs = await this.deps.listChrome();
216
+ if (procs === null)
217
+ throw new Error('process table unreadable');
218
+ // Every agent's normal-Chrome profiles on this host, read from the process table.
219
+ this.hostTotal = procs.filter((p) => /\/\.instar\/state\/playwright-profiles\//.test(p.userDataDir)).length;
220
+ const owned = new Map(procs.filter((p) => this.isOwned(p.userDataDir)).map((p) => [p.userDataDir, p]));
221
+ // Reconcile the ledger with what is running. An entry whose process is gone is removed;
222
+ // a process with no entry, or a different (pid, start time), is adopted afresh.
223
+ const entries = new Map();
224
+ for (const e of this.readLedger()) {
225
+ if (!this.isOwned(e.userDataDir))
226
+ continue;
227
+ const p = owned.get(e.userDataDir);
228
+ if (!p) {
229
+ this.remove(e);
230
+ this.lastKey.delete(e.userDataDir);
231
+ continue;
232
+ }
233
+ if (e.pid === null) {
234
+ const bound = { ...e, pid: p.pid, processStartTime: p.startTime };
235
+ this.write(bound);
236
+ entries.set(e.userDataDir, bound);
237
+ }
238
+ else if (e.pid === p.pid && e.processStartTime === p.startTime) {
239
+ entries.set(e.userDataDir, e);
240
+ }
241
+ }
242
+ for (const [dir, p] of owned) {
243
+ if (entries.has(dir))
244
+ continue;
245
+ const at = new Date(now).toISOString();
246
+ const adopted = {
247
+ userDataDir: dir, pid: p.pid, processStartTime: p.startTime, agent: this.deps.agentName,
248
+ sessionName: null, topicId: null, purpose: 'adopted', openedAt: at, lastUsedAt: at,
249
+ ttlMinutes: settings.ttlMinutes, ttlDeclared: false,
250
+ leaseUntil: new Date(now + settings.ttlMinutes * MIN).toISOString(), completedAt: null,
251
+ };
252
+ this.write(adopted);
253
+ entries.set(dir, adopted);
254
+ this.audit({ event: 'adopted', profile: this.profile(dir) });
255
+ }
256
+ const tmux = await this.deps.tmuxSessions();
257
+ const idleMs = await this.deps.inputIdleMs();
258
+ const repair = this.deps.signInRepairOpen();
259
+ let checks = 0;
260
+ const reports = [];
261
+ for (const e of [...entries.values()].sort((a, b) => a.openedAt.localeCompare(b.openedAt))) {
262
+ const ownerAlive = e.sessionName ? (tmux === null ? null : tmux.includes(e.sessionName)) : null;
263
+ let v = settings.keepProfiles.includes(path.basename(e.userDataDir))
264
+ ? { verdict: 'keep', ground: null, reason: 'allowlisted' }
265
+ : closeGround(e, now, settings.idleMinutes, ownerAlive);
266
+ if (v.verdict === 'would-close')
267
+ v = await this.keepChecks(e, v, idleMs, repair, checks++ < MAX_CHECKS_PER_PASS);
268
+ reports.push({
269
+ profile: this.profile(e.userDataDir), pid: e.pid, purpose: e.purpose, sessionName: e.sessionName,
270
+ openedAt: e.openedAt, lastUsedAt: e.lastUsedAt, leaseUntil: e.leaseUntil, ttlDeclared: e.ttlDeclared,
271
+ verdict: v.verdict, ground: v.ground, reason: v.reason,
272
+ });
273
+ const key = `${v.verdict}:${v.ground}:${v.reason}`;
274
+ if (this.lastKey.get(e.userDataDir) !== key) {
275
+ this.lastKey.set(e.userDataDir, key);
276
+ this.audit({ event: v.verdict === 'would-close' ? 'would-close' : 'keep', profile: this.profile(e.userDataDir), purpose: e.purpose, ground: v.ground, reason: v.reason });
277
+ }
278
+ }
279
+ this.reports = reports;
280
+ this.lastSweepAt = now;
281
+ if (reports.length > settings.maxPerAgent)
282
+ this.audit({ event: 'over-agent-cap', owned: reports.length, cap: settings.maxPerAgent });
283
+ }
284
+ async keepChecks(e, v, idleMs, repair, budget) {
285
+ const keep = (reason) => ({ verdict: 'keep', ground: v.ground, reason });
286
+ if (idleMs === null)
287
+ return keep('operator-unreadable');
288
+ if (idleMs < OPERATOR_ACTIVE_MS)
289
+ return keep('operator-active');
290
+ if (repair === null)
291
+ return keep('sign-in-repair-unreadable');
292
+ if (repair)
293
+ return keep('sign-in-repair-open');
294
+ if (!budget)
295
+ return keep('check-budget');
296
+ const download = await this.deps.downloadActive(e.userDataDir).catch(() => null); // @silent-fallback-ok — unknown download state keeps the browser
297
+ if (download === null)
298
+ return keep('download-unreadable');
299
+ if (download)
300
+ return keep('download-active');
301
+ const tabs = await this.deps.checkTabs(e.userDataDir).catch(() => 'unreadable'); // @silent-fallback-ok — unreadable tabs keep the browser
302
+ if (tabs === 'unreadable' || tabs.includes('unreadable'))
303
+ return keep('unreadable-tabs');
304
+ if (tabs.includes('yes'))
305
+ return keep('unsaved-input');
306
+ return v;
307
+ }
308
+ status() {
309
+ const s = this.deps.settings();
310
+ return {
311
+ enabled: s.enabled,
312
+ dryRun: true,
313
+ canClose: false,
314
+ lastSweepAt: this.lastSweepAt === null ? null : new Date(this.lastSweepAt).toISOString(),
315
+ lastError: this.lastError,
316
+ breakerUntil: this.breakerUntil > this.now() ? new Date(this.breakerUntil).toISOString() : null,
317
+ owned: this.reports.length,
318
+ adopted: this.reports.filter((r) => r.purpose === 'adopted').length,
319
+ hostTotal: this.hostTotal,
320
+ maxPerAgent: s.maxPerAgent,
321
+ maxPerHost: s.maxPerHost,
322
+ overAgentCap: this.reports.length > s.maxPerAgent,
323
+ overHostCap: this.hostTotal !== null && this.hostTotal > s.maxPerHost,
324
+ wouldClose: this.reports.filter((r) => r.verdict === 'would-close').length,
325
+ keptUnsaved: this.reports.filter((r) => r.reason === 'unsaved-input').length,
326
+ keptUnreadable: this.reports.filter((r) => r.reason === 'unreadable-tabs').length,
327
+ instances: this.reports,
328
+ };
329
+ }
330
+ }
331
+ let active = null;
332
+ export function setActiveBrowserCare(sweep) { active = sweep; }
333
+ export function getActiveBrowserCare() { return active; }
334
+ //# sourceMappingURL=BrowserCare.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BrowserCare.js","sourceRoot":"","sources":["../../../src/monitoring/machineMaintenance/BrowserCare.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Honest lock reading (docs/specs/machine-self-maintenance.md, Part A).
3
+ *
4
+ * The session flag `CGSSessionScreenIsLocked` is one input and never the answer:
5
+ * on 2026-11-01 it read true on a Mac whose screensaver a keypress dismissed with
6
+ * no password. This is the spec's decision table, first matching row wins, with
7
+ * every input reported beside the verdict. Conflicting or unreadable evidence is
8
+ * `unknown`, never `locked`. Pure: the readings come from the caller.
9
+ */
10
+ export type MachineLockState = 'unlocked' | 'locked' | 'screensaver-or-display-sleep' | 'unknown' | 'not-applicable';
11
+ /** `sysadminctl -screenLock status`: `immediate`, `off`, a delay, or unreadable. */
12
+ export type PasswordRequired = 'immediate' | 'off' | 'delayed' | null;
13
+ export interface LockReadingInputs {
14
+ /** The session flag. Null when the helper gave no reading. */
15
+ flagLocked: boolean | null;
16
+ passwordRequired: PasswordRequired;
17
+ screensaverRunning: boolean | null;
18
+ displayAsleep: boolean | null;
19
+ lockShieldSeen: boolean | null;
20
+ consoleSession: boolean | null;
21
+ loginDone: boolean | null;
22
+ }
23
+ export interface LockVerdict {
24
+ lockState: MachineLockState;
25
+ /** The table row that decided, 1 to 5; 0 when the platform has no such reading. */
26
+ row: number;
27
+ reason: string;
28
+ inputs: LockReadingInputs;
29
+ }
30
+ export declare const EMPTY_LOCK_INPUTS: LockReadingInputs;
31
+ export declare function decideLockState(inputs: LockReadingInputs): LockVerdict;
32
+ /** Parses `sysadminctl -screenLock status`, which prints on stderr. */
33
+ export declare function parsePasswordRequired(output: string): PasswordRequired;
34
+ //# sourceMappingURL=lockState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lockState.d.ts","sourceRoot":"","sources":["../../../src/monitoring/machineMaintenance/lockState.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,QAAQ,GAAG,8BAA8B,GAAG,SAAS,GAAG,gBAAgB,CAAC;AAErH,oFAAoF;AACpF,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG,KAAK,GAAG,SAAS,GAAG,IAAI,CAAC;AAEtE,MAAM,WAAW,iBAAiB;IAChC,8DAA8D;IAC9D,UAAU,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3B,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,kBAAkB,EAAE,OAAO,GAAG,IAAI,CAAC;IACnC,aAAa,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9B,cAAc,EAAE,OAAO,GAAG,IAAI,CAAC;IAC/B,cAAc,EAAE,OAAO,GAAG,IAAI,CAAC;IAC/B,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,gBAAgB,CAAC;IAC5B,mFAAmF;IACnF,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,iBAAiB,CAAC;CAC3B;AAED,eAAO,MAAM,iBAAiB,EAAE,iBAG/B,CAAC;AAEF,wBAAgB,eAAe,CAAC,MAAM,EAAE,iBAAiB,GAAG,WAAW,CAoBtE;AAED,uEAAuE;AACvE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,CAKtE"}