muonroi-cli 1.8.3 → 1.8.4

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 (39) hide show
  1. package/LICENSE +9 -21
  2. package/README.md +133 -122
  3. package/dist/src/cli/cost-forensics.js +12 -12
  4. package/dist/src/council/prompts.js +20 -20
  5. package/dist/src/generated/version.d.ts +1 -1
  6. package/dist/src/generated/version.js +1 -1
  7. package/dist/src/mcp/oauth-callback.js +2 -2
  8. package/dist/src/mcp/setup-guide-text.d.ts +1 -1
  9. package/dist/src/mcp/setup-guide-text.js +77 -76
  10. package/dist/src/ops/doctor.js +7 -7
  11. package/dist/src/orchestrator/prompts.js +159 -159
  12. package/dist/src/orchestrator/tool-engine.d.ts +4 -0
  13. package/dist/src/orchestrator/tool-engine.js +49 -0
  14. package/dist/src/pil/layer1-intent.js +37 -37
  15. package/dist/src/pil/layer2_5-ponytail.js +8 -8
  16. package/dist/src/product-loop/done-gate.js +3 -3
  17. package/dist/src/product-loop/loop-driver.js +18 -18
  18. package/dist/src/product-loop/progress-snapshot.js +4 -4
  19. package/dist/src/providers/mcp-vision-bridge.js +48 -48
  20. package/dist/src/reporter/index.js +1 -1
  21. package/dist/src/scaffold/bb-ecosystem-apply.js +47 -47
  22. package/dist/src/scaffold/bb-quality-gate.js +5 -5
  23. package/dist/src/scaffold/continuation-prompt.js +60 -60
  24. package/dist/src/scaffold/init-new.js +453 -453
  25. package/dist/src/self-qa/agentic-loop.js +19 -19
  26. package/dist/src/storage/interaction-log.js +5 -5
  27. package/dist/src/storage/migrations.js +125 -125
  28. package/dist/src/storage/session-experience-store.js +4 -4
  29. package/dist/src/storage/sessions.js +43 -43
  30. package/dist/src/storage/transcript.js +100 -100
  31. package/dist/src/storage/usage.js +14 -14
  32. package/dist/src/storage/workspaces.js +12 -12
  33. package/dist/src/ui/slash/council-inspect.js +4 -4
  34. package/dist/src/ui/use-app-logic.js +0 -0
  35. package/dist/src/utils/clipboard-image.js +23 -23
  36. package/dist/src/utils/install-manager.js +12 -10
  37. package/dist/src/utils/side-question.js +2 -2
  38. package/dist/src/utils/skills.js +3 -3
  39. package/package.json +2 -2
