@oratis/lisa 0.5.0 → 0.8.0

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 (133) hide show
  1. package/README.md +5 -0
  2. package/dist/autostart/install.d.ts +28 -0
  3. package/dist/autostart/install.d.ts.map +1 -0
  4. package/dist/autostart/install.js +180 -0
  5. package/dist/autostart/install.js.map +1 -0
  6. package/dist/cli.js +49 -1
  7. package/dist/cli.js.map +1 -1
  8. package/dist/heartbeat/install.d.ts.map +1 -1
  9. package/dist/heartbeat/install.js +1 -43
  10. package/dist/heartbeat/install.js.map +1 -1
  11. package/dist/heartbeat/runner.d.ts.map +1 -1
  12. package/dist/heartbeat/runner.js +11 -0
  13. package/dist/heartbeat/runner.js.map +1 -1
  14. package/dist/idle/runner.d.ts +12 -0
  15. package/dist/idle/runner.d.ts.map +1 -1
  16. package/dist/idle/runner.js +33 -2
  17. package/dist/idle/runner.js.map +1 -1
  18. package/dist/integrations/aider/observer.d.ts +48 -0
  19. package/dist/integrations/aider/observer.d.ts.map +1 -0
  20. package/dist/integrations/aider/observer.js +196 -0
  21. package/dist/integrations/aider/observer.js.map +1 -0
  22. package/dist/integrations/comparisons.d.ts +23 -0
  23. package/dist/integrations/comparisons.d.ts.map +1 -0
  24. package/dist/integrations/comparisons.js +47 -0
  25. package/dist/integrations/comparisons.js.map +1 -0
  26. package/dist/integrations/dispatch-ledger.d.ts +51 -0
  27. package/dist/integrations/dispatch-ledger.d.ts.map +1 -0
  28. package/dist/integrations/dispatch-ledger.js +106 -0
  29. package/dist/integrations/dispatch-ledger.js.map +1 -0
  30. package/dist/integrations/github-pr/observer.d.ts +85 -0
  31. package/dist/integrations/github-pr/observer.d.ts.map +1 -0
  32. package/dist/integrations/github-pr/observer.js +261 -0
  33. package/dist/integrations/github-pr/observer.js.map +1 -0
  34. package/dist/integrations/hub.d.ts.map +1 -1
  35. package/dist/integrations/hub.js +10 -0
  36. package/dist/integrations/hub.js.map +1 -1
  37. package/dist/integrations/opencode/observer.d.ts +74 -0
  38. package/dist/integrations/opencode/observer.d.ts.map +1 -0
  39. package/dist/integrations/opencode/observer.js +207 -0
  40. package/dist/integrations/opencode/observer.js.map +1 -0
  41. package/dist/integrations/registry.d.ts.map +1 -1
  42. package/dist/integrations/registry.js +3 -1
  43. package/dist/integrations/registry.js.map +1 -1
  44. package/dist/integrations/scheduled-dispatch.d.ts +42 -0
  45. package/dist/integrations/scheduled-dispatch.d.ts.map +1 -0
  46. package/dist/integrations/scheduled-dispatch.js +140 -0
  47. package/dist/integrations/scheduled-dispatch.js.map +1 -0
  48. package/dist/launchd.d.ts +18 -0
  49. package/dist/launchd.d.ts.map +1 -0
  50. package/dist/launchd.js +60 -0
  51. package/dist/launchd.js.map +1 -0
  52. package/dist/orchestrator/journal.d.ts +46 -0
  53. package/dist/orchestrator/journal.d.ts.map +1 -0
  54. package/dist/orchestrator/journal.js +82 -0
  55. package/dist/orchestrator/journal.js.map +1 -0
  56. package/dist/orchestrator/recap.d.ts +38 -0
  57. package/dist/orchestrator/recap.d.ts.map +1 -0
  58. package/dist/orchestrator/recap.js +134 -0
  59. package/dist/orchestrator/recap.js.map +1 -0
  60. package/dist/screen_advisor/engine.d.ts +79 -0
  61. package/dist/screen_advisor/engine.d.ts.map +1 -0
  62. package/dist/screen_advisor/engine.js +128 -0
  63. package/dist/screen_advisor/engine.js.map +1 -0
  64. package/dist/soul/birth.d.ts.map +1 -1
  65. package/dist/soul/birth.js +8 -0
  66. package/dist/soul/birth.js.map +1 -1
  67. package/dist/soul/lock.d.ts +7 -4
  68. package/dist/soul/lock.d.ts.map +1 -1
  69. package/dist/soul/lock.js +33 -9
  70. package/dist/soul/lock.js.map +1 -1
  71. package/dist/tools/agent_recap.d.ts +21 -0
  72. package/dist/tools/agent_recap.d.ts.map +1 -0
  73. package/dist/tools/agent_recap.js +43 -0
  74. package/dist/tools/agent_recap.js.map +1 -0
  75. package/dist/tools/compare_agents.d.ts +16 -0
  76. package/dist/tools/compare_agents.d.ts.map +1 -0
  77. package/dist/tools/compare_agents.js +145 -0
  78. package/dist/tools/compare_agents.js.map +1 -0
  79. package/dist/tools/dispatch_agent.d.ts +13 -0
  80. package/dist/tools/dispatch_agent.d.ts.map +1 -1
  81. package/dist/tools/dispatch_agent.js +49 -37
  82. package/dist/tools/dispatch_agent.js.map +1 -1
  83. package/dist/tools/exec-util.d.ts +18 -0
  84. package/dist/tools/exec-util.d.ts.map +1 -0
  85. package/dist/tools/exec-util.js +72 -0
  86. package/dist/tools/exec-util.js.map +1 -0
  87. package/dist/tools/inspect_agent.d.ts +21 -0
  88. package/dist/tools/inspect_agent.d.ts.map +1 -0
  89. package/dist/tools/inspect_agent.js +87 -0
  90. package/dist/tools/inspect_agent.js.map +1 -0
  91. package/dist/tools/list_agents.d.ts +21 -0
  92. package/dist/tools/list_agents.d.ts.map +1 -0
  93. package/dist/tools/list_agents.js +88 -0
  94. package/dist/tools/list_agents.js.map +1 -0
  95. package/dist/tools/pr_status.d.ts +31 -0
  96. package/dist/tools/pr_status.d.ts.map +1 -0
  97. package/dist/tools/pr_status.js +90 -0
  98. package/dist/tools/pr_status.js.map +1 -0
  99. package/dist/tools/registry.d.ts.map +1 -1
  100. package/dist/tools/registry.js +26 -0
  101. package/dist/tools/registry.js.map +1 -1
  102. package/dist/tools/repo_digest.d.ts +33 -0
  103. package/dist/tools/repo_digest.d.ts.map +1 -0
  104. package/dist/tools/repo_digest.js +113 -0
  105. package/dist/tools/repo_digest.js.map +1 -0
  106. package/dist/tools/review_diff.d.ts +28 -0
  107. package/dist/tools/review_diff.d.ts.map +1 -0
  108. package/dist/tools/review_diff.js +68 -0
  109. package/dist/tools/review_diff.js.map +1 -0
  110. package/dist/tools/run_checks.d.ts +15 -0
  111. package/dist/tools/run_checks.d.ts.map +1 -0
  112. package/dist/tools/run_checks.js +117 -0
  113. package/dist/tools/run_checks.js.map +1 -0
  114. package/dist/tools/scheduled_dispatch.d.ts +27 -0
  115. package/dist/tools/scheduled_dispatch.d.ts.map +1 -0
  116. package/dist/tools/scheduled_dispatch.js +57 -0
  117. package/dist/tools/scheduled_dispatch.js.map +1 -0
  118. package/dist/tools/signal_agent.d.ts +36 -0
  119. package/dist/tools/signal_agent.d.ts.map +1 -0
  120. package/dist/tools/signal_agent.js +140 -0
  121. package/dist/tools/signal_agent.js.map +1 -0
  122. package/dist/web/island.d.ts +1 -1
  123. package/dist/web/island.d.ts.map +1 -1
  124. package/dist/web/island.js +139 -27
  125. package/dist/web/island.js.map +1 -1
  126. package/dist/web/lisa-html.d.ts +1 -1
  127. package/dist/web/lisa-html.d.ts.map +1 -1
  128. package/dist/web/lisa-html.js +132 -4
  129. package/dist/web/lisa-html.js.map +1 -1
  130. package/dist/web/server.d.ts.map +1 -1
  131. package/dist/web/server.js +190 -0
  132. package/dist/web/server.js.map +1 -1
  133. package/package.json +1 -1
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Orchestrator journal (L6) — a small temporal record of agent activity.
3
+ *
4
+ * The hub (L1) only holds a *live snapshot*; once a session goes idle/done it
5
+ * falls out of `hub.list()`. The advisor (L5) surfaces relevance-gated alerts.
6
+ * Neither answers "what actually happened across all my agents while I was
7
+ * away?" — which needs a record over *time*, including sessions that have since
8
+ * ended. This journal is that record: every meaningful state transition the hub
9
+ * emits is appended to a capped ring buffer, from which recap.ts synthesizes a
10
+ * cross-agent "while you were away" digest.
11
+ *
12
+ * In-memory + capped (no growth): a recap covers the current server's uptime,
13
+ * which is exactly the window the user was away *for*. PRIVACY: stores only the
14
+ * same structural metadata the hub emits (agent, project, state, tool/file
15
+ * names, error strings) — never prompts, replies, or file contents.
16
+ */
17
+ const MAX_EVENTS = 400;
18
+ const events = [];
19
+ /** Compact, structural one-liner from a session's Tier-2 activity. */
20
+ export function summarizeActivity(s) {
21
+ const a = s.activity;
22
+ if (!a)
23
+ return undefined;
24
+ const bits = [];
25
+ const tool = a.lastTools?.length ? a.lastTools[a.lastTools.length - 1] : "";
26
+ if (tool)
27
+ bits.push(tool);
28
+ if (a.lastCommandName)
29
+ bits.push("$" + a.lastCommandName);
30
+ const file = a.filesTouched?.length
31
+ ? a.filesTouched[a.filesTouched.length - 1].split("/").pop()
32
+ : "";
33
+ if (file)
34
+ bits.push(file);
35
+ return bits.length ? bits.join(" · ") : undefined;
36
+ }
37
+ /**
38
+ * Append a transition. Consecutive events for the same session with the same
39
+ * state + reason are collapsed (we only record *changes*), so a session that
40
+ * sits in "working" for an hour produces one entry, not hundreds.
41
+ */
42
+ export function recordEvent(s, now = Date.now()) {
43
+ // Find the most recent event for this session.
44
+ let prev;
45
+ for (let i = events.length - 1; i >= 0; i--) {
46
+ if (events[i].sessionId === s.sessionId) {
47
+ prev = events[i];
48
+ break;
49
+ }
50
+ }
51
+ if (prev && prev.state === s.state && prev.stateReason === s.stateReason) {
52
+ return null; // no real transition
53
+ }
54
+ const ev = {
55
+ agent: s.agent,
56
+ sessionId: s.sessionId,
57
+ project: s.project,
58
+ cwd: s.cwd,
59
+ state: s.state,
60
+ stateReason: s.stateReason,
61
+ at: Number.isFinite(s.lastMtime) && s.lastMtime > 0 ? s.lastMtime : now,
62
+ activity: summarizeActivity(s),
63
+ error: s.activity?.lastError,
64
+ };
65
+ events.push(ev);
66
+ if (events.length > MAX_EVENTS)
67
+ events.splice(0, events.length - MAX_EVENTS);
68
+ return ev;
69
+ }
70
+ /** All recorded events (oldest → newest). */
71
+ export function allEvents() {
72
+ return events.slice();
73
+ }
74
+ /** Events at or after `sinceMs` (epoch ms), oldest → newest. */
75
+ export function eventsSince(sinceMs) {
76
+ return events.filter((e) => e.at >= sinceMs);
77
+ }
78
+ /** Test hook — wipe the buffer. */
79
+ export function _resetJournalForTest() {
80
+ events.length = 0;
81
+ }
82
+ //# sourceMappingURL=journal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"journal.js","sourceRoot":"","sources":["../../src/orchestrator/journal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Recap (L6) — synthesize the orchestrator journal into a cross-agent
3
+ * "while you were away" digest. Deterministic (no LLM): given the journal
4
+ * events in a time window, group by project, tally how each session ended,
5
+ * and surface the notable moments (errors, finishes, merged PRs, blocks).
6
+ *
7
+ * This is the narrative counterpart to the advisor's alerts and list_agents'
8
+ * roster: it answers "what happened, across everything, since I left?"
9
+ */
10
+ import type { AgentEvent } from "./journal.js";
11
+ export interface ProjectRecap {
12
+ project: string;
13
+ agents: string[];
14
+ /** Distinct sessions seen in the window. */
15
+ sessions: number;
16
+ finished: number;
17
+ errored: number;
18
+ active: number;
19
+ /** Up to a few file basenames touched. */
20
+ files: string[];
21
+ /** Human-readable notable lines for this project. */
22
+ notable: string[];
23
+ }
24
+ export interface Recap {
25
+ sinceMs: number;
26
+ now: number;
27
+ /** Distinct sessions that had any event in the window. */
28
+ totalSessions: number;
29
+ totalEvents: number;
30
+ projects: ProjectRecap[];
31
+ /** One-line headline. */
32
+ headline: string;
33
+ }
34
+ /** Build the structured recap from journal events in [sinceMs, now]. Pure. */
35
+ export declare function buildRecap(events: AgentEvent[], sinceMs: number, now: number): Recap;
36
+ /** Render the recap as a readable multi-line digest. Pure. */
37
+ export declare function formatRecap(recap: Recap): string;
38
+ //# sourceMappingURL=recap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recap.d.ts","sourceRoot":"","sources":["../../src/orchestrator/recap.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/C,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,qDAAqD;IACrD,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,KAAK;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,0DAA0D;IAC1D,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,yBAAyB;IACzB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAoBD,8EAA8E;AAC9E,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,KAAK,CA6GpF;AAED,8DAA8D;AAC9D,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAShD"}
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Recap (L6) — synthesize the orchestrator journal into a cross-agent
3
+ * "while you were away" digest. Deterministic (no LLM): given the journal
4
+ * events in a time window, group by project, tally how each session ended,
5
+ * and surface the notable moments (errors, finishes, merged PRs, blocks).
6
+ *
7
+ * This is the narrative counterpart to the advisor's alerts and list_agents'
8
+ * roster: it answers "what happened, across everything, since I left?"
9
+ */
10
+ const FILES_PER_PROJECT = 6;
11
+ function basename(p) {
12
+ return p.split("/").pop() || p;
13
+ }
14
+ /** Build the structured recap from journal events in [sinceMs, now]. Pure. */
15
+ export function buildRecap(events, sinceMs, now) {
16
+ const inWindow = events.filter((e) => e.at >= sinceMs);
17
+ // Roll up per session (the latest meaningful state wins).
18
+ const sessions = new Map();
19
+ for (const e of inWindow) {
20
+ let r = sessions.get(e.sessionId);
21
+ if (!r) {
22
+ r = {
23
+ agent: e.agent,
24
+ project: e.project || "(unknown)",
25
+ lastState: e.state,
26
+ lastReason: e.stateReason,
27
+ lastAt: e.at,
28
+ files: new Set(),
29
+ errored: false,
30
+ };
31
+ sessions.set(e.sessionId, r);
32
+ }
33
+ if (e.at >= r.lastAt) {
34
+ r.lastState = e.state;
35
+ r.lastReason = e.stateReason;
36
+ r.lastAt = e.at;
37
+ if (e.activity)
38
+ r.lastActivity = e.activity;
39
+ }
40
+ if (e.state === "error") {
41
+ r.errored = true;
42
+ if (e.error || e.stateReason)
43
+ r.lastError = e.error || e.stateReason;
44
+ }
45
+ if (e.activity) {
46
+ // The activity summary's last token is often a file basename; cheap to keep.
47
+ const f = e.activity.split(" · ").find((t) => /\.[a-z0-9]+$/i.test(t));
48
+ if (f)
49
+ r.files.add(f);
50
+ }
51
+ }
52
+ // Group sessions by project.
53
+ const byProject = new Map();
54
+ for (const r of sessions.values()) {
55
+ const list = byProject.get(r.project) ?? [];
56
+ list.push(r);
57
+ byProject.set(r.project, list);
58
+ }
59
+ const projects = [];
60
+ let totalFinished = 0, totalErrored = 0, totalActive = 0;
61
+ for (const [project, rolls] of byProject) {
62
+ const agents = [...new Set(rolls.map((r) => r.agent))].sort();
63
+ let finished = 0, errored = 0, active = 0;
64
+ const files = new Set();
65
+ const notable = [];
66
+ for (const r of rolls) {
67
+ if (r.errored) {
68
+ errored++;
69
+ notable.push(`✗ ${r.agent} errored${r.lastError ? `: ${r.lastError}` : ""}`);
70
+ }
71
+ else if (r.lastState === "done") {
72
+ finished++;
73
+ notable.push(`✓ ${r.agent} finished${r.lastReason ? ` (${r.lastReason})` : ""}`);
74
+ }
75
+ else if (r.lastState === "working" || r.lastState === "waiting") {
76
+ active++;
77
+ if (r.lastState === "waiting" && r.lastReason)
78
+ notable.push(`• ${r.agent} waiting — ${r.lastReason}`);
79
+ }
80
+ for (const f of r.files)
81
+ files.add(basename(f));
82
+ }
83
+ totalFinished += finished;
84
+ totalErrored += errored;
85
+ totalActive += active;
86
+ projects.push({
87
+ project,
88
+ agents,
89
+ sessions: rolls.length,
90
+ finished,
91
+ errored,
92
+ active,
93
+ files: [...files].slice(0, FILES_PER_PROJECT),
94
+ notable: notable.slice(0, 6),
95
+ });
96
+ }
97
+ // Errors first, then most sessions, then name.
98
+ projects.sort((a, b) => b.errored - a.errored || b.sessions - a.sessions || a.project.localeCompare(b.project));
99
+ const parts = [];
100
+ if (totalFinished)
101
+ parts.push(`${totalFinished} finished`);
102
+ if (totalErrored)
103
+ parts.push(`${totalErrored} errored`);
104
+ if (totalActive)
105
+ parts.push(`${totalActive} still going`);
106
+ const headline = sessions.size === 0
107
+ ? "No agent activity in this window."
108
+ : `${sessions.size} agent session${sessions.size === 1 ? "" : "s"} across ` +
109
+ `${projects.length} project${projects.length === 1 ? "" : "s"}` +
110
+ (parts.length ? ` — ${parts.join(", ")}.` : ".");
111
+ return {
112
+ sinceMs,
113
+ now,
114
+ totalSessions: sessions.size,
115
+ totalEvents: inWindow.length,
116
+ projects,
117
+ headline,
118
+ };
119
+ }
120
+ /** Render the recap as a readable multi-line digest. Pure. */
121
+ export function formatRecap(recap) {
122
+ if (recap.totalSessions === 0)
123
+ return recap.headline;
124
+ const lines = [recap.headline, ""];
125
+ for (const p of recap.projects) {
126
+ lines.push(`${p.project} · ${p.agents.join(", ")}`);
127
+ for (const n of p.notable)
128
+ lines.push(` ${n}`);
129
+ if (p.files.length)
130
+ lines.push(` touched: ${p.files.join(", ")}`);
131
+ }
132
+ return lines.join("\n");
133
+ }
134
+ //# sourceMappingURL=recap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recap.js","sourceRoot":"","sources":["../../src/orchestrator/recap.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Screen advisor — periodic, opt-in screen-aware coaching.
3
+ *
4
+ * When enabled, the server captures a full-screen screenshot every N minutes,
5
+ * asks the model for the single best next coding step grounded in what's on
6
+ * screen, and pushes it to the Lisa Island as a suggestion card. Clicking it
7
+ * prefills the suggestion into the chat composer so the user can confirm before
8
+ * any coding agent is dispatched.
9
+ *
10
+ * PRIVACY (this is a sensitive capability — treat it as such):
11
+ * - DISABLED by default. Nothing is captured until the user turns it on in
12
+ * Settings.
13
+ * - The screenshot only leaves the machine for the single analysis call to
14
+ * the model the user already uses; the image is never persisted by LISA
15
+ * (capture writes a temp PNG that the capture layer deletes), and only the
16
+ * short text suggestion is kept in memory.
17
+ * - The suggestion never auto-runs anything: clicking it only prefills chat.
18
+ *
19
+ * This module is provider-agnostic and side-effect-light so the parsing and
20
+ * config logic can be unit-tested without a real LLM or a real screen.
21
+ */
22
+ export interface ScreenAdvisorConfig {
23
+ /** Master switch. Off by default — capture only happens when true. */
24
+ enabled: boolean;
25
+ /** Minutes between captures. Clamped to [MIN, MAX]. */
26
+ intervalMinutes: number;
27
+ }
28
+ export declare const DEFAULT_SCREEN_ADVISOR_CONFIG: ScreenAdvisorConfig;
29
+ export declare const MIN_INTERVAL_MINUTES = 2;
30
+ export declare const MAX_INTERVAL_MINUTES = 240;
31
+ export declare const SCREEN_ADVISOR_CONFIG_PATH: string;
32
+ /** Coerce arbitrary input into a valid config (clamped interval, boolean enabled). */
33
+ export declare function normalizeConfig(raw: Partial<ScreenAdvisorConfig> | null | undefined): ScreenAdvisorConfig;
34
+ export declare function loadScreenAdvisorConfig(p?: string): Promise<ScreenAdvisorConfig>;
35
+ export declare function saveScreenAdvisorConfig(cfg: ScreenAdvisorConfig, p?: string): Promise<ScreenAdvisorConfig>;
36
+ /** A single screen-grounded next-step suggestion. */
37
+ export interface ScreenSuggestion {
38
+ /** ≤8-word imperative headline. */
39
+ title: string;
40
+ /** 1–2 sentences citing what was on screen. */
41
+ rationale: string;
42
+ /** Self-contained prompt a coding agent could act on. */
43
+ task: string;
44
+ /** ISO timestamp, stamped by the caller. */
45
+ at: string;
46
+ }
47
+ export declare const SCREEN_ADVISOR_SYSTEM = "You are Lisa's screen advisor. You are shown ONE screenshot of the user's screen. Suggest the single highest-value next CODING step, grounded in what is actually visible \u2014 an error, a failing test, a TODO/FIXME, an open file, a diff, a PR, a design. Be specific and actionable: prefer something a coding agent could pick up and finish.\n\nRespond with ONLY a compact JSON object \u2014 no prose, no markdown, no code fences:\n{\"title\":\"<=8-word imperative headline\",\"rationale\":\"1-2 sentences citing what you saw\",\"task\":\"a self-contained prompt for a coding agent: exactly what to do, and in which file/dir if visible\"}\n\nIf the screen shows nothing actionable for coding (a video, a chat, the desktop, unrelated browsing), respond with exactly: {\"skip\":true}";
48
+ /**
49
+ * Tolerantly parse the model's reply into a suggestion. Strips code fences,
50
+ * extracts the first JSON object, and returns null for {"skip":true} or any
51
+ * malformed / incomplete reply (so the loop simply surfaces nothing).
52
+ */
53
+ export declare function parseSuggestion(text: string | null | undefined): Omit<ScreenSuggestion, "at"> | null;
54
+ /** Minimal provider surface the analyzer needs (keeps the engine testable). */
55
+ export interface SuggestionProvider {
56
+ runTurn(opts: {
57
+ systemPrompt: string;
58
+ messages: Array<{
59
+ role: "user" | "assistant";
60
+ content: unknown;
61
+ }>;
62
+ tools: unknown[];
63
+ model: string;
64
+ maxTokens?: number;
65
+ }): Promise<{
66
+ content: Array<{
67
+ type: string;
68
+ text?: string;
69
+ }>;
70
+ }>;
71
+ }
72
+ /** Run one screenshot through the model and parse the suggestion (or null). */
73
+ export declare function analyzeScreenshot(opts: {
74
+ provider: SuggestionProvider;
75
+ model: string;
76
+ imageBase64: string;
77
+ mediaType?: string;
78
+ }): Promise<Omit<ScreenSuggestion, "at"> | null>;
79
+ //# sourceMappingURL=engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/screen_advisor/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAMH,MAAM,WAAW,mBAAmB;IAClC,sEAAsE;IACtE,OAAO,EAAE,OAAO,CAAC;IACjB,uDAAuD;IACvD,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,eAAO,MAAM,6BAA6B,EAAE,mBAG3C,CAAC;AAEF,eAAO,MAAM,oBAAoB,IAAI,CAAC;AACtC,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAExC,eAAO,MAAM,0BAA0B,QAA8C,CAAC;AAEtF,sFAAsF;AACtF,wBAAgB,eAAe,CAC7B,GAAG,EAAE,OAAO,CAAC,mBAAmB,CAAC,GAAG,IAAI,GAAG,SAAS,GACnD,mBAAmB,CAQrB;AAED,wBAAsB,uBAAuB,CAC3C,CAAC,GAAE,MAAmC,GACrC,OAAO,CAAC,mBAAmB,CAAC,CAO9B;AAED,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,mBAAmB,EACxB,CAAC,GAAE,MAAmC,GACrC,OAAO,CAAC,mBAAmB,CAAC,CAK9B;AAED,qDAAqD;AACrD,MAAM,WAAW,gBAAgB;IAC/B,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,eAAO,MAAM,qBAAqB,ixBAKwG,CAAC;AAE3I;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,GAAG,IAAI,CAwBpG;AAED,+EAA+E;AAC/E,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,IAAI,EAAE;QACZ,YAAY,EAAE,MAAM,CAAC;QACrB,QAAQ,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;YAAC,OAAO,EAAE,OAAO,CAAA;SAAE,CAAC,CAAC;QAClE,KAAK,EAAE,OAAO,EAAE,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC,CAAC;CAClE;AAED,+EAA+E;AAC/E,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,CAyB/C"}
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Screen advisor — periodic, opt-in screen-aware coaching.
3
+ *
4
+ * When enabled, the server captures a full-screen screenshot every N minutes,
5
+ * asks the model for the single best next coding step grounded in what's on
6
+ * screen, and pushes it to the Lisa Island as a suggestion card. Clicking it
7
+ * prefills the suggestion into the chat composer so the user can confirm before
8
+ * any coding agent is dispatched.
9
+ *
10
+ * PRIVACY (this is a sensitive capability — treat it as such):
11
+ * - DISABLED by default. Nothing is captured until the user turns it on in
12
+ * Settings.
13
+ * - The screenshot only leaves the machine for the single analysis call to
14
+ * the model the user already uses; the image is never persisted by LISA
15
+ * (capture writes a temp PNG that the capture layer deletes), and only the
16
+ * short text suggestion is kept in memory.
17
+ * - The suggestion never auto-runs anything: clicking it only prefills chat.
18
+ *
19
+ * This module is provider-agnostic and side-effect-light so the parsing and
20
+ * config logic can be unit-tested without a real LLM or a real screen.
21
+ */
22
+ import fsp from "node:fs/promises";
23
+ import path from "node:path";
24
+ import { LISA_HOME } from "../paths.js";
25
+ export const DEFAULT_SCREEN_ADVISOR_CONFIG = {
26
+ enabled: false,
27
+ intervalMinutes: 10,
28
+ };
29
+ export const MIN_INTERVAL_MINUTES = 2;
30
+ export const MAX_INTERVAL_MINUTES = 240;
31
+ export const SCREEN_ADVISOR_CONFIG_PATH = path.join(LISA_HOME, "screen-advisor.json");
32
+ /** Coerce arbitrary input into a valid config (clamped interval, boolean enabled). */
33
+ export function normalizeConfig(raw) {
34
+ const enabled = raw?.enabled === true;
35
+ let n = Number(raw?.intervalMinutes);
36
+ if (!Number.isFinite(n))
37
+ n = DEFAULT_SCREEN_ADVISOR_CONFIG.intervalMinutes;
38
+ n = Math.round(n);
39
+ if (n < MIN_INTERVAL_MINUTES)
40
+ n = MIN_INTERVAL_MINUTES;
41
+ if (n > MAX_INTERVAL_MINUTES)
42
+ n = MAX_INTERVAL_MINUTES;
43
+ return { enabled, intervalMinutes: n };
44
+ }
45
+ export async function loadScreenAdvisorConfig(p = SCREEN_ADVISOR_CONFIG_PATH) {
46
+ try {
47
+ const raw = JSON.parse(await fsp.readFile(p, "utf8"));
48
+ return normalizeConfig(raw);
49
+ }
50
+ catch {
51
+ return { ...DEFAULT_SCREEN_ADVISOR_CONFIG };
52
+ }
53
+ }
54
+ export async function saveScreenAdvisorConfig(cfg, p = SCREEN_ADVISOR_CONFIG_PATH) {
55
+ const norm = normalizeConfig(cfg);
56
+ await fsp.mkdir(path.dirname(p), { recursive: true });
57
+ await fsp.writeFile(p, JSON.stringify(norm, null, 2));
58
+ return norm;
59
+ }
60
+ export const SCREEN_ADVISOR_SYSTEM = `You are Lisa's screen advisor. You are shown ONE screenshot of the user's screen. Suggest the single highest-value next CODING step, grounded in what is actually visible — an error, a failing test, a TODO/FIXME, an open file, a diff, a PR, a design. Be specific and actionable: prefer something a coding agent could pick up and finish.
61
+
62
+ Respond with ONLY a compact JSON object — no prose, no markdown, no code fences:
63
+ {"title":"<=8-word imperative headline","rationale":"1-2 sentences citing what you saw","task":"a self-contained prompt for a coding agent: exactly what to do, and in which file/dir if visible"}
64
+
65
+ If the screen shows nothing actionable for coding (a video, a chat, the desktop, unrelated browsing), respond with exactly: {"skip":true}`;
66
+ /**
67
+ * Tolerantly parse the model's reply into a suggestion. Strips code fences,
68
+ * extracts the first JSON object, and returns null for {"skip":true} or any
69
+ * malformed / incomplete reply (so the loop simply surfaces nothing).
70
+ */
71
+ export function parseSuggestion(text) {
72
+ if (!text)
73
+ return null;
74
+ let s = text.trim();
75
+ // Drop a leading ```json / ``` fence and a trailing fence if present.
76
+ s = s.replace(/^```[a-zA-Z]*\s*/, "").replace(/\s*```$/, "").trim();
77
+ const a = s.indexOf("{");
78
+ const b = s.lastIndexOf("}");
79
+ if (a < 0 || b <= a)
80
+ return null;
81
+ let obj;
82
+ try {
83
+ obj = JSON.parse(s.slice(a, b + 1));
84
+ }
85
+ catch {
86
+ return null;
87
+ }
88
+ if (obj.skip === true)
89
+ return null;
90
+ const title = typeof obj.title === "string" ? obj.title.trim() : "";
91
+ const task = typeof obj.task === "string" ? obj.task.trim() : "";
92
+ if (!title || !task)
93
+ return null;
94
+ const rationale = typeof obj.rationale === "string" ? obj.rationale.trim() : "";
95
+ return {
96
+ title: title.slice(0, 120),
97
+ rationale: rationale.slice(0, 400),
98
+ task: task.slice(0, 2000),
99
+ };
100
+ }
101
+ /** Run one screenshot through the model and parse the suggestion (or null). */
102
+ export async function analyzeScreenshot(opts) {
103
+ const result = await opts.provider.runTurn({
104
+ systemPrompt: SCREEN_ADVISOR_SYSTEM,
105
+ messages: [
106
+ {
107
+ role: "user",
108
+ content: [
109
+ { type: "text", text: "Here is my screen right now. What is the single best next coding step?" },
110
+ {
111
+ type: "image",
112
+ source: {
113
+ type: "base64",
114
+ media_type: opts.mediaType ?? "image/png",
115
+ data: opts.imageBase64,
116
+ },
117
+ },
118
+ ],
119
+ },
120
+ ],
121
+ tools: [],
122
+ model: opts.model,
123
+ maxTokens: 600,
124
+ });
125
+ const textBlock = result.content.find((b) => b.type === "text");
126
+ return parseSuggestion(textBlock?.text ?? "");
127
+ }
128
+ //# sourceMappingURL=engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/screen_advisor/engine.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"birth.d.ts","sourceRoot":"","sources":["../../src/soul/birth.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,eAAe,EAWhB,MAAM,YAAY,CAAC;AAQpB,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAClD;AA8BD,wBAAsB,KAAK,CAAC,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAOlE;AAmKD,OAAO,EAAE,eAAe,EAAE,CAAC"}
1
+ {"version":3,"file":"birth.d.ts","sourceRoot":"","sources":["../../src/soul/birth.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,eAAe,EAWhB,MAAM,YAAY,CAAC;AAQpB,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAClD;AA8BD,wBAAsB,KAAK,CAAC,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAOlE;AA2KD,OAAO,EAAE,eAAe,EAAE,CAAC"}
@@ -161,6 +161,14 @@ function parseBirthOutput(raw) {
161
161
  if (!parsed.first_value?.slug || !parsed.first_desire?.slug) {
162
162
  throw new Error("birth output missing first_value or first_desire");
163
163
  }
164
+ // Smaller models sometimes return `constitution` as an array of strings
165
+ // when the prompt asks for a "markdown list". Coerce to a numbered
166
+ // markdown block so downstream string ops work uniformly.
167
+ if (Array.isArray(parsed.constitution)) {
168
+ parsed.constitution = parsed.constitution
169
+ .map((line, i) => `${i + 1}. ${String(line).replace(/^\s*\d+[.)]\s*/, "")}`)
170
+ .join("\n");
171
+ }
164
172
  return parsed;
165
173
  }
166
174
  function countLines(s) {
@@ -1 +1 @@
1
- {"version":3,"file":"birth.js","sourceRoot":"","sources":["../../src/soul/birth.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EACL,cAAc,EACd,MAAM,EACN,eAAe,EACf,aAAa,EACb,QAAQ,EACR,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,SAAS,EACT,YAAY,EACZ,SAAS,EACT,UAAU,EACV,WAAW,GACZ,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,EACL,gBAAgB,GAGjB,MAAM,YAAY,CAAC;AAapB,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;iIA0B4G,CAAC;AAElI,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,OAAqB,EAAE;IACjD,IAAI,MAAM,MAAM,EAAE,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CACb,kGAAkG,CACnG,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,cAAc,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,IAAkB;IAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACzC,MAAM,cAAc,EAAE,CAAC;IAEvB,UAAU;IACV,MAAM,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC,CAAC;IAC5D,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;IAC5B,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC;IACtB,0EAA0E;IAC1E,uEAAuE;IACvE,wEAAwE;IACxE,MAAM,YAAY,EAAE,CAAC;IACrB,MAAM,MAAM,CAAC;QACX,IAAI,EAAE,MAAM;QACZ,MAAM,EAAE,QAAQ,IAAI,CAAC,MAAM,YAAY,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,iBAAiB,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG;KAC5R,CAAC,CAAC;IAEH,oBAAoB;IACpB,MAAM,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,yCAAyC,EAAE,CAAC,CAAC;IAClF,MAAM,QAAQ,GAAG,gBAAgB,CAAC,IAAI,CAAC,KAAK,IAAI,aAAa,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC;QACpC,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,aAAa;QAClC,YAAY,EAAE,YAAY;QAC1B,KAAK,EAAE,EAAE;QACT,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EACF,UAAU,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,uCAAuC;qBACjF;iBACF;aACF;SACF;QACD,SAAS,EAAE,KAAK;KACjB,CAAC,CAAC;IACH,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO;SACvB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;SAChC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAE,CAAsB,CAAC,IAAI,CAAC;SACxC,IAAI,CAAC,EAAE,CAAC;SACR,IAAI,EAAE,CAAC;IACV,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;IAErC,kBAAkB;IAClB,MAAM,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;IAC7D,MAAM,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAE7B,MAAM,MAAM,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC;IAC/E,MAAM,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAErC,MAAM,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC;IAC7E,MAAM,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAEnC,MAAM,MAAM,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,MAAM,CAAC,YAAY,CAAC,aAAa,EAAE,CAAC,CAAC;IAChG,MAAM,iBAAiB,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IAE7C,MAAM,MAAM,CAAC;QACX,IAAI,EAAE,aAAa;QACnB,MAAM,EAAE,KAAK,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE;KACxC,CAAC,CAAC;IACH,MAAM,UAAU,CAAC;QACf,IAAI,EAAE,MAAM,CAAC,WAAW,CAAC,IAAI;QAC7B,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC,KAAK;QAC/B,IAAI,EAAE,MAAM,CAAC,WAAW,CAAC,IAAI;QAC7B,SAAS,EAAE,IAAI,CAAC,MAAM;KACvB,CAAC,CAAC;IAEH,MAAM,MAAM,CAAC;QACX,IAAI,EAAE,cAAc;QACpB,MAAM,EAAE,KAAK,MAAM,CAAC,YAAY,CAAC,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,EAAE;KAChG,CAAC,CAAC;IACH,MAAM,WAAW,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC,YAAY,CAAC,IAAI;QAC9B,IAAI,EAAE,MAAM,CAAC,YAAY,CAAC,IAAI;QAC9B,GAAG,EAAE,MAAM,CAAC,YAAY,CAAC,GAAG;QAC5B,UAAU,EAAE,MAAM,CAAC,YAAY,CAAC,UAAU;QAC1C,eAAe,EAAE,MAAM,CAAC,YAAY,CAAC,gBAAgB;QACrD,MAAM,EAAE,IAAI,CAAC,MAAM;KACpB,CAAC,CAAC;IAEH,6BAA6B;IAC7B,MAAM,aAAa,CAAC,EAAE,GAAG,gBAAgB,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IAClF,MAAM,QAAQ,CAAC,MAAM,aAAa,EAAE,CAAC,CAAC;IAEtC,MAAM,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,YAAY,EAAE,CAAC,CAAC;AACrE,CAAC;AAED,SAAS,YAAY;IACnB,MAAM,SAAS,GAAG,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACzD,MAAM,QAAQ,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;IAC/B,MAAM,QAAQ,GAAG,MAAM;SACpB,UAAU,CAAC,QAAQ,CAAC;SACpB,MAAM,CAAC,QAAQ,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC;SACzC,MAAM,CAAC,KAAK,CAAC,CAAC;IACjB,sEAAsE;IACtE,MAAM,IAAI,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;IACvC,OAAO;QACL,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QAChC,MAAM,EAAE,QAAQ;QAChB,UAAU,EAAE,SAAS;QACrB,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,GAAW;IACjC,iEAAiE;IACjE,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACpC,MAAM,KAAK,GAAG,CAAC,CAAS,EAAE,EAAE,CAC1B,MAAM,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,eAAe,CAAC,GAAG,eAAe,CAAC;QACxE,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,mBAAmB,CAAC,CAAC;IACnE,4BAA4B;IAC5B,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,UAAU,CAAC;IAChE,OAAO;QACL,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;QAChB,iBAAiB,EAAE,GAAG,CAAC,CAAC,CAAC;QACzB,YAAY,EAAE,GAAG,CAAC,CAAC,CAAC;QACpB,aAAa,EAAE,GAAG,CAAC,CAAC,CAAC;QACrB,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC;KACpB,CAAC;IACF,0EAA0E;IAC1E,6DAA6D;IAC7D,KAAK,KAAK,CAAC;AACb,CAAC;AAiBD,SAAS,gBAAgB,CAAC,GAAW;IACnC,MAAM,QAAQ,GAAG,GAAG;SACjB,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC;SAChC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;SACpB,IAAI,EAAE,CAAC;IACV,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAgB,CAAC;IACnD,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QAChF,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC;QAC5D,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;AACzD,CAAC;AAED,8EAA8E;AAC9E,OAAO,EAAE,eAAe,EAAE,CAAC"}
1
+ {"version":3,"file":"birth.js","sourceRoot":"","sources":["../../src/soul/birth.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EACL,cAAc,EACd,MAAM,EACN,eAAe,EACf,aAAa,EACb,QAAQ,EACR,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,SAAS,EACT,YAAY,EACZ,SAAS,EACT,UAAU,EACV,WAAW,GACZ,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,EACL,gBAAgB,GAGjB,MAAM,YAAY,CAAC;AAapB,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;iIA0B4G,CAAC;AAElI,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,OAAqB,EAAE;IACjD,IAAI,MAAM,MAAM,EAAE,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CACb,kGAAkG,CACnG,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,cAAc,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,IAAkB;IAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACzC,MAAM,cAAc,EAAE,CAAC;IAEvB,UAAU;IACV,MAAM,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC,CAAC;IAC5D,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;IAC5B,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC;IACtB,0EAA0E;IAC1E,uEAAuE;IACvE,wEAAwE;IACxE,MAAM,YAAY,EAAE,CAAC;IACrB,MAAM,MAAM,CAAC;QACX,IAAI,EAAE,MAAM;QACZ,MAAM,EAAE,QAAQ,IAAI,CAAC,MAAM,YAAY,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,iBAAiB,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG;KAC5R,CAAC,CAAC;IAEH,oBAAoB;IACpB,MAAM,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,yCAAyC,EAAE,CAAC,CAAC;IAClF,MAAM,QAAQ,GAAG,gBAAgB,CAAC,IAAI,CAAC,KAAK,IAAI,aAAa,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC;QACpC,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,aAAa;QAClC,YAAY,EAAE,YAAY;QAC1B,KAAK,EAAE,EAAE;QACT,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EACF,UAAU,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,uCAAuC;qBACjF;iBACF;aACF;SACF;QACD,SAAS,EAAE,KAAK;KACjB,CAAC,CAAC;IACH,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO;SACvB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;SAChC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAE,CAAsB,CAAC,IAAI,CAAC;SACxC,IAAI,CAAC,EAAE,CAAC;SACR,IAAI,EAAE,CAAC;IACV,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;IAErC,kBAAkB;IAClB,MAAM,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;IAC7D,MAAM,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAE7B,MAAM,MAAM,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC;IAC/E,MAAM,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAErC,MAAM,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC;IAC7E,MAAM,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAEnC,MAAM,MAAM,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,MAAM,CAAC,YAAY,CAAC,aAAa,EAAE,CAAC,CAAC;IAChG,MAAM,iBAAiB,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IAE7C,MAAM,MAAM,CAAC;QACX,IAAI,EAAE,aAAa;QACnB,MAAM,EAAE,KAAK,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE;KACxC,CAAC,CAAC;IACH,MAAM,UAAU,CAAC;QACf,IAAI,EAAE,MAAM,CAAC,WAAW,CAAC,IAAI;QAC7B,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC,KAAK;QAC/B,IAAI,EAAE,MAAM,CAAC,WAAW,CAAC,IAAI;QAC7B,SAAS,EAAE,IAAI,CAAC,MAAM;KACvB,CAAC,CAAC;IAEH,MAAM,MAAM,CAAC;QACX,IAAI,EAAE,cAAc;QACpB,MAAM,EAAE,KAAK,MAAM,CAAC,YAAY,CAAC,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,EAAE;KAChG,CAAC,CAAC;IACH,MAAM,WAAW,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC,YAAY,CAAC,IAAI;QAC9B,IAAI,EAAE,MAAM,CAAC,YAAY,CAAC,IAAI;QAC9B,GAAG,EAAE,MAAM,CAAC,YAAY,CAAC,GAAG;QAC5B,UAAU,EAAE,MAAM,CAAC,YAAY,CAAC,UAAU;QAC1C,eAAe,EAAE,MAAM,CAAC,YAAY,CAAC,gBAAgB;QACrD,MAAM,EAAE,IAAI,CAAC,MAAM;KACpB,CAAC,CAAC;IAEH,6BAA6B;IAC7B,MAAM,aAAa,CAAC,EAAE,GAAG,gBAAgB,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IAClF,MAAM,QAAQ,CAAC,MAAM,aAAa,EAAE,CAAC,CAAC;IAEtC,MAAM,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,YAAY,EAAE,CAAC,CAAC;AACrE,CAAC;AAED,SAAS,YAAY;IACnB,MAAM,SAAS,GAAG,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACzD,MAAM,QAAQ,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;IAC/B,MAAM,QAAQ,GAAG,MAAM;SACpB,UAAU,CAAC,QAAQ,CAAC;SACpB,MAAM,CAAC,QAAQ,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC;SACzC,MAAM,CAAC,KAAK,CAAC,CAAC;IACjB,sEAAsE;IACtE,MAAM,IAAI,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;IACvC,OAAO;QACL,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QAChC,MAAM,EAAE,QAAQ;QAChB,UAAU,EAAE,SAAS;QACrB,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,GAAW;IACjC,iEAAiE;IACjE,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACpC,MAAM,KAAK,GAAG,CAAC,CAAS,EAAE,EAAE,CAC1B,MAAM,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,eAAe,CAAC,GAAG,eAAe,CAAC;QACxE,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,mBAAmB,CAAC,CAAC;IACnE,4BAA4B;IAC5B,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,UAAU,CAAC;IAChE,OAAO;QACL,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;QAChB,iBAAiB,EAAE,GAAG,CAAC,CAAC,CAAC;QACzB,YAAY,EAAE,GAAG,CAAC,CAAC,CAAC;QACpB,aAAa,EAAE,GAAG,CAAC,CAAC,CAAC;QACrB,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC;KACpB,CAAC;IACF,0EAA0E;IAC1E,6DAA6D;IAC7D,KAAK,KAAK,CAAC;AACb,CAAC;AAiBD,SAAS,gBAAgB,CAAC,GAAW;IACnC,MAAM,QAAQ,GAAG,GAAG;SACjB,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC;SAChC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;SACpB,IAAI,EAAE,CAAC;IACV,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAgB,CAAC;IACnD,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QAChF,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC;QAC5D,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;IACtE,CAAC;IACD,wEAAwE;IACxE,mEAAmE;IACnE,0DAA0D;IAC1D,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;QACvC,MAAM,CAAC,YAAY,GAAI,MAAM,CAAC,YAA0B;aACrD,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,EAAE,CAAC;aAC3E,IAAI,CAAC,IAAI,CAAC,CAAC;IAChB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;AACzD,CAAC;AAED,8EAA8E;AAC9E,OAAO,EAAE,eAAe,EAAE,CAAC"}
@@ -9,10 +9,13 @@
9
9
  * - lose a desire-progress append (read-modify-write race), or
10
10
  * - collide on .git/index.lock (one commit fails).
11
11
  *
12
- * withFileLock implements a portable advisory mutex via exclusive file
13
- * creation (`open(..., "wx")` succeeds only if the file doesn't exist). It
14
- * self-heals from a crashed holder via a staleness timeout + a best-effort
15
- * liveness check on the recorded pid.
12
+ * withFileLock implements a portable advisory mutex by writing the lock body to
13
+ * a private temp file and then `link()`-ing it into place link() fails if the
14
+ * target exists, so the lock is created exclusively AND already holds its full
15
+ * content (no window where a contender can read a half-written file and mistake
16
+ * it for stale). It self-heals from a crashed holder via a staleness timeout +
17
+ * a best-effort liveness check on the recorded pid, stealing atomically by
18
+ * renaming the stale file away so racing contenders can't clobber each other.
16
19
  */
17
20
  export interface FileLockOpts {
18
21
  /** Treat a held lock as abandoned after this many ms (crashed holder). */
@@ -1 +1 @@
1
- {"version":3,"file":"lock.d.ts","sourceRoot":"","sources":["../../src/soul/lock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAOH,MAAM,WAAW,YAAY;IAC3B,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAoCD;;;GAGG;AACH,wBAAsB,YAAY,CAAC,CAAC,EAClC,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,IAAI,GAAE,YAAiB,GACtB,OAAO,CAAC,CAAC,CAAC,CAmCZ;AAED,0CAA0C;AAC1C,eAAO,MAAM,cAAc,QAAqC,CAAC;AAEjE;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,CAErF"}
1
+ {"version":3,"file":"lock.d.ts","sourceRoot":"","sources":["../../src/soul/lock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAOH,MAAM,WAAW,YAAY;IAC3B,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAyCD;;;GAGG;AACH,wBAAsB,YAAY,CAAC,CAAC,EAClC,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,IAAI,GAAE,YAAiB,GACtB,OAAO,CAAC,CAAC,CAAC,CAkDZ;AAED,0CAA0C;AAC1C,eAAO,MAAM,cAAc,QAAqC,CAAC;AAEjE;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,CAErF"}