@@ -65,25 +65,25 @@ export function createMockBrain(script) {
65
65
  // ---------------------------------------------------------------------------
66
66
  // LLM brain — uses the configured provider stack
67
67
  // ---------------------------------------------------------------------------
68
- const DEFAULT_SYSTEM_PROMPT = `You are a QA agent driving a TUI via an agent-harness.
69
- Your job: given a free-form goal and the current TUI state (semantic tree + recent events),
70
- decide the SINGLE next action.
71
-
72
- Reply with a strict JSON object — no prose, no markdown fences:
73
-
74
- {"action":"type","text":"...","reason":"short"}
75
- {"action":"press","key":"Enter|Escape|Down|Up|Tab","reason":"short"}
76
- {"action":"wait_for","idle":true,"timeoutMs":5000,"reason":"..."}
77
- {"action":"wait_for","selector":"id=askcard","timeoutMs":5000,"reason":"..."}
78
- {"action":"wait_for","event":"askcard-open","timeoutMs":5000,"reason":"..."}
79
- {"action":"done","verdict":"pass","reason":"goal achieved"}
80
- {"action":"done","verdict":"fail","reason":"goal cannot be achieved"}
81
-
82
- Rules:
83
- - One action per turn. Do not batch.
84
- - Prefer wait_for after type/press to let the TUI settle.
85
- - If the goal looks satisfied, return done(pass).
86
- - If an error toast appears or the TUI is stuck, return done(fail).
68
+ const DEFAULT_SYSTEM_PROMPT = `You are a QA agent driving a TUI via an agent-harness.
69
+ Your job: given a free-form goal and the current TUI state (semantic tree + recent events),
70
+ decide the SINGLE next action.
71
+
72
+ Reply with a strict JSON object — no prose, no markdown fences:
73
+
74
+ {"action":"type","text":"...","reason":"short"}
75
+ {"action":"press","key":"Enter|Escape|Down|Up|Tab","reason":"short"}
76
+ {"action":"wait_for","idle":true,"timeoutMs":5000,"reason":"..."}
77
+ {"action":"wait_for","selector":"id=askcard","timeoutMs":5000,"reason":"..."}
78
+ {"action":"wait_for","event":"askcard-open","timeoutMs":5000,"reason":"..."}
79
+ {"action":"done","verdict":"pass","reason":"goal achieved"}
80
+ {"action":"done","verdict":"fail","reason":"goal cannot be achieved"}
81
+
82
+ Rules:
83
+ - One action per turn. Do not batch.
84
+ - Prefer wait_for after type/press to let the TUI settle.
85
+ - If the goal looks satisfied, return done(pass).
86
+ - If an error toast appears or the TUI is stuck, return done(fail).
87
87
  - Stay within ${"${maxTurns}"} turns. Be concise.`;
88
88
  /**
89
89
  * Pull a usable text body out of an AI SDK generateText result.
@@ -55,10 +55,10 @@ export function selectEEInjectionsForRun(runId, limit = 20) {
55
55
  try {
56
56
  const db = getDatabase();
57
57
  return db
58
- .prepare(`SELECT session_id, event_subtype, duration_ms, metadata_json, created_at
59
- FROM interaction_logs
60
- WHERE session_id = ? AND event_type = 'ee_injection'
61
- ORDER BY created_at DESC
58
+ .prepare(`SELECT session_id, event_subtype, duration_ms, metadata_json, created_at
59
+ FROM interaction_logs
60
+ WHERE session_id = ? AND event_type = 'ee_injection'
61
+ ORDER BY created_at DESC
62
62
  LIMIT ?`)
63
63
  .all(runId, limit);
64
64
  }
@@ -74,7 +74,7 @@ export function logInteraction(sessionId, eventType, metadata) {
74
74
  try {
75
75
  const db = getDatabase();
76
76
  const metadataJson = metadata?.data ? JSON.stringify(metadata.data) : null;
77
- db.prepare(`INSERT INTO interaction_logs (session_id, event_type, event_subtype, model, duration_ms, input_tokens, output_tokens, metadata_json, created_at)
77
+ db.prepare(`INSERT INTO interaction_logs (session_id, event_type, event_subtype, model, duration_ms, input_tokens, output_tokens, metadata_json, created_at)
78
78
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(sessionId, eventType, metadata?.eventSubtype ?? null, metadata?.model ?? null, metadata?.durationMs ?? null, metadata?.inputTokens ?? null, metadata?.outputTokens ?? null, metadataJson, new Date().toISOString());
79
79
  maybePruneOld();
80
80
  }
@@ -13,9 +13,9 @@ export function applyMigrations(db) {
13
13
  db.pragma("user_version = 2");
14
14
  }
15
15
  if (version < 3) {
16
- db.exec(`
17
- ALTER TABLE usage_events ADD COLUMN pil_active INTEGER NOT NULL DEFAULT 0;
18
- ALTER TABLE usage_events ADD COLUMN enrichment_delta INTEGER NOT NULL DEFAULT 0;
16
+ db.exec(`
17
+ ALTER TABLE usage_events ADD COLUMN pil_active INTEGER NOT NULL DEFAULT 0;
18
+ ALTER TABLE usage_events ADD COLUMN enrichment_delta INTEGER NOT NULL DEFAULT 0;
19
19
  `);
20
20
  db.pragma("user_version = 3");
21
21
  }
@@ -34,24 +34,24 @@ export function applyMigrations(db) {
34
34
  db.pragma("user_version = 4");
35
35
  }
36
36
  if (version < 5) {
37
- db.exec(`
38
- CREATE TABLE IF NOT EXISTS interaction_logs (
39
- id INTEGER PRIMARY KEY AUTOINCREMENT,
40
- session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
41
- event_type TEXT NOT NULL,
42
- event_subtype TEXT,
43
- model TEXT,
44
- duration_ms INTEGER,
45
- input_tokens INTEGER,
46
- output_tokens INTEGER,
47
- metadata_json TEXT,
48
- created_at TEXT NOT NULL
49
- ) STRICT;
50
-
51
- CREATE INDEX IF NOT EXISTS idx_interaction_logs_session
52
- ON interaction_logs(session_id, created_at DESC);
53
- CREATE INDEX IF NOT EXISTS idx_interaction_logs_event_type
54
- ON interaction_logs(event_type, created_at DESC);
37
+ db.exec(`
38
+ CREATE TABLE IF NOT EXISTS interaction_logs (
39
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
40
+ session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
41
+ event_type TEXT NOT NULL,
42
+ event_subtype TEXT,
43
+ model TEXT,
44
+ duration_ms INTEGER,
45
+ input_tokens INTEGER,
46
+ output_tokens INTEGER,
47
+ metadata_json TEXT,
48
+ created_at TEXT NOT NULL
49
+ ) STRICT;
50
+
51
+ CREATE INDEX IF NOT EXISTS idx_interaction_logs_session
52
+ ON interaction_logs(session_id, created_at DESC);
53
+ CREATE INDEX IF NOT EXISTS idx_interaction_logs_event_type
54
+ ON interaction_logs(event_type, created_at DESC);
55
55
  `);
56
56
  db.pragma("user_version = 5");
57
57
  }
@@ -100,113 +100,113 @@ export function applyMigrations(db) {
100
100
  migrate();
101
101
  }
102
102
  function createInitialSchema(db) {
103
- db.exec(`
104
- CREATE TABLE IF NOT EXISTS workspaces (
105
- id TEXT PRIMARY KEY,
106
- scope_key TEXT NOT NULL UNIQUE,
107
- canonical_path TEXT NOT NULL,
108
- git_root TEXT,
109
- display_name TEXT NOT NULL,
110
- last_seen_at TEXT NOT NULL
111
- ) STRICT;
112
-
113
- CREATE TABLE IF NOT EXISTS sessions (
114
- id TEXT PRIMARY KEY,
115
- workspace_id TEXT NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
116
- parent_session_id TEXT REFERENCES sessions(id) ON DELETE SET NULL,
117
- title TEXT,
118
- model TEXT NOT NULL,
119
- mode TEXT NOT NULL,
120
- cwd_at_start TEXT NOT NULL,
121
- cwd_last TEXT NOT NULL,
122
- status TEXT NOT NULL,
123
- created_at TEXT NOT NULL,
124
- updated_at TEXT NOT NULL
125
- ) STRICT;
126
-
127
- CREATE TABLE IF NOT EXISTS messages (
128
- session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
129
- seq INTEGER NOT NULL,
130
- role TEXT NOT NULL,
131
- message_json TEXT NOT NULL,
132
- created_at TEXT NOT NULL,
133
- status TEXT,
134
- PRIMARY KEY (session_id, seq)
135
- ) STRICT;
136
-
137
- CREATE TABLE IF NOT EXISTS tool_calls (
138
- id INTEGER PRIMARY KEY AUTOINCREMENT,
139
- session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
140
- message_seq INTEGER NOT NULL,
141
- tool_call_id TEXT NOT NULL,
142
- tool_name TEXT NOT NULL,
143
- args_json TEXT NOT NULL,
144
- status TEXT NOT NULL,
145
- started_at TEXT NOT NULL,
146
- completed_at TEXT,
147
- UNIQUE(session_id, tool_call_id)
148
- ) STRICT;
149
-
150
- CREATE TABLE IF NOT EXISTS tool_results (
151
- id INTEGER PRIMARY KEY AUTOINCREMENT,
152
- tool_call_row_id INTEGER NOT NULL REFERENCES tool_calls(id) ON DELETE CASCADE,
153
- output_kind TEXT NOT NULL,
154
- output_json TEXT NOT NULL,
155
- success INTEGER NOT NULL,
156
- created_at TEXT NOT NULL
157
- ) STRICT;
158
-
159
- CREATE TABLE IF NOT EXISTS usage_events (
160
- id INTEGER PRIMARY KEY AUTOINCREMENT,
161
- session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
162
- message_seq INTEGER,
163
- source TEXT NOT NULL,
164
- model TEXT NOT NULL,
165
- input_tokens INTEGER NOT NULL DEFAULT 0,
166
- output_tokens INTEGER NOT NULL DEFAULT 0,
167
- total_tokens INTEGER NOT NULL DEFAULT 0,
168
- cost_micros INTEGER NOT NULL DEFAULT 0,
169
- created_at TEXT NOT NULL,
170
- cache_read_tokens INTEGER NOT NULL DEFAULT 0,
171
- cache_creation_tokens INTEGER NOT NULL DEFAULT 0
172
- ) STRICT;
173
-
174
- CREATE TABLE IF NOT EXISTS compactions (
175
- id INTEGER PRIMARY KEY AUTOINCREMENT,
176
- session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
177
- first_kept_seq INTEGER NOT NULL,
178
- summary TEXT NOT NULL,
179
- tokens_before INTEGER NOT NULL DEFAULT 0,
180
- created_at TEXT NOT NULL
181
- ) STRICT;
182
-
183
- CREATE INDEX IF NOT EXISTS idx_sessions_workspace_updated
184
- ON sessions(workspace_id, updated_at DESC);
185
- CREATE INDEX IF NOT EXISTS idx_sessions_parent_id
186
- ON sessions(parent_session_id);
187
- CREATE INDEX IF NOT EXISTS idx_messages_session_seq
188
- ON messages(session_id, seq);
189
- CREATE INDEX IF NOT EXISTS idx_tool_calls_session_seq
190
- ON tool_calls(session_id, message_seq);
191
- CREATE INDEX IF NOT EXISTS idx_usage_events_session_created
192
- ON usage_events(session_id, created_at DESC);
193
- CREATE INDEX IF NOT EXISTS idx_compactions_session_created
194
- ON compactions(session_id, created_at DESC);
103
+ db.exec(`
104
+ CREATE TABLE IF NOT EXISTS workspaces (
105
+ id TEXT PRIMARY KEY,
106
+ scope_key TEXT NOT NULL UNIQUE,
107
+ canonical_path TEXT NOT NULL,
108
+ git_root TEXT,
109
+ display_name TEXT NOT NULL,
110
+ last_seen_at TEXT NOT NULL
111
+ ) STRICT;
112
+
113
+ CREATE TABLE IF NOT EXISTS sessions (
114
+ id TEXT PRIMARY KEY,
115
+ workspace_id TEXT NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
116
+ parent_session_id TEXT REFERENCES sessions(id) ON DELETE SET NULL,
117
+ title TEXT,
118
+ model TEXT NOT NULL,
119
+ mode TEXT NOT NULL,
120
+ cwd_at_start TEXT NOT NULL,
121
+ cwd_last TEXT NOT NULL,
122
+ status TEXT NOT NULL,
123
+ created_at TEXT NOT NULL,
124
+ updated_at TEXT NOT NULL
125
+ ) STRICT;
126
+
127
+ CREATE TABLE IF NOT EXISTS messages (
128
+ session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
129
+ seq INTEGER NOT NULL,
130
+ role TEXT NOT NULL,
131
+ message_json TEXT NOT NULL,
132
+ created_at TEXT NOT NULL,
133
+ status TEXT,
134
+ PRIMARY KEY (session_id, seq)
135
+ ) STRICT;
136
+
137
+ CREATE TABLE IF NOT EXISTS tool_calls (
138
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
139
+ session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
140
+ message_seq INTEGER NOT NULL,
141
+ tool_call_id TEXT NOT NULL,
142
+ tool_name TEXT NOT NULL,
143
+ args_json TEXT NOT NULL,
144
+ status TEXT NOT NULL,
145
+ started_at TEXT NOT NULL,
146
+ completed_at TEXT,
147
+ UNIQUE(session_id, tool_call_id)
148
+ ) STRICT;
149
+
150
+ CREATE TABLE IF NOT EXISTS tool_results (
151
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
152
+ tool_call_row_id INTEGER NOT NULL REFERENCES tool_calls(id) ON DELETE CASCADE,
153
+ output_kind TEXT NOT NULL,
154
+ output_json TEXT NOT NULL,
155
+ success INTEGER NOT NULL,
156
+ created_at TEXT NOT NULL
157
+ ) STRICT;
158
+
159
+ CREATE TABLE IF NOT EXISTS usage_events (
160
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
161
+ session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
162
+ message_seq INTEGER,
163
+ source TEXT NOT NULL,
164
+ model TEXT NOT NULL,
165
+ input_tokens INTEGER NOT NULL DEFAULT 0,
166
+ output_tokens INTEGER NOT NULL DEFAULT 0,
167
+ total_tokens INTEGER NOT NULL DEFAULT 0,
168
+ cost_micros INTEGER NOT NULL DEFAULT 0,
169
+ created_at TEXT NOT NULL,
170
+ cache_read_tokens INTEGER NOT NULL DEFAULT 0,
171
+ cache_creation_tokens INTEGER NOT NULL DEFAULT 0
172
+ ) STRICT;
173
+
174
+ CREATE TABLE IF NOT EXISTS compactions (
175
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
176
+ session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
177
+ first_kept_seq INTEGER NOT NULL,
178
+ summary TEXT NOT NULL,
179
+ tokens_before INTEGER NOT NULL DEFAULT 0,
180
+ created_at TEXT NOT NULL
181
+ ) STRICT;
182
+
183
+ CREATE INDEX IF NOT EXISTS idx_sessions_workspace_updated
184
+ ON sessions(workspace_id, updated_at DESC);
185
+ CREATE INDEX IF NOT EXISTS idx_sessions_parent_id
186
+ ON sessions(parent_session_id);
187
+ CREATE INDEX IF NOT EXISTS idx_messages_session_seq
188
+ ON messages(session_id, seq);
189
+ CREATE INDEX IF NOT EXISTS idx_tool_calls_session_seq
190
+ ON tool_calls(session_id, message_seq);
191
+ CREATE INDEX IF NOT EXISTS idx_usage_events_session_created
192
+ ON usage_events(session_id, created_at DESC);
193
+ CREATE INDEX IF NOT EXISTS idx_compactions_session_created
194
+ ON compactions(session_id, created_at DESC);
195
195
  `);
196
196
  }
197
197
  function createCompactionSchema(db) {
198
- db.exec(`
199
- CREATE TABLE IF NOT EXISTS compactions (
200
- id INTEGER PRIMARY KEY AUTOINCREMENT,
201
- session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
202
- first_kept_seq INTEGER NOT NULL,
203
- summary TEXT NOT NULL,
204
- tokens_before INTEGER NOT NULL DEFAULT 0,
205
- created_at TEXT NOT NULL
206
- ) STRICT;
207
-
208
- CREATE INDEX IF NOT EXISTS idx_compactions_session_created
209
- ON compactions(session_id, created_at DESC);
198
+ db.exec(`
199
+ CREATE TABLE IF NOT EXISTS compactions (
200
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
201
+ session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
202
+ first_kept_seq INTEGER NOT NULL,
203
+ summary TEXT NOT NULL,
204
+ tokens_before INTEGER NOT NULL DEFAULT 0,
205
+ created_at TEXT NOT NULL
206
+ ) STRICT;
207
+
208
+ CREATE INDEX IF NOT EXISTS idx_compactions_session_created
209
+ ON compactions(session_id, created_at DESC);
210
210
  `);
211
211
  }
212
212
  //# sourceMappingURL=migrations.js.map
@@ -70,8 +70,8 @@ function parseCounts(json) {
70
70
  export function selectSessionExperience(sessionId) {
71
71
  try {
72
72
  const row = getDatabase()
73
- .prepare(`SELECT metadata_json FROM interaction_logs
74
- WHERE session_id = ? AND event_type = ?
73
+ .prepare(`SELECT metadata_json FROM interaction_logs
74
+ WHERE session_id = ? AND event_type = ?
75
75
  ORDER BY created_at DESC, id DESC LIMIT 1`)
76
76
  .get(sessionId, EVENT_TYPE);
77
77
  return parseCounts(row?.metadata_json ?? null);
@@ -150,8 +150,8 @@ export function computeExperienceAggregate(rows, limit = 100) {
150
150
  export function aggregateSessionExperience(limit = 100) {
151
151
  try {
152
152
  const rows = getDatabase()
153
- .prepare(`SELECT session_id, metadata_json, created_at FROM interaction_logs
154
- WHERE event_type = ?
153
+ .prepare(`SELECT session_id, metadata_json, created_at FROM interaction_logs
154
+ WHERE event_type = ?
155
155
  ORDER BY created_at DESC, id DESC`)
156
156
  .all(EVENT_TYPE);
157
157
  return computeExperienceAggregate(rows, limit);
@@ -43,12 +43,12 @@ export class SessionStore {
43
43
  const now = new Date().toISOString();
44
44
  const id = createSessionId();
45
45
  const db = getDatabase();
46
- db.prepare(`
47
- INSERT INTO sessions (
48
- id, workspace_id, title, model, mode, cwd_at_start, cwd_last, status, created_at, updated_at
49
- ) VALUES (
50
- @id, @workspace_id, NULL, @model, @mode, @cwd_at_start, @cwd_last, 'active', @created_at, @updated_at
51
- )
46
+ db.prepare(`
47
+ INSERT INTO sessions (
48
+ id, workspace_id, title, model, mode, cwd_at_start, cwd_last, status, created_at, updated_at
49
+ ) VALUES (
50
+ @id, @workspace_id, NULL, @model, @mode, @cwd_at_start, @cwd_last, 'active', @created_at, @updated_at
51
+ )
52
52
  `).run({
53
53
  id,
54
54
  workspace_id: this.workspace.id,
@@ -73,35 +73,35 @@ export class SessionStore {
73
73
  */
74
74
  listRecentSessions(limit = 20) {
75
75
  const rows = getDatabase()
76
- .prepare(`
77
- SELECT s.id, s.workspace_id, s.title, s.model, s.mode, s.cwd_at_start, s.cwd_last, s.status, s.created_at, s.updated_at
78
- FROM sessions s
79
- WHERE s.workspace_id = ?
80
- AND EXISTS (SELECT 1 FROM messages m WHERE m.session_id = s.id)
81
- ORDER BY s.updated_at DESC
82
- LIMIT ?
76
+ .prepare(`
77
+ SELECT s.id, s.workspace_id, s.title, s.model, s.mode, s.cwd_at_start, s.cwd_last, s.status, s.created_at, s.updated_at
78
+ FROM sessions s
79
+ WHERE s.workspace_id = ?
80
+ AND EXISTS (SELECT 1 FROM messages m WHERE m.session_id = s.id)
81
+ ORDER BY s.updated_at DESC
82
+ LIMIT ?
83
83
  `)
84
84
  .all(this.workspace.id, limit);
85
85
  return rows.map(toSessionInfo);
86
86
  }
87
87
  getLatestSession() {
88
88
  const row = getDatabase()
89
- .prepare(`
90
- SELECT id, workspace_id, title, model, mode, cwd_at_start, cwd_last, status, created_at, updated_at
91
- FROM sessions
92
- WHERE workspace_id = ?
93
- ORDER BY updated_at DESC
94
- LIMIT 1
89
+ .prepare(`
90
+ SELECT id, workspace_id, title, model, mode, cwd_at_start, cwd_last, status, created_at, updated_at
91
+ FROM sessions
92
+ WHERE workspace_id = ?
93
+ ORDER BY updated_at DESC
94
+ LIMIT 1
95
95
  `)
96
96
  .get(this.workspace.id);
97
97
  return row ? toSessionInfo(row) : null;
98
98
  }
99
99
  getSessionById(id) {
100
100
  const row = getDatabase()
101
- .prepare(`
102
- SELECT id, workspace_id, title, model, mode, cwd_at_start, cwd_last, status, created_at, updated_at
103
- FROM sessions
104
- WHERE id = ?
101
+ .prepare(`
102
+ SELECT id, workspace_id, title, model, mode, cwd_at_start, cwd_last, status, created_at, updated_at
103
+ FROM sessions
104
+ WHERE id = ?
105
105
  `)
106
106
  .get(id);
107
107
  return row ? toSessionInfo(row) : null;
@@ -116,49 +116,49 @@ export class SessionStore {
116
116
  setStatus(id, status) {
117
117
  const now = new Date().toISOString();
118
118
  getDatabase()
119
- .prepare(`
120
- UPDATE sessions
121
- SET status = ?, updated_at = ?
122
- WHERE id = ?
119
+ .prepare(`
120
+ UPDATE sessions
121
+ SET status = ?, updated_at = ?
122
+ WHERE id = ?
123
123
  `)
124
124
  .run(status, now, id);
125
125
  }
126
126
  setTitle(id, title) {
127
127
  const now = new Date().toISOString();
128
128
  getDatabase()
129
- .prepare(`
130
- UPDATE sessions
131
- SET title = ?, updated_at = ?
132
- WHERE id = ?
129
+ .prepare(`
130
+ UPDATE sessions
131
+ SET title = ?, updated_at = ?
132
+ WHERE id = ?
133
133
  `)
134
134
  .run(title, now, id);
135
135
  }
136
136
  setModel(id, model) {
137
137
  const now = new Date().toISOString();
138
138
  getDatabase()
139
- .prepare(`
140
- UPDATE sessions
141
- SET model = ?, updated_at = ?
142
- WHERE id = ?
139
+ .prepare(`
140
+ UPDATE sessions
141
+ SET model = ?, updated_at = ?
142
+ WHERE id = ?
143
143
  `)
144
144
  .run(model, now, id);
145
145
  }
146
146
  setMode(id, mode) {
147
147
  const now = new Date().toISOString();
148
148
  getDatabase()
149
- .prepare(`
150
- UPDATE sessions
151
- SET mode = ?, updated_at = ?
152
- WHERE id = ?
149
+ .prepare(`
150
+ UPDATE sessions
151
+ SET mode = ?, updated_at = ?
152
+ WHERE id = ?
153
153
  `)
154
154
  .run(mode, now, id);
155
155
  }
156
156
  touchSession(id, cwd) {
157
157
  getDatabase()
158
- .prepare(`
159
- UPDATE sessions
160
- SET cwd_last = ?, updated_at = ?
161
- WHERE id = ?
158
+ .prepare(`
159
+ UPDATE sessions
160
+ SET cwd_last = ?, updated_at = ?
161
+ WHERE id = ?
162
162
  `)
163
163
  .run(cwd, new Date().toISOString(), id);
164
164
  